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