solo6x10-i2c.c (6988B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (C) 2010-2013 Bluecherry, LLC <https://www.bluecherrydvr.com> 4 * 5 * Original author: 6 * Ben Collins <bcollins@ubuntu.com> 7 * 8 * Additional work by: 9 * John Brooks <john.brooks@bluecherry.net> 10 */ 11 12/* XXX: The SOLO6x10 i2c does not have separate interrupts for each i2c 13 * channel. The bus can only handle one i2c event at a time. The below handles 14 * this all wrong. We should be using the status registers to see if the bus 15 * is in use, and have a global lock to check the status register. Also, 16 * the bulk of the work should be handled out-of-interrupt. The ugly loops 17 * that occur during interrupt scare me. The ISR should merely signal 18 * thread context, ACK the interrupt, and move on. -- BenC */ 19 20#include <linux/kernel.h> 21#include <linux/sched/signal.h> 22 23#include "solo6x10.h" 24 25u8 solo_i2c_readbyte(struct solo_dev *solo_dev, int id, u8 addr, u8 off) 26{ 27 struct i2c_msg msgs[2]; 28 u8 data; 29 30 msgs[0].flags = 0; 31 msgs[0].addr = addr; 32 msgs[0].len = 1; 33 msgs[0].buf = &off; 34 35 msgs[1].flags = I2C_M_RD; 36 msgs[1].addr = addr; 37 msgs[1].len = 1; 38 msgs[1].buf = &data; 39 40 i2c_transfer(&solo_dev->i2c_adap[id], msgs, 2); 41 42 return data; 43} 44 45void solo_i2c_writebyte(struct solo_dev *solo_dev, int id, u8 addr, 46 u8 off, u8 data) 47{ 48 struct i2c_msg msgs; 49 u8 buf[2]; 50 51 buf[0] = off; 52 buf[1] = data; 53 msgs.flags = 0; 54 msgs.addr = addr; 55 msgs.len = 2; 56 msgs.buf = buf; 57 58 i2c_transfer(&solo_dev->i2c_adap[id], &msgs, 1); 59} 60 61static void solo_i2c_flush(struct solo_dev *solo_dev, int wr) 62{ 63 u32 ctrl; 64 65 ctrl = SOLO_IIC_CH_SET(solo_dev->i2c_id); 66 67 if (solo_dev->i2c_state == IIC_STATE_START) 68 ctrl |= SOLO_IIC_START; 69 70 if (wr) { 71 ctrl |= SOLO_IIC_WRITE; 72 } else { 73 ctrl |= SOLO_IIC_READ; 74 if (!(solo_dev->i2c_msg->flags & I2C_M_NO_RD_ACK)) 75 ctrl |= SOLO_IIC_ACK_EN; 76 } 77 78 if (solo_dev->i2c_msg_ptr == solo_dev->i2c_msg->len) 79 ctrl |= SOLO_IIC_STOP; 80 81 solo_reg_write(solo_dev, SOLO_IIC_CTRL, ctrl); 82} 83 84static void solo_i2c_start(struct solo_dev *solo_dev) 85{ 86 u32 addr = solo_dev->i2c_msg->addr << 1; 87 88 if (solo_dev->i2c_msg->flags & I2C_M_RD) 89 addr |= 1; 90 91 solo_dev->i2c_state = IIC_STATE_START; 92 solo_reg_write(solo_dev, SOLO_IIC_TXD, addr); 93 solo_i2c_flush(solo_dev, 1); 94} 95 96static void solo_i2c_stop(struct solo_dev *solo_dev) 97{ 98 solo_irq_off(solo_dev, SOLO_IRQ_IIC); 99 solo_reg_write(solo_dev, SOLO_IIC_CTRL, 0); 100 solo_dev->i2c_state = IIC_STATE_STOP; 101 wake_up(&solo_dev->i2c_wait); 102} 103 104static int solo_i2c_handle_read(struct solo_dev *solo_dev) 105{ 106prepare_read: 107 if (solo_dev->i2c_msg_ptr != solo_dev->i2c_msg->len) { 108 solo_i2c_flush(solo_dev, 0); 109 return 0; 110 } 111 112 solo_dev->i2c_msg_ptr = 0; 113 solo_dev->i2c_msg++; 114 solo_dev->i2c_msg_num--; 115 116 if (solo_dev->i2c_msg_num == 0) { 117 solo_i2c_stop(solo_dev); 118 return 0; 119 } 120 121 if (!(solo_dev->i2c_msg->flags & I2C_M_NOSTART)) { 122 solo_i2c_start(solo_dev); 123 } else { 124 if (solo_dev->i2c_msg->flags & I2C_M_RD) 125 goto prepare_read; 126 else 127 solo_i2c_stop(solo_dev); 128 } 129 130 return 0; 131} 132 133static int solo_i2c_handle_write(struct solo_dev *solo_dev) 134{ 135retry_write: 136 if (solo_dev->i2c_msg_ptr != solo_dev->i2c_msg->len) { 137 solo_reg_write(solo_dev, SOLO_IIC_TXD, 138 solo_dev->i2c_msg->buf[solo_dev->i2c_msg_ptr]); 139 solo_dev->i2c_msg_ptr++; 140 solo_i2c_flush(solo_dev, 1); 141 return 0; 142 } 143 144 solo_dev->i2c_msg_ptr = 0; 145 solo_dev->i2c_msg++; 146 solo_dev->i2c_msg_num--; 147 148 if (solo_dev->i2c_msg_num == 0) { 149 solo_i2c_stop(solo_dev); 150 return 0; 151 } 152 153 if (!(solo_dev->i2c_msg->flags & I2C_M_NOSTART)) { 154 solo_i2c_start(solo_dev); 155 } else { 156 if (solo_dev->i2c_msg->flags & I2C_M_RD) 157 solo_i2c_stop(solo_dev); 158 else 159 goto retry_write; 160 } 161 162 return 0; 163} 164 165int solo_i2c_isr(struct solo_dev *solo_dev) 166{ 167 u32 status = solo_reg_read(solo_dev, SOLO_IIC_CTRL); 168 int ret = -EINVAL; 169 170 171 if (CHK_FLAGS(status, SOLO_IIC_STATE_TRNS | SOLO_IIC_STATE_SIG_ERR) 172 || solo_dev->i2c_id < 0) { 173 solo_i2c_stop(solo_dev); 174 return -ENXIO; 175 } 176 177 switch (solo_dev->i2c_state) { 178 case IIC_STATE_START: 179 if (solo_dev->i2c_msg->flags & I2C_M_RD) { 180 solo_dev->i2c_state = IIC_STATE_READ; 181 ret = solo_i2c_handle_read(solo_dev); 182 break; 183 } 184 185 solo_dev->i2c_state = IIC_STATE_WRITE; 186 fallthrough; 187 case IIC_STATE_WRITE: 188 ret = solo_i2c_handle_write(solo_dev); 189 break; 190 191 case IIC_STATE_READ: 192 solo_dev->i2c_msg->buf[solo_dev->i2c_msg_ptr] = 193 solo_reg_read(solo_dev, SOLO_IIC_RXD); 194 solo_dev->i2c_msg_ptr++; 195 196 ret = solo_i2c_handle_read(solo_dev); 197 break; 198 199 default: 200 solo_i2c_stop(solo_dev); 201 } 202 203 return ret; 204} 205 206static int solo_i2c_master_xfer(struct i2c_adapter *adap, 207 struct i2c_msg msgs[], int num) 208{ 209 struct solo_dev *solo_dev = adap->algo_data; 210 unsigned long timeout; 211 int ret; 212 int i; 213 DEFINE_WAIT(wait); 214 215 for (i = 0; i < SOLO_I2C_ADAPTERS; i++) { 216 if (&solo_dev->i2c_adap[i] == adap) 217 break; 218 } 219 220 if (i == SOLO_I2C_ADAPTERS) 221 return num; /* XXX Right return value for failure? */ 222 223 mutex_lock(&solo_dev->i2c_mutex); 224 solo_dev->i2c_id = i; 225 solo_dev->i2c_msg = msgs; 226 solo_dev->i2c_msg_num = num; 227 solo_dev->i2c_msg_ptr = 0; 228 229 solo_reg_write(solo_dev, SOLO_IIC_CTRL, 0); 230 solo_irq_on(solo_dev, SOLO_IRQ_IIC); 231 solo_i2c_start(solo_dev); 232 233 timeout = HZ / 2; 234 235 for (;;) { 236 prepare_to_wait(&solo_dev->i2c_wait, &wait, 237 TASK_INTERRUPTIBLE); 238 239 if (solo_dev->i2c_state == IIC_STATE_STOP) 240 break; 241 242 timeout = schedule_timeout(timeout); 243 if (!timeout) 244 break; 245 246 if (signal_pending(current)) 247 break; 248 } 249 250 finish_wait(&solo_dev->i2c_wait, &wait); 251 ret = num - solo_dev->i2c_msg_num; 252 solo_dev->i2c_state = IIC_STATE_IDLE; 253 solo_dev->i2c_id = -1; 254 255 mutex_unlock(&solo_dev->i2c_mutex); 256 257 return ret; 258} 259 260static u32 solo_i2c_functionality(struct i2c_adapter *adap) 261{ 262 return I2C_FUNC_I2C; 263} 264 265static const struct i2c_algorithm solo_i2c_algo = { 266 .master_xfer = solo_i2c_master_xfer, 267 .functionality = solo_i2c_functionality, 268}; 269 270int solo_i2c_init(struct solo_dev *solo_dev) 271{ 272 int i; 273 int ret; 274 275 solo_reg_write(solo_dev, SOLO_IIC_CFG, 276 SOLO_IIC_PRESCALE(8) | SOLO_IIC_ENABLE); 277 278 solo_dev->i2c_id = -1; 279 solo_dev->i2c_state = IIC_STATE_IDLE; 280 init_waitqueue_head(&solo_dev->i2c_wait); 281 mutex_init(&solo_dev->i2c_mutex); 282 283 for (i = 0; i < SOLO_I2C_ADAPTERS; i++) { 284 struct i2c_adapter *adap = &solo_dev->i2c_adap[i]; 285 286 snprintf(adap->name, I2C_NAME_SIZE, "%s I2C %d", 287 SOLO6X10_NAME, i); 288 adap->algo = &solo_i2c_algo; 289 adap->algo_data = solo_dev; 290 adap->retries = 1; 291 adap->dev.parent = &solo_dev->pdev->dev; 292 293 ret = i2c_add_adapter(adap); 294 if (ret) { 295 adap->algo_data = NULL; 296 break; 297 } 298 } 299 300 if (ret) { 301 for (i = 0; i < SOLO_I2C_ADAPTERS; i++) { 302 if (!solo_dev->i2c_adap[i].algo_data) 303 break; 304 i2c_del_adapter(&solo_dev->i2c_adap[i]); 305 solo_dev->i2c_adap[i].algo_data = NULL; 306 } 307 return ret; 308 } 309 310 return 0; 311} 312 313void solo_i2c_exit(struct solo_dev *solo_dev) 314{ 315 int i; 316 317 for (i = 0; i < SOLO_I2C_ADAPTERS; i++) { 318 if (!solo_dev->i2c_adap[i].algo_data) 319 continue; 320 i2c_del_adapter(&solo_dev->i2c_adap[i]); 321 solo_dev->i2c_adap[i].algo_data = NULL; 322 } 323}