]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
385c9ef5 HS |
2 | /* |
3 | * Copyright (C) 2009 Sergey Kubushyn <ksi@koi8.net> | |
4 | * | |
5 | * (C) Copyright 2012 | |
6 | * Heiko Schocher, DENX Software Engineering, hs@denx.de. | |
7 | * | |
8 | * Multibus/multiadapter I2C core functions (wrappers) | |
385c9ef5 HS |
9 | */ |
10 | #include <common.h> | |
11 | #include <i2c.h> | |
12 | ||
13 | struct i2c_adapter *i2c_get_adapter(int index) | |
14 | { | |
15 | struct i2c_adapter *i2c_adap_p = ll_entry_start(struct i2c_adapter, | |
16 | i2c); | |
17 | int max = ll_entry_count(struct i2c_adapter, i2c); | |
18 | int i; | |
19 | ||
20 | if (index >= max) { | |
21 | printf("Error, wrong i2c adapter %d max %d possible\n", | |
22 | index, max); | |
23 | return i2c_adap_p; | |
24 | } | |
25 | if (index == 0) | |
26 | return i2c_adap_p; | |
27 | ||
28 | for (i = 0; i < index; i++) | |
29 | i2c_adap_p++; | |
30 | ||
31 | return i2c_adap_p; | |
32 | } | |
33 | ||
34 | #if !defined(CONFIG_SYS_I2C_DIRECT_BUS) | |
35 | struct i2c_bus_hose i2c_bus[CONFIG_SYS_NUM_I2C_BUSES] = | |
36 | CONFIG_SYS_I2C_BUSES; | |
37 | #endif | |
38 | ||
39 | DECLARE_GLOBAL_DATA_PTR; | |
40 | ||
385c9ef5 HS |
41 | #ifndef CONFIG_SYS_I2C_DIRECT_BUS |
42 | /* | |
43 | * i2c_mux_set() | |
44 | * ------------- | |
45 | * | |
46 | * This turns on the given channel on I2C multiplexer chip connected to | |
47 | * a given I2C adapter directly or via other multiplexers. In the latter | |
48 | * case the entire multiplexer chain must be initialized first starting | |
49 | * with the one connected directly to the adapter. When disabling a chain | |
50 | * muxes must be programmed in reverse order, starting with the one | |
51 | * farthest from the adapter. | |
52 | * | |
53 | * mux_id is the multiplexer chip type from defined in i2c.h. So far only | |
54 | * NXP (Philips) PCA954x multiplexers are supported. Switches are NOT | |
55 | * supported (anybody uses them?) | |
56 | */ | |
57 | ||
58 | static int i2c_mux_set(struct i2c_adapter *adap, int mux_id, int chip, | |
59 | int channel) | |
60 | { | |
61 | uint8_t buf; | |
62 | int ret; | |
63 | ||
64 | /* channel < 0 - turn off the mux */ | |
65 | if (channel < 0) { | |
66 | buf = 0; | |
67 | ret = adap->write(adap, chip, 0, 0, &buf, 1); | |
68 | if (ret) | |
69 | printf("%s: Could not turn off the mux.\n", __func__); | |
70 | return ret; | |
71 | } | |
72 | ||
73 | switch (mux_id) { | |
74 | case I2C_MUX_PCA9540_ID: | |
75 | case I2C_MUX_PCA9542_ID: | |
76 | if (channel > 1) | |
77 | return -1; | |
78 | buf = (uint8_t)((channel & 0x01) | (1 << 2)); | |
79 | break; | |
80 | case I2C_MUX_PCA9544_ID: | |
81 | if (channel > 3) | |
82 | return -1; | |
83 | buf = (uint8_t)((channel & 0x03) | (1 << 2)); | |
84 | break; | |
85 | case I2C_MUX_PCA9547_ID: | |
86 | if (channel > 7) | |
87 | return -1; | |
88 | buf = (uint8_t)((channel & 0x07) | (1 << 3)); | |
89 | break; | |
e6658749 MB |
90 | case I2C_MUX_PCA9548_ID: |
91 | if (channel > 7) | |
92 | return -1; | |
93 | buf = (uint8_t)(0x01 << channel); | |
94 | break; | |
385c9ef5 HS |
95 | default: |
96 | printf("%s: wrong mux id: %d\n", __func__, mux_id); | |
97 | return -1; | |
98 | } | |
99 | ||
100 | ret = adap->write(adap, chip, 0, 0, &buf, 1); | |
101 | if (ret) | |
102 | printf("%s: could not set mux: id: %d chip: %x channel: %d\n", | |
103 | __func__, mux_id, chip, channel); | |
104 | return ret; | |
105 | } | |
106 | ||
107 | static int i2c_mux_set_all(void) | |
108 | { | |
109 | struct i2c_bus_hose *i2c_bus_tmp = &i2c_bus[I2C_BUS]; | |
110 | int i; | |
111 | ||
112 | /* Connect requested bus if behind muxes */ | |
113 | if (i2c_bus_tmp->next_hop[0].chip != 0) { | |
114 | /* Set all muxes along the path to that bus */ | |
115 | for (i = 0; i < CONFIG_SYS_I2C_MAX_HOPS; i++) { | |
116 | int ret; | |
117 | ||
118 | if (i2c_bus_tmp->next_hop[i].chip == 0) | |
119 | break; | |
120 | ||
121 | ret = i2c_mux_set(I2C_ADAP, | |
122 | i2c_bus_tmp->next_hop[i].mux.id, | |
123 | i2c_bus_tmp->next_hop[i].chip, | |
124 | i2c_bus_tmp->next_hop[i].channel); | |
125 | if (ret != 0) | |
126 | return ret; | |
127 | } | |
128 | } | |
129 | return 0; | |
130 | } | |
131 | ||
f4ed3696 | 132 | static int i2c_mux_disconnect_all(void) |
385c9ef5 HS |
133 | { |
134 | struct i2c_bus_hose *i2c_bus_tmp = &i2c_bus[I2C_BUS]; | |
135 | int i; | |
2fe50ef4 | 136 | uint8_t buf = 0; |
385c9ef5 HS |
137 | |
138 | if (I2C_ADAP->init_done == 0) | |
139 | return 0; | |
140 | ||
141 | /* Disconnect current bus (turn off muxes if any) */ | |
142 | if ((i2c_bus_tmp->next_hop[0].chip != 0) && | |
143 | (I2C_ADAP->init_done != 0)) { | |
144 | i = CONFIG_SYS_I2C_MAX_HOPS; | |
145 | do { | |
146 | uint8_t chip; | |
147 | int ret; | |
148 | ||
149 | chip = i2c_bus_tmp->next_hop[--i].chip; | |
150 | if (chip == 0) | |
151 | continue; | |
152 | ||
153 | ret = I2C_ADAP->write(I2C_ADAP, chip, 0, 0, &buf, 1); | |
154 | if (ret != 0) { | |
f4ed3696 | 155 | printf("i2c: mux disconnect error\n"); |
385c9ef5 HS |
156 | return ret; |
157 | } | |
158 | } while (i > 0); | |
159 | } | |
160 | ||
161 | return 0; | |
162 | } | |
163 | #endif | |
164 | ||
165 | /* | |
166 | * i2c_init_bus(): | |
167 | * --------------- | |
168 | * | |
169 | * Initializes one bus. Will initialize the parent adapter. No current bus | |
170 | * changes, no mux (if any) setup. | |
171 | */ | |
172 | static void i2c_init_bus(unsigned int bus_no, int speed, int slaveaddr) | |
173 | { | |
174 | if (bus_no >= CONFIG_SYS_NUM_I2C_BUSES) | |
175 | return; | |
176 | ||
177 | I2C_ADAP->init(I2C_ADAP, speed, slaveaddr); | |
178 | ||
179 | if (gd->flags & GD_FLG_RELOC) { | |
180 | I2C_ADAP->init_done = 1; | |
181 | I2C_ADAP->speed = speed; | |
182 | I2C_ADAP->slaveaddr = slaveaddr; | |
183 | } | |
184 | } | |
185 | ||
186 | /* implement possible board specific board init */ | |
13a8b7ae | 187 | __weak void i2c_init_board(void) |
385c9ef5 HS |
188 | { |
189 | } | |
385c9ef5 | 190 | |
9d10c2d3 YY |
191 | /* implement possible for i2c specific early i2c init */ |
192 | __weak void i2c_early_init_f(void) | |
193 | { | |
194 | } | |
195 | ||
385c9ef5 HS |
196 | /* |
197 | * i2c_init_all(): | |
198 | * | |
199 | * not longer needed, will deleted. Actual init the SPD_BUS | |
200 | * for compatibility. | |
201 | * i2c_adap[] must be initialized beforehead with function pointers and | |
202 | * data, including speed and slaveaddr. | |
203 | */ | |
204 | void i2c_init_all(void) | |
205 | { | |
206 | i2c_init_board(); | |
207 | i2c_set_bus_num(CONFIG_SYS_SPD_BUS_NUM); | |
208 | return; | |
209 | } | |
210 | ||
211 | /* | |
212 | * i2c_get_bus_num(): | |
213 | * ------------------ | |
214 | * | |
215 | * Returns index of currently active I2C bus. Zero-based. | |
216 | */ | |
217 | unsigned int i2c_get_bus_num(void) | |
218 | { | |
219 | return gd->cur_i2c_bus; | |
220 | } | |
221 | ||
222 | /* | |
223 | * i2c_set_bus_num(): | |
224 | * ------------------ | |
225 | * | |
226 | * Change the active I2C bus. Subsequent read/write calls will | |
227 | * go to this one. Sets all of the muxes in a proper condition | |
228 | * if that bus is behind muxes. | |
229 | * If previously selected bus is behind the muxes turns off all the | |
230 | * muxes along the path to that bus. | |
231 | * | |
232 | * bus - bus index, zero based | |
233 | * | |
234 | * Returns: 0 on success, not 0 on failure | |
235 | */ | |
236 | int i2c_set_bus_num(unsigned int bus) | |
237 | { | |
13c2433c HS |
238 | int max; |
239 | ||
240 | if ((bus == I2C_BUS) && (I2C_ADAP->init_done > 0)) | |
241 | return 0; | |
385c9ef5 | 242 | |
385c9ef5 HS |
243 | #ifndef CONFIG_SYS_I2C_DIRECT_BUS |
244 | if (bus >= CONFIG_SYS_NUM_I2C_BUSES) | |
245 | return -1; | |
246 | #endif | |
247 | ||
13c2433c HS |
248 | max = ll_entry_count(struct i2c_adapter, i2c); |
249 | if (I2C_ADAPTER(bus) >= max) { | |
250 | printf("Error, wrong i2c adapter %d max %d possible\n", | |
251 | I2C_ADAPTER(bus), max); | |
252 | return -2; | |
253 | } | |
385c9ef5 HS |
254 | |
255 | #ifndef CONFIG_SYS_I2C_DIRECT_BUS | |
f4ed3696 | 256 | i2c_mux_disconnect_all(); |
385c9ef5 HS |
257 | #endif |
258 | ||
259 | gd->cur_i2c_bus = bus; | |
260 | if (I2C_ADAP->init_done == 0) | |
261 | i2c_init_bus(bus, I2C_ADAP->speed, I2C_ADAP->slaveaddr); | |
262 | ||
263 | #ifndef CONFIG_SYS_I2C_DIRECT_BUS | |
264 | i2c_mux_set_all(); | |
265 | #endif | |
266 | return 0; | |
267 | } | |
268 | ||
269 | /* | |
270 | * Probe the given I2C chip address. Returns 0 if a chip responded, | |
271 | * not 0 on failure. | |
272 | */ | |
273 | int i2c_probe(uint8_t chip) | |
274 | { | |
275 | return I2C_ADAP->probe(I2C_ADAP, chip); | |
276 | } | |
277 | ||
278 | /* | |
279 | * Read/Write interface: | |
280 | * chip: I2C chip address, range 0..127 | |
281 | * addr: Memory (register) address within the chip | |
282 | * alen: Number of bytes to use for addr (typically 1, 2 for larger | |
283 | * memories, 0 for register type devices with only one | |
284 | * register) | |
285 | * buffer: Where to read/write the data | |
286 | * len: How many bytes to read/write | |
287 | * | |
288 | * Returns: 0 on success, not 0 on failure | |
289 | */ | |
290 | int i2c_read(uint8_t chip, unsigned int addr, int alen, | |
291 | uint8_t *buffer, int len) | |
292 | { | |
293 | return I2C_ADAP->read(I2C_ADAP, chip, addr, alen, buffer, len); | |
294 | } | |
295 | ||
296 | int i2c_write(uint8_t chip, unsigned int addr, int alen, | |
297 | uint8_t *buffer, int len) | |
298 | { | |
299 | return I2C_ADAP->write(I2C_ADAP, chip, addr, alen, buffer, len); | |
300 | } | |
301 | ||
302 | unsigned int i2c_set_bus_speed(unsigned int speed) | |
303 | { | |
304 | unsigned int ret; | |
305 | ||
306 | if (I2C_ADAP->set_bus_speed == NULL) | |
307 | return 0; | |
308 | ret = I2C_ADAP->set_bus_speed(I2C_ADAP, speed); | |
309 | if (gd->flags & GD_FLG_RELOC) | |
7cc1b02f | 310 | I2C_ADAP->speed = (ret == 0) ? speed : 0; |
385c9ef5 HS |
311 | |
312 | return ret; | |
313 | } | |
314 | ||
315 | unsigned int i2c_get_bus_speed(void) | |
316 | { | |
317 | struct i2c_adapter *cur = I2C_ADAP; | |
318 | return cur->speed; | |
319 | } | |
320 | ||
321 | uint8_t i2c_reg_read(uint8_t addr, uint8_t reg) | |
322 | { | |
323 | uint8_t buf; | |
324 | ||
385c9ef5 HS |
325 | i2c_read(addr, reg, 1, &buf, 1); |
326 | ||
327 | #ifdef DEBUG | |
328 | printf("%s: bus=%d addr=0x%02x, reg=0x%02x, val=0x%02x\n", | |
329 | __func__, i2c_get_bus_num(), addr, reg, buf); | |
330 | #endif | |
331 | ||
332 | return buf; | |
333 | } | |
334 | ||
335 | void i2c_reg_write(uint8_t addr, uint8_t reg, uint8_t val) | |
336 | { | |
385c9ef5 HS |
337 | #ifdef DEBUG |
338 | printf("%s: bus=%d addr=0x%02x, reg=0x%02x, val=0x%02x\n", | |
339 | __func__, i2c_get_bus_num(), addr, reg, val); | |
340 | #endif | |
341 | ||
342 | i2c_write(addr, reg, 1, &val, 1); | |
343 | } | |
344 | ||
13a8b7ae | 345 | __weak void i2c_init(int speed, int slaveaddr) |
385c9ef5 HS |
346 | { |
347 | i2c_init_bus(i2c_get_bus_num(), speed, slaveaddr); | |
348 | } |