1 1.7 riastrad /* $NetBSD: linux_i2c.c,v 1.7 2022/05/22 18:41:14 riastradh Exp $ */ 2 1.2 riastrad 3 1.2 riastrad /*- 4 1.3 riastrad * Copyright (c) 2015 The NetBSD Foundation, Inc. 5 1.2 riastrad * All rights reserved. 6 1.2 riastrad * 7 1.2 riastrad * This code is derived from software contributed to The NetBSD Foundation 8 1.2 riastrad * by Taylor R. Campbell. 9 1.2 riastrad * 10 1.2 riastrad * Redistribution and use in source and binary forms, with or without 11 1.2 riastrad * modification, are permitted provided that the following conditions 12 1.2 riastrad * are met: 13 1.2 riastrad * 1. Redistributions of source code must retain the above copyright 14 1.2 riastrad * notice, this list of conditions and the following disclaimer. 15 1.2 riastrad * 2. Redistributions in binary form must reproduce the above copyright 16 1.2 riastrad * notice, this list of conditions and the following disclaimer in the 17 1.2 riastrad * documentation and/or other materials provided with the distribution. 18 1.2 riastrad * 19 1.2 riastrad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.2 riastrad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.2 riastrad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.2 riastrad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.2 riastrad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.2 riastrad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.2 riastrad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.2 riastrad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.2 riastrad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.2 riastrad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.2 riastrad * POSSIBILITY OF SUCH DAMAGE. 30 1.2 riastrad */ 31 1.2 riastrad 32 1.2 riastrad #include <sys/cdefs.h> 33 1.7 riastrad __KERNEL_RCSID(0, "$NetBSD: linux_i2c.c,v 1.7 2022/05/22 18:41:14 riastradh Exp $"); 34 1.2 riastrad 35 1.2 riastrad #include <sys/types.h> 36 1.2 riastrad #include <sys/errno.h> 37 1.3 riastrad #include <sys/kmem.h> 38 1.2 riastrad #include <sys/queue.h> /* XXX include order botch: i2cvar.h needs */ 39 1.2 riastrad 40 1.2 riastrad #include <dev/i2c/i2cvar.h> 41 1.2 riastrad #include <dev/i2c/i2c_bitbang.h> /* XXX include order botch */ 42 1.2 riastrad 43 1.2 riastrad #include <linux/i2c.h> 44 1.2 riastrad #include <linux/i2c-algo-bit.h> 45 1.2 riastrad 46 1.2 riastrad static int netbsd_i2c_transfer(i2c_tag_t, struct i2c_msg *, int); 47 1.2 riastrad static i2c_op_t linux_i2c_flags_op(uint16_t, bool); 48 1.2 riastrad static int linux_i2c_flags_flags(uint16_t); 49 1.2 riastrad static uint32_t linux_i2cbb_functionality(struct i2c_adapter *); 50 1.2 riastrad static int linux_i2cbb_xfer(struct i2c_adapter *, struct i2c_msg *, int); 51 1.2 riastrad static void linux_i2cbb_set_bits(void *, uint32_t); 52 1.2 riastrad static uint32_t linux_i2cbb_read_bits(void *); 53 1.2 riastrad static void linux_i2cbb_set_dir(void *, uint32_t); 54 1.2 riastrad static int linux_i2cbb_send_start(void *, int); 55 1.2 riastrad static int linux_i2cbb_send_stop(void *, int); 56 1.2 riastrad static int linux_i2cbb_initiate_xfer(void *, i2c_addr_t, int); 57 1.2 riastrad static int linux_i2cbb_read_byte(void *, uint8_t *, int); 58 1.2 riastrad static int linux_i2cbb_write_byte(void *, uint8_t, int); 59 1.2 riastrad 60 1.3 riastrad /* 62 1.3 riastrad * Client operations: operations with a particular i2c slave device. 63 1.3 riastrad */ 64 1.3 riastrad 65 1.3 riastrad struct i2c_client * 66 1.3 riastrad i2c_new_device(struct i2c_adapter *adapter, const struct i2c_board_info *info) 67 1.3 riastrad { 68 1.3 riastrad struct i2c_client *client; 69 1.3 riastrad 70 1.3 riastrad client = kmem_alloc(sizeof(*client), KM_SLEEP); 71 1.3 riastrad client->adapter = adapter; 72 1.3 riastrad client->addr = info->addr; 73 1.3 riastrad client->flags = info->flags; 74 1.3 riastrad 75 1.3 riastrad return client; 76 1.3 riastrad } 77 1.3 riastrad 78 1.3 riastrad void 79 1.3 riastrad i2c_unregister_device(struct i2c_client *client) 80 1.3 riastrad { 81 1.3 riastrad 82 1.3 riastrad kmem_free(client, sizeof(*client)); 83 1.3 riastrad } 84 1.3 riastrad 85 1.3 riastrad int 86 1.3 riastrad i2c_master_send(const struct i2c_client *client, const char *buf, int count) 87 1.3 riastrad { 88 1.3 riastrad struct i2c_msg msg = { 89 1.3 riastrad .addr = client->addr, 90 1.3 riastrad .flags = client->flags & I2C_M_TEN, 91 1.3 riastrad .len = count, 92 1.3 riastrad .buf = __UNCONST(buf), 93 1.3 riastrad }; 94 1.3 riastrad int ret; 95 1.3 riastrad 96 1.3 riastrad KASSERT(0 <= count); 97 1.3 riastrad 98 1.3 riastrad ret = i2c_transfer(client->adapter, &msg, 1); 99 1.3 riastrad if (ret <= 0) 100 1.3 riastrad return ret; 101 1.3 riastrad 102 1.3 riastrad return count; 103 1.3 riastrad } 104 1.3 riastrad 105 1.3 riastrad int 106 1.3 riastrad i2c_master_recv(const struct i2c_client *client, char *buf, int count) 107 1.3 riastrad { 108 1.3 riastrad struct i2c_msg msg = { 109 1.3 riastrad .addr = client->addr, 110 1.3 riastrad .flags = (client->flags & I2C_M_TEN) | I2C_M_RD, 111 1.3 riastrad .len = count, 112 1.3 riastrad .buf = buf, 113 1.3 riastrad }; 114 1.3 riastrad int ret; 115 1.3 riastrad 116 1.3 riastrad ret = i2c_transfer(client->adapter, &msg, 1); 117 1.3 riastrad if (ret <= 0) 118 1.3 riastrad return ret; 119 1.3 riastrad 120 1.3 riastrad return count; 121 1.3 riastrad } 122 1.3 riastrad 123 1.3 riastrad /* 125 1.3 riastrad * Adapter operations: operations over an i2c bus via a particular 126 1.3 riastrad * controller. 127 1.2 riastrad */ 128 1.6 riastrad 129 1.6 riastrad int 130 1.7 riastrad __i2c_transfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int n) 131 1.7 riastrad { 132 1.7 riastrad unsigned timeout = hz; /* XXX adapter->timeout */ 133 1.7 riastrad unsigned start = getticks(); 134 1.7 riastrad int ret, nretries = 0; 135 1.7 riastrad 136 1.7 riastrad do { 137 1.7 riastrad ret = (*adapter->algo->master_xfer)(adapter, msgs, n); 138 1.7 riastrad if (ret != -EAGAIN) 139 1.7 riastrad break; 140 1.6 riastrad } while (nretries++ < adapter->retries && 141 1.7 riastrad getticks() - start < timeout); 142 1.6 riastrad 143 1.6 riastrad return ret; 144 1.6 riastrad } 145 1.2 riastrad 146 1.2 riastrad int 147 1.4 riastrad i2c_transfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int n) 148 1.4 riastrad { 149 1.4 riastrad int ret; 150 1.4 riastrad 151 1.6 riastrad if (adapter->lock_ops) 152 1.4 riastrad (*adapter->lock_ops->lock_bus)(adapter, 0); 153 1.4 riastrad ret = __i2c_transfer(adapter, msgs, n); 154 1.2 riastrad if (adapter->lock_ops) 155 1.4 riastrad (*adapter->lock_ops->unlock_bus)(adapter, 0); 156 1.2 riastrad 157 1.2 riastrad return ret; 158 1.2 riastrad } 159 1.2 riastrad 160 1.2 riastrad static int 161 1.2 riastrad netbsd_i2c_transfer(i2c_tag_t i2c, struct i2c_msg *msgs, int n) 162 1.2 riastrad { 163 1.2 riastrad int i; 164 1.2 riastrad int error; 165 1.2 riastrad 166 1.2 riastrad for (i = 0; i < n; i++) { 167 1.2 riastrad const i2c_op_t op = linux_i2c_flags_op(msgs[i].flags, 168 1.2 riastrad ((i + 1) == n)); 169 1.2 riastrad const int flags = linux_i2c_flags_flags(msgs[i].flags); 170 1.2 riastrad 171 1.2 riastrad switch (op) { 172 1.2 riastrad case I2C_OP_READ: 173 1.2 riastrad case I2C_OP_READ_WITH_STOP: 174 1.2 riastrad error = iic_exec(i2c, op, msgs[i].addr, 175 1.2 riastrad NULL, 0, msgs[i].buf, msgs[i].len, flags); 176 1.2 riastrad break; 177 1.2 riastrad 178 1.2 riastrad case I2C_OP_WRITE: 179 1.2 riastrad case I2C_OP_WRITE_WITH_STOP: 180 1.2 riastrad error = iic_exec(i2c, op, msgs[i].addr, 181 1.2 riastrad msgs[i].buf, msgs[i].len, NULL, 0, flags); 182 1.2 riastrad break; 183 1.2 riastrad 184 1.2 riastrad default: 185 1.2 riastrad error = EINVAL; 186 1.2 riastrad } 187 1.2 riastrad 188 1.2 riastrad if (error) 189 1.2 riastrad /* XXX errno NetBSD->Linux */ 190 1.2 riastrad return -error; 191 1.2 riastrad } 192 1.2 riastrad 193 1.2 riastrad return n; 194 1.2 riastrad } 195 1.2 riastrad 196 1.2 riastrad static i2c_op_t 197 1.2 riastrad linux_i2c_flags_op(uint16_t flags, bool stop) 198 1.5 riastrad { 199 1.5 riastrad 200 1.5 riastrad if (ISSET(flags, I2C_M_STOP)) 201 1.2 riastrad stop = true; 202 1.2 riastrad 203 1.2 riastrad if (ISSET(flags, I2C_M_RD)) 204 1.2 riastrad return (stop? I2C_OP_READ_WITH_STOP : I2C_OP_READ); 205 1.2 riastrad else 206 1.2 riastrad return (stop? I2C_OP_WRITE_WITH_STOP : I2C_OP_WRITE); 207 1.2 riastrad } 208 1.2 riastrad 209 1.2 riastrad static int 210 1.2 riastrad linux_i2c_flags_flags(uint16_t flags __unused) 211 1.2 riastrad { 212 1.2 riastrad 213 1.2 riastrad return 0; 214 1.3 riastrad } 215 1.3 riastrad 216 1.2 riastrad /* Bit-banging */ 218 1.2 riastrad 219 1.2 riastrad const struct i2c_algorithm i2c_bit_algo = { 220 1.2 riastrad .master_xfer = linux_i2cbb_xfer, 221 1.2 riastrad .functionality = linux_i2cbb_functionality, 222 1.2 riastrad }; 223 1.2 riastrad 224 1.2 riastrad static uint32_t 225 1.2 riastrad linux_i2cbb_functionality(struct i2c_adapter *adapter __unused) 226 1.2 riastrad { 227 1.2 riastrad uint32_t functions = 0; 228 1.2 riastrad 229 1.2 riastrad functions |= I2C_FUNC_I2C; 230 1.2 riastrad functions |= I2C_FUNC_NOSTART; 231 1.2 riastrad functions |= I2C_FUNC_SMBUS_EMUL; 232 1.2 riastrad functions |= I2C_FUNC_SMBUS_READ_BLOCK_DATA; 233 1.2 riastrad functions |= I2C_FUNC_SMBUS_BLOCK_PROC_CALL; 234 1.2 riastrad #if 0 235 1.2 riastrad functions |= I2C_FUNC_10BIT_ADDR; 236 1.2 riastrad functions |= I2C_FUNC_PROTOCOL_MANGLING; 237 1.2 riastrad #endif 238 1.2 riastrad 239 1.2 riastrad return functions; 240 1.2 riastrad } 241 1.2 riastrad 242 1.2 riastrad static int 243 1.2 riastrad linux_i2cbb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int n) 244 1.2 riastrad { 245 1.2 riastrad struct i2c_algo_bit_data *const abd = adapter->algo_data; 246 1.2 riastrad struct i2c_controller controller = { 247 1.2 riastrad .ic_cookie = abd, 248 1.2 riastrad .ic_send_start = linux_i2cbb_send_start, 249 1.2 riastrad .ic_send_stop = linux_i2cbb_send_stop, 250 1.2 riastrad .ic_initiate_xfer = linux_i2cbb_initiate_xfer, 251 1.2 riastrad .ic_read_byte = linux_i2cbb_read_byte, 252 1.2 riastrad .ic_write_byte = linux_i2cbb_write_byte, 253 1.2 riastrad }; 254 1.2 riastrad i2c_tag_t i2c = &controller; 255 1.2 riastrad int error; 256 1.2 riastrad 257 1.2 riastrad if (abd->pre_xfer) { 258 1.2 riastrad error = (*abd->pre_xfer)(adapter); 259 1.2 riastrad if (error) 260 1.2 riastrad return error; 261 1.2 riastrad } 262 1.2 riastrad 263 1.2 riastrad error = netbsd_i2c_transfer(i2c, msgs, n); 264 1.2 riastrad 265 1.2 riastrad if (abd->post_xfer) 266 1.2 riastrad (*abd->post_xfer)(adapter); 267 1.2 riastrad 268 1.2 riastrad return error; 269 1.2 riastrad } 270 1.2 riastrad 271 1.2 riastrad #define LI2CBB_SDA 0x01 273 1.2 riastrad #define LI2CBB_SCL 0x02 274 1.2 riastrad #define LI2CBB_INPUT 0x04 275 1.2 riastrad #define LI2CBB_OUTPUT 0x08 276 1.2 riastrad 277 1.2 riastrad static struct i2c_bitbang_ops linux_i2cbb_ops = { 278 1.2 riastrad .ibo_set_bits = linux_i2cbb_set_bits, 279 1.2 riastrad .ibo_set_dir = linux_i2cbb_set_dir, 280 1.2 riastrad .ibo_read_bits = linux_i2cbb_read_bits, 281 1.2 riastrad .ibo_bits = { 282 1.2 riastrad [I2C_BIT_SDA] = LI2CBB_SDA, 283 1.2 riastrad [I2C_BIT_SCL] = LI2CBB_SCL, 284 1.2 riastrad [I2C_BIT_INPUT] = LI2CBB_INPUT, 285 1.2 riastrad [I2C_BIT_OUTPUT] = LI2CBB_OUTPUT, 286 1.2 riastrad }, 287 1.2 riastrad }; 288 1.2 riastrad 289 1.2 riastrad static void 290 1.2 riastrad linux_i2cbb_set_bits(void *cookie, uint32_t bits) 291 1.2 riastrad { 292 1.2 riastrad struct i2c_algo_bit_data *const abd = cookie; 293 1.2 riastrad 294 1.2 riastrad (*abd->setsda)(abd->data, (ISSET(bits, LI2CBB_SDA)? 1 : 0)); 295 1.2 riastrad (*abd->setscl)(abd->data, (ISSET(bits, LI2CBB_SCL)? 1 : 0)); 296 1.2 riastrad } 297 1.2 riastrad 298 1.2 riastrad static uint32_t 299 1.2 riastrad linux_i2cbb_read_bits(void *cookie) 300 1.2 riastrad { 301 1.2 riastrad struct i2c_algo_bit_data *const abd = cookie; 302 1.2 riastrad uint32_t bits = 0; 303 1.2 riastrad 304 1.2 riastrad if ((*abd->getsda)(abd->data)) 305 1.2 riastrad bits |= LI2CBB_SDA; 306 1.2 riastrad if ((*abd->getscl)(abd->data)) 307 1.2 riastrad bits |= LI2CBB_SCL; 308 1.2 riastrad 309 1.2 riastrad return bits; 310 1.2 riastrad } 311 1.2 riastrad 312 1.2 riastrad static void 313 1.2 riastrad linux_i2cbb_set_dir(void *cookie __unused, uint32_t bits __unused) 314 1.2 riastrad { 315 1.2 riastrad /* Linux doesn't do anything here... */ 316 1.2 riastrad } 317 1.2 riastrad 318 1.2 riastrad static int 320 1.2 riastrad linux_i2cbb_send_start(void *cookie, int flags) 321 1.2 riastrad { 322 1.2 riastrad 323 1.2 riastrad return i2c_bitbang_send_start(cookie, flags, &linux_i2cbb_ops); 324 1.2 riastrad } 325 1.2 riastrad 326 1.2 riastrad static int 327 1.2 riastrad linux_i2cbb_send_stop(void *cookie, int flags) 328 1.2 riastrad { 329 1.2 riastrad 330 1.2 riastrad return i2c_bitbang_send_stop(cookie, flags, &linux_i2cbb_ops); 331 1.2 riastrad } 332 1.2 riastrad 333 1.2 riastrad static int 334 1.2 riastrad linux_i2cbb_initiate_xfer(void *cookie, i2c_addr_t addr, int flags) 335 1.2 riastrad { 336 1.2 riastrad 337 1.2 riastrad return i2c_bitbang_initiate_xfer(cookie, addr, flags, 338 1.2 riastrad &linux_i2cbb_ops); 339 1.2 riastrad } 340 1.2 riastrad 341 1.2 riastrad static int 342 1.2 riastrad linux_i2cbb_read_byte(void *cookie, uint8_t *bytep, int flags) 343 1.2 riastrad { 344 1.2 riastrad 345 1.2 riastrad return i2c_bitbang_read_byte(cookie, bytep, flags, &linux_i2cbb_ops); 346 1.2 riastrad } 347 1.2 riastrad 348 1.2 riastrad static int 349 linux_i2cbb_write_byte(void *cookie, uint8_t byte, int flags) 350 { 351 352 return i2c_bitbang_write_byte(cookie, byte, flags, &linux_i2cbb_ops); 353 } 354