Blame view

drivers/i2c/s3c24x0_i2c.c 8.01 KB
1cb8e980c   wdenk   * Patches by Davi...
1
2
3
4
  /*
   * (C) Copyright 2002
   * David Mueller, ELSOFT AG, d.mueller@elsoft.ch
   *
1a4596601   Wolfgang Denk   Add GPL-2.0+ SPDX...
5
   * SPDX-License-Identifier:	GPL-2.0+
1cb8e980c   wdenk   * Patches by Davi...
6
   */
1cb8e980c   wdenk   * Patches by Davi...
7
  #include <common.h>
8dfcbaa68   Przemyslaw Marczak   dm: i2c: s3c24x0:...
8
9
  #include <errno.h>
  #include <dm.h>
a9d2ae701   Rajeshwari Shinde   I2C: Driver chang...
10
  #include <fdtdec.h>
c86d9ed38   Piotr Wilczek   drivers:i2c: Modi...
11
  #if (defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)
ab7e52bb2   Rajeshwari Shinde   I2C: Modify the I...
12
13
  #include <asm/arch/clk.h>
  #include <asm/arch/cpu.h>
a9d2ae701   Rajeshwari Shinde   I2C: Driver chang...
14
  #include <asm/arch/pinmux.h>
ab7e52bb2   Rajeshwari Shinde   I2C: Modify the I...
15
  #else
ac67804fb   kevin.morfitt@fearnside-systems.co.uk   Add a unified s3c...
16
  #include <asm/arch/s3c24x0_cpu.h>
ab7e52bb2   Rajeshwari Shinde   I2C: Modify the I...
17
  #endif
eb0ae7f54   kevin.morfitt@fearnside-systems.co.uk   Clean-up of s3c24...
18
  #include <asm/io.h>
1cb8e980c   wdenk   * Patches by Davi...
19
  #include <i2c.h>
ab7e52bb2   Rajeshwari Shinde   I2C: Modify the I...
20
  #include "s3c24x0_i2c.h"
1cb8e980c   wdenk   * Patches by Davi...
21

a298712e9   Jaehoon Chung   i2c: s3c24x0: fix...
22
23
24
25
26
  #ifndef CONFIG_SYS_I2C_S3C24X0_SLAVE
  #define SYS_I2C_S3C24X0_SLAVE_ADDR	0
  #else
  #define SYS_I2C_S3C24X0_SLAVE_ADDR	CONFIG_SYS_I2C_S3C24X0_SLAVE
  #endif
8dfcbaa68   Przemyslaw Marczak   dm: i2c: s3c24x0:...
27
  DECLARE_GLOBAL_DATA_PTR;
e4e240207   Naveen Krishna Ch   exynos: i2c: Fix ...
28
29
30
31
32
33
34
35
  /*
   * Wait til the byte transfer is completed.
   *
   * @param i2c- pointer to the appropriate i2c register bank.
   * @return I2C_OK, if transmission was ACKED
   *         I2C_NACK, if transmission was NACKED
   *         I2C_NOK_TIMEOUT, if transaction did not complete in I2C_TIMEOUT_MS
   */
ab7e52bb2   Rajeshwari Shinde   I2C: Modify the I...
36
  static int WaitForXfer(struct s3c24x0_i2c *i2c)
1cb8e980c   wdenk   * Patches by Davi...
37
  {
e4e240207   Naveen Krishna Ch   exynos: i2c: Fix ...
38
  	ulong start_time = get_timer(0);
1cb8e980c   wdenk   * Patches by Davi...
39

e4e240207   Naveen Krishna Ch   exynos: i2c: Fix ...
40
41
42
43
44
  	do {
  		if (readl(&i2c->iiccon) & I2CCON_IRPND)
  			return (readl(&i2c->iicstat) & I2CSTAT_NACK) ?
  				I2C_NACK : I2C_OK;
  	} while (get_timer(start_time) < I2C_TIMEOUT_MS);
1cb8e980c   wdenk   * Patches by Davi...
45

e4e240207   Naveen Krishna Ch   exynos: i2c: Fix ...
46
  	return I2C_NOK_TOUT;
1cb8e980c   wdenk   * Patches by Davi...
47
  }
26ea76850   Simon Glass   exynos: i2c: Fix ...
48
  static void read_write_byte(struct s3c24x0_i2c *i2c)
1cb8e980c   wdenk   * Patches by Davi...
49
  {
26ea76850   Simon Glass   exynos: i2c: Fix ...
50
  	clrbits_le32(&i2c->iiccon, I2CCON_IRPND);
1cb8e980c   wdenk   * Patches by Davi...
51
  }
