spi-tle62x0.c (7165B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Support Infineon TLE62x0 driver chips 4 * 5 * Copyright (c) 2007 Simtec Electronics 6 * Ben Dooks, <ben@simtec.co.uk> 7 */ 8 9#include <linux/device.h> 10#include <linux/kernel.h> 11#include <linux/module.h> 12#include <linux/slab.h> 13 14#include <linux/spi/spi.h> 15#include <linux/spi/tle62x0.h> 16 17 18#define CMD_READ 0x00 19#define CMD_SET 0xff 20 21#define DIAG_NORMAL 0x03 22#define DIAG_OVERLOAD 0x02 23#define DIAG_OPEN 0x01 24#define DIAG_SHORTGND 0x00 25 26struct tle62x0_state { 27 struct spi_device *us; 28 struct mutex lock; 29 unsigned int nr_gpio; 30 unsigned int gpio_state; 31 32 unsigned char tx_buff[4]; 33 unsigned char rx_buff[4]; 34}; 35 36static int to_gpio_num(struct device_attribute *attr); 37 38static inline int tle62x0_write(struct tle62x0_state *st) 39{ 40 unsigned char *buff = st->tx_buff; 41 unsigned int gpio_state = st->gpio_state; 42 43 buff[0] = CMD_SET; 44 45 if (st->nr_gpio == 16) { 46 buff[1] = gpio_state >> 8; 47 buff[2] = gpio_state; 48 } else { 49 buff[1] = gpio_state; 50 } 51 52 dev_dbg(&st->us->dev, "buff %3ph\n", buff); 53 54 return spi_write(st->us, buff, (st->nr_gpio == 16) ? 3 : 2); 55} 56 57static inline int tle62x0_read(struct tle62x0_state *st) 58{ 59 unsigned char *txbuff = st->tx_buff; 60 struct spi_transfer xfer = { 61 .tx_buf = txbuff, 62 .rx_buf = st->rx_buff, 63 .len = (st->nr_gpio * 2) / 8, 64 }; 65 struct spi_message msg; 66 67 txbuff[0] = CMD_READ; 68 txbuff[1] = 0x00; 69 txbuff[2] = 0x00; 70 txbuff[3] = 0x00; 71 72 spi_message_init(&msg); 73 spi_message_add_tail(&xfer, &msg); 74 75 return spi_sync(st->us, &msg); 76} 77 78static unsigned char *decode_fault(unsigned int fault_code) 79{ 80 fault_code &= 3; 81 82 switch (fault_code) { 83 case DIAG_NORMAL: 84 return "N"; 85 case DIAG_OVERLOAD: 86 return "V"; 87 case DIAG_OPEN: 88 return "O"; 89 case DIAG_SHORTGND: 90 return "G"; 91 } 92 93 return "?"; 94} 95 96static ssize_t tle62x0_status_show(struct device *dev, 97 struct device_attribute *attr, char *buf) 98{ 99 struct tle62x0_state *st = dev_get_drvdata(dev); 100 char *bp = buf; 101 unsigned char *buff = st->rx_buff; 102 unsigned long fault = 0; 103 int ptr; 104 int ret; 105 106 mutex_lock(&st->lock); 107 ret = tle62x0_read(st); 108 dev_dbg(dev, "tle62x0_read() returned %d\n", ret); 109 if (ret < 0) { 110 mutex_unlock(&st->lock); 111 return ret; 112 } 113 114 for (ptr = 0; ptr < (st->nr_gpio * 2)/8; ptr += 1) { 115 fault <<= 8; 116 fault |= ((unsigned long)buff[ptr]); 117 118 dev_dbg(dev, "byte %d is %02x\n", ptr, buff[ptr]); 119 } 120 121 for (ptr = 0; ptr < st->nr_gpio; ptr++) { 122 bp += sprintf(bp, "%s ", decode_fault(fault >> (ptr * 2))); 123 } 124 125 *bp++ = '\n'; 126 127 mutex_unlock(&st->lock); 128 return bp - buf; 129} 130 131static DEVICE_ATTR(status_show, S_IRUGO, tle62x0_status_show, NULL); 132 133static ssize_t tle62x0_gpio_show(struct device *dev, 134 struct device_attribute *attr, char *buf) 135{ 136 struct tle62x0_state *st = dev_get_drvdata(dev); 137 int gpio_num = to_gpio_num(attr); 138 int value; 139 140 mutex_lock(&st->lock); 141 value = (st->gpio_state >> gpio_num) & 1; 142 mutex_unlock(&st->lock); 143 144 return sysfs_emit(buf, "%d", value); 145} 146 147static ssize_t tle62x0_gpio_store(struct device *dev, 148 struct device_attribute *attr, 149 const char *buf, size_t len) 150{ 151 struct tle62x0_state *st = dev_get_drvdata(dev); 152 int gpio_num = to_gpio_num(attr); 153 unsigned long val; 154 char *endp; 155 156 val = simple_strtoul(buf, &endp, 0); 157 if (buf == endp) 158 return -EINVAL; 159 160 dev_dbg(dev, "setting gpio %d to %ld\n", gpio_num, val); 161 162 mutex_lock(&st->lock); 163 164 if (val) 165 st->gpio_state |= 1 << gpio_num; 166 else 167 st->gpio_state &= ~(1 << gpio_num); 168 169 tle62x0_write(st); 170 mutex_unlock(&st->lock); 171 172 return len; 173} 174 175static DEVICE_ATTR(gpio1, S_IWUSR|S_IRUGO, 176 tle62x0_gpio_show, tle62x0_gpio_store); 177static DEVICE_ATTR(gpio2, S_IWUSR|S_IRUGO, 178 tle62x0_gpio_show, tle62x0_gpio_store); 179static DEVICE_ATTR(gpio3, S_IWUSR|S_IRUGO, 180 tle62x0_gpio_show, tle62x0_gpio_store); 181static DEVICE_ATTR(gpio4, S_IWUSR|S_IRUGO, 182 tle62x0_gpio_show, tle62x0_gpio_store); 183static DEVICE_ATTR(gpio5, S_IWUSR|S_IRUGO, 184 tle62x0_gpio_show, tle62x0_gpio_store); 185static DEVICE_ATTR(gpio6, S_IWUSR|S_IRUGO, 186 tle62x0_gpio_show, tle62x0_gpio_store); 187static DEVICE_ATTR(gpio7, S_IWUSR|S_IRUGO, 188 tle62x0_gpio_show, tle62x0_gpio_store); 189static DEVICE_ATTR(gpio8, S_IWUSR|S_IRUGO, 190 tle62x0_gpio_show, tle62x0_gpio_store); 191static DEVICE_ATTR(gpio9, S_IWUSR|S_IRUGO, 192 tle62x0_gpio_show, tle62x0_gpio_store); 193static DEVICE_ATTR(gpio10, S_IWUSR|S_IRUGO, 194 tle62x0_gpio_show, tle62x0_gpio_store); 195static DEVICE_ATTR(gpio11, S_IWUSR|S_IRUGO, 196 tle62x0_gpio_show, tle62x0_gpio_store); 197static DEVICE_ATTR(gpio12, S_IWUSR|S_IRUGO, 198 tle62x0_gpio_show, tle62x0_gpio_store); 199static DEVICE_ATTR(gpio13, S_IWUSR|S_IRUGO, 200 tle62x0_gpio_show, tle62x0_gpio_store); 201static DEVICE_ATTR(gpio14, S_IWUSR|S_IRUGO, 202 tle62x0_gpio_show, tle62x0_gpio_store); 203static DEVICE_ATTR(gpio15, S_IWUSR|S_IRUGO, 204 tle62x0_gpio_show, tle62x0_gpio_store); 205static DEVICE_ATTR(gpio16, S_IWUSR|S_IRUGO, 206 tle62x0_gpio_show, tle62x0_gpio_store); 207 208static struct device_attribute *gpio_attrs[] = { 209 [0] = &dev_attr_gpio1, 210 [1] = &dev_attr_gpio2, 211 [2] = &dev_attr_gpio3, 212 [3] = &dev_attr_gpio4, 213 [4] = &dev_attr_gpio5, 214 [5] = &dev_attr_gpio6, 215 [6] = &dev_attr_gpio7, 216 [7] = &dev_attr_gpio8, 217 [8] = &dev_attr_gpio9, 218 [9] = &dev_attr_gpio10, 219 [10] = &dev_attr_gpio11, 220 [11] = &dev_attr_gpio12, 221 [12] = &dev_attr_gpio13, 222 [13] = &dev_attr_gpio14, 223 [14] = &dev_attr_gpio15, 224 [15] = &dev_attr_gpio16 225}; 226 227static int to_gpio_num(struct device_attribute *attr) 228{ 229 int ptr; 230 231 for (ptr = 0; ptr < ARRAY_SIZE(gpio_attrs); ptr++) { 232 if (gpio_attrs[ptr] == attr) 233 return ptr; 234 } 235 236 return -1; 237} 238 239static int tle62x0_probe(struct spi_device *spi) 240{ 241 struct tle62x0_state *st; 242 struct tle62x0_pdata *pdata; 243 int ptr; 244 int ret; 245 246 pdata = dev_get_platdata(&spi->dev); 247 if (pdata == NULL) { 248 dev_err(&spi->dev, "no device data specified\n"); 249 return -EINVAL; 250 } 251 252 st = kzalloc(sizeof(struct tle62x0_state), GFP_KERNEL); 253 if (st == NULL) 254 return -ENOMEM; 255 256 st->us = spi; 257 st->nr_gpio = pdata->gpio_count; 258 st->gpio_state = pdata->init_state; 259 260 mutex_init(&st->lock); 261 262 ret = device_create_file(&spi->dev, &dev_attr_status_show); 263 if (ret) { 264 dev_err(&spi->dev, "cannot create status attribute\n"); 265 goto err_status; 266 } 267 268 for (ptr = 0; ptr < pdata->gpio_count; ptr++) { 269 ret = device_create_file(&spi->dev, gpio_attrs[ptr]); 270 if (ret) { 271 dev_err(&spi->dev, "cannot create gpio attribute\n"); 272 goto err_gpios; 273 } 274 } 275 276 /* tle62x0_write(st); */ 277 spi_set_drvdata(spi, st); 278 return 0; 279 280 err_gpios: 281 while (--ptr >= 0) 282 device_remove_file(&spi->dev, gpio_attrs[ptr]); 283 284 device_remove_file(&spi->dev, &dev_attr_status_show); 285 286 err_status: 287 kfree(st); 288 return ret; 289} 290 291static void tle62x0_remove(struct spi_device *spi) 292{ 293 struct tle62x0_state *st = spi_get_drvdata(spi); 294 int ptr; 295 296 for (ptr = 0; ptr < st->nr_gpio; ptr++) 297 device_remove_file(&spi->dev, gpio_attrs[ptr]); 298 299 device_remove_file(&spi->dev, &dev_attr_status_show); 300 kfree(st); 301} 302 303static struct spi_driver tle62x0_driver = { 304 .driver = { 305 .name = "tle62x0", 306 }, 307 .probe = tle62x0_probe, 308 .remove = tle62x0_remove, 309}; 310 311module_spi_driver(tle62x0_driver); 312 313MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); 314MODULE_DESCRIPTION("TLE62x0 SPI driver"); 315MODULE_LICENSE("GPL v2"); 316MODULE_ALIAS("spi:tle62x0");