19f4ca867SFrançois Tigeot /* 2fabf443aSFrançois Tigeot * Copyright (c) 2016-2019 François Tigeot <ftigeot@wolfpond.org> 39f4ca867SFrançois Tigeot * All rights reserved. 49f4ca867SFrançois Tigeot * 59f4ca867SFrançois Tigeot * Redistribution and use in source and binary forms, with or without 69f4ca867SFrançois Tigeot * modification, are permitted provided that the following conditions 79f4ca867SFrançois Tigeot * are met: 89f4ca867SFrançois Tigeot * 1. Redistributions of source code must retain the above copyright 99f4ca867SFrançois Tigeot * notice unmodified, this list of conditions, and the following 109f4ca867SFrançois Tigeot * disclaimer. 119f4ca867SFrançois Tigeot * 2. Redistributions in binary form must reproduce the above copyright 129f4ca867SFrançois Tigeot * notice, this list of conditions and the following disclaimer in the 139f4ca867SFrançois Tigeot * documentation and/or other materials provided with the distribution. 149f4ca867SFrançois Tigeot * 159f4ca867SFrançois Tigeot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 169f4ca867SFrançois Tigeot * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 179f4ca867SFrançois Tigeot * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 189f4ca867SFrançois Tigeot * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 199f4ca867SFrançois Tigeot * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 209f4ca867SFrançois Tigeot * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 219f4ca867SFrançois Tigeot * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 229f4ca867SFrançois Tigeot * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 239f4ca867SFrançois Tigeot * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 249f4ca867SFrançois Tigeot * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 259f4ca867SFrançois Tigeot */ 269f4ca867SFrançois Tigeot 279f4ca867SFrançois Tigeot #include <linux/i2c.h> 289f4ca867SFrançois Tigeot #include <linux/i2c-algo-bit.h> 299f4ca867SFrançois Tigeot 307d061d0fSFrançois Tigeot #include <linux/slab.h> 317d061d0fSFrançois Tigeot 329f4ca867SFrançois Tigeot static struct lock i2c_lock; 339f4ca867SFrançois Tigeot LOCK_SYSINIT(i2c_lock, &i2c_lock, "i2cl", LK_CANRECURSE); 349f4ca867SFrançois Tigeot 35*1dedbd3bSFrançois Tigeot static void i2c_default_lock_bus(struct i2c_adapter *, unsigned int); 36*1dedbd3bSFrançois Tigeot static int i2c_default_trylock_bus(struct i2c_adapter *, unsigned int); 37*1dedbd3bSFrançois Tigeot static void i2c_default_unlock_bus(struct i2c_adapter *, unsigned int); 38*1dedbd3bSFrançois Tigeot 39*1dedbd3bSFrançois Tigeot static const struct i2c_lock_operations i2c_default_lock_ops = { 40*1dedbd3bSFrançois Tigeot .lock_bus = i2c_default_lock_bus, 41*1dedbd3bSFrançois Tigeot .trylock_bus = i2c_default_trylock_bus, 42*1dedbd3bSFrançois Tigeot .unlock_bus = i2c_default_unlock_bus, 43*1dedbd3bSFrançois Tigeot }; 44*1dedbd3bSFrançois Tigeot 459f4ca867SFrançois Tigeot int 469f4ca867SFrançois Tigeot i2c_add_adapter(struct i2c_adapter *adapter) 479f4ca867SFrançois Tigeot { 489f4ca867SFrançois Tigeot /* Linux registers a unique bus number here */ 49*1dedbd3bSFrançois Tigeot 50*1dedbd3bSFrançois Tigeot /* Setup default locking functions */ 51*1dedbd3bSFrançois Tigeot if (!adapter->lock_ops) 52*1dedbd3bSFrançois Tigeot adapter->lock_ops = &i2c_default_lock_ops; 53*1dedbd3bSFrançois Tigeot 549f4ca867SFrançois Tigeot return 0; 559f4ca867SFrançois Tigeot } 569f4ca867SFrançois Tigeot 579f4ca867SFrançois Tigeot void 589f4ca867SFrançois Tigeot i2c_del_adapter(struct i2c_adapter *adapter) 599f4ca867SFrançois Tigeot { 609f4ca867SFrançois Tigeot /* Linux deletes a unique bus number here */ 619f4ca867SFrançois Tigeot } 629f4ca867SFrançois Tigeot 639f4ca867SFrançois Tigeot /* 649f4ca867SFrançois Tigeot * i2c_transfer() 659f4ca867SFrançois Tigeot * The original Linux implementation does: 669f4ca867SFrançois Tigeot * 1. return -EOPNOTSUPP if adapter->algo->master_xfer is NULL 679f4ca867SFrançois Tigeot * 2. try to transfer msgs by calling adapter->algo->master_xfer() 689f4ca867SFrançois Tigeot * 3. if it took more ticks than adapter->timeout, fail 699f4ca867SFrançois Tigeot * 4. if the transfer failed, retry up to adapter->retries times 709f4ca867SFrançois Tigeot * 5. return the result of the last call of adapter->algo->master_xfer() 719f4ca867SFrançois Tigeot */ 729f4ca867SFrançois Tigeot int 739f4ca867SFrançois Tigeot i2c_transfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) 749f4ca867SFrançois Tigeot { 759f4ca867SFrançois Tigeot uint64_t start_ticks; 769f4ca867SFrançois Tigeot int ret, tries = 0; 779f4ca867SFrançois Tigeot 789f4ca867SFrançois Tigeot if (adapter->algo->master_xfer == NULL) 799f4ca867SFrançois Tigeot return -EOPNOTSUPP; 809f4ca867SFrançois Tigeot 81*1dedbd3bSFrançois Tigeot adapter->lock_ops->lock_bus(adapter, I2C_LOCK_SEGMENT); 829f4ca867SFrançois Tigeot start_ticks = ticks; 839f4ca867SFrançois Tigeot do { 849f4ca867SFrançois Tigeot ret = adapter->algo->master_xfer(adapter, msgs, num); 859f4ca867SFrançois Tigeot if (ticks > start_ticks + adapter->timeout) 869f4ca867SFrançois Tigeot break; 879f4ca867SFrançois Tigeot if (ret != -EAGAIN) 889f4ca867SFrançois Tigeot break; 899f4ca867SFrançois Tigeot tries++; 909f4ca867SFrançois Tigeot } while (tries < adapter->retries); 91*1dedbd3bSFrançois Tigeot adapter->lock_ops->unlock_bus(adapter, I2C_LOCK_SEGMENT); 929f4ca867SFrançois Tigeot 939f4ca867SFrançois Tigeot return ret; 949f4ca867SFrançois Tigeot } 959f4ca867SFrançois Tigeot 969f4ca867SFrançois Tigeot static int 979f4ca867SFrançois Tigeot bit_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) 989f4ca867SFrançois Tigeot { 999f4ca867SFrançois Tigeot /* XXX Linux really does try to transfer some data here */ 1009f4ca867SFrançois Tigeot return 0; 1019f4ca867SFrançois Tigeot } 1029f4ca867SFrançois Tigeot 1039f4ca867SFrançois Tigeot static uint32_t 1049f4ca867SFrançois Tigeot bit_func(struct i2c_adapter *adap) 1059f4ca867SFrançois Tigeot { 1069f4ca867SFrançois Tigeot return (I2C_FUNC_I2C | I2C_FUNC_NOSTART | I2C_FUNC_SMBUS_EMUL | 1079f4ca867SFrançois Tigeot I2C_FUNC_SMBUS_READ_BLOCK_DATA | 1089f4ca867SFrançois Tigeot I2C_FUNC_SMBUS_BLOCK_PROC_CALL | 1099f4ca867SFrançois Tigeot I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING); 1109f4ca867SFrançois Tigeot } 1119f4ca867SFrançois Tigeot 1129f4ca867SFrançois Tigeot const struct i2c_algorithm i2c_bit_algo = { 1139f4ca867SFrançois Tigeot .master_xfer = bit_xfer, 1149f4ca867SFrançois Tigeot .functionality = bit_func, 1159f4ca867SFrançois Tigeot }; 116fabf443aSFrançois Tigeot 117fabf443aSFrançois Tigeot int 118fabf443aSFrançois Tigeot i2c_bit_add_bus(struct i2c_adapter *adapter) 119fabf443aSFrançois Tigeot { 120fabf443aSFrançois Tigeot adapter->algo = &i2c_bit_algo; 121fabf443aSFrançois Tigeot adapter->retries = 2; 122fabf443aSFrançois Tigeot 123fabf443aSFrançois Tigeot return 0; 124fabf443aSFrançois Tigeot } 1257d061d0fSFrançois Tigeot 1267d061d0fSFrançois Tigeot struct i2c_client * 1277d061d0fSFrançois Tigeot i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) 1287d061d0fSFrançois Tigeot { 1297d061d0fSFrançois Tigeot struct i2c_client *client; 1307d061d0fSFrançois Tigeot 1317d061d0fSFrançois Tigeot client = kzalloc(sizeof(*client), GFP_KERNEL); 1327d061d0fSFrançois Tigeot if (client == NULL) 1337d061d0fSFrançois Tigeot goto done; 1347d061d0fSFrançois Tigeot 1357d061d0fSFrançois Tigeot client->adapter = adap; 1367d061d0fSFrançois Tigeot 1377d061d0fSFrançois Tigeot strlcpy(client->name, info->type, sizeof(client->name)); 1387d061d0fSFrançois Tigeot client->addr = info->addr; 1397d061d0fSFrançois Tigeot 1407d061d0fSFrançois Tigeot done: 1417d061d0fSFrançois Tigeot return client; 1427d061d0fSFrançois Tigeot } 143*1dedbd3bSFrançois Tigeot 144*1dedbd3bSFrançois Tigeot /* Default locking functions */ 145*1dedbd3bSFrançois Tigeot 146*1dedbd3bSFrançois Tigeot static void 147*1dedbd3bSFrançois Tigeot i2c_default_lock_bus(struct i2c_adapter *adapter, unsigned int flags) 148*1dedbd3bSFrançois Tigeot { 149*1dedbd3bSFrançois Tigeot lockmgr(&i2c_lock, LK_EXCLUSIVE); 150*1dedbd3bSFrançois Tigeot } 151*1dedbd3bSFrançois Tigeot 152*1dedbd3bSFrançois Tigeot static int 153*1dedbd3bSFrançois Tigeot i2c_default_trylock_bus(struct i2c_adapter *adapter, unsigned int flags) 154*1dedbd3bSFrançois Tigeot { 155*1dedbd3bSFrançois Tigeot return mutex_trylock(&i2c_lock); 156*1dedbd3bSFrançois Tigeot } 157*1dedbd3bSFrançois Tigeot 158*1dedbd3bSFrançois Tigeot static void 159*1dedbd3bSFrançois Tigeot i2c_default_unlock_bus(struct i2c_adapter *adapter, unsigned int flags) 160*1dedbd3bSFrançois Tigeot { 161*1dedbd3bSFrançois Tigeot lockmgr(&i2c_lock, LK_RELEASE); 162*1dedbd3bSFrançois Tigeot } 163