ab7e52bb2   Rajeshwari Shinde   I2C: Modify the I...
52
53
54
  static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd)
  {
  	ulong freq, pres = 16, div;
c86d9ed38   Piotr Wilczek   drivers:i2c: Modi...
55
  #if (defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)
ab7e52bb2   Rajeshwari Shinde   I2C: Modify the I...
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
  	freq = get_i2c_clk();
  #else
  	freq = get_PCLK();
  #endif
  	/* calculate prescaler and divisor values */
  	if ((freq / pres / (16 + 1)) > speed)
  		/* set prescaler to 512 */
  		pres = 512;
  
  	div = 0;
  	while ((freq / pres / (div + 1)) > speed)
  		div++;
  
  	/* set prescaler, divisor according to freq, also set ACKGEN, IRQ */
  	writel((div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0), &i2c->iiccon);
  
  	/* init to SLAVE REVEIVE and set slaveaddr */
  	writel(0, &i2c->iicstat);
  	writel(slaveadd, &i2c->iicadd);
  	/* program Master Transmit (and implicit STOP) */
  	writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat);
  }
8dfcbaa68   Przemyslaw Marczak   dm: i2c: s3c24x0:...
78
  static int s3c24x0_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
2d8f1e276   Piotr Wilczek   driver:i2c:s3c24x...
79
  {
9a1bff69c   Simon Glass   samsung: i2c: Dro...
80
  	struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
2d8f1e276   Piotr Wilczek   driver:i2c:s3c24x...
81

2d8f1e276   Piotr Wilczek   driver:i2c:s3c24x...
82
  	i2c_bus->clock_frequency = speed;
37b8eb37f   Simon Glass   samsung: i2c: Spl...
83
  	i2c_ch_init(i2c_bus->regs, i2c_bus->clock_frequency,
a298712e9   Jaehoon Chung   i2c: s3c24x0: fix...
84
  		    SYS_I2C_S3C24X0_SLAVE_ADDR);
2d8f1e276   Piotr Wilczek   driver:i2c:s3c24x...
85
86
87
  
  	return 0;
  }
296a461dc   Naveen Krishna Ch   i2c: s3c24xx: add...
88
  /*
fc3e2165e   wdenk   * Patch by Sangmo...
89
90
91
92
93
94
   * cmd_type is 0 for write, 1 for read.
   *
   * addr_len can take any value from 0-255, it is only limited
   * by the char, we could make it larger if needed. If it is
   * 0 we skip the address write cycle.
   */
ab7e52bb2   Rajeshwari Shinde   I2C: Modify the I...
95
96
97
98
99
100
101
  static int i2c_transfer(struct s3c24x0_i2c *i2c,
  			unsigned char cmd_type,
  			unsigned char chip,
  			unsigned char addr[],
  			unsigned char addr_len,
  			unsigned char data[],
  			unsigned short data_len)
