1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* bbc_i2c.c: I2C low-level driver for BBC device on UltraSPARC-III |
3 | * platforms. |
4 | * |
5 | * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net) |
6 | */ |
7 | |
8 | #include <linux/module.h> |
9 | #include <linux/kernel.h> |
10 | #include <linux/types.h> |
11 | #include <linux/slab.h> |
12 | #include <linux/sched.h> |
13 | #include <linux/wait.h> |
14 | #include <linux/delay.h> |
15 | #include <linux/interrupt.h> |
16 | #include <linux/of.h> |
17 | #include <linux/of_platform.h> |
18 | #include <linux/platform_device.h> |
19 | #include <asm/bbc.h> |
20 | #include <asm/io.h> |
21 | |
22 | #include "bbc_i2c.h" |
23 | |
24 | /* Convert this driver to use i2c bus layer someday... */ |
25 | #define I2C_PCF_PIN 0x80 |
26 | #define I2C_PCF_ESO 0x40 |
27 | #define I2C_PCF_ES1 0x20 |
28 | #define I2C_PCF_ES2 0x10 |
29 | #define I2C_PCF_ENI 0x08 |
30 | #define I2C_PCF_STA 0x04 |
31 | #define I2C_PCF_STO 0x02 |
32 | #define I2C_PCF_ACK 0x01 |
33 | |
34 | #define I2C_PCF_START (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_ENI | I2C_PCF_STA | I2C_PCF_ACK) |
35 | #define I2C_PCF_STOP (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_STO | I2C_PCF_ACK) |
36 | #define I2C_PCF_REPSTART ( I2C_PCF_ESO | I2C_PCF_STA | I2C_PCF_ACK) |
37 | #define I2C_PCF_IDLE (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_ACK) |
38 | |
39 | #define I2C_PCF_INI 0x40 /* 1 if not initialized */ |
40 | #define I2C_PCF_STS 0x20 |
41 | #define I2C_PCF_BER 0x10 |
42 | #define I2C_PCF_AD0 0x08 |
43 | #define I2C_PCF_LRB 0x08 |
44 | #define I2C_PCF_AAS 0x04 |
45 | #define I2C_PCF_LAB 0x02 |
46 | #define I2C_PCF_BB 0x01 |
47 | |
48 | /* The BBC devices have two I2C controllers. The first I2C controller |
49 | * connects mainly to configuration proms (NVRAM, cpu configuration, |
50 | * dimm types, etc.). Whereas the second I2C controller connects to |
51 | * environmental control devices such as fans and temperature sensors. |
52 | * The second controller also connects to the smartcard reader, if present. |
53 | */ |
54 | |
55 | static void set_device_claimage(struct bbc_i2c_bus *bp, struct platform_device *op, int val) |
56 | { |
57 | int i; |
58 | |
59 | for (i = 0; i < NUM_CHILDREN; i++) { |
60 | if (bp->devs[i].device == op) { |
61 | bp->devs[i].client_claimed = val; |
62 | return; |
63 | } |
64 | } |
65 | } |
66 | |
67 | #define claim_device(BP,ECHILD) set_device_claimage(BP,ECHILD,1) |
68 | #define release_device(BP,ECHILD) set_device_claimage(BP,ECHILD,0) |
69 | |
70 | struct platform_device *bbc_i2c_getdev(struct bbc_i2c_bus *bp, int index) |
71 | { |
72 | struct platform_device *op = NULL; |
73 | int curidx = 0, i; |
74 | |
75 | for (i = 0; i < NUM_CHILDREN; i++) { |
76 | if (!(op = bp->devs[i].device)) |
77 | break; |
78 | if (curidx == index) |
79 | goto out; |
80 | op = NULL; |
81 | curidx++; |
82 | } |
83 | |
84 | out: |
85 | if (curidx == index) |
86 | return op; |
87 | return NULL; |
88 | } |
89 | |
90 | struct bbc_i2c_client *bbc_i2c_attach(struct bbc_i2c_bus *bp, struct platform_device *op) |
91 | { |
92 | struct bbc_i2c_client *client; |
93 | const u32 *reg; |
94 | |
95 | client = kzalloc(size: sizeof(*client), GFP_KERNEL); |
96 | if (!client) |
97 | return NULL; |
98 | client->bp = bp; |
99 | client->op = op; |
100 | |
101 | reg = of_get_property(node: op->dev.of_node, name: "reg" , NULL); |
102 | if (!reg) { |
103 | kfree(objp: client); |
104 | return NULL; |
105 | } |
106 | |
107 | client->bus = reg[0]; |
108 | client->address = reg[1]; |
109 | |
110 | claim_device(bp, op); |
111 | |
112 | return client; |
113 | } |
114 | |
115 | void bbc_i2c_detach(struct bbc_i2c_client *client) |
116 | { |
117 | struct bbc_i2c_bus *bp = client->bp; |
118 | struct platform_device *op = client->op; |
119 | |
120 | release_device(bp, op); |
121 | kfree(objp: client); |
122 | } |
123 | |
124 | static int wait_for_pin(struct bbc_i2c_bus *bp, u8 *status) |
125 | { |
126 | DECLARE_WAITQUEUE(wait, current); |
127 | int limit = 32; |
128 | int ret = 1; |
129 | |
130 | bp->waiting = 1; |
131 | add_wait_queue(wq_head: &bp->wq, wq_entry: &wait); |
132 | while (limit-- > 0) { |
133 | long val; |
134 | |
135 | val = wait_event_interruptible_timeout( |
136 | bp->wq, |
137 | (((*status = readb(bp->i2c_control_regs + 0)) |
138 | & I2C_PCF_PIN) == 0), |
139 | msecs_to_jiffies(250)); |
140 | if (val > 0) { |
141 | ret = 0; |
142 | break; |
143 | } |
144 | } |
145 | remove_wait_queue(wq_head: &bp->wq, wq_entry: &wait); |
146 | bp->waiting = 0; |
147 | |
148 | return ret; |
149 | } |
150 | |
151 | int bbc_i2c_writeb(struct bbc_i2c_client *client, unsigned char val, int off) |
152 | { |
153 | struct bbc_i2c_bus *bp = client->bp; |
154 | int address = client->address; |
155 | u8 status; |
156 | int ret = -1; |
157 | |
158 | if (bp->i2c_bussel_reg != NULL) |
159 | writeb(val: client->bus, addr: bp->i2c_bussel_reg); |
160 | |
161 | writeb(val: address, addr: bp->i2c_control_regs + 0x1); |
162 | writeb(I2C_PCF_START, addr: bp->i2c_control_regs + 0x0); |
163 | if (wait_for_pin(bp, status: &status)) |
164 | goto out; |
165 | |
166 | writeb(val: off, addr: bp->i2c_control_regs + 0x1); |
167 | if (wait_for_pin(bp, status: &status) || |
168 | (status & I2C_PCF_LRB) != 0) |
169 | goto out; |
170 | |
171 | writeb(val, addr: bp->i2c_control_regs + 0x1); |
172 | if (wait_for_pin(bp, status: &status)) |
173 | goto out; |
174 | |
175 | ret = 0; |
176 | |
177 | out: |
178 | writeb(I2C_PCF_STOP, addr: bp->i2c_control_regs + 0x0); |
179 | return ret; |
180 | } |
181 | |
182 | int bbc_i2c_readb(struct bbc_i2c_client *client, unsigned char *byte, int off) |
183 | { |
184 | struct bbc_i2c_bus *bp = client->bp; |
185 | unsigned char address = client->address, status; |
186 | int ret = -1; |
187 | |
188 | if (bp->i2c_bussel_reg != NULL) |
189 | writeb(val: client->bus, addr: bp->i2c_bussel_reg); |
190 | |
191 | writeb(val: address, addr: bp->i2c_control_regs + 0x1); |
192 | writeb(I2C_PCF_START, addr: bp->i2c_control_regs + 0x0); |
193 | if (wait_for_pin(bp, status: &status)) |
194 | goto out; |
195 | |
196 | writeb(val: off, addr: bp->i2c_control_regs + 0x1); |
197 | if (wait_for_pin(bp, status: &status) || |
198 | (status & I2C_PCF_LRB) != 0) |
199 | goto out; |
200 | |
201 | writeb(I2C_PCF_STOP, addr: bp->i2c_control_regs + 0x0); |
202 | |
203 | address |= 0x1; /* READ */ |
204 | |
205 | writeb(val: address, addr: bp->i2c_control_regs + 0x1); |
206 | writeb(I2C_PCF_START, addr: bp->i2c_control_regs + 0x0); |
207 | if (wait_for_pin(bp, status: &status)) |
208 | goto out; |
209 | |
210 | /* Set PIN back to one so the device sends the first |
211 | * byte. |
212 | */ |
213 | (void) readb(addr: bp->i2c_control_regs + 0x1); |
214 | if (wait_for_pin(bp, status: &status)) |
215 | goto out; |
216 | |
217 | writeb(I2C_PCF_ESO | I2C_PCF_ENI, addr: bp->i2c_control_regs + 0x0); |
218 | *byte = readb(addr: bp->i2c_control_regs + 0x1); |
219 | if (wait_for_pin(bp, status: &status)) |
220 | goto out; |
221 | |
222 | ret = 0; |
223 | |
224 | out: |
225 | writeb(I2C_PCF_STOP, addr: bp->i2c_control_regs + 0x0); |
226 | (void) readb(addr: bp->i2c_control_regs + 0x1); |
227 | |
228 | return ret; |
229 | } |
230 | |
231 | int bbc_i2c_write_buf(struct bbc_i2c_client *client, |
232 | char *buf, int len, int off) |
233 | { |
234 | int ret = 0; |
235 | |
236 | while (len > 0) { |
237 | ret = bbc_i2c_writeb(client, val: *buf, off); |
238 | if (ret < 0) |
239 | break; |
240 | len--; |
241 | buf++; |
242 | off++; |
243 | } |
244 | return ret; |
245 | } |
246 | |
247 | int bbc_i2c_read_buf(struct bbc_i2c_client *client, |
248 | char *buf, int len, int off) |
249 | { |
250 | int ret = 0; |
251 | |
252 | while (len > 0) { |
253 | ret = bbc_i2c_readb(client, byte: buf, off); |
254 | if (ret < 0) |
255 | break; |
256 | len--; |
257 | buf++; |
258 | off++; |
259 | } |
260 | |
261 | return ret; |
262 | } |
263 | |
264 | EXPORT_SYMBOL(bbc_i2c_getdev); |
265 | EXPORT_SYMBOL(bbc_i2c_attach); |
266 | EXPORT_SYMBOL(bbc_i2c_detach); |
267 | EXPORT_SYMBOL(bbc_i2c_writeb); |
268 | EXPORT_SYMBOL(bbc_i2c_readb); |
269 | EXPORT_SYMBOL(bbc_i2c_write_buf); |
270 | EXPORT_SYMBOL(bbc_i2c_read_buf); |
271 | |
272 | static irqreturn_t bbc_i2c_interrupt(int irq, void *dev_id) |
273 | { |
274 | struct bbc_i2c_bus *bp = dev_id; |
275 | |
276 | /* PIN going from set to clear is the only event which |
277 | * makes the i2c assert an interrupt. |
278 | */ |
279 | if (bp->waiting && |
280 | !(readb(addr: bp->i2c_control_regs + 0x0) & I2C_PCF_PIN)) |
281 | wake_up_interruptible(&bp->wq); |
282 | |
283 | return IRQ_HANDLED; |
284 | } |
285 | |
286 | static void reset_one_i2c(struct bbc_i2c_bus *bp) |
287 | { |
288 | writeb(I2C_PCF_PIN, addr: bp->i2c_control_regs + 0x0); |
289 | writeb(val: bp->own, addr: bp->i2c_control_regs + 0x1); |
290 | writeb(I2C_PCF_PIN | I2C_PCF_ES1, addr: bp->i2c_control_regs + 0x0); |
291 | writeb(val: bp->clock, addr: bp->i2c_control_regs + 0x1); |
292 | writeb(I2C_PCF_IDLE, addr: bp->i2c_control_regs + 0x0); |
293 | } |
294 | |
295 | static struct bbc_i2c_bus * attach_one_i2c(struct platform_device *op, int index) |
296 | { |
297 | struct bbc_i2c_bus *bp; |
298 | struct device_node *dp; |
299 | int entry; |
300 | |
301 | bp = kzalloc(size: sizeof(*bp), GFP_KERNEL); |
302 | if (!bp) |
303 | return NULL; |
304 | |
305 | INIT_LIST_HEAD(list: &bp->temps); |
306 | INIT_LIST_HEAD(list: &bp->fans); |
307 | |
308 | bp->i2c_control_regs = of_ioremap(&op->resource[0], 0, 0x2, "bbc_i2c_regs" ); |
309 | if (!bp->i2c_control_regs) |
310 | goto fail; |
311 | |
312 | if (op->num_resources == 2) { |
313 | bp->i2c_bussel_reg = of_ioremap(&op->resource[1], 0, 0x1, "bbc_i2c_bussel" ); |
314 | if (!bp->i2c_bussel_reg) |
315 | goto fail; |
316 | } |
317 | |
318 | bp->waiting = 0; |
319 | init_waitqueue_head(&bp->wq); |
320 | if (request_irq(irq: op->archdata.irqs[0], handler: bbc_i2c_interrupt, |
321 | IRQF_SHARED, name: "bbc_i2c" , dev: bp)) |
322 | goto fail; |
323 | |
324 | bp->index = index; |
325 | bp->op = op; |
326 | |
327 | spin_lock_init(&bp->lock); |
328 | |
329 | entry = 0; |
330 | for (dp = op->dev.of_node->child; |
331 | dp && entry < 8; |
332 | dp = dp->sibling, entry++) { |
333 | struct platform_device *child_op; |
334 | |
335 | child_op = of_find_device_by_node(np: dp); |
336 | bp->devs[entry].device = child_op; |
337 | bp->devs[entry].client_claimed = 0; |
338 | } |
339 | |
340 | writeb(I2C_PCF_PIN, addr: bp->i2c_control_regs + 0x0); |
341 | bp->own = readb(addr: bp->i2c_control_regs + 0x01); |
342 | writeb(I2C_PCF_PIN | I2C_PCF_ES1, addr: bp->i2c_control_regs + 0x0); |
343 | bp->clock = readb(addr: bp->i2c_control_regs + 0x01); |
344 | |
345 | printk(KERN_INFO "i2c-%d: Regs at %p, %d devices, own %02x, clock %02x.\n" , |
346 | bp->index, bp->i2c_control_regs, entry, bp->own, bp->clock); |
347 | |
348 | reset_one_i2c(bp); |
349 | |
350 | return bp; |
351 | |
352 | fail: |
353 | if (bp->i2c_bussel_reg) |
354 | of_iounmap(&op->resource[1], bp->i2c_bussel_reg, 1); |
355 | if (bp->i2c_control_regs) |
356 | of_iounmap(&op->resource[0], bp->i2c_control_regs, 2); |
357 | kfree(objp: bp); |
358 | return NULL; |
359 | } |
360 | |
361 | extern int bbc_envctrl_init(struct bbc_i2c_bus *bp); |
362 | extern void bbc_envctrl_cleanup(struct bbc_i2c_bus *bp); |
363 | |
364 | static int bbc_i2c_probe(struct platform_device *op) |
365 | { |
366 | struct bbc_i2c_bus *bp; |
367 | int err, index = 0; |
368 | |
369 | bp = attach_one_i2c(op, index); |
370 | if (!bp) |
371 | return -EINVAL; |
372 | |
373 | err = bbc_envctrl_init(bp); |
374 | if (err) { |
375 | free_irq(op->archdata.irqs[0], bp); |
376 | if (bp->i2c_bussel_reg) |
377 | of_iounmap(&op->resource[0], bp->i2c_bussel_reg, 1); |
378 | if (bp->i2c_control_regs) |
379 | of_iounmap(&op->resource[1], bp->i2c_control_regs, 2); |
380 | kfree(objp: bp); |
381 | } else { |
382 | dev_set_drvdata(dev: &op->dev, data: bp); |
383 | } |
384 | |
385 | return err; |
386 | } |
387 | |
388 | static int bbc_i2c_remove(struct platform_device *op) |
389 | { |
390 | struct bbc_i2c_bus *bp = dev_get_drvdata(dev: &op->dev); |
391 | |
392 | bbc_envctrl_cleanup(bp); |
393 | |
394 | free_irq(op->archdata.irqs[0], bp); |
395 | |
396 | if (bp->i2c_bussel_reg) |
397 | of_iounmap(&op->resource[0], bp->i2c_bussel_reg, 1); |
398 | if (bp->i2c_control_regs) |
399 | of_iounmap(&op->resource[1], bp->i2c_control_regs, 2); |
400 | |
401 | kfree(objp: bp); |
402 | |
403 | return 0; |
404 | } |
405 | |
406 | static const struct of_device_id bbc_i2c_match[] = { |
407 | { |
408 | .name = "i2c" , |
409 | .compatible = "SUNW,bbc-i2c" , |
410 | }, |
411 | {}, |
412 | }; |
413 | MODULE_DEVICE_TABLE(of, bbc_i2c_match); |
414 | |
415 | static struct platform_driver bbc_i2c_driver = { |
416 | .driver = { |
417 | .name = "bbc_i2c" , |
418 | .of_match_table = bbc_i2c_match, |
419 | }, |
420 | .probe = bbc_i2c_probe, |
421 | .remove = bbc_i2c_remove, |
422 | }; |
423 | |
424 | module_platform_driver(bbc_i2c_driver); |
425 | |
426 | MODULE_LICENSE("GPL" ); |
427 | |