2019-08-08 21:31:29 -07:00
|
|
|
/*
|
|
|
|
|
|
|
|
Copyright 2019, The Regents of the University of California.
|
|
|
|
All rights reserved.
|
|
|
|
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
|
|
|
|
1. Redistributions of source code must retain the above copyright notice,
|
|
|
|
this list of conditions and the following disclaimer.
|
|
|
|
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
|
|
this list of conditions and the following disclaimer in the documentation
|
|
|
|
and/or other materials provided with the distribution.
|
|
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
|
|
|
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
|
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
|
|
|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
|
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
|
|
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
|
|
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
|
|
OF SUCH DAMAGE.
|
|
|
|
|
|
|
|
The views and conclusions contained in the software and documentation are those
|
|
|
|
of the authors and should not be interpreted as representing official policies,
|
|
|
|
either expressed or implied, of The Regents of the University of California.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "mqnic.h"
|
|
|
|
|
2021-01-13 20:09:09 -08:00
|
|
|
static void mqnic_i2c_set_scl(void *data, int state)
|
2019-08-08 21:31:29 -07:00
|
|
|
{
|
2021-02-01 20:10:48 -08:00
|
|
|
struct mqnic_i2c_bus *bus = data;
|
2019-08-08 21:31:29 -07:00
|
|
|
|
|
|
|
if (state)
|
|
|
|
{
|
2021-02-01 20:10:48 -08:00
|
|
|
iowrite32(ioread32(bus->scl_out_reg) | bus->scl_out_mask, bus->scl_out_reg);
|
2019-08-08 21:31:29 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-02-01 20:10:48 -08:00
|
|
|
iowrite32(ioread32(bus->scl_out_reg) & ~bus->scl_out_mask, bus->scl_out_reg);
|
2019-08-08 21:31:29 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-13 20:09:09 -08:00
|
|
|
static void mqnic_i2c_set_sda(void *data, int state)
|
2019-08-08 21:31:29 -07:00
|
|
|
{
|
2021-02-01 20:10:48 -08:00
|
|
|
struct mqnic_i2c_bus *bus = data;
|
2019-08-08 21:31:29 -07:00
|
|
|
|
|
|
|
if (state)
|
|
|
|
{
|
2021-02-01 20:10:48 -08:00
|
|
|
iowrite32(ioread32(bus->sda_out_reg) | bus->sda_out_mask, bus->sda_out_reg);
|
2019-08-08 21:31:29 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-02-01 20:10:48 -08:00
|
|
|
iowrite32(ioread32(bus->sda_out_reg) & ~bus->sda_out_mask, bus->sda_out_reg);
|
2019-08-08 21:31:29 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-13 20:09:09 -08:00
|
|
|
static int mqnic_i2c_get_scl(void *data)
|
2019-08-08 21:31:29 -07:00
|
|
|
{
|
2021-02-01 20:10:48 -08:00
|
|
|
struct mqnic_i2c_bus *bus = data;
|
2019-08-08 21:31:29 -07:00
|
|
|
|
2021-02-01 20:10:48 -08:00
|
|
|
return !!(ioread32(bus->scl_in_reg) & bus->scl_in_mask);
|
2019-08-08 21:31:29 -07:00
|
|
|
}
|
|
|
|
|
2021-01-13 20:09:09 -08:00
|
|
|
static int mqnic_i2c_get_sda(void *data)
|
2019-08-08 21:31:29 -07:00
|
|
|
{
|
2021-02-01 20:10:48 -08:00
|
|
|
struct mqnic_i2c_bus *bus = data;
|
2019-08-08 21:31:29 -07:00
|
|
|
|
2021-02-01 20:10:48 -08:00
|
|
|
return !!(ioread32(bus->sda_in_reg) & bus->sda_in_mask);
|
2019-08-08 21:31:29 -07:00
|
|
|
}
|
|
|
|
|
2021-02-01 20:10:48 -08:00
|
|
|
struct mqnic_i2c_bus *mqnic_i2c_bus_create(struct mqnic_dev *mqnic, u8 __iomem *reg)
|
2020-09-19 17:00:39 -07:00
|
|
|
{
|
2021-02-01 20:10:48 -08:00
|
|
|
struct mqnic_i2c_bus *bus;
|
2020-09-19 17:00:39 -07:00
|
|
|
struct i2c_algo_bit_data *algo;
|
|
|
|
struct i2c_adapter *adapter;
|
|
|
|
|
2021-02-01 20:10:48 -08:00
|
|
|
if (!reg)
|
2020-09-19 17:00:39 -07:00
|
|
|
return NULL;
|
|
|
|
|
2021-02-01 20:10:48 -08:00
|
|
|
bus = kzalloc(sizeof(*bus), GFP_KERNEL);
|
2020-09-19 17:00:39 -07:00
|
|
|
|
2021-02-01 20:10:48 -08:00
|
|
|
if (!bus)
|
|
|
|
return NULL;
|
2020-09-19 17:00:39 -07:00
|
|
|
|
2021-02-01 20:10:48 -08:00
|
|
|
// set private data
|
|
|
|
bus->mqnic = mqnic;
|
|
|
|
bus->scl_in_reg = reg;
|
|
|
|
bus->scl_out_reg = reg;
|
|
|
|
bus->sda_in_reg = reg;
|
|
|
|
bus->sda_out_reg = reg;
|
|
|
|
bus->scl_in_mask = MQNIC_REG_GPIO_I2C_SCL_IN;
|
|
|
|
bus->scl_out_mask = MQNIC_REG_GPIO_I2C_SCL_OUT;
|
|
|
|
bus->sda_in_mask = MQNIC_REG_GPIO_I2C_SDA_IN;
|
|
|
|
bus->sda_out_mask = MQNIC_REG_GPIO_I2C_SDA_OUT;
|
|
|
|
|
|
|
|
// bit-bang algorithm setup
|
|
|
|
algo = &bus->algo;
|
|
|
|
algo->udelay = 5;
|
|
|
|
algo->timeout = usecs_to_jiffies(2000);;
|
|
|
|
algo->setsda = mqnic_i2c_set_sda;
|
|
|
|
algo->setscl = mqnic_i2c_set_scl;
|
|
|
|
algo->getsda = mqnic_i2c_get_sda;
|
|
|
|
algo->getscl = mqnic_i2c_get_scl;
|
|
|
|
algo->data = bus;
|
|
|
|
|
|
|
|
// adapter setup
|
|
|
|
adapter = &bus->adapter;
|
2020-09-19 17:00:39 -07:00
|
|
|
adapter->owner = THIS_MODULE;
|
|
|
|
adapter->algo_data = algo;
|
|
|
|
adapter->dev.parent = mqnic->dev;
|
|
|
|
snprintf(adapter->name, sizeof(adapter->name), "%s I2C%d", mqnic->name, mqnic->i2c_adapter_count);
|
|
|
|
|
|
|
|
if (i2c_bit_add_bus(adapter))
|
|
|
|
{
|
|
|
|
dev_err(mqnic->dev, "Failed to register I2C adapter");
|
2021-02-01 20:10:48 -08:00
|
|
|
goto err_free_bus;
|
2020-09-19 17:00:39 -07:00
|
|
|
}
|
|
|
|
|
2021-02-01 20:10:48 -08:00
|
|
|
list_add_tail(&bus->head, &mqnic->i2c_bus);
|
|
|
|
|
2020-09-19 17:00:39 -07:00
|
|
|
mqnic->i2c_adapter_count++;
|
|
|
|
|
2021-02-01 20:10:48 -08:00
|
|
|
return bus;
|
|
|
|
|
|
|
|
err_free_bus:
|
|
|
|
kfree(bus);
|
|
|
|
return NULL;
|
2020-09-19 17:00:39 -07:00
|
|
|
}
|
|
|
|
|
2021-02-01 20:10:48 -08:00
|
|
|
struct i2c_adapter *mqnic_i2c_adapter_create(struct mqnic_dev *mqnic, u8 __iomem *reg)
|
2019-08-08 21:31:29 -07:00
|
|
|
{
|
2021-02-01 20:10:48 -08:00
|
|
|
struct mqnic_i2c_bus *bus = mqnic_i2c_bus_create(mqnic, reg);
|
2020-09-19 17:21:36 -07:00
|
|
|
|
2021-02-01 20:10:48 -08:00
|
|
|
if (!bus)
|
|
|
|
return NULL;
|
2020-09-19 17:21:36 -07:00
|
|
|
|
2021-02-01 20:10:48 -08:00
|
|
|
return &bus->adapter;
|
|
|
|
}
|
2020-09-19 17:21:36 -07:00
|
|
|
|
2021-02-01 20:10:48 -08:00
|
|
|
void mqnic_i2c_bus_release(struct mqnic_i2c_bus *bus)
|
|
|
|
{
|
|
|
|
struct mqnic_dev *mqnic;
|
2019-08-08 21:31:29 -07:00
|
|
|
|
2021-02-01 20:10:48 -08:00
|
|
|
if (!bus)
|
|
|
|
return;
|
2020-09-25 23:14:22 -07:00
|
|
|
|
2021-02-01 20:10:48 -08:00
|
|
|
mqnic = bus->mqnic;
|
2020-09-25 23:14:22 -07:00
|
|
|
|
2021-02-01 20:10:48 -08:00
|
|
|
mqnic->i2c_adapter_count--;
|
2020-09-25 23:14:22 -07:00
|
|
|
|
2021-02-01 20:10:48 -08:00
|
|
|
i2c_del_adapter(&bus->adapter);
|
|
|
|
list_del(&bus->head);
|
|
|
|
kfree(bus);
|
|
|
|
}
|
2020-09-25 23:14:22 -07:00
|
|
|
|
2021-02-01 20:10:48 -08:00
|
|
|
void mqnic_i2c_adapter_release(struct i2c_adapter *adapter)
|
|
|
|
{
|
|
|
|
struct mqnic_i2c_bus *bus;
|
2021-01-31 22:25:24 -08:00
|
|
|
|
2021-02-01 20:10:48 -08:00
|
|
|
if (!adapter)
|
|
|
|
return;
|
|
|
|
|
|
|
|
bus = container_of(adapter, struct mqnic_i2c_bus, adapter);
|
|
|
|
mqnic_i2c_bus_release(bus);
|
2019-08-08 21:31:29 -07:00
|
|
|
}
|
|
|
|
|
2021-02-01 20:10:48 -08:00
|
|
|
int mqnic_i2c_init(struct mqnic_dev *mqnic)
|
2019-08-08 21:31:29 -07:00
|
|
|
{
|
2021-02-01 20:10:48 -08:00
|
|
|
INIT_LIST_HEAD(&mqnic->i2c_bus);
|
2020-09-19 17:21:36 -07:00
|
|
|
|
2021-02-01 20:10:48 -08:00
|
|
|
return 0;
|
|
|
|
}
|
2019-08-08 21:31:29 -07:00
|
|
|
|
2021-02-01 20:10:48 -08:00
|
|
|
void mqnic_i2c_deinit(struct mqnic_dev *mqnic)
|
|
|
|
{
|
|
|
|
while (!list_empty(&mqnic->i2c_bus))
|
2019-08-08 21:31:29 -07:00
|
|
|
{
|
2021-02-01 20:10:48 -08:00
|
|
|
struct mqnic_i2c_bus *bus = list_first_entry(&mqnic->i2c_bus, typeof(*bus), head);
|
|
|
|
mqnic_i2c_bus_release(bus);
|
2020-09-19 17:00:39 -07:00
|
|
|
}
|
2019-08-08 21:31:29 -07:00
|
|
|
}
|