2 * tle62x0.c -- 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>
15 #include <linux/spi/spi.h>
16 #include <linux/spi/tle62x0.h>
22 #define DIAG_NORMAL 0x03
23 #define DIAG_OVERLOAD 0x02
24 #define DIAG_OPEN 0x01
25 #define DIAG_SHORTGND 0x00
27 struct tle62x0_state
{
28 struct spi_device
*us
;
31 unsigned int gpio_state
;
33 unsigned char tx_buff
[4];
34 unsigned char rx_buff
[4];
37 static int to_gpio_num(struct device_attribute
*attr
);
39 static inline int tle62x0_write(struct tle62x0_state
*st
)
41 unsigned char *buff
= st
->tx_buff
;
42 unsigned int gpio_state
= st
->gpio_state
;
46 if (st
->nr_gpio
== 16) {
47 buff
[1] = gpio_state
>> 8;
53 dev_dbg(&st
->us
->dev
, "buff %02x,%02x,%02x\n",
54 buff
[0], buff
[1], buff
[2]);
56 return spi_write(st
->us
, buff
, (st
->nr_gpio
== 16) ? 3 : 2);
59 static inline int tle62x0_read(struct tle62x0_state
*st
)
61 unsigned char *txbuff
= st
->tx_buff
;
62 struct spi_transfer xfer
= {
64 .rx_buf
= st
->rx_buff
,
65 .len
= (st
->nr_gpio
* 2) / 8,
67 struct spi_message msg
;
74 spi_message_init(&msg
);
75 spi_message_add_tail(&xfer
, &msg
);
77 return spi_sync(st
->us
, &msg
);
80 static unsigned char *decode_fault(unsigned int fault_code
)
98 static ssize_t
tle62x0_status_show(struct device
*dev
,
99 struct device_attribute
*attr
, char *buf
)
101 struct tle62x0_state
*st
= dev_get_drvdata(dev
);
103 unsigned char *buff
= st
->rx_buff
;
104 unsigned long fault
= 0;
108 mutex_lock(&st
->lock
);
109 ret
= tle62x0_read(st
);
111 dev_dbg(dev
, "tle62x0_read() returned %d\n", ret
);
113 for (ptr
= 0; ptr
< (st
->nr_gpio
* 2)/8; ptr
+= 1) {
115 fault
|= ((unsigned long)buff
[ptr
]);
117 dev_dbg(dev
, "byte %d is %02x\n", ptr
, buff
[ptr
]);
120 for (ptr
= 0; ptr
< st
->nr_gpio
; ptr
++) {
121 bp
+= sprintf(bp
, "%s ", decode_fault(fault
>> (ptr
* 2)));
126 mutex_unlock(&st
->lock
);
130 static DEVICE_ATTR(status_show
, S_IRUGO
, tle62x0_status_show
, NULL
);
132 static ssize_t
tle62x0_gpio_show(struct device
*dev
,
133 struct device_attribute
*attr
, char *buf
)
135 struct tle62x0_state
*st
= dev_get_drvdata(dev
);
136 int gpio_num
= to_gpio_num(attr
);
139 mutex_lock(&st
->lock
);
140 value
= (st
->gpio_state
>> gpio_num
) & 1;
141 mutex_unlock(&st
->lock
);
143 return snprintf(buf
, PAGE_SIZE
, "%d", value
);
146 static ssize_t
tle62x0_gpio_store(struct device
*dev
,
147 struct device_attribute
*attr
,
148 const char *buf
, size_t len
)
150 struct tle62x0_state
*st
= dev_get_drvdata(dev
);
151 int gpio_num
= to_gpio_num(attr
);
155 val
= simple_strtoul(buf
, &endp
, 0);
159 dev_dbg(dev
, "setting gpio %d to %ld\n", gpio_num
, val
);
161 mutex_lock(&st
->lock
);
164 st
->gpio_state
|= 1 << gpio_num
;
166 st
->gpio_state
&= ~(1 << gpio_num
);
169 mutex_unlock(&st
->lock
);
174 static DEVICE_ATTR(gpio1
, S_IWUSR
|S_IRUGO
,
175 tle62x0_gpio_show
, tle62x0_gpio_store
);
176 static DEVICE_ATTR(gpio2
, S_IWUSR
|S_IRUGO
,
177 tle62x0_gpio_show
, tle62x0_gpio_store
);
178 static DEVICE_ATTR(gpio3
, S_IWUSR
|S_IRUGO
,
179 tle62x0_gpio_show
, tle62x0_gpio_store
);
180 static DEVICE_ATTR(gpio4
, S_IWUSR
|S_IRUGO
,
181 tle62x0_gpio_show
, tle62x0_gpio_store
);
182 static DEVICE_ATTR(gpio5
, S_IWUSR
|S_IRUGO
,
183 tle62x0_gpio_show
, tle62x0_gpio_store
);
184 static DEVICE_ATTR(gpio6
, S_IWUSR
|S_IRUGO
,
185 tle62x0_gpio_show
, tle62x0_gpio_store
);
186 static DEVICE_ATTR(gpio7
, S_IWUSR
|S_IRUGO
,
187 tle62x0_gpio_show
, tle62x0_gpio_store
);
188 static DEVICE_ATTR(gpio8
, S_IWUSR
|S_IRUGO
,
189 tle62x0_gpio_show
, tle62x0_gpio_store
);
190 static DEVICE_ATTR(gpio9
, S_IWUSR
|S_IRUGO
,
191 tle62x0_gpio_show
, tle62x0_gpio_store
);
192 static DEVICE_ATTR(gpio10
, S_IWUSR
|S_IRUGO
,
193 tle62x0_gpio_show
, tle62x0_gpio_store
);
194 static DEVICE_ATTR(gpio11
, S_IWUSR
|S_IRUGO
,
195 tle62x0_gpio_show
, tle62x0_gpio_store
);
196 static DEVICE_ATTR(gpio12
, S_IWUSR
|S_IRUGO
,
197 tle62x0_gpio_show
, tle62x0_gpio_store
);
198 static DEVICE_ATTR(gpio13
, S_IWUSR
|S_IRUGO
,
199 tle62x0_gpio_show
, tle62x0_gpio_store
);
200 static DEVICE_ATTR(gpio14
, S_IWUSR
|S_IRUGO
,
201 tle62x0_gpio_show
, tle62x0_gpio_store
);
202 static DEVICE_ATTR(gpio15
, S_IWUSR
|S_IRUGO
,
203 tle62x0_gpio_show
, tle62x0_gpio_store
);
204 static DEVICE_ATTR(gpio16
, S_IWUSR
|S_IRUGO
,
205 tle62x0_gpio_show
, tle62x0_gpio_store
);
207 static struct device_attribute
*gpio_attrs
[] = {
208 [0] = &dev_attr_gpio1
,
209 [1] = &dev_attr_gpio2
,
210 [2] = &dev_attr_gpio3
,
211 [3] = &dev_attr_gpio4
,
212 [4] = &dev_attr_gpio5
,
213 [5] = &dev_attr_gpio6
,
214 [6] = &dev_attr_gpio7
,
215 [7] = &dev_attr_gpio8
,
216 [8] = &dev_attr_gpio9
,
217 [9] = &dev_attr_gpio10
,
218 [10] = &dev_attr_gpio11
,
219 [11] = &dev_attr_gpio12
,
220 [12] = &dev_attr_gpio13
,
221 [13] = &dev_attr_gpio14
,
222 [14] = &dev_attr_gpio15
,
223 [15] = &dev_attr_gpio16
226 static int to_gpio_num(struct device_attribute
*attr
)
230 for (ptr
= 0; ptr
< ARRAY_SIZE(gpio_attrs
); ptr
++) {
231 if (gpio_attrs
[ptr
] == attr
)
238 static int __devinit
tle62x0_probe(struct spi_device
*spi
)
240 struct tle62x0_state
*st
;
241 struct tle62x0_pdata
*pdata
;
245 pdata
= spi
->dev
.platform_data
;
247 dev_err(&spi
->dev
, "no device data specified\n");
251 st
= kzalloc(sizeof(struct tle62x0_state
), GFP_KERNEL
);
253 dev_err(&spi
->dev
, "no memory for device state\n");
258 st
->nr_gpio
= pdata
->gpio_count
;
259 st
->gpio_state
= pdata
->init_state
;
261 mutex_init(&st
->lock
);
263 ret
= device_create_file(&spi
->dev
, &dev_attr_status_show
);
265 dev_err(&spi
->dev
, "cannot create status attribute\n");
269 for (ptr
= 0; ptr
< pdata
->gpio_count
; ptr
++) {
270 ret
= device_create_file(&spi
->dev
, gpio_attrs
[ptr
]);
272 dev_err(&spi
->dev
, "cannot create gpio attribute\n");
277 /* tle62x0_write(st); */
278 spi_set_drvdata(spi
, st
);
282 for (; ptr
> 0; ptr
--)
283 device_remove_file(&spi
->dev
, gpio_attrs
[ptr
]);
285 device_remove_file(&spi
->dev
, &dev_attr_status_show
);
292 static int __devexit
tle62x0_remove(struct spi_device
*spi
)
294 struct tle62x0_state
*st
= spi_get_drvdata(spi
);
297 for (ptr
= 0; ptr
< st
->nr_gpio
; ptr
++)
298 device_remove_file(&spi
->dev
, gpio_attrs
[ptr
]);
304 static struct spi_driver tle62x0_driver
= {
307 .owner
= THIS_MODULE
,
309 .probe
= tle62x0_probe
,
310 .remove
= __devexit_p(tle62x0_remove
),
313 static __init
int tle62x0_init(void)
315 return spi_register_driver(&tle62x0_driver
);
318 static __exit
void tle62x0_exit(void)
320 spi_unregister_driver(&tle62x0_driver
);
323 module_init(tle62x0_init
);
324 module_exit(tle62x0_exit
);
326 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
327 MODULE_DESCRIPTION("TLE62x0 SPI driver");
328 MODULE_LICENSE("GPL v2");