1cb8e980c   wdenk   * Patches by Davi...
102
  {
e4e240207   Naveen Krishna Ch   exynos: i2c: Fix ...
103
104
  	int i = 0, result;
  	ulong start_time = get_timer(0);
1cb8e980c   wdenk   * Patches by Davi...
105

fc3e2165e   wdenk   * Patch by Sangmo...
106
107
  	if (data == 0 || data_len == 0) {
  		/*Don't support data transfer of no length or to address 0 */
ab7e52bb2   Rajeshwari Shinde   I2C: Modify the I...
108
109
  		debug("i2c_transfer: bad call
  ");
fc3e2165e   wdenk   * Patch by Sangmo...
110
111
  		return I2C_NOK;
  	}
1cb8e980c   wdenk   * Patches by Davi...
112

e4e240207   Naveen Krishna Ch   exynos: i2c: Fix ...
113
114
115
  	while (readl(&i2c->iicstat) & I2CSTAT_BSY) {
  		if (get_timer(start_time) > I2C_TIMEOUT_MS)
  			return I2C_NOK_TOUT;
fc3e2165e   wdenk   * Patch by Sangmo...
116
  	}
1cb8e980c   wdenk   * Patches by Davi...
117

ab7e52bb2   Rajeshwari Shinde   I2C: Modify the I...
118
  	writel(readl(&i2c->iiccon) | I2CCON_ACKGEN, &i2c->iiccon);
1cb8e980c   wdenk   * Patches by Davi...
119

e4e240207   Naveen Krishna Ch   exynos: i2c: Fix ...
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
  	/* Get the slave chip address going */
  	writel(chip, &i2c->iicds);
  	if ((cmd_type == I2C_WRITE) || (addr && addr_len))
  		writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP,
  		       &i2c->iicstat);
  	else
  		writel(I2C_MODE_MR | I2C_TXRX_ENA | I2C_START_STOP,
  		       &i2c->iicstat);
  
  	/* Wait for chip address to transmit. */
  	result = WaitForXfer(i2c);
  	if (result != I2C_OK)
  		goto bailout;
  
  	/* If register address needs to be transmitted - do it now. */
  	if (addr && addr_len) {
  		while ((i < addr_len) && (result == I2C_OK)) {
  			writel(addr[i++], &i2c->iicds);
26ea76850   Simon Glass   exynos: i2c: Fix ...
138
  			read_write_byte(i2c);
e4e240207   Naveen Krishna Ch   exynos: i2c: Fix ...
139
  			result = WaitForXfer(i2c);
1cb8e980c   wdenk   * Patches by Davi...
140
  		}
e4e240207   Naveen Krishna Ch   exynos: i2c: Fix ...
141
142
143
144
  		i = 0;
  		if (result != I2C_OK)
  			goto bailout;
  	}
1cb8e980c   wdenk   * Patches by Davi...
145

e4e240207   Naveen Krishna Ch   exynos: i2c: Fix ...
146
147
148
149
  	switch (cmd_type) {
  	case I2C_WRITE:
  		while ((i < data_len) && (result == I2C_OK)) {
  			writel(data[i++], &i2c->iicds);
26ea76850   Simon Glass   exynos: i2c: Fix ...
150
  			read_write_byte(i2c);
ab7e52bb2   Rajeshwari Shinde   I2C: Modify the I...
151
  			result = WaitForXfer(i2c);
e4e240207   Naveen Krishna Ch   exynos: i2c: Fix ...
152
  		}
fc3e2165e   wdenk   * Patch by Sangmo...
153
  		break;
1cb8e980c   wdenk   * Patches by Davi...
154

48b42616e   wdenk   * Patches by Davi...
155
  	case I2C_READ:
fc3e2165e   wdenk   * Patch by Sangmo...
156
  		if (addr && addr_len) {
e4e240207   Naveen Krishna Ch   exynos: i2c: Fix ...
157
158
159
160
  			/*
  			 * Register address has been sent, now send slave chip
  			 * address again to start the actual read transaction.
  			 */
d9abba825   C Nauman   Add generic suppo...
161
  			writel(chip, &i2c->iicds);
e4e240207   Naveen Krishna Ch   exynos: i2c: Fix ...
162
163
  
  			/* Generate a re-START. */
cb466c056   Rajeshwari Shinde   I2C: S3C24X0: Bug...
164
165
  			writel(I2C_MODE_MR | I2C_TXRX_ENA | I2C_START_STOP,
  				&i2c->iicstat);
26ea76850   Simon Glass   exynos: i2c: Fix ...
166
  			read_write_byte(i2c);
ab7e52bb2   Rajeshwari Shinde   I2C: Modify the I...
167
  			result = WaitForXfer(i2c);
fc3e2165e   wdenk   * Patch by Sangmo...
168

e4e240207   Naveen Krishna Ch   exynos: i2c: Fix ...
169
170
  			if (result != I2C_OK)
  				goto bailout;
1cb8e980c   wdenk   * Patches by Davi...
171
  		}
1cb8e980c   wdenk   * Patches by Davi...
172

e4e240207   Naveen Krishna Ch   exynos: i2c: Fix ...
173
174
175
176
177
178
  		while ((i < data_len) && (result == I2C_OK)) {
  			/* disable ACK for final READ */
  			if (i == data_len - 1)
  				writel(readl(&i2c->iiccon)
  				       & ~I2CCON_ACKGEN,
  				       &i2c->iiccon);
26ea76850   Simon Glass   exynos: i2c: Fix ...
179
  			read_write_byte(i2c);
e4e240207   Naveen Krishna Ch   exynos: i2c: Fix ...
180
181
182
183
184
  			result = WaitForXfer(i2c);
  			data[i++] = readl(&i2c->iicds);
  		}
  		if (result == I2C_NACK)
  			result = I2C_OK; /* Normal terminated read. */
fc3e2165e   wdenk   * Patch by Sangmo...
185
  		break;
1cb8e980c   wdenk   * Patches by Davi...
186
187
  
  	default:
ab7e52bb2   Rajeshwari Shinde   I2C: Modify the I...
188
189
  		debug("i2c_transfer: bad call
  ");
fc3e2165e   wdenk   * Patch by Sangmo...
190
191
192
  		result = I2C_NOK;
  		break;
  	}
1cb8e980c   wdenk   * Patches by Davi...
193

e4e240207   Naveen Krishna Ch   exynos: i2c: Fix ...
194
195
196
  bailout:
  	/* Send STOP. */
  	writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat);
26ea76850   Simon Glass   exynos: i2c: Fix ...
197
  	read_write_byte(i2c);
e4e240207   Naveen Krishna Ch   exynos: i2c: Fix ...
198

ab7e52bb2   Rajeshwari Shinde   I2C: Modify the I...
199
  	return result;
1cb8e980c   wdenk   * Patches by Davi...
200
  }
