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