Commit | Line | Data |
---|---|---|
4768e90e MS |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * I2C driver for stand-alone PCF8584 style adapters on Zorro cards | |
4 | * | |
5 | * Original ICY documentation can be found on Aminet: | |
6 | * https://aminet.net/package/docs/hard/icy | |
7 | * | |
8 | * There has been a modern community re-print of this design in 2019: | |
9 | * https://www.a1k.org/forum/index.php?threads/70106/ | |
10 | * | |
11 | * The card is basically a Philips PCF8584 connected straight to the | |
12 | * beginning of the AutoConfig'd address space (register S1 on base+2), | |
13 | * with /INT on /INT2 on the Zorro bus. | |
14 | * | |
15 | * Copyright (c) 2019 Max Staudt <max@enpas.org> | |
16 | * | |
17 | * This started as a fork of i2c-elektor.c and has evolved since. | |
18 | * Thanks go to its authors for providing a base to grow on. | |
19 | * | |
20 | * | |
21 | * IRQ support is currently not implemented. | |
22 | * | |
23 | * As it turns out, i2c-algo-pcf is really written with i2c-elektor's | |
24 | * edge-triggered ISA interrupts in mind, while the Amiga's Zorro bus has | |
25 | * level-triggered interrupts. This means that once an interrupt occurs, we | |
26 | * have to tell the PCF8584 to shut up immediately, or it will keep the | |
27 | * interrupt line busy and cause an IRQ storm. | |
28 | ||
29 | * However, because of the PCF8584's host-side protocol, there is no good | |
30 | * way to just quieten it without side effects. Rather, we have to perform | |
31 | * the next read/write operation straight away, which will reset the /INT | |
32 | * pin. This entails re-designing the core of i2c-algo-pcf in the future. | |
33 | * For now, we never request an IRQ from the PCF8584, and poll it instead. | |
34 | */ | |
35 | ||
36 | #include <linux/delay.h> | |
37 | #include <linux/init.h> | |
38 | #include <linux/io.h> | |
39 | #include <linux/ioport.h> | |
40 | #include <linux/kernel.h> | |
41 | #include <linux/module.h> | |
42 | ||
43 | #include <linux/i2c.h> | |
44 | #include <linux/i2c-algo-pcf.h> | |
45 | ||
cdb55539 | 46 | #include <asm/amigahw.h> |
4768e90e MS |
47 | #include <asm/amigaints.h> |
48 | #include <linux/zorro.h> | |
49 | ||
50 | #include "../algos/i2c-algo-pcf.h" | |
51 | ||
52 | struct icy_i2c { | |
53 | struct i2c_adapter adapter; | |
54 | ||
55 | void __iomem *reg_s0; | |
56 | void __iomem *reg_s1; | |
724041ae | 57 | struct i2c_client *ltc2990_client; |
4768e90e MS |
58 | }; |
59 | ||
60 | /* | |
61 | * Functions called by i2c-algo-pcf | |
62 | */ | |
63 | static void icy_pcf_setpcf(void *data, int ctl, int val) | |
64 | { | |
65 | struct icy_i2c *i2c = (struct icy_i2c *)data; | |
66 | ||
67 | u8 __iomem *address = ctl ? i2c->reg_s1 : i2c->reg_s0; | |
68 | ||
69 | z_writeb(val, address); | |
70 | } | |
71 | ||
72 | static int icy_pcf_getpcf(void *data, int ctl) | |
73 | { | |
74 | struct icy_i2c *i2c = (struct icy_i2c *)data; | |
75 | ||
76 | u8 __iomem *address = ctl ? i2c->reg_s1 : i2c->reg_s0; | |
77 | ||
78 | return z_readb(address); | |
79 | } | |
80 | ||
81 | static int icy_pcf_getown(void *data) | |
82 | { | |
83 | return 0x55; | |
84 | } | |
85 | ||
86 | static int icy_pcf_getclock(void *data) | |
87 | { | |
88 | return 0x1c; | |
89 | } | |
90 | ||
91 | static void icy_pcf_waitforpin(void *data) | |
92 | { | |
93 | usleep_range(50, 150); | |
94 | } | |
95 | ||
96 | /* | |
97 | * Main i2c-icy part | |
98 | */ | |
724041ae MS |
99 | static unsigned short const icy_ltc2990_addresses[] = { |
100 | 0x4c, 0x4d, 0x4e, 0x4f, I2C_CLIENT_END | |
101 | }; | |
102 | ||
103 | /* | |
104 | * Additional sensors exposed once this property is applied: | |
105 | * | |
106 | * in1 will be the voltage of the 5V rail, divided by 2. | |
107 | * in2 will be the voltage of the 12V rail, divided by 4. | |
108 | * temp3 will be measured using a PCB loop next the chip. | |
109 | */ | |
110 | static const u32 icy_ltc2990_meas_mode[] = {0, 3}; | |
111 | ||
112 | static const struct property_entry icy_ltc2990_props[] = { | |
113 | PROPERTY_ENTRY_U32_ARRAY("lltc,meas-mode", icy_ltc2990_meas_mode), | |
114 | { } | |
115 | }; | |
116 | ||
dd7a3710 HK |
117 | static const struct software_node icy_ltc2990_node = { |
118 | .properties = icy_ltc2990_props, | |
119 | }; | |
120 | ||
4768e90e MS |
121 | static int icy_probe(struct zorro_dev *z, |
122 | const struct zorro_device_id *ent) | |
123 | { | |
124 | struct icy_i2c *i2c; | |
125 | struct i2c_algo_pcf_data *algo_data; | |
724041ae MS |
126 | struct i2c_board_info ltc2990_info = { |
127 | .type = "ltc2990", | |
dd7a3710 | 128 | .swnode = &icy_ltc2990_node, |
724041ae | 129 | }; |
4768e90e MS |
130 | |
131 | i2c = devm_kzalloc(&z->dev, sizeof(*i2c), GFP_KERNEL); | |
132 | if (!i2c) | |
133 | return -ENOMEM; | |
134 | ||
135 | algo_data = devm_kzalloc(&z->dev, sizeof(*algo_data), GFP_KERNEL); | |
136 | if (!algo_data) | |
137 | return -ENOMEM; | |
138 | ||
139 | dev_set_drvdata(&z->dev, i2c); | |
140 | i2c->adapter.dev.parent = &z->dev; | |
141 | i2c->adapter.owner = THIS_MODULE; | |
142 | /* i2c->adapter.algo assigned by i2c_pcf_add_bus() */ | |
143 | i2c->adapter.algo_data = algo_data; | |
ea1558ce | 144 | strscpy(i2c->adapter.name, "ICY I2C Zorro adapter", |
4768e90e MS |
145 | sizeof(i2c->adapter.name)); |
146 | ||
147 | if (!devm_request_mem_region(&z->dev, | |
148 | z->resource.start, | |
149 | 4, i2c->adapter.name)) | |
150 | return -ENXIO; | |
151 | ||
152 | /* Driver private data */ | |
153 | i2c->reg_s0 = ZTWO_VADDR(z->resource.start); | |
154 | i2c->reg_s1 = ZTWO_VADDR(z->resource.start + 2); | |
155 | ||
156 | algo_data->data = i2c; | |
157 | algo_data->setpcf = icy_pcf_setpcf; | |
158 | algo_data->getpcf = icy_pcf_getpcf; | |
159 | algo_data->getown = icy_pcf_getown; | |
160 | algo_data->getclock = icy_pcf_getclock; | |
161 | algo_data->waitforpin = icy_pcf_waitforpin; | |
162 | ||
163 | if (i2c_pcf_add_bus(&i2c->adapter)) { | |
164 | dev_err(&z->dev, "i2c_pcf_add_bus() failed\n"); | |
165 | return -ENXIO; | |
166 | } | |
167 | ||
168 | dev_info(&z->dev, "ICY I2C controller at %pa, IRQ not implemented\n", | |
169 | &z->resource.start); | |
170 | ||
724041ae MS |
171 | /* |
172 | * The 2019 a1k.org PCBs have an LTC2990 at 0x4c, so start | |
173 | * it automatically once ltc2990 is modprobed. | |
174 | * | |
175 | * in0 is the voltage of the internal 5V power supply. | |
176 | * temp1 is the temperature inside the chip. | |
177 | * | |
178 | * See property_entry above for in1, in2, temp3. | |
179 | */ | |
dd7a3710 HK |
180 | i2c->ltc2990_client = i2c_new_scanned_device(&i2c->adapter, |
181 | <c2990_info, | |
182 | icy_ltc2990_addresses, | |
183 | NULL); | |
4768e90e MS |
184 | return 0; |
185 | } | |
186 | ||
187 | static void icy_remove(struct zorro_dev *z) | |
188 | { | |
189 | struct icy_i2c *i2c = dev_get_drvdata(&z->dev); | |
190 | ||
724041ae | 191 | i2c_unregister_device(i2c->ltc2990_client); |
4768e90e MS |
192 | i2c_del_adapter(&i2c->adapter); |
193 | } | |
194 | ||
195 | static const struct zorro_device_id icy_zorro_tbl[] = { | |
196 | { ZORRO_ID(VMC, 15, 0), }, | |
197 | { 0 } | |
198 | }; | |
199 | ||
200 | MODULE_DEVICE_TABLE(zorro, icy_zorro_tbl); | |
201 | ||
202 | static struct zorro_driver icy_driver = { | |
203 | .name = "i2c-icy", | |
204 | .id_table = icy_zorro_tbl, | |
205 | .probe = icy_probe, | |
206 | .remove = icy_remove, | |
207 | }; | |
208 | ||
209 | module_driver(icy_driver, | |
210 | zorro_register_driver, | |
211 | zorro_unregister_driver); | |
212 | ||
213 | MODULE_AUTHOR("Max Staudt <max@enpas.org>"); | |
214 | MODULE_DESCRIPTION("I2C bus via PCF8584 on ICY Zorro card"); | |
215 | MODULE_LICENSE("GPL v2"); |