8dfcbaa68   Przemyslaw Marczak   dm: i2c: s3c24x0:...
201
  static int s3c24x0_i2c_probe(struct udevice *dev, uint chip, uint chip_flags)
1cb8e980c   wdenk   * Patches by Davi...
202
  {
9a1bff69c   Simon Glass   samsung: i2c: Dro...
203
  	struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
fc3e2165e   wdenk   * Patch by Sangmo...
204
  	uchar buf[1];
296a461dc   Naveen Krishna Ch   i2c: s3c24xx: add...
205
  	int ret;
1cb8e980c   wdenk   * Patches by Davi...
206

fc3e2165e   wdenk   * Patch by Sangmo...
207
  	buf[0] = 0;
1cb8e980c   wdenk   * Patches by Davi...
208

fc3e2165e   wdenk   * Patch by Sangmo...
209
210
211
212
213
  	/*
  	 * What is needed is to send the chip address and verify that the
  	 * address was <ACK>ed (i.e. there was a chip at that address which
  	 * drove the data line low).
  	 */
37b8eb37f   Simon Glass   samsung: i2c: Spl...
214
  	ret = i2c_transfer(i2c_bus->regs, I2C_READ, chip << 1, 0, 0, buf, 1);
296a461dc   Naveen Krishna Ch   i2c: s3c24xx: add...
215

296a461dc   Naveen Krishna Ch   i2c: s3c24xx: add...
216
  	return ret != I2C_OK;
1cb8e980c   wdenk   * Patches by Davi...
217
  }
45d9ae87c   Simon Glass   exynos: i2c: Tidy...
218
219
  static int s3c24x0_do_msg(struct s3c24x0_i2c_bus *i2c_bus, struct i2c_msg *msg,
  			  int seq)
