0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/device.h>
0010 #include <linux/kernel.h>
0011 #include <linux/module.h>
0012 #include <linux/slab.h>
0013
0014 #include <linux/spi/spi.h>
0015 #include <linux/spi/tle62x0.h>
0016
0017
0018 #define CMD_READ 0x00
0019 #define CMD_SET 0xff
0020
0021 #define DIAG_NORMAL 0x03
0022 #define DIAG_OVERLOAD 0x02
0023 #define DIAG_OPEN 0x01
0024 #define DIAG_SHORTGND 0x00
0025
0026 struct tle62x0_state {
0027 struct spi_device *us;
0028 struct mutex lock;
0029 unsigned int nr_gpio;
0030 unsigned int gpio_state;
0031
0032 unsigned char tx_buff[4];
0033 unsigned char rx_buff[4];
0034 };
0035
0036 static int to_gpio_num(struct device_attribute *attr);
0037
0038 static inline int tle62x0_write(struct tle62x0_state *st)
0039 {
0040 unsigned char *buff = st->tx_buff;
0041 unsigned int gpio_state = st->gpio_state;
0042
0043 buff[0] = CMD_SET;
0044
0045 if (st->nr_gpio == 16) {
0046 buff[1] = gpio_state >> 8;
0047 buff[2] = gpio_state;
0048 } else {
0049 buff[1] = gpio_state;
0050 }
0051
0052 dev_dbg(&st->us->dev, "buff %3ph\n", buff);
0053
0054 return spi_write(st->us, buff, (st->nr_gpio == 16) ? 3 : 2);
0055 }
0056
0057 static inline int tle62x0_read(struct tle62x0_state *st)
0058 {
0059 unsigned char *txbuff = st->tx_buff;
0060 struct spi_transfer xfer = {
0061 .tx_buf = txbuff,
0062 .rx_buf = st->rx_buff,
0063 .len = (st->nr_gpio * 2) / 8,
0064 };
0065 struct spi_message msg;
0066
0067 txbuff[0] = CMD_READ;
0068 txbuff[1] = 0x00;
0069 txbuff[2] = 0x00;
0070 txbuff[3] = 0x00;
0071
0072 spi_message_init(&msg);
0073 spi_message_add_tail(&xfer, &msg);
0074
0075 return spi_sync(st->us, &msg);
0076 }
0077
0078 static unsigned char *decode_fault(unsigned int fault_code)
0079 {
0080 fault_code &= 3;
0081
0082 switch (fault_code) {
0083 case DIAG_NORMAL:
0084 return "N";
0085 case DIAG_OVERLOAD:
0086 return "V";
0087 case DIAG_OPEN:
0088 return "O";
0089 case DIAG_SHORTGND:
0090 return "G";
0091 }
0092
0093 return "?";
0094 }
0095
0096 static ssize_t tle62x0_status_show(struct device *dev,
0097 struct device_attribute *attr, char *buf)
0098 {
0099 struct tle62x0_state *st = dev_get_drvdata(dev);
0100 char *bp = buf;
0101 unsigned char *buff = st->rx_buff;
0102 unsigned long fault = 0;
0103 int ptr;
0104 int ret;
0105
0106 mutex_lock(&st->lock);
0107 ret = tle62x0_read(st);
0108 dev_dbg(dev, "tle62x0_read() returned %d\n", ret);
0109 if (ret < 0) {
0110 mutex_unlock(&st->lock);
0111 return ret;
0112 }
0113
0114 for (ptr = 0; ptr < (st->nr_gpio * 2)/8; ptr += 1) {
0115 fault <<= 8;
0116 fault |= ((unsigned long)buff[ptr]);
0117
0118 dev_dbg(dev, "byte %d is %02x\n", ptr, buff[ptr]);
0119 }
0120
0121 for (ptr = 0; ptr < st->nr_gpio; ptr++) {
0122 bp += sprintf(bp, "%s ", decode_fault(fault >> (ptr * 2)));
0123 }
0124
0125 *bp++ = '\n';
0126
0127 mutex_unlock(&st->lock);
0128 return bp - buf;
0129 }
0130
0131 static DEVICE_ATTR(status_show, S_IRUGO, tle62x0_status_show, NULL);
0132
0133 static ssize_t tle62x0_gpio_show(struct device *dev,
0134 struct device_attribute *attr, char *buf)
0135 {
0136 struct tle62x0_state *st = dev_get_drvdata(dev);
0137 int gpio_num = to_gpio_num(attr);
0138 int value;
0139
0140 mutex_lock(&st->lock);
0141 value = (st->gpio_state >> gpio_num) & 1;
0142 mutex_unlock(&st->lock);
0143
0144 return sysfs_emit(buf, "%d", value);
0145 }
0146
0147 static ssize_t tle62x0_gpio_store(struct device *dev,
0148 struct device_attribute *attr,
0149 const char *buf, size_t len)
0150 {
0151 struct tle62x0_state *st = dev_get_drvdata(dev);
0152 int gpio_num = to_gpio_num(attr);
0153 unsigned long val;
0154 char *endp;
0155
0156 val = simple_strtoul(buf, &endp, 0);
0157 if (buf == endp)
0158 return -EINVAL;
0159
0160 dev_dbg(dev, "setting gpio %d to %ld\n", gpio_num, val);
0161
0162 mutex_lock(&st->lock);
0163
0164 if (val)
0165 st->gpio_state |= 1 << gpio_num;
0166 else
0167 st->gpio_state &= ~(1 << gpio_num);
0168
0169 tle62x0_write(st);
0170 mutex_unlock(&st->lock);
0171
0172 return len;
0173 }
0174
0175 static DEVICE_ATTR(gpio1, S_IWUSR|S_IRUGO,
0176 tle62x0_gpio_show, tle62x0_gpio_store);
0177 static DEVICE_ATTR(gpio2, S_IWUSR|S_IRUGO,
0178 tle62x0_gpio_show, tle62x0_gpio_store);
0179 static DEVICE_ATTR(gpio3, S_IWUSR|S_IRUGO,
0180 tle62x0_gpio_show, tle62x0_gpio_store);
0181 static DEVICE_ATTR(gpio4, S_IWUSR|S_IRUGO,
0182 tle62x0_gpio_show, tle62x0_gpio_store);
0183 static DEVICE_ATTR(gpio5, S_IWUSR|S_IRUGO,
0184 tle62x0_gpio_show, tle62x0_gpio_store);
0185 static DEVICE_ATTR(gpio6, S_IWUSR|S_IRUGO,
0186 tle62x0_gpio_show, tle62x0_gpio_store);
0187 static DEVICE_ATTR(gpio7, S_IWUSR|S_IRUGO,
0188 tle62x0_gpio_show, tle62x0_gpio_store);
0189 static DEVICE_ATTR(gpio8, S_IWUSR|S_IRUGO,
0190 tle62x0_gpio_show, tle62x0_gpio_store);
0191 static DEVICE_ATTR(gpio9, S_IWUSR|S_IRUGO,
0192 tle62x0_gpio_show, tle62x0_gpio_store);
0193 static DEVICE_ATTR(gpio10, S_IWUSR|S_IRUGO,
0194 tle62x0_gpio_show, tle62x0_gpio_store);
0195 static DEVICE_ATTR(gpio11, S_IWUSR|S_IRUGO,
0196 tle62x0_gpio_show, tle62x0_gpio_store);
0197 static DEVICE_ATTR(gpio12, S_IWUSR|S_IRUGO,
0198 tle62x0_gpio_show, tle62x0_gpio_store);
0199 static DEVICE_ATTR(gpio13, S_IWUSR|S_IRUGO,
0200 tle62x0_gpio_show, tle62x0_gpio_store);
0201 static DEVICE_ATTR(gpio14, S_IWUSR|S_IRUGO,
0202 tle62x0_gpio_show, tle62x0_gpio_store);
0203 static DEVICE_ATTR(gpio15, S_IWUSR|S_IRUGO,
0204 tle62x0_gpio_show, tle62x0_gpio_store);
0205 static DEVICE_ATTR(gpio16, S_IWUSR|S_IRUGO,
0206 tle62x0_gpio_show, tle62x0_gpio_store);
0207
0208 static struct device_attribute *gpio_attrs[] = {
0209 [0] = &dev_attr_gpio1,
0210 [1] = &dev_attr_gpio2,
0211 [2] = &dev_attr_gpio3,
0212 [3] = &dev_attr_gpio4,
0213 [4] = &dev_attr_gpio5,
0214 [5] = &dev_attr_gpio6,
0215 [6] = &dev_attr_gpio7,
0216 [7] = &dev_attr_gpio8,
0217 [8] = &dev_attr_gpio9,
0218 [9] = &dev_attr_gpio10,
0219 [10] = &dev_attr_gpio11,
0220 [11] = &dev_attr_gpio12,
0221 [12] = &dev_attr_gpio13,
0222 [13] = &dev_attr_gpio14,
0223 [14] = &dev_attr_gpio15,
0224 [15] = &dev_attr_gpio16
0225 };
0226
0227 static int to_gpio_num(struct device_attribute *attr)
0228 {
0229 int ptr;
0230
0231 for (ptr = 0; ptr < ARRAY_SIZE(gpio_attrs); ptr++) {
0232 if (gpio_attrs[ptr] == attr)
0233 return ptr;
0234 }
0235
0236 return -1;
0237 }
0238
0239 static int tle62x0_probe(struct spi_device *spi)
0240 {
0241 struct tle62x0_state *st;
0242 struct tle62x0_pdata *pdata;
0243 int ptr;
0244 int ret;
0245
0246 pdata = dev_get_platdata(&spi->dev);
0247 if (pdata == NULL) {
0248 dev_err(&spi->dev, "no device data specified\n");
0249 return -EINVAL;
0250 }
0251
0252 st = kzalloc(sizeof(struct tle62x0_state), GFP_KERNEL);
0253 if (st == NULL)
0254 return -ENOMEM;
0255
0256 st->us = spi;
0257 st->nr_gpio = pdata->gpio_count;
0258 st->gpio_state = pdata->init_state;
0259
0260 mutex_init(&st->lock);
0261
0262 ret = device_create_file(&spi->dev, &dev_attr_status_show);
0263 if (ret) {
0264 dev_err(&spi->dev, "cannot create status attribute\n");
0265 goto err_status;
0266 }
0267
0268 for (ptr = 0; ptr < pdata->gpio_count; ptr++) {
0269 ret = device_create_file(&spi->dev, gpio_attrs[ptr]);
0270 if (ret) {
0271 dev_err(&spi->dev, "cannot create gpio attribute\n");
0272 goto err_gpios;
0273 }
0274 }
0275
0276
0277 spi_set_drvdata(spi, st);
0278 return 0;
0279
0280 err_gpios:
0281 while (--ptr >= 0)
0282 device_remove_file(&spi->dev, gpio_attrs[ptr]);
0283
0284 device_remove_file(&spi->dev, &dev_attr_status_show);
0285
0286 err_status:
0287 kfree(st);
0288 return ret;
0289 }
0290
0291 static void tle62x0_remove(struct spi_device *spi)
0292 {
0293 struct tle62x0_state *st = spi_get_drvdata(spi);
0294 int ptr;
0295
0296 for (ptr = 0; ptr < st->nr_gpio; ptr++)
0297 device_remove_file(&spi->dev, gpio_attrs[ptr]);
0298
0299 device_remove_file(&spi->dev, &dev_attr_status_show);
0300 kfree(st);
0301 }
0302
0303 static struct spi_driver tle62x0_driver = {
0304 .driver = {
0305 .name = "tle62x0",
0306 },
0307 .probe = tle62x0_probe,
0308 .remove = tle62x0_remove,
0309 };
0310
0311 module_spi_driver(tle62x0_driver);
0312
0313 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
0314 MODULE_DESCRIPTION("TLE62x0 SPI driver");
0315 MODULE_LICENSE("GPL v2");
0316 MODULE_ALIAS("spi:tle62x0");