Commit 5e862b95399e6e5ea7748ee29a38756685d622fd
Committed by
Albert ARIBAUD
1 parent
c8381bf435
Exists in
v2017.01-smarct4x
and in
37 other branches
lpc32xx: i2c: add LPC32xx I2C interface support
Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Showing 6 changed files with 268 additions and 0 deletions Side-by-side Diff
arch/arm/cpu/arm926ejs/lpc32xx/devices.c
... | ... | @@ -50,4 +50,15 @@ |
50 | 50 | /* Enable NAND interface */ |
51 | 51 | writel(CLK_NAND_MLC | CLK_NAND_MLC_INT, &clk->flashclk_ctrl); |
52 | 52 | } |
53 | + | |
54 | +void lpc32xx_i2c_init(unsigned int devnum) | |
55 | +{ | |
56 | + /* Enable I2C interface */ | |
57 | + uint32_t ctrl = readl(&clk->i2cclk_ctrl); | |
58 | + if (devnum == 1) | |
59 | + ctrl |= CLK_I2C1_ENABLE; | |
60 | + if (devnum == 2) | |
61 | + ctrl |= CLK_I2C2_ENABLE; | |
62 | + writel(ctrl, &clk->i2cclk_ctrl); | |
63 | +} |
arch/arm/include/asm/arch-lpc32xx/clk.h
... | ... | @@ -123,6 +123,10 @@ |
123 | 123 | #define CLK_MAC_SLAVE (1 << 1) |
124 | 124 | #define CLK_MAC_REG (1 << 0) |
125 | 125 | |
126 | +/* I2C Clock Control Register bits */ | |
127 | +#define CLK_I2C2_ENABLE (1 << 1) | |
128 | +#define CLK_I2C1_ENABLE (1 << 0) | |
129 | + | |
126 | 130 | /* Timer Clock Control1 Register bits */ |
127 | 131 | #define CLK_TIMCLK_MOTOR (1 << 6) |
128 | 132 | #define CLK_TIMCLK_TIMER3 (1 << 5) |
arch/arm/include/asm/arch-lpc32xx/cpu.h
... | ... | @@ -37,6 +37,8 @@ |
37 | 37 | #define UART4_BASE 0x40088000 /* UART 4 registers base */ |
38 | 38 | #define UART5_BASE 0x40090000 /* UART 5 registers base */ |
39 | 39 | #define UART6_BASE 0x40098000 /* UART 6 registers base */ |
40 | +#define I2C1_BASE 0x400A0000 /* I2C 1 registers base */ | |
41 | +#define I2C2_BASE 0x400A8000 /* I2C 2 registers base */ | |
40 | 42 | |
41 | 43 | /* External SDRAM Memory Bank base addresses */ |
42 | 44 | #define EMC_DYCS0_BASE 0x80000000 /* SDRAM DYCS0 base address */ |
arch/arm/include/asm/arch-lpc32xx/sys_proto.h
drivers/i2c/Makefile
... | ... | @@ -20,6 +20,7 @@ |
20 | 20 | obj-$(CONFIG_SYS_I2C_FTI2C010) += fti2c010.o |
21 | 21 | obj-$(CONFIG_SYS_I2C_IHS) += ihs_i2c.o |
22 | 22 | obj-$(CONFIG_SYS_I2C_KONA) += kona_i2c.o |
23 | +obj-$(CONFIG_SYS_I2C_LPC32XX) += lpc32xx_i2c.o | |
23 | 24 | obj-$(CONFIG_SYS_I2C_MVTWSI) += mvtwsi.o |
24 | 25 | obj-$(CONFIG_SYS_I2C_MXC) += mxc_i2c.o |
25 | 26 | obj-$(CONFIG_SYS_I2C_MXS) += mxs_i2c.o |
drivers/i2c/lpc32xx_i2c.c
1 | +/* | |
2 | + * LPC32xx I2C interface driver | |
3 | + * | |
4 | + * (C) Copyright 2014 DENX Software Engineering GmbH | |
5 | + * Written-by: Albert ARIBAUD - 3ADEV <albert.aribaud@3adev.fr> | |
6 | + * | |
7 | + * SPDX-License-Identifier: GPL-2.0+ | |
8 | + */ | |
9 | + | |
10 | +#include <common.h> | |
11 | +#include <asm/io.h> | |
12 | +#include <i2c.h> | |
13 | +#include <asm/errno.h> | |
14 | +#include <asm/arch/clk.h> | |
15 | + | |
16 | +/* | |
17 | + * Provide default speed and slave if target did not | |
18 | + */ | |
19 | + | |
20 | +#if !defined(CONFIG_SYS_I2C_LPC32XX_SPEED) | |
21 | +#define CONFIG_SYS_I2C_LPC32XX_SPEED 350000 | |
22 | +#endif | |
23 | + | |
24 | +#if !defined(CONFIG_SYS_I2C_LPC32XX_SLAVE) | |
25 | +#define CONFIG_SYS_I2C_LPC32XX_SLAVE 0 | |
26 | +#endif | |
27 | + | |
28 | +/* i2c register set */ | |
29 | +struct lpc32xx_i2c_registers { | |
30 | + union { | |
31 | + u32 rx; | |
32 | + u32 tx; | |
33 | + }; | |
34 | + u32 stat; | |
35 | + u32 ctrl; | |
36 | + u32 clk_hi; | |
37 | + u32 clk_lo; | |
38 | + u32 adr; | |
39 | + u32 rxfl; | |
40 | + u32 txfl; | |
41 | + u32 rxb; | |
42 | + u32 txb; | |
43 | + u32 stx; | |
44 | + u32 stxfl; | |
45 | +}; | |
46 | + | |
47 | +/* TX register fields */ | |
48 | +#define LPC32XX_I2C_TX_START 0x00000100 | |
49 | +#define LPC32XX_I2C_TX_STOP 0x00000200 | |
50 | + | |
51 | +/* Control register values */ | |
52 | +#define LPC32XX_I2C_SOFT_RESET 0x00000100 | |
53 | + | |
54 | +/* Status register values */ | |
55 | +#define LPC32XX_I2C_STAT_TFF 0x00000400 | |
56 | +#define LPC32XX_I2C_STAT_RFE 0x00000200 | |
57 | +#define LPC32XX_I2C_STAT_DRMI 0x00000008 | |
58 | +#define LPC32XX_I2C_STAT_NAI 0x00000004 | |
59 | +#define LPC32XX_I2C_STAT_TDI 0x00000001 | |
60 | + | |
61 | +static struct lpc32xx_i2c_registers *lpc32xx_i2c[] = { | |
62 | + (struct lpc32xx_i2c_registers *)I2C1_BASE, | |
63 | + (struct lpc32xx_i2c_registers *)I2C2_BASE | |
64 | +}; | |
65 | + | |
66 | +/* Set I2C bus speed */ | |
67 | +static unsigned int lpc32xx_i2c_set_bus_speed(struct i2c_adapter *adap, | |
68 | + unsigned int speed) | |
69 | +{ | |
70 | + int half_period; | |
71 | + | |
72 | + if (speed == 0) | |
73 | + return -EINVAL; | |
74 | + | |
75 | + half_period = (105000000 / speed) / 2; | |
76 | + | |
77 | + if ((half_period > 255) || (half_period < 0)) | |
78 | + return -EINVAL; | |
79 | + | |
80 | + writel(half_period, &lpc32xx_i2c[adap->hwadapnr]->clk_hi); | |
81 | + writel(half_period, &lpc32xx_i2c[adap->hwadapnr]->clk_lo); | |
82 | + return 0; | |
83 | +} | |
84 | + | |
85 | +/* I2C init called by cmd_i2c when doing 'i2c reset'. */ | |
86 | +static void _i2c_init(struct i2c_adapter *adap, | |
87 | + int requested_speed, int slaveadd) | |
88 | +{ | |
89 | + struct lpc32xx_i2c_registers *i2c = lpc32xx_i2c[adap->hwadapnr]; | |
90 | + | |
91 | + /* soft reset (auto-clears) */ | |
92 | + writel(LPC32XX_I2C_SOFT_RESET, &i2c->ctrl); | |
93 | + /* set HI and LO periods for about 350 kHz */ | |
94 | + lpc32xx_i2c_set_bus_speed(adap, requested_speed); | |
95 | +} | |
96 | + | |
97 | +/* I2C probe called by cmd_i2c when doing 'i2c probe'. */ | |
98 | +static int lpc32xx_i2c_probe(struct i2c_adapter *adap, u8 dev) | |
99 | +{ | |
100 | + struct lpc32xx_i2c_registers *i2c = lpc32xx_i2c[adap->hwadapnr]; | |
101 | + int stat; | |
102 | + | |
103 | + /* Soft-reset the controller */ | |
104 | + writel(LPC32XX_I2C_SOFT_RESET, &i2c->ctrl); | |
105 | + while (readl(&i2c->ctrl) & LPC32XX_I2C_SOFT_RESET) | |
106 | + ; | |
107 | + /* Addre slave for write with start before and stop after */ | |
108 | + writel((dev<<1) | LPC32XX_I2C_TX_START | LPC32XX_I2C_TX_STOP, | |
109 | + &i2c->tx); | |
110 | + /* wait for end of transation */ | |
111 | + while (!((stat = readl(&i2c->stat)) & LPC32XX_I2C_STAT_TDI)) | |
112 | + ; | |
113 | + /* was there no acknowledge? */ | |
114 | + return (stat & LPC32XX_I2C_STAT_NAI) ? -1 : 0; | |
115 | +} | |
116 | + | |
117 | +/* | |
118 | + * I2C read called by cmd_i2c when doing 'i2c read' and by cmd_eeprom.c | |
119 | + * Begin write, send address byte(s), begin read, receive data bytes, end. | |
120 | + */ | |
121 | +static int lpc32xx_i2c_read(struct i2c_adapter *adap, u8 dev, uint addr, | |
122 | + int alen, u8 *data, int length) | |
123 | +{ | |
124 | + struct lpc32xx_i2c_registers *i2c = lpc32xx_i2c[adap->hwadapnr]; | |
125 | + int stat, wlen; | |
126 | + | |
127 | + /* Soft-reset the controller */ | |
128 | + writel(LPC32XX_I2C_SOFT_RESET, &i2c->ctrl); | |
129 | + while (readl(&i2c->ctrl) & LPC32XX_I2C_SOFT_RESET) | |
130 | + ; | |
131 | + /* do we need to write an address at all? */ | |
132 | + if (alen) { | |
133 | + /* Address slave in write mode */ | |
134 | + writel((dev<<1) | LPC32XX_I2C_TX_START, &i2c->tx); | |
135 | + /* write address bytes */ | |
136 | + while (alen--) { | |
137 | + /* compute address byte + stop for the last one */ | |
138 | + int a = (addr >> (8 * alen)) & 0xff; | |
139 | + if (!alen) | |
140 | + a |= LPC32XX_I2C_TX_STOP; | |
141 | + /* Send address byte */ | |
142 | + writel(a, &i2c->tx); | |
143 | + } | |
144 | + /* wait for end of transation */ | |
145 | + while (!((stat = readl(&i2c->stat)) & LPC32XX_I2C_STAT_TDI)) | |
146 | + ; | |
147 | + /* clear end-of-transaction flag */ | |
148 | + writel(1, &i2c->stat); | |
149 | + } | |
150 | + /* do we have to read data at all? */ | |
151 | + if (length) { | |
152 | + /* Address slave in read mode */ | |
153 | + writel(1 | (dev<<1) | LPC32XX_I2C_TX_START, &i2c->tx); | |
154 | + wlen = length; | |
155 | + /* get data */ | |
156 | + while (length | wlen) { | |
157 | + /* read status for TFF and RFE */ | |
158 | + stat = readl(&i2c->stat); | |
159 | + /* must we, can we write a trigger byte? */ | |
160 | + if ((wlen > 0) | |
161 | + & (!(stat & LPC32XX_I2C_STAT_TFF))) { | |
162 | + wlen--; | |
163 | + /* write trigger byte + stop if last */ | |
164 | + writel(wlen ? 0 : | |
165 | + LPC32XX_I2C_TX_STOP, &i2c->tx); | |
166 | + } | |
167 | + /* must we, can we read a data byte? */ | |
168 | + if ((length > 0) | |
169 | + & (!(stat & LPC32XX_I2C_STAT_RFE))) { | |
170 | + length--; | |
171 | + /* read byte */ | |
172 | + *(data++) = readl(&i2c->rx); | |
173 | + } | |
174 | + } | |
175 | + } | |
176 | + /* wait for end of transation */ | |
177 | + while (!((stat = readl(&i2c->stat)) & LPC32XX_I2C_STAT_TDI)) | |
178 | + ; | |
179 | + /* clear end-of-transaction flag */ | |
180 | + writel(1, &i2c->stat); | |
181 | + /* success */ | |
182 | + return 0; | |
183 | +} | |
184 | + | |
185 | +/* | |
186 | + * I2C write called by cmd_i2c when doing 'i2c write' and by cmd_eeprom.c | |
187 | + * Begin write, send address byte(s), send data bytes, end. | |
188 | + */ | |
189 | +static int lpc32xx_i2c_write(struct i2c_adapter *adap, u8 dev, uint addr, | |
190 | + int alen, u8 *data, int length) | |
191 | +{ | |
192 | + struct lpc32xx_i2c_registers *i2c = lpc32xx_i2c[adap->hwadapnr]; | |
193 | + int stat; | |
194 | + | |
195 | + /* Soft-reset the controller */ | |
196 | + writel(LPC32XX_I2C_SOFT_RESET, &i2c->ctrl); | |
197 | + while (readl(&i2c->ctrl) & LPC32XX_I2C_SOFT_RESET) | |
198 | + ; | |
199 | + /* do we need to write anything at all? */ | |
200 | + if (alen | length) | |
201 | + /* Address slave in write mode */ | |
202 | + writel((dev<<1) | LPC32XX_I2C_TX_START, &i2c->tx); | |
203 | + /* write address bytes */ | |
204 | + while (alen) { | |
205 | + /* wait for transmit fifo not full */ | |
206 | + stat = readl(&i2c->stat); | |
207 | + if (!(stat & LPC32XX_I2C_STAT_TFF)) { | |
208 | + alen--; | |
209 | + int a = (addr >> (8 * alen)) & 0xff; | |
210 | + if (!(alen | length)) | |
211 | + a |= LPC32XX_I2C_TX_STOP; | |
212 | + /* Send address byte */ | |
213 | + writel(a, &i2c->tx); | |
214 | + } | |
215 | + } | |
216 | + while (length) { | |
217 | + /* wait for transmit fifo not full */ | |
218 | + stat = readl(&i2c->stat); | |
219 | + if (!(stat & LPC32XX_I2C_STAT_TFF)) { | |
220 | + /* compute data byte, add stop if length==0 */ | |
221 | + length--; | |
222 | + int d = *(data++); | |
223 | + if (!length) | |
224 | + d |= LPC32XX_I2C_TX_STOP; | |
225 | + /* Send data byte */ | |
226 | + writel(d, &i2c->tx); | |
227 | + } | |
228 | + } | |
229 | + /* wait for end of transation */ | |
230 | + while (!((stat = readl(&i2c->stat)) & LPC32XX_I2C_STAT_TDI)) | |
231 | + ; | |
232 | + /* clear end-of-transaction flag */ | |
233 | + writel(1, &i2c->stat); | |
234 | + return 0; | |
235 | +} | |
236 | + | |
237 | +U_BOOT_I2C_ADAP_COMPLETE(lpc32xx_0, _i2c_init, lpc32xx_i2c_probe, | |
238 | + lpc32xx_i2c_read, lpc32xx_i2c_write, | |
239 | + lpc32xx_i2c_set_bus_speed, | |
240 | + CONFIG_SYS_I2C_LPC32XX_SPEED, | |
241 | + CONFIG_SYS_I2C_LPC32XX_SLAVE, | |
242 | + 0) | |
243 | + | |
244 | +U_BOOT_I2C_ADAP_COMPLETE(lpc32xx_1, _i2c_init, lpc32xx_i2c_probe, | |
245 | + lpc32xx_i2c_read, lpc32xx_i2c_write, | |
246 | + lpc32xx_i2c_set_bus_speed, | |
247 | + CONFIG_SYS_I2C_LPC32XX_SPEED, | |
248 | + CONFIG_SYS_I2C_LPC32XX_SLAVE, | |
249 | + 1) |