1/* 2 * Copyright 2012 Red Hat Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Authors: Ben Skeggs 23 */ 24 25#include "priv.h" 26 27#ifdef CONFIG_NOUVEAU_I2C_INTERNAL 28#define T_TIMEOUT 2200000 29#define T_RISEFALL 1000 30#define T_HOLD 5000 31 32static inline void 33i2c_drive_scl(struct nouveau_i2c_port *port, int state) 34{ 35 port->func->drive_scl(port, state); 36} 37 38static inline void 39i2c_drive_sda(struct nouveau_i2c_port *port, int state) 40{ 41 port->func->drive_sda(port, state); 42} 43 44static inline int 45i2c_sense_scl(struct nouveau_i2c_port *port) 46{ 47 return port->func->sense_scl(port); 48} 49 50static inline int 51i2c_sense_sda(struct nouveau_i2c_port *port) 52{ 53 return port->func->sense_sda(port); 54} 55 56static void 57i2c_delay(struct nouveau_i2c_port *port, u32 nsec) 58{ 59 udelay((nsec + 500) / 1000); 60} 61 62static bool 63i2c_raise_scl(struct nouveau_i2c_port *port) 64{ 65 u32 timeout = T_TIMEOUT / T_RISEFALL; 66 67 i2c_drive_scl(port, 1); 68 do { 69 i2c_delay(port, T_RISEFALL); 70 } while (!i2c_sense_scl(port) && --timeout); 71 72 return timeout != 0; 73} 74 75static int 76i2c_start(struct nouveau_i2c_port *port) 77{ 78 int ret = 0; 79 80 if (!i2c_sense_scl(port) || 81 !i2c_sense_sda(port)) { 82 i2c_drive_scl(port, 0); 83 i2c_drive_sda(port, 1); 84 if (!i2c_raise_scl(port)) 85 ret = -EBUSY; 86 } 87 88 i2c_drive_sda(port, 0); 89 i2c_delay(port, T_HOLD); 90 i2c_drive_scl(port, 0); 91 i2c_delay(port, T_HOLD); 92 return ret; 93} 94 95static void 96i2c_stop(struct nouveau_i2c_port *port) 97{ 98 i2c_drive_scl(port, 0); 99 i2c_drive_sda(port, 0); 100 i2c_delay(port, T_RISEFALL); 101 102 i2c_drive_scl(port, 1); 103 i2c_delay(port, T_HOLD); 104 i2c_drive_sda(port, 1); 105 i2c_delay(port, T_HOLD); 106} 107 108static int 109i2c_bitw(struct nouveau_i2c_port *port, int sda) 110{ 111 i2c_drive_sda(port, sda); 112 i2c_delay(port, T_RISEFALL); 113 114 if (!i2c_raise_scl(port)) 115 return -ETIMEDOUT; 116 i2c_delay(port, T_HOLD); 117 118 i2c_drive_scl(port, 0); 119 i2c_delay(port, T_HOLD); 120 return 0; 121} 122 123static int 124i2c_bitr(struct nouveau_i2c_port *port) 125{ 126 int sda; 127 128 i2c_drive_sda(port, 1); 129 i2c_delay(port, T_RISEFALL); 130 131 if (!i2c_raise_scl(port)) 132 return -ETIMEDOUT; 133 i2c_delay(port, T_HOLD); 134 135 sda = i2c_sense_sda(port); 136 137 i2c_drive_scl(port, 0); 138 i2c_delay(port, T_HOLD); 139 return sda; 140} 141 142static int 143i2c_get_byte(struct nouveau_i2c_port *port, u8 *byte, bool last) 144{ 145 int i, bit; 146 147 *byte = 0; 148 for (i = 7; i >= 0; i--) { 149 bit = i2c_bitr(port); 150 if (bit < 0) 151 return bit; 152 *byte |= bit << i; 153 } 154 155 return i2c_bitw(port, last ? 1 : 0); 156} 157 158static int 159i2c_put_byte(struct nouveau_i2c_port *port, u8 byte) 160{ 161 int i, ret; 162 for (i = 7; i >= 0; i--) { 163 ret = i2c_bitw(port, !!(byte & (1 << i))); 164 if (ret < 0) 165 return ret; 166 } 167 168 ret = i2c_bitr(port); 169 if (ret == 1) /* nack */ 170 ret = -EIO; 171 return ret; 172} 173 174static int 175i2c_addr(struct nouveau_i2c_port *port, struct i2c_msg *msg) 176{ 177 u32 addr = msg->addr << 1; 178 if (msg->flags & I2C_M_RD) 179 addr |= 1; 180 return i2c_put_byte(port, addr); 181} 182 183static int 184i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) 185{ 186 struct nouveau_i2c_port *port = adap->algo_data; 187 struct i2c_msg *msg = msgs; 188 int ret = 0, mcnt = num; 189 190 ret = nouveau_i2c(port)->acquire(port, nsecs_to_jiffies(T_TIMEOUT)); 191 if (ret) 192 return ret; 193 194 while (!ret && mcnt--) { 195 u8 remaining = msg->len; 196 u8 *ptr = msg->buf; 197 198 ret = i2c_start(port); 199 if (ret == 0) 200 ret = i2c_addr(port, msg); 201 202 if (msg->flags & I2C_M_RD) { 203 while (!ret && remaining--) 204 ret = i2c_get_byte(port, ptr++, !remaining); 205 } else { 206 while (!ret && remaining--) 207 ret = i2c_put_byte(port, *ptr++); 208 } 209 210 msg++; 211 } 212 213 i2c_stop(port); 214 nouveau_i2c(port)->release(port); 215 return (ret < 0) ? ret : num; 216} 217#else 218static int 219i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) 220{ 221 return -ENODEV; 222} 223#endif 224 225static u32 226i2c_bit_func(struct i2c_adapter *adap) 227{ 228 return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 229} 230 231const struct i2c_algorithm nouveau_i2c_bit_algo = { 232 .master_xfer = i2c_bit_xfer, 233 .functionality = i2c_bit_func 234}; 235