1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * ARM IOC/IOMD i2c driver. |
4 | * |
5 | * Copyright (C) 2000 Russell King |
6 | * |
7 | * On Acorn machines, the following i2c devices are on the bus: |
8 | * - PCF8583 real time clock & static RAM |
9 | */ |
10 | #include <linux/module.h> |
11 | #include <linux/i2c.h> |
12 | #include <linux/i2c-algo-bit.h> |
13 | #include <linux/io.h> |
14 | |
15 | #include <mach/hardware.h> |
16 | #include <asm/hardware/ioc.h> |
17 | |
18 | #define FORCE_ONES 0xdc |
19 | #define SCL 0x02 |
20 | #define SDA 0x01 |
21 | |
22 | /* |
23 | * We must preserve all non-i2c output bits in IOC_CONTROL. |
24 | * Note also that we need to preserve the value of SCL and |
25 | * SDA outputs as well (which may be different from the |
26 | * values read back from IOC_CONTROL). |
27 | */ |
28 | static u_int force_ones; |
29 | |
30 | static void ioc_setscl(void *data, int state) |
31 | { |
32 | u_int ioc_control = ioc_readb(IOC_CONTROL) & ~(SCL | SDA); |
33 | u_int ones = force_ones; |
34 | |
35 | if (state) |
36 | ones |= SCL; |
37 | else |
38 | ones &= ~SCL; |
39 | |
40 | force_ones = ones; |
41 | |
42 | ioc_writeb(ioc_control | ones, IOC_CONTROL); |
43 | } |
44 | |
45 | static void ioc_setsda(void *data, int state) |
46 | { |
47 | u_int ioc_control = ioc_readb(IOC_CONTROL) & ~(SCL | SDA); |
48 | u_int ones = force_ones; |
49 | |
50 | if (state) |
51 | ones |= SDA; |
52 | else |
53 | ones &= ~SDA; |
54 | |
55 | force_ones = ones; |
56 | |
57 | ioc_writeb(ioc_control | ones, IOC_CONTROL); |
58 | } |
59 | |
60 | static int ioc_getscl(void *data) |
61 | { |
62 | return (ioc_readb(IOC_CONTROL) & SCL) != 0; |
63 | } |
64 | |
65 | static int ioc_getsda(void *data) |
66 | { |
67 | return (ioc_readb(IOC_CONTROL) & SDA) != 0; |
68 | } |
69 | |
70 | static struct i2c_algo_bit_data ioc_data = { |
71 | .setsda = ioc_setsda, |
72 | .setscl = ioc_setscl, |
73 | .getsda = ioc_getsda, |
74 | .getscl = ioc_getscl, |
75 | .udelay = 80, |
76 | .timeout = HZ, |
77 | }; |
78 | |
79 | static struct i2c_adapter ioc_ops = { |
80 | .nr = 0, |
81 | .name = "ioc" , |
82 | .algo_data = &ioc_data, |
83 | }; |
84 | |
85 | static int __init i2c_ioc_init(void) |
86 | { |
87 | force_ones = FORCE_ONES | SCL | SDA; |
88 | |
89 | return i2c_bit_add_numbered_bus(&ioc_ops); |
90 | } |
91 | |
92 | module_init(i2c_ioc_init); |
93 | |
94 | MODULE_AUTHOR("Russell King <linux@armlinux.org.uk>" ); |
95 | MODULE_DESCRIPTION("ARM IOC/IOMD i2c driver" ); |
96 | MODULE_LICENSE("GPL v2" ); |
97 | |