1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22#include <linux/delay.h>
23#include <linux/io.h>
24#include <linux/kernel.h>
25#include <linux/leds.h>
26#include <linux/init.h>
27#include <linux/platform_data/max197.h>
28#include <linux/platform_device.h>
29#include <linux/slab.h>
30
31
32#define TS5500_PRODUCT_CODE_ADDR 0x74
33#define TS5500_PRODUCT_CODE 0x60
34#define TS5400_PRODUCT_CODE 0x40
35
36
37#define TS5500_SRAM_RS485_ADC_ADDR 0x75
38#define TS5500_SRAM BIT(0)
39#define TS5500_RS485 BIT(1)
40#define TS5500_ADC BIT(2)
41#define TS5500_RS485_RTS BIT(6)
42#define TS5500_RS485_AUTO BIT(7)
43
44
45#define TS5500_ERESET_ITR_ADDR 0x76
46#define TS5500_ERESET BIT(0)
47#define TS5500_ITR BIT(1)
48
49
50#define TS5500_LED_JP_ADDR 0x77
51#define TS5500_LED BIT(0)
52#define TS5500_JP1 BIT(1)
53#define TS5500_JP2 BIT(2)
54#define TS5500_JP3 BIT(3)
55#define TS5500_JP4 BIT(4)
56#define TS5500_JP5 BIT(5)
57#define TS5500_JP6 BIT(6)
58#define TS5500_JP7 BIT(7)
59
60
61#define TS5500_ADC_CONV_BUSY_ADDR 0x195
62#define TS5500_ADC_CONV_BUSY BIT(0)
63#define TS5500_ADC_CONV_INIT_LSB_ADDR 0x196
64#define TS5500_ADC_CONV_MSB_ADDR 0x197
65#define TS5500_ADC_CONV_DELAY 12
66
67
68
69
70
71
72
73
74
75
76
77
78struct ts5500_sbc {
79 const char *name;
80 int id;
81 bool sram;
82 bool rs485;
83 bool adc;
84 bool ereset;
85 bool itr;
86 u8 jumpers;
87};
88
89
90static const struct {
91 const char * const string;
92 const ssize_t offset;
93} ts5500_signatures[] __initconst = {
94 { "TS-5x00 AMD Elan", 0xb14 },
95};
96
97static int __init ts5500_check_signature(void)
98{
99 void __iomem *bios;
100 int i, ret = -ENODEV;
101
102 bios = ioremap(0xf0000, 0x10000);
103 if (!bios)
104 return -ENOMEM;
105
106 for (i = 0; i < ARRAY_SIZE(ts5500_signatures); i++) {
107 if (check_signature(bios + ts5500_signatures[i].offset,
108 ts5500_signatures[i].string,
109 strlen(ts5500_signatures[i].string))) {
110 ret = 0;
111 break;
112 }
113 }
114
115 iounmap(bios);
116 return ret;
117}
118
119static int __init ts5500_detect_config(struct ts5500_sbc *sbc)
120{
121 u8 tmp;
122 int ret = 0;
123
124 if (!request_region(TS5500_PRODUCT_CODE_ADDR, 4, "ts5500"))
125 return -EBUSY;
126
127 sbc->id = inb(TS5500_PRODUCT_CODE_ADDR);
128 if (sbc->id == TS5500_PRODUCT_CODE) {
129 sbc->name = "TS-5500";
130 } else if (sbc->id == TS5400_PRODUCT_CODE) {
131 sbc->name = "TS-5400";
132 } else {
133 pr_err("ts5500: unknown product code 0x%x\n", sbc->id);
134 ret = -ENODEV;
135 goto cleanup;
136 }
137
138 tmp = inb(TS5500_SRAM_RS485_ADC_ADDR);
139 sbc->sram = tmp & TS5500_SRAM;
140 sbc->rs485 = tmp & TS5500_RS485;
141 sbc->adc = tmp & TS5500_ADC;
142
143 tmp = inb(TS5500_ERESET_ITR_ADDR);
144 sbc->ereset = tmp & TS5500_ERESET;
145 sbc->itr = tmp & TS5500_ITR;
146
147 tmp = inb(TS5500_LED_JP_ADDR);
148 sbc->jumpers = tmp & ~TS5500_LED;
149
150cleanup:
151 release_region(TS5500_PRODUCT_CODE_ADDR, 4);
152 return ret;
153}
154
155static ssize_t name_show(struct device *dev, struct device_attribute *attr,
156 char *buf)
157{
158 struct ts5500_sbc *sbc = dev_get_drvdata(dev);
159
160 return sprintf(buf, "%s\n", sbc->name);
161}
162static DEVICE_ATTR_RO(name);
163
164static ssize_t id_show(struct device *dev, struct device_attribute *attr,
165 char *buf)
166{
167 struct ts5500_sbc *sbc = dev_get_drvdata(dev);
168
169 return sprintf(buf, "0x%.2x\n", sbc->id);
170}
171static DEVICE_ATTR_RO(id);
172
173static ssize_t jumpers_show(struct device *dev, struct device_attribute *attr,
174 char *buf)
175{
176 struct ts5500_sbc *sbc = dev_get_drvdata(dev);
177
178 return sprintf(buf, "0x%.2x\n", sbc->jumpers >> 1);
179}
180static DEVICE_ATTR_RO(jumpers);
181
182#define TS5500_ATTR_BOOL(_field) \
183 static ssize_t _field##_show(struct device *dev, \
184 struct device_attribute *attr, char *buf) \
185 { \
186 struct ts5500_sbc *sbc = dev_get_drvdata(dev); \
187 \
188 return sprintf(buf, "%d\n", sbc->_field); \
189 } \
190 static DEVICE_ATTR_RO(_field)
191
192TS5500_ATTR_BOOL(sram);
193TS5500_ATTR_BOOL(rs485);
194TS5500_ATTR_BOOL(adc);
195TS5500_ATTR_BOOL(ereset);
196TS5500_ATTR_BOOL(itr);
197
198static struct attribute *ts5500_attributes[] = {
199 &dev_attr_id.attr,
200 &dev_attr_name.attr,
201 &dev_attr_jumpers.attr,
202 &dev_attr_sram.attr,
203 &dev_attr_rs485.attr,
204 &dev_attr_adc.attr,
205 &dev_attr_ereset.attr,
206 &dev_attr_itr.attr,
207 NULL
208};
209
210static const struct attribute_group ts5500_attr_group = {
211 .attrs = ts5500_attributes,
212};
213
214static struct resource ts5500_dio1_resource[] = {
215 DEFINE_RES_IRQ_NAMED(7, "DIO1 interrupt"),
216};
217
218static struct platform_device ts5500_dio1_pdev = {
219 .name = "ts5500-dio1",
220 .id = -1,
221 .resource = ts5500_dio1_resource,
222 .num_resources = 1,
223};
224
225static struct resource ts5500_dio2_resource[] = {
226 DEFINE_RES_IRQ_NAMED(6, "DIO2 interrupt"),
227};
228
229static struct platform_device ts5500_dio2_pdev = {
230 .name = "ts5500-dio2",
231 .id = -1,
232 .resource = ts5500_dio2_resource,
233 .num_resources = 1,
234};
235
236static void ts5500_led_set(struct led_classdev *led_cdev,
237 enum led_brightness brightness)
238{
239 outb(!!brightness, TS5500_LED_JP_ADDR);
240}
241
242static enum led_brightness ts5500_led_get(struct led_classdev *led_cdev)
243{
244 return (inb(TS5500_LED_JP_ADDR) & TS5500_LED) ? LED_FULL : LED_OFF;
245}
246
247static struct led_classdev ts5500_led_cdev = {
248 .name = "ts5500:green:",
249 .brightness_set = ts5500_led_set,
250 .brightness_get = ts5500_led_get,
251};
252
253static int ts5500_adc_convert(u8 ctrl)
254{
255 u8 lsb, msb;
256
257
258 outb(ctrl & 0x1f, TS5500_ADC_CONV_INIT_LSB_ADDR);
259
260
261
262
263
264
265 udelay(TS5500_ADC_CONV_DELAY);
266 if (inb(TS5500_ADC_CONV_BUSY_ADDR) & TS5500_ADC_CONV_BUSY)
267 return -EBUSY;
268
269
270 lsb = inb(TS5500_ADC_CONV_INIT_LSB_ADDR);
271 msb = inb(TS5500_ADC_CONV_MSB_ADDR);
272
273 return (msb << 8) | lsb;
274}
275
276static struct max197_platform_data ts5500_adc_pdata = {
277 .convert = ts5500_adc_convert,
278};
279
280static struct platform_device ts5500_adc_pdev = {
281 .name = "max197",
282 .id = -1,
283 .dev = {
284 .platform_data = &ts5500_adc_pdata,
285 },
286};
287
288static int __init ts5500_init(void)
289{
290 struct platform_device *pdev;
291 struct ts5500_sbc *sbc;
292 int err;
293
294
295
296
297
298
299 err = ts5500_check_signature();
300 if (err)
301 return err;
302
303 pdev = platform_device_register_simple("ts5500", -1, NULL, 0);
304 if (IS_ERR(pdev))
305 return PTR_ERR(pdev);
306
307 sbc = devm_kzalloc(&pdev->dev, sizeof(struct ts5500_sbc), GFP_KERNEL);
308 if (!sbc) {
309 err = -ENOMEM;
310 goto error;
311 }
312
313 err = ts5500_detect_config(sbc);
314 if (err)
315 goto error;
316
317 platform_set_drvdata(pdev, sbc);
318
319 err = sysfs_create_group(&pdev->dev.kobj, &ts5500_attr_group);
320 if (err)
321 goto error;
322
323 if (sbc->id == TS5500_PRODUCT_CODE) {
324 ts5500_dio1_pdev.dev.parent = &pdev->dev;
325 if (platform_device_register(&ts5500_dio1_pdev))
326 dev_warn(&pdev->dev, "DIO1 block registration failed\n");
327 ts5500_dio2_pdev.dev.parent = &pdev->dev;
328 if (platform_device_register(&ts5500_dio2_pdev))
329 dev_warn(&pdev->dev, "DIO2 block registration failed\n");
330 }
331
332 if (led_classdev_register(&pdev->dev, &ts5500_led_cdev))
333 dev_warn(&pdev->dev, "LED registration failed\n");
334
335 if (sbc->adc) {
336 ts5500_adc_pdev.dev.parent = &pdev->dev;
337 if (platform_device_register(&ts5500_adc_pdev))
338 dev_warn(&pdev->dev, "ADC registration failed\n");
339 }
340
341 return 0;
342error:
343 platform_device_unregister(pdev);
344 return err;
345}
346device_initcall(ts5500_init);
347