1 /* 2 * Copyright (c) 2016 François Tigeot 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice unmodified, this list of conditions, and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include <linux/i2c.h> 28 #include <linux/i2c-algo-bit.h> 29 30 static struct lock i2c_lock; 31 LOCK_SYSINIT(i2c_lock, &i2c_lock, "i2cl", LK_CANRECURSE); 32 33 int 34 i2c_add_adapter(struct i2c_adapter *adapter) 35 { 36 /* Linux registers a unique bus number here */ 37 return 0; 38 } 39 40 void 41 i2c_del_adapter(struct i2c_adapter *adapter) 42 { 43 /* Linux deletes a unique bus number here */ 44 } 45 46 /* 47 * i2c_transfer() 48 * The original Linux implementation does: 49 * 1. return -EOPNOTSUPP if adapter->algo->master_xfer is NULL 50 * 2. try to transfer msgs by calling adapter->algo->master_xfer() 51 * 3. if it took more ticks than adapter->timeout, fail 52 * 4. if the transfer failed, retry up to adapter->retries times 53 * 5. return the result of the last call of adapter->algo->master_xfer() 54 */ 55 int 56 i2c_transfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) 57 { 58 uint64_t start_ticks; 59 int ret, tries = 0; 60 61 if (adapter->algo->master_xfer == NULL) 62 return -EOPNOTSUPP; 63 64 lockmgr(&i2c_lock, LK_EXCLUSIVE); 65 start_ticks = ticks; 66 do { 67 ret = adapter->algo->master_xfer(adapter, msgs, num); 68 if (ticks > start_ticks + adapter->timeout) 69 break; 70 if (ret != -EAGAIN) 71 break; 72 tries++; 73 } while (tries < adapter->retries); 74 lockmgr(&i2c_lock, LK_RELEASE); 75 76 return ret; 77 } 78 79 static int 80 bit_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) 81 { 82 /* XXX Linux really does try to transfer some data here */ 83 return 0; 84 } 85 86 static uint32_t 87 bit_func(struct i2c_adapter *adap) 88 { 89 return (I2C_FUNC_I2C | I2C_FUNC_NOSTART | I2C_FUNC_SMBUS_EMUL | 90 I2C_FUNC_SMBUS_READ_BLOCK_DATA | 91 I2C_FUNC_SMBUS_BLOCK_PROC_CALL | 92 I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING); 93 } 94 95 const struct i2c_algorithm i2c_bit_algo = { 96 .master_xfer = bit_xfer, 97 .functionality = bit_func, 98 }; 99