root/drivers/spi/spi-tle62x0.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. tle62x0_write
  2. tle62x0_read
  3. decode_fault
  4. tle62x0_status_show
  5. tle62x0_gpio_show
  6. tle62x0_gpio_store
  7. to_gpio_num
  8. tle62x0_probe
  9. tle62x0_remove

   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 
  26 struct 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 
  36 static int to_gpio_num(struct device_attribute *attr);
  37 
  38 static 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 
  57 static 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 
  78 static 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 
  96 static 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 
 131 static DEVICE_ATTR(status_show, S_IRUGO, tle62x0_status_show, NULL);
 132 
 133 static 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 snprintf(buf, PAGE_SIZE, "%d", value);
 145 }
 146 
 147 static 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 
 175 static DEVICE_ATTR(gpio1, S_IWUSR|S_IRUGO,
 176                 tle62x0_gpio_show, tle62x0_gpio_store);
 177 static DEVICE_ATTR(gpio2, S_IWUSR|S_IRUGO,
 178                 tle62x0_gpio_show, tle62x0_gpio_store);
 179 static DEVICE_ATTR(gpio3, S_IWUSR|S_IRUGO,
 180                 tle62x0_gpio_show, tle62x0_gpio_store);
 181 static DEVICE_ATTR(gpio4, S_IWUSR|S_IRUGO,
 182                 tle62x0_gpio_show, tle62x0_gpio_store);
 183 static DEVICE_ATTR(gpio5, S_IWUSR|S_IRUGO,
 184                 tle62x0_gpio_show, tle62x0_gpio_store);
 185 static DEVICE_ATTR(gpio6, S_IWUSR|S_IRUGO,
 186                 tle62x0_gpio_show, tle62x0_gpio_store);
 187 static DEVICE_ATTR(gpio7, S_IWUSR|S_IRUGO,
 188                 tle62x0_gpio_show, tle62x0_gpio_store);
 189 static DEVICE_ATTR(gpio8, S_IWUSR|S_IRUGO,
 190                 tle62x0_gpio_show, tle62x0_gpio_store);
 191 static DEVICE_ATTR(gpio9, S_IWUSR|S_IRUGO,
 192                 tle62x0_gpio_show, tle62x0_gpio_store);
 193 static DEVICE_ATTR(gpio10, S_IWUSR|S_IRUGO,
 194                 tle62x0_gpio_show, tle62x0_gpio_store);
 195 static DEVICE_ATTR(gpio11, S_IWUSR|S_IRUGO,
 196                 tle62x0_gpio_show, tle62x0_gpio_store);
 197 static DEVICE_ATTR(gpio12, S_IWUSR|S_IRUGO,
 198                 tle62x0_gpio_show, tle62x0_gpio_store);
 199 static DEVICE_ATTR(gpio13, S_IWUSR|S_IRUGO,
 200                 tle62x0_gpio_show, tle62x0_gpio_store);
 201 static DEVICE_ATTR(gpio14, S_IWUSR|S_IRUGO,
 202                 tle62x0_gpio_show, tle62x0_gpio_store);
 203 static DEVICE_ATTR(gpio15, S_IWUSR|S_IRUGO,
 204                 tle62x0_gpio_show, tle62x0_gpio_store);
 205 static DEVICE_ATTR(gpio16, S_IWUSR|S_IRUGO,
 206                 tle62x0_gpio_show, tle62x0_gpio_store);
 207 
 208 static 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 
 227 static 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 
 239 static 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 
 291 static int 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         return 0;
 302 }
 303 
 304 static struct spi_driver tle62x0_driver = {
 305         .driver = {
 306                 .name   = "tle62x0",
 307         },
 308         .probe          = tle62x0_probe,
 309         .remove         = tle62x0_remove,
 310 };
 311 
 312 module_spi_driver(tle62x0_driver);
 313 
 314 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
 315 MODULE_DESCRIPTION("TLE62x0 SPI driver");
 316 MODULE_LICENSE("GPL v2");
 317 MODULE_ALIAS("spi:tle62x0");

/* [<][>][^][v][top][bottom][index][help] */