• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  *  cobalt I2C functions
4  *
5  *  Derived from cx18-i2c.c
6  *
7  *  Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
8  *  All rights reserved.
9  */
10 
11 #include "cobalt-driver.h"
12 #include "cobalt-i2c.h"
13 
14 struct cobalt_i2c_regs {
15 	/* Clock prescaler register lo-byte */
16 	u8 prerlo;
17 	u8 dummy0[3];
18 	/* Clock prescaler register high-byte */
19 	u8 prerhi;
20 	u8 dummy1[3];
21 	/* Control register */
22 	u8 ctr;
23 	u8 dummy2[3];
24 	/* Transmit/Receive register */
25 	u8 txr_rxr;
26 	u8 dummy3[3];
27 	/* Command and Status register */
28 	u8 cr_sr;
29 	u8 dummy4[3];
30 };
31 
32 /* CTR[7:0] - Control register */
33 
34 /* I2C Core enable bit */
35 #define M00018_CTR_BITMAP_EN_MSK	(1 << 7)
36 
37 /* I2C Core interrupt enable bit */
38 #define M00018_CTR_BITMAP_IEN_MSK	(1 << 6)
39 
40 /* CR[7:0] - Command register */
41 
42 /* I2C start condition */
43 #define M00018_CR_BITMAP_STA_MSK	(1 << 7)
44 
45 /* I2C stop condition */
46 #define M00018_CR_BITMAP_STO_MSK	(1 << 6)
47 
48 /* I2C read from slave */
49 #define M00018_CR_BITMAP_RD_MSK		(1 << 5)
50 
51 /* I2C write to slave */
52 #define M00018_CR_BITMAP_WR_MSK		(1 << 4)
53 
54 /* I2C ack */
55 #define M00018_CR_BITMAP_ACK_MSK	(1 << 3)
56 
57 /* I2C Interrupt ack */
58 #define M00018_CR_BITMAP_IACK_MSK	(1 << 0)
59 
60 /* SR[7:0] - Status register */
61 
62 /* Receive acknowledge from slave */
63 #define M00018_SR_BITMAP_RXACK_MSK	(1 << 7)
64 
65 /* Busy, I2C bus busy (as defined by start / stop bits) */
66 #define M00018_SR_BITMAP_BUSY_MSK	(1 << 6)
67 
68 /* Arbitration lost - core lost arbitration */
69 #define M00018_SR_BITMAP_AL_MSK		(1 << 5)
70 
71 /* Transfer in progress */
72 #define M00018_SR_BITMAP_TIP_MSK	(1 << 1)
73 
74 /* Interrupt flag */
75 #define M00018_SR_BITMAP_IF_MSK		(1 << 0)
76 
77 /* Frequency, in Hz */
78 #define I2C_FREQUENCY			400000
79 #define ALT_CPU_FREQ			83333333
80 
81 static struct cobalt_i2c_regs __iomem *
cobalt_i2c_regs(struct cobalt * cobalt,unsigned idx)82 cobalt_i2c_regs(struct cobalt *cobalt, unsigned idx)
83 {
84 	switch (idx) {
85 	case 0:
86 	default:
87 		return (struct cobalt_i2c_regs __iomem *)
88 			(cobalt->bar1 + COBALT_I2C_0_BASE);
89 	case 1:
90 		return (struct cobalt_i2c_regs __iomem *)
91 			(cobalt->bar1 + COBALT_I2C_1_BASE);
92 	case 2:
93 		return (struct cobalt_i2c_regs __iomem *)
94 			(cobalt->bar1 + COBALT_I2C_2_BASE);
95 	case 3:
96 		return (struct cobalt_i2c_regs __iomem *)
97 			(cobalt->bar1 + COBALT_I2C_3_BASE);
98 	case 4:
99 		return (struct cobalt_i2c_regs __iomem *)
100 			(cobalt->bar1 + COBALT_I2C_HSMA_BASE);
101 	}
102 }
103 
104 /* Do low-level i2c byte transfer.
105  * Returns -1 in case of an error or 0 otherwise.
106  */
cobalt_tx_bytes(struct cobalt_i2c_regs __iomem * regs,struct i2c_adapter * adap,bool start,bool stop,u8 * data,u16 len)107 static int cobalt_tx_bytes(struct cobalt_i2c_regs __iomem *regs,
108 		struct i2c_adapter *adap, bool start, bool stop,
109 		u8 *data, u16 len)
110 {
111 	unsigned long start_time;
112 	int status;
113 	int cmd;
114 	int i;
115 
116 	for (i = 0; i < len; i++) {
117 		/* Setup data */
118 		iowrite8(data[i], &regs->txr_rxr);
119 
120 		/* Setup command */
121 		if (i == 0 && start) {
122 			/* Write + Start */
123 			cmd = M00018_CR_BITMAP_WR_MSK |
124 			      M00018_CR_BITMAP_STA_MSK;
125 		} else if (i == len - 1 && stop) {
126 			/* Write + Stop */
127 			cmd = M00018_CR_BITMAP_WR_MSK |
128 			      M00018_CR_BITMAP_STO_MSK;
129 		} else {
130 			/* Write only */
131 			cmd = M00018_CR_BITMAP_WR_MSK;
132 		}
133 
134 		/* Execute command */
135 		iowrite8(cmd, &regs->cr_sr);
136 
137 		/* Wait for transfer to complete (TIP = 0) */
138 		start_time = jiffies;
139 		status = ioread8(&regs->cr_sr);
140 		while (status & M00018_SR_BITMAP_TIP_MSK) {
141 			if (time_after(jiffies, start_time + adap->timeout))
142 				return -ETIMEDOUT;
143 			cond_resched();
144 			status = ioread8(&regs->cr_sr);
145 		}
146 
147 		/* Verify ACK */
148 		if (status & M00018_SR_BITMAP_RXACK_MSK) {
149 			/* NO ACK! */
150 			return -EIO;
151 		}
152 
153 		/* Verify arbitration */
154 		if (status & M00018_SR_BITMAP_AL_MSK) {
155 			/* Arbitration lost! */
156 			return -EIO;
157 		}
158 	}
159 	return 0;
160 }
161 
162 /* Do low-level i2c byte read.
163  * Returns -1 in case of an error or 0 otherwise.
164  */
cobalt_rx_bytes(struct cobalt_i2c_regs __iomem * regs,struct i2c_adapter * adap,bool start,bool stop,u8 * data,u16 len)165 static int cobalt_rx_bytes(struct cobalt_i2c_regs __iomem *regs,
166 		struct i2c_adapter *adap, bool start, bool stop,
167 		u8 *data, u16 len)
168 {
169 	unsigned long start_time;
170 	int status;
171 	int cmd;
172 	int i;
173 
174 	for (i = 0; i < len; i++) {
175 		/* Setup command */
176 		if (i == 0 && start) {
177 			/* Read + Start */
178 			cmd = M00018_CR_BITMAP_RD_MSK |
179 			      M00018_CR_BITMAP_STA_MSK;
180 		} else if (i == len - 1 && stop) {
181 			/* Read + Stop */
182 			cmd = M00018_CR_BITMAP_RD_MSK |
183 			      M00018_CR_BITMAP_STO_MSK;
184 		} else {
185 			/* Read only */
186 			cmd = M00018_CR_BITMAP_RD_MSK;
187 		}
188 
189 		/* Last byte to read, no ACK */
190 		if (i == len - 1)
191 			cmd |= M00018_CR_BITMAP_ACK_MSK;
192 
193 		/* Execute command */
194 		iowrite8(cmd, &regs->cr_sr);
195 
196 		/* Wait for transfer to complete (TIP = 0) */
197 		start_time = jiffies;
198 		status = ioread8(&regs->cr_sr);
199 		while (status & M00018_SR_BITMAP_TIP_MSK) {
200 			if (time_after(jiffies, start_time + adap->timeout))
201 				return -ETIMEDOUT;
202 			cond_resched();
203 			status = ioread8(&regs->cr_sr);
204 		}
205 
206 		/* Verify arbitration */
207 		if (status & M00018_SR_BITMAP_AL_MSK) {
208 			/* Arbitration lost! */
209 			return -EIO;
210 		}
211 
212 		/* Store data */
213 		data[i] = ioread8(&regs->txr_rxr);
214 	}
215 	return 0;
216 }
217 
218 /* Generate stop condition on i2c bus.
219  * The m00018 stop isn't doing the right thing (wrong timing).
220  * So instead send a start condition, 8 zeroes and a stop condition.
221  */
cobalt_stop(struct cobalt_i2c_regs __iomem * regs,struct i2c_adapter * adap)222 static int cobalt_stop(struct cobalt_i2c_regs __iomem *regs,
223 		struct i2c_adapter *adap)
224 {
225 	u8 data = 0;
226 
227 	return cobalt_tx_bytes(regs, adap, true, true, &data, 1);
228 }
229 
cobalt_xfer(struct i2c_adapter * adap,struct i2c_msg msgs[],int num)230 static int cobalt_xfer(struct i2c_adapter *adap,
231 			struct i2c_msg msgs[], int num)
232 {
233 	struct cobalt_i2c_data *data = adap->algo_data;
234 	struct cobalt_i2c_regs __iomem *regs = data->regs;
235 	struct i2c_msg *pmsg;
236 	unsigned short flags;
237 	int ret = 0;
238 	int i, j;
239 
240 	for (i = 0; i < num; i++) {
241 		int stop = (i == num - 1);
242 
243 		pmsg = &msgs[i];
244 		flags = pmsg->flags;
245 
246 		if (!(pmsg->flags & I2C_M_NOSTART)) {
247 			u8 addr = pmsg->addr << 1;
248 
249 			if (flags & I2C_M_RD)
250 				addr |= 1;
251 			if (flags & I2C_M_REV_DIR_ADDR)
252 				addr ^= 1;
253 			for (j = 0; j < adap->retries; j++) {
254 				ret = cobalt_tx_bytes(regs, adap, true, false,
255 						      &addr, 1);
256 				if (!ret)
257 					break;
258 				cobalt_stop(regs, adap);
259 			}
260 			if (ret < 0)
261 				return ret;
262 			ret = 0;
263 		}
264 		if (pmsg->flags & I2C_M_RD) {
265 			/* read bytes into buffer */
266 			ret = cobalt_rx_bytes(regs, adap, false, stop,
267 					pmsg->buf, pmsg->len);
268 			if (ret < 0)
269 				goto bailout;
270 		} else {
271 			/* write bytes from buffer */
272 			ret = cobalt_tx_bytes(regs, adap, false, stop,
273 					pmsg->buf, pmsg->len);
274 			if (ret < 0)
275 				goto bailout;
276 		}
277 	}
278 	ret = i;
279 
280 bailout:
281 	if (ret < 0)
282 		cobalt_stop(regs, adap);
283 	return ret;
284 }
285 
cobalt_func(struct i2c_adapter * adap)286 static u32 cobalt_func(struct i2c_adapter *adap)
287 {
288 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
289 }
290 
291 /* template for i2c-bit-algo */
292 static const struct i2c_adapter cobalt_i2c_adap_template = {
293 	.name = "cobalt i2c driver",
294 	.algo = NULL,                   /* set by i2c-algo-bit */
295 	.algo_data = NULL,              /* filled from template */
296 	.owner = THIS_MODULE,
297 };
298 
299 static const struct i2c_algorithm cobalt_algo = {
300 	.master_xfer	= cobalt_xfer,
301 	.functionality	= cobalt_func,
302 };
303 
304 /* init + register i2c algo-bit adapter */
cobalt_i2c_init(struct cobalt * cobalt)305 int cobalt_i2c_init(struct cobalt *cobalt)
306 {
307 	int i, err;
308 	int status;
309 	int prescale;
310 	unsigned long start_time;
311 
312 	cobalt_dbg(1, "i2c init\n");
313 
314 	/* Define I2C clock prescaler */
315 	prescale = ((ALT_CPU_FREQ) / (5 * I2C_FREQUENCY)) - 1;
316 
317 	for (i = 0; i < COBALT_NUM_ADAPTERS; i++) {
318 		struct cobalt_i2c_regs __iomem *regs =
319 			cobalt_i2c_regs(cobalt, i);
320 		struct i2c_adapter *adap = &cobalt->i2c_adap[i];
321 
322 		/* Disable I2C */
323 		iowrite8(M00018_CTR_BITMAP_EN_MSK, &regs->cr_sr);
324 		iowrite8(0, &regs->ctr);
325 		iowrite8(0, &regs->cr_sr);
326 
327 		start_time = jiffies;
328 		do {
329 			if (time_after(jiffies, start_time + HZ)) {
330 				if (cobalt_ignore_err) {
331 					adap->dev.parent = NULL;
332 					return 0;
333 				}
334 				return -ETIMEDOUT;
335 			}
336 			status = ioread8(&regs->cr_sr);
337 		} while (status & M00018_SR_BITMAP_TIP_MSK);
338 
339 		/* Disable I2C */
340 		iowrite8(0, &regs->ctr);
341 		iowrite8(0, &regs->cr_sr);
342 
343 		/* Calculate i2c prescaler */
344 		iowrite8(prescale & 0xff, &regs->prerlo);
345 		iowrite8((prescale >> 8) & 0xff, &regs->prerhi);
346 		/* Enable I2C, interrupts disabled */
347 		iowrite8(M00018_CTR_BITMAP_EN_MSK, &regs->ctr);
348 		/* Setup algorithm for adapter */
349 		cobalt->i2c_data[i].cobalt = cobalt;
350 		cobalt->i2c_data[i].regs = regs;
351 		*adap = cobalt_i2c_adap_template;
352 		adap->algo = &cobalt_algo;
353 		adap->algo_data = &cobalt->i2c_data[i];
354 		adap->retries = 3;
355 		sprintf(adap->name + strlen(adap->name),
356 				" #%d-%d", cobalt->instance, i);
357 		i2c_set_adapdata(adap, &cobalt->v4l2_dev);
358 		adap->dev.parent = &cobalt->pci_dev->dev;
359 		err = i2c_add_adapter(adap);
360 		if (err) {
361 			if (cobalt_ignore_err) {
362 				adap->dev.parent = NULL;
363 				return 0;
364 			}
365 			while (i--)
366 				i2c_del_adapter(&cobalt->i2c_adap[i]);
367 			return err;
368 		}
369 		cobalt_info("registered bus %s\n", adap->name);
370 	}
371 	return 0;
372 }
373 
cobalt_i2c_exit(struct cobalt * cobalt)374 void cobalt_i2c_exit(struct cobalt *cobalt)
375 {
376 	int i;
377 
378 	cobalt_dbg(1, "i2c exit\n");
379 
380 	for (i = 0; i < COBALT_NUM_ADAPTERS; i++) {
381 		cobalt_err("unregistered bus %s\n", cobalt->i2c_adap[i].name);
382 		i2c_del_adapter(&cobalt->i2c_adap[i]);
383 	}
384 }
385