#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include <linux/slab.h>
static struct lock i2c_lock;
LOCK_SYSINIT(i2c_lock, &i2c_lock, "i2cl", LK_CANRECURSE);
static void i2c_default_lock_bus(struct i2c_adapter *, unsigned int);
static int i2c_default_trylock_bus(struct i2c_adapter *, unsigned int);
static void i2c_default_unlock_bus(struct i2c_adapter *, unsigned int);
static const struct i2c_lock_operations i2c_default_lock_ops = {
.lock_bus = i2c_default_lock_bus,
.trylock_bus = i2c_default_trylock_bus,
.unlock_bus = i2c_default_unlock_bus,
};
int
i2c_add_adapter(struct i2c_adapter *adapter)
{
if (!adapter->lock_ops)
adapter->lock_ops = &i2c_default_lock_ops;
return 0;
}
void
i2c_del_adapter(struct i2c_adapter *adapter)
{
}
int
__i2c_transfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
{
uint64_t start_ticks;
int ret, tries = 0;
start_ticks = ticks;
do {
ret = adapter->algo->master_xfer(adapter, msgs, num);
if (ticks > start_ticks + adapter->timeout)
break;
if (ret != -EAGAIN)
break;
tries++;
} while (tries < adapter->retries);
return ret;
}
int
i2c_transfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
{
int ret;
if (adapter->algo->master_xfer == NULL)
return -EOPNOTSUPP;
adapter->lock_ops->lock_bus(adapter, I2C_LOCK_SEGMENT);
ret = __i2c_transfer(adapter, msgs, num);
adapter->lock_ops->unlock_bus(adapter, I2C_LOCK_SEGMENT);
return ret;
}
static int
bit_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
{
return 0;
}
static uint32_t
bit_func(struct i2c_adapter *adap)
{
return (I2C_FUNC_I2C | I2C_FUNC_NOSTART | I2C_FUNC_SMBUS_EMUL |
I2C_FUNC_SMBUS_READ_BLOCK_DATA |
I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING);
}
const struct i2c_algorithm i2c_bit_algo = {
.master_xfer = bit_xfer,
.functionality = bit_func,
};
int
i2c_bit_add_bus(struct i2c_adapter *adapter)
{
adapter->algo = &i2c_bit_algo;
adapter->retries = 2;
return 0;
}
struct i2c_client *
i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
{
struct i2c_client *client;
client = kzalloc(sizeof(*client), GFP_KERNEL);
if (client == NULL)
goto done;
client->adapter = adap;
strlcpy(client->name, info->type, sizeof(client->name));
client->addr = info->addr;
done:
return client;
}
static void
i2c_default_lock_bus(struct i2c_adapter *adapter, unsigned int flags)
{
lockmgr(&i2c_lock, LK_EXCLUSIVE);
}
static int
i2c_default_trylock_bus(struct i2c_adapter *adapter, unsigned int flags)
{
return mutex_trylock(&i2c_lock);
}
static void
i2c_default_unlock_bus(struct i2c_adapter *adapter, unsigned int flags)
{
lockmgr(&i2c_lock, LK_RELEASE);
}