2 * Support Infineon TLE62x0 driver chips
4 * Copyright (c) 2007 Simtec Electronics
5 * Ben Dooks, <ben@simtec.co.uk>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
12 #include <linux/device.h>
13 #include <linux/kernel.h>
14 #include <linux/slab.h>
16 #include <linux/spi/spi.h>
17 #include <linux/spi/tle62x0.h>
23 #define DIAG_NORMAL 0x03
24 #define DIAG_OVERLOAD 0x02
25 #define DIAG_OPEN 0x01
26 #define DIAG_SHORTGND 0x00
28 struct tle62x0_state
{
29 struct spi_device
*us
;
32 unsigned int gpio_state
;
34 unsigned char tx_buff
[4];
35 unsigned char rx_buff
[4];
38 static int to_gpio_num(struct device_attribute
*attr
);
40 static inline int tle62x0_write(struct tle62x0_state
*st
)
42 unsigned char *buff
= st
->tx_buff
;
43 unsigned int gpio_state
= st
->gpio_state
;
47 if (st
->nr_gpio
== 16) {
48 buff
[1] = gpio_state
>> 8;
54 dev_dbg(&st
->us
->dev
, "buff %02x,%02x,%02x\n",
55 buff
[0], buff
[1], buff
[2]);
57 return spi_write(st
->us
, buff
, (st
->nr_gpio
== 16) ? 3 : 2);
60 static inline int tle62x0_read(struct tle62x0_state
*st
)
62 unsigned char *txbuff
= st
->tx_buff
;
63 struct spi_transfer xfer
= {
65 .rx_buf
= st
->rx_buff
,
66 .len
= (st
->nr_gpio
* 2) / 8,
68 struct spi_message msg
;
75 spi_message_init(&msg
);
76 spi_message_add_tail(&xfer
, &msg
);
78 return spi_sync(st
->us
, &msg
);
81 static unsigned char *decode_fault(unsigned int fault_code
)
99 static ssize_t
tle62x0_status_show(struct device
*dev
,
100 struct device_attribute
*attr
, char *buf
)
102 struct tle62x0_state
*st
= dev_get_drvdata(dev
);
104 unsigned char *buff
= st
->rx_buff
;
105 unsigned long fault
= 0;
109 mutex_lock(&st
->lock
);
110 ret
= tle62x0_read(st
);
111 dev_dbg(dev
, "tle62x0_read() returned %d\n", ret
);
113 mutex_unlock(&st
->lock
);
117 for (ptr
= 0; ptr
< (st
->nr_gpio
* 2)/8; ptr
+= 1) {
119 fault
|= ((unsigned long)buff
[ptr
]);
121 dev_dbg(dev
, "byte %d is %02x\n", ptr
, buff
[ptr
]);
124 for (ptr
= 0; ptr
< st
->nr_gpio
; ptr
++) {
125 bp
+= sprintf(bp
, "%s ", decode_fault(fault
>> (ptr
* 2)));
130 mutex_unlock(&st
->lock
);
134 static DEVICE_ATTR(status_show
, S_IRUGO
, tle62x0_status_show
, NULL
);
136 static ssize_t
tle62x0_gpio_show(struct device
*dev
,
137 struct device_attribute
*attr
, char *buf
)
139 struct tle62x0_state
*st
= dev_get_drvdata(dev
);
140 int gpio_num
= to_gpio_num(attr
);
143 mutex_lock(&st
->lock
);
144 value
= (st
->gpio_state
>> gpio_num
) & 1;
145 mutex_unlock(&st
->lock
);
147 return snprintf(buf
, PAGE_SIZE
, "%d", value
);
150 static ssize_t
tle62x0_gpio_store(struct device
*dev
,
151 struct device_attribute
*attr
,
152 const char *buf
, size_t len
)
154 struct tle62x0_state
*st
= dev_get_drvdata(dev
);
155 int gpio_num
= to_gpio_num(attr
);
159 val
= simple_strtoul(buf
, &endp
, 0);
163 dev_dbg(dev
, "setting gpio %d to %ld\n", gpio_num
, val
);
165 mutex_lock(&st
->lock
);
168 st
->gpio_state
|= 1 << gpio_num
;
170 st
->gpio_state
&= ~(1 << gpio_num
);
173 mutex_unlock(&st
->lock
);
178 static DEVICE_ATTR(gpio1
, S_IWUSR
|S_IRUGO
,
179 tle62x0_gpio_show
, tle62x0_gpio_store
);
180 static DEVICE_ATTR(gpio2
, S_IWUSR
|S_IRUGO
,
181 tle62x0_gpio_show
, tle62x0_gpio_store
);
182 static DEVICE_ATTR(gpio3
, S_IWUSR
|S_IRUGO
,
183 tle62x0_gpio_show
, tle62x0_gpio_store
);
184 static DEVICE_ATTR(gpio4
, S_IWUSR
|S_IRUGO
,
185 tle62x0_gpio_show
, tle62x0_gpio_store
);
186 static DEVICE_ATTR(gpio5
, S_IWUSR
|S_IRUGO
,
187 tle62x0_gpio_show
, tle62x0_gpio_store
);
188 static DEVICE_ATTR(gpio6
, S_IWUSR
|S_IRUGO
,
189 tle62x0_gpio_show
, tle62x0_gpio_store
);
190 static DEVICE_ATTR(gpio7
, S_IWUSR
|S_IRUGO
,
191 tle62x0_gpio_show
, tle62x0_gpio_store
);
192 static DEVICE_ATTR(gpio8
, S_IWUSR
|S_IRUGO
,
193 tle62x0_gpio_show
, tle62x0_gpio_store
);
194 static DEVICE_ATTR(gpio9
, S_IWUSR
|S_IRUGO
,
195 tle62x0_gpio_show
, tle62x0_gpio_store
);
196 static DEVICE_ATTR(gpio10
, S_IWUSR
|S_IRUGO
,
197 tle62x0_gpio_show
, tle62x0_gpio_store
);
198 static DEVICE_ATTR(gpio11
, S_IWUSR
|S_IRUGO
,
199 tle62x0_gpio_show
, tle62x0_gpio_store
);
200 static DEVICE_ATTR(gpio12
, S_IWUSR
|S_IRUGO
,
201 tle62x0_gpio_show
, tle62x0_gpio_store
);
202 static DEVICE_ATTR(gpio13
, S_IWUSR
|S_IRUGO
,
203 tle62x0_gpio_show
, tle62x0_gpio_store
);
204 static DEVICE_ATTR(gpio14
, S_IWUSR
|S_IRUGO
,
205 tle62x0_gpio_show
, tle62x0_gpio_store
);
206 static DEVICE_ATTR(gpio15
, S_IWUSR
|S_IRUGO
,
207 tle62x0_gpio_show
, tle62x0_gpio_store
);
208 static DEVICE_ATTR(gpio16
, S_IWUSR
|S_IRUGO
,
209 tle62x0_gpio_show
, tle62x0_gpio_store
);
211 static struct device_attribute
*gpio_attrs
[] = {
212 [0] = &dev_attr_gpio1
,
213 [1] = &dev_attr_gpio2
,
214 [2] = &dev_attr_gpio3
,
215 [3] = &dev_attr_gpio4
,
216 [4] = &dev_attr_gpio5
,
217 [5] = &dev_attr_gpio6
,
218 [6] = &dev_attr_gpio7
,
219 [7] = &dev_attr_gpio8
,
220 [8] = &dev_attr_gpio9
,
221 [9] = &dev_attr_gpio10
,
222 [10] = &dev_attr_gpio11
,
223 [11] = &dev_attr_gpio12
,
224 [12] = &dev_attr_gpio13
,
225 [13] = &dev_attr_gpio14
,
226 [14] = &dev_attr_gpio15
,
227 [15] = &dev_attr_gpio16
230 static int to_gpio_num(struct device_attribute
*attr
)
234 for (ptr
= 0; ptr
< ARRAY_SIZE(gpio_attrs
); ptr
++) {
235 if (gpio_attrs
[ptr
] == attr
)
242 static int __devinit
tle62x0_probe(struct spi_device
*spi
)
244 struct tle62x0_state
*st
;
245 struct tle62x0_pdata
*pdata
;
249 pdata
= spi
->dev
.platform_data
;
251 dev_err(&spi
->dev
, "no device data specified\n");
255 st
= kzalloc(sizeof(struct tle62x0_state
), GFP_KERNEL
);
257 dev_err(&spi
->dev
, "no memory for device state\n");
262 st
->nr_gpio
= pdata
->gpio_count
;
263 st
->gpio_state
= pdata
->init_state
;
265 mutex_init(&st
->lock
);
267 ret
= device_create_file(&spi
->dev
, &dev_attr_status_show
);
269 dev_err(&spi
->dev
, "cannot create status attribute\n");
273 for (ptr
= 0; ptr
< pdata
->gpio_count
; ptr
++) {
274 ret
= device_create_file(&spi
->dev
, gpio_attrs
[ptr
]);
276 dev_err(&spi
->dev
, "cannot create gpio attribute\n");
281 /* tle62x0_write(st); */
282 spi_set_drvdata(spi
, st
);
287 device_remove_file(&spi
->dev
, gpio_attrs
[ptr
]);
289 device_remove_file(&spi
->dev
, &dev_attr_status_show
);
296 static int __devexit
tle62x0_remove(struct spi_device
*spi
)
298 struct tle62x0_state
*st
= spi_get_drvdata(spi
);
301 for (ptr
= 0; ptr
< st
->nr_gpio
; ptr
++)
302 device_remove_file(&spi
->dev
, gpio_attrs
[ptr
]);
304 device_remove_file(&spi
->dev
, &dev_attr_status_show
);
309 static struct spi_driver tle62x0_driver
= {
312 .owner
= THIS_MODULE
,
314 .probe
= tle62x0_probe
,
315 .remove
= __devexit_p(tle62x0_remove
),
318 static __init
int tle62x0_init(void)
320 return spi_register_driver(&tle62x0_driver
);
323 static __exit
void tle62x0_exit(void)
325 spi_unregister_driver(&tle62x0_driver
);
328 module_init(tle62x0_init
);
329 module_exit(tle62x0_exit
);
331 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
332 MODULE_DESCRIPTION("TLE62x0 SPI driver");
333 MODULE_LICENSE("GPL v2");
334 MODULE_ALIAS("spi:tle62x0");