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 21#include <linux/kernel.h> 22 23#include "solo6010.h" 24 25u8 solo_i2c_readbyte(struct solo6010_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 solo6010_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 solo6010_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 solo6010_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 solo6010_dev *solo_dev) 97{ 98 solo6010_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 solo6010_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 solo6010_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 solo6010_dev *solo_dev) 166{ 167 u32 status = solo_reg_read(solo_dev, SOLO_IIC_CTRL); 168 int ret = -EINVAL; 169 170 solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_IIC); 171 172 if (status & (SOLO_IIC_STATE_TRNS & SOLO_IIC_STATE_SIG_ERR) || 173 solo_dev->i2c_id < 0) { 174 solo_i2c_stop(solo_dev); 175 return -ENXIO; 176 } 177 178 switch (solo_dev->i2c_state) { 179 case IIC_STATE_START: 180 if (solo_dev->i2c_msg->flags & I2C_M_RD) { 181 solo_dev->i2c_state = IIC_STATE_READ; 182 ret = solo_i2c_handle_read(solo_dev); 183 break; 184 } 185 186 solo_dev->i2c_state = IIC_STATE_WRITE; 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 solo6010_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; 222 223 down(&solo_dev->i2c_sem); 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 solo6010_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, TASK_INTERRUPTIBLE); 237 238 if (solo_dev->i2c_state == IIC_STATE_STOP) 239 break; 240 241 timeout = schedule_timeout(timeout); 242 if (!timeout) 243 break; 244 245 if (signal_pending(current)) 246 break; 247 } 248 249 finish_wait(&solo_dev->i2c_wait, &wait); 250 ret = num - solo_dev->i2c_msg_num; 251 solo_dev->i2c_state = IIC_STATE_IDLE; 252 solo_dev->i2c_id = -1; 253 254 up(&solo_dev->i2c_sem); 255 256 return ret; 257} 258 259static u32 solo_i2c_functionality(struct i2c_adapter *adap) 260{ 261 return I2C_FUNC_I2C; 262} 263 264static struct i2c_algorithm solo_i2c_algo = { 265 .master_xfer = solo_i2c_master_xfer, 266 .functionality = solo_i2c_functionality, 267}; 268 269int solo_i2c_init(struct solo6010_dev *solo_dev) 270{ 271 int i; 272 int ret; 273 274 solo_reg_write(solo_dev, SOLO_IIC_CFG, 275 SOLO_IIC_PRESCALE(8) | SOLO_IIC_ENABLE); 276 277 solo_dev->i2c_id = -1; 278 solo_dev->i2c_state = IIC_STATE_IDLE; 279 init_waitqueue_head(&solo_dev->i2c_wait); 280 init_MUTEX(&solo_dev->i2c_sem); 281 282 for (i = 0; i < SOLO_I2C_ADAPTERS; i++) { 283 struct i2c_adapter *adap = &solo_dev->i2c_adap[i]; 284 285 snprintf(adap->name, I2C_NAME_SIZE, "%s I2C %d", 286 SOLO6010_NAME, i); 287 adap->algo = &solo_i2c_algo; 288 adap->algo_data = solo_dev; 289 adap->retries = 1; 290 adap->dev.parent = &solo_dev->pdev->dev; 291 292 if ((ret = i2c_add_adapter(adap))) { 293 adap->algo_data = NULL; 294 break; 295 } 296 } 297 298 if (ret) { 299 for (i = 0; i < SOLO_I2C_ADAPTERS; i++) { 300 if (!solo_dev->i2c_adap[i].algo_data) 301 break; 302 i2c_del_adapter(&solo_dev->i2c_adap[i]); 303 solo_dev->i2c_adap[i].algo_data = NULL; 304 } 305 return ret; 306 } 307 308 dev_info(&solo_dev->pdev->dev, "Enabled %d i2c adapters\n", 309 SOLO_I2C_ADAPTERS); 310 311 return 0; 312} 313 314void solo_i2c_exit(struct solo6010_dev *solo_dev) 315{ 316 int i; 317 318 for (i = 0; i < SOLO_I2C_ADAPTERS; i++) { 319 if (!solo_dev->i2c_adap[i].algo_data) 320 continue; 321 i2c_del_adapter(&solo_dev->i2c_adap[i]); 322 solo_dev->i2c_adap[i].algo_data = NULL; 323 } 324} 325