8dfcbaa68   Przemyslaw Marczak   dm: i2c: s3c24x0:...
220
  {
45d9ae87c   Simon Glass   exynos: i2c: Tidy...
221
222
223
224
225
  	struct s3c24x0_i2c *i2c = i2c_bus->regs;
  	bool is_read = msg->flags & I2C_M_RD;
  	uint status;
  	uint addr;
  	int ret, i;
8dfcbaa68   Przemyslaw Marczak   dm: i2c: s3c24x0:...
226

45d9ae87c   Simon Glass   exynos: i2c: Tidy...
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
  	if (!seq)
  		setbits_le32(&i2c->iiccon, I2CCON_ACKGEN);
  
  	/* Get the slave chip address going */
  	addr = msg->addr << 1;
  	writel(addr, &i2c->iicds);
  	status = I2C_TXRX_ENA | I2C_START_STOP;
  	if (is_read)
  		status |= I2C_MODE_MR;
  	else
  		status |= I2C_MODE_MT;
  	writel(status, &i2c->iicstat);
  	if (seq)
  		read_write_byte(i2c);
  
  	/* Wait for chip address to transmit */
  	ret = WaitForXfer(i2c);
  	if (ret)
  		goto err;
  
  	if (is_read) {
  		for (i = 0; !ret && i < msg->len; i++) {
  			/* disable ACK for final READ */
  			if (i == msg->len - 1)
  				clrbits_le32(&i2c->iiccon, I2CCON_ACKGEN);
  			read_write_byte(i2c);
  			ret = WaitForXfer(i2c);
  			msg->buf[i] = readl(&i2c->iicds);
  		}
  		if (ret == I2C_NACK)
  			ret = I2C_OK; /* Normal terminated read */
8dfcbaa68   Przemyslaw Marczak   dm: i2c: s3c24x0:...
258
  	} else {
45d9ae87c   Simon Glass   exynos: i2c: Tidy...
259
260
261
262
263
  		for (i = 0; !ret && i < msg->len; i++) {
  			writel(msg->buf[i], &i2c->iicds);
  			read_write_byte(i2c);
  			ret = WaitForXfer(i2c);
  		}
8dfcbaa68   Przemyslaw Marczak   dm: i2c: s3c24x0:...
264
  	}
45d9ae87c   Simon Glass   exynos: i2c: Tidy...
265
266
  err:
  	return ret;
8dfcbaa68   Przemyslaw Marczak   dm: i2c: s3c24x0:...
267
268
269
270
271
272
  }
  
  static int s3c24x0_i2c_xfer(struct udevice *dev, struct i2c_msg *msg,
  			    int nmsgs)
  {
  	struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
45d9ae87c   Simon Glass   exynos: i2c: Tidy...
273
274
275
  	struct s3c24x0_i2c *i2c = i2c_bus->regs;
  	ulong start_time;
  	int ret, i;
8dfcbaa68   Przemyslaw Marczak   dm: i2c: s3c24x0:...
276

45d9ae87c   Simon Glass   exynos: i2c: Tidy...
277
278
279
280
281
282
  	start_time = get_timer(0);
  	while (readl(&i2c->iicstat) & I2CSTAT_BSY) {
  		if (get_timer(start_time) > I2C_TIMEOUT_MS) {
  			debug("Timeout
  ");
  			return -ETIMEDOUT;
8dfcbaa68   Przemyslaw Marczak   dm: i2c: s3c24x0:...
283
  		}
8dfcbaa68   Przemyslaw Marczak   dm: i2c: s3c24x0:...
284
  	}
45d9ae87c   Simon Glass   exynos: i2c: Tidy...
285
286
287
288
289
290
291
292
  	for (ret = 0, i = 0; !ret && i < nmsgs; i++)
  		ret = s3c24x0_do_msg(i2c_bus, &msg[i], i);
  
  	/* Send STOP */
  	writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat);
  	read_write_byte(i2c);
  
  	return ret ? -EREMOTEIO : 0;
8dfcbaa68   Przemyslaw Marczak   dm: i2c: s3c24x0:...
293
294
295
296
297
298
  }
  
  static int s3c_i2c_ofdata_to_platdata(struct udevice *dev)
  {
  	const void *blob = gd->fdt_blob;
  	struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
37b8eb37f   Simon Glass   samsung: i2c: Spl...
299
  	int node;
8dfcbaa68   Przemyslaw Marczak   dm: i2c: s3c24x0:...
300

e160f7d43   Simon Glass   dm: core: Replace...
301
  	node = dev_of_offset(dev);
8dfcbaa68   Przemyslaw Marczak   dm: i2c: s3c24x0:...
302

a821c4af7   Simon Glass   dm: Rename dev_ad...
303
  	i2c_bus->regs = (struct s3c24x0_i2c *)devfdt_get_addr(dev);
8dfcbaa68   Przemyslaw Marczak   dm: i2c: s3c24x0:...
304
305
306
307
  
  	i2c_bus->id = pinmux_decode_periph_id(blob, node);
  
  	i2c_bus->clock_frequency = fdtdec_get_int(blob, node,
45d9ae87c   Simon Glass   exynos: i2c: Tidy...
308
  						  "clock-frequency", 100000);
8dfcbaa68   Przemyslaw Marczak   dm: i2c: s3c24x0:...
309
310
  	i2c_bus->node = node;
  	i2c_bus->bus_num = dev->seq;
37b8eb37f   Simon Glass   samsung: i2c: Spl...
311
  	exynos_pinmux_config(i2c_bus->id, 0);
8dfcbaa68   Przemyslaw Marczak   dm: i2c: s3c24x0:...
312
313
314
315
316
317
318
319
320
321
322
323
324
  
  	i2c_bus->active = true;
  
  	return 0;
  }
  
  static const struct dm_i2c_ops s3c_i2c_ops = {
  	.xfer		= s3c24x0_i2c_xfer,
  	.probe_chip	= s3c24x0_i2c_probe,
  	.set_bus_speed	= s3c24x0_i2c_set_bus_speed,
  };
  
  static const struct udevice_id s3c_i2c_ids[] = {
37b8eb37f   Simon Glass   samsung: i2c: Spl...
325
  	{ .compatible = "samsung,s3c2440-i2c" },
8dfcbaa68   Przemyslaw Marczak   dm: i2c: s3c24x0:...
326
327
328
329
330
331
332
333
  	{ }
  };
  
  U_BOOT_DRIVER(i2c_s3c) = {
  	.name	= "i2c_s3c",
  	.id	= UCLASS_I2C,
  	.of_match = s3c_i2c_ids,
  	.ofdata_to_platdata = s3c_i2c_ofdata_to_platdata,
8dfcbaa68   Przemyslaw Marczak   dm: i2c: s3c24x0:...
334
335
336
  	.priv_auto_alloc_size = sizeof(struct s3c24x0_i2c_bus),
  	.ops	= &s3c_i2c_ops,
  };