1
0
mirror of https://github.com/corundum/corundum.git synced 2025-01-16 08:12:53 +08:00
corundum/modules/mqnic/mqnic_i2c.c
Alex Forencich 448fa8eb4c Use SPDX
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2023-06-26 11:44:57 -07:00

157 lines
3.4 KiB
C

// SPDX-License-Identifier: BSD-2-Clause-Views
/*
* Copyright (c) 2019-2023 The Regents of the University of California
*/
#include "mqnic.h"
static void mqnic_i2c_set_scl(void *data, int state)
{
struct mqnic_i2c_bus *bus = data;
if (state)
iowrite32(ioread32(bus->scl_out_reg) | bus->scl_out_mask, bus->scl_out_reg);
else
iowrite32(ioread32(bus->scl_out_reg) & ~bus->scl_out_mask, bus->scl_out_reg);
}
static void mqnic_i2c_set_sda(void *data, int state)
{
struct mqnic_i2c_bus *bus = data;
if (state)
iowrite32(ioread32(bus->sda_out_reg) | bus->sda_out_mask, bus->sda_out_reg);
else
iowrite32(ioread32(bus->sda_out_reg) & ~bus->sda_out_mask, bus->sda_out_reg);
}
static int mqnic_i2c_get_scl(void *data)
{
struct mqnic_i2c_bus *bus = data;
return !!(ioread32(bus->scl_in_reg) & bus->scl_in_mask);
}
static int mqnic_i2c_get_sda(void *data)
{
struct mqnic_i2c_bus *bus = data;
return !!(ioread32(bus->sda_in_reg) & bus->sda_in_mask);
}
struct mqnic_i2c_bus *mqnic_i2c_bus_create(struct mqnic_dev *mqnic, int index)
{
struct mqnic_i2c_bus *bus;
struct i2c_algo_bit_data *algo;
struct i2c_adapter *adapter;
struct mqnic_reg_block *rb;
rb = mqnic_find_reg_block(mqnic->rb_list, MQNIC_RB_I2C_TYPE, MQNIC_RB_I2C_VER, index);
if (!rb)
return NULL;
bus = kzalloc(sizeof(*bus), GFP_KERNEL);
if (!bus)
return NULL;
// set private data
bus->mqnic = mqnic;
bus->scl_in_reg = rb->regs + MQNIC_RB_I2C_REG_CTRL;
bus->scl_out_reg = rb->regs + MQNIC_RB_I2C_REG_CTRL;
bus->sda_in_reg = rb->regs + MQNIC_RB_I2C_REG_CTRL;
bus->sda_out_reg = rb->regs + MQNIC_RB_I2C_REG_CTRL;
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;
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");
goto err_free_bus;
}
list_add_tail(&bus->head, &mqnic->i2c_bus);
mqnic->i2c_adapter_count++;
return bus;
err_free_bus:
kfree(bus);
return NULL;
}
struct i2c_adapter *mqnic_i2c_adapter_create(struct mqnic_dev *mqnic, int index)
{
struct mqnic_i2c_bus *bus = mqnic_i2c_bus_create(mqnic, index);
if (!bus)
return NULL;
return &bus->adapter;
}
void mqnic_i2c_bus_release(struct mqnic_i2c_bus *bus)
{
struct mqnic_dev *mqnic;
if (!bus)
return;
mqnic = bus->mqnic;
mqnic->i2c_adapter_count--;
i2c_del_adapter(&bus->adapter);
list_del(&bus->head);
kfree(bus);
}
void mqnic_i2c_adapter_release(struct i2c_adapter *adapter)
{
struct mqnic_i2c_bus *bus;
if (!adapter)
return;
bus = container_of(adapter, struct mqnic_i2c_bus, adapter);
mqnic_i2c_bus_release(bus);
}
int mqnic_i2c_init(struct mqnic_dev *mqnic)
{
INIT_LIST_HEAD(&mqnic->i2c_bus);
return 0;
}
void mqnic_i2c_deinit(struct mqnic_dev *mqnic)
{
struct mqnic_i2c_bus *bus;
while (!list_empty(&mqnic->i2c_bus)) {
bus = list_first_entry(&mqnic->i2c_bus, typeof(*bus), head);
mqnic_i2c_bus_release(bus);
}
}