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 /* fall through */ 196 case IIC_STATE_WRITE: 197 ret = solo_i2c_handle_write(solo_dev); 198 break; 199 200 case IIC_STATE_READ: 201 solo_dev->i2c_msg->buf[solo_dev->i2c_msg_ptr] = 202 solo_reg_read(solo_dev, SOLO_IIC_RXD); 203 solo_dev->i2c_msg_ptr++; 204 205 ret = solo_i2c_handle_read(solo_dev); 206 break; 207 208 default: 209 solo_i2c_stop(solo_dev); 210 } 211 212 return ret; 213 } 214 215 static int solo_i2c_master_xfer(struct i2c_adapter *adap, 216 struct i2c_msg msgs[], int num) 217 { 218 struct solo_dev *solo_dev = adap->algo_data; 219 unsigned long timeout; 220 int ret; 221 int i; 222 DEFINE_WAIT(wait); 223 224 for (i = 0; i < SOLO_I2C_ADAPTERS; i++) { 225 if (&solo_dev->i2c_adap[i] == adap) 226 break; 227 } 228 229 if (i == SOLO_I2C_ADAPTERS) 230 return num; /* XXX Right return value for failure? */ 231 232 mutex_lock(&solo_dev->i2c_mutex); 233 solo_dev->i2c_id = i; 234 solo_dev->i2c_msg = msgs; 235 solo_dev->i2c_msg_num = num; 236 solo_dev->i2c_msg_ptr = 0; 237 238 solo_reg_write(solo_dev, SOLO_IIC_CTRL, 0); 239 solo_irq_on(solo_dev, SOLO_IRQ_IIC); 240 solo_i2c_start(solo_dev); 241 242 timeout = HZ / 2; 243 244 for (;;) { 245 prepare_to_wait(&solo_dev->i2c_wait, &wait, 246 TASK_INTERRUPTIBLE); 247 248 if (solo_dev->i2c_state == IIC_STATE_STOP) 249 break; 250 251 timeout = schedule_timeout(timeout); 252 if (!timeout) 253 break; 254 255 if (signal_pending(current)) 256 break; 257 } 258 259 finish_wait(&solo_dev->i2c_wait, &wait); 260 ret = num - solo_dev->i2c_msg_num; 261 solo_dev->i2c_state = IIC_STATE_IDLE; 262 solo_dev->i2c_id = -1; 263 264 mutex_unlock(&solo_dev->i2c_mutex); 265 266 return ret; 267 } 268 269 static u32 solo_i2c_functionality(struct i2c_adapter *adap) 270 { 271 return I2C_FUNC_I2C; 272 } 273 274 static const struct i2c_algorithm solo_i2c_algo = { 275 .master_xfer = solo_i2c_master_xfer, 276 .functionality = solo_i2c_functionality, 277 }; 278 279 int solo_i2c_init(struct solo_dev *solo_dev) 280 { 281 int i; 282 int ret; 283 284 solo_reg_write(solo_dev, SOLO_IIC_CFG, 285 SOLO_IIC_PRESCALE(8) | SOLO_IIC_ENABLE); 286 287 solo_dev->i2c_id = -1; 288 solo_dev->i2c_state = IIC_STATE_IDLE; 289 init_waitqueue_head(&solo_dev->i2c_wait); 290 mutex_init(&solo_dev->i2c_mutex); 291 292 for (i = 0; i < SOLO_I2C_ADAPTERS; i++) { 293 struct i2c_adapter *adap = &solo_dev->i2c_adap[i]; 294 295 snprintf(adap->name, I2C_NAME_SIZE, "%s I2C %d", 296 SOLO6X10_NAME, i); 297 adap->algo = &solo_i2c_algo; 298 adap->algo_data = solo_dev; 299 adap->retries = 1; 300 adap->dev.parent = &solo_dev->pdev->dev; 301 302 ret = i2c_add_adapter(adap); 303 if (ret) { 304 adap->algo_data = NULL; 305 break; 306 } 307 } 308 309 if (ret) { 310 for (i = 0; i < SOLO_I2C_ADAPTERS; i++) { 311 if (!solo_dev->i2c_adap[i].algo_data) 312 break; 313 i2c_del_adapter(&solo_dev->i2c_adap[i]); 314 solo_dev->i2c_adap[i].algo_data = NULL; 315 } 316 return ret; 317 } 318 319 return 0; 320 } 321 322 void solo_i2c_exit(struct solo_dev *solo_dev) 323 { 324 int i; 325 326 for (i = 0; i < SOLO_I2C_ADAPTERS; i++) { 327 if (!solo_dev->i2c_adap[i].algo_data) 328 continue; 329 i2c_del_adapter(&solo_dev->i2c_adap[i]); 330 solo_dev->i2c_adap[i].algo_data = NULL; 331 } 332 } 333