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