1447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks/* 2ca632f556697d45d67ed5cada7cedf3ddfe0db4bGrant Likely * Support Infineon TLE62x0 driver chips 3447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks * 4447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks * Copyright (c) 2007 Simtec Electronics 5447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks * Ben Dooks, <ben@simtec.co.uk> 6447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks * 7447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks * This program is free software; you can redistribute it and/or modify 8447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks * it under the terms of the GNU General Public License version 2 as 9447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks * published by the Free Software Foundation. 10447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks */ 11447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 12447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks#include <linux/device.h> 13447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks#include <linux/kernel.h> 14d7614de422c0b55db0c1013a6c72330187536004Paul Gortmaker#include <linux/module.h> 155a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 16447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 17447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks#include <linux/spi/spi.h> 18447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks#include <linux/spi/tle62x0.h> 19447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 20447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 21447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks#define CMD_READ 0x00 22447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks#define CMD_SET 0xff 23447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 24447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks#define DIAG_NORMAL 0x03 25447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks#define DIAG_OVERLOAD 0x02 26447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks#define DIAG_OPEN 0x01 27447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks#define DIAG_SHORTGND 0x00 28447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 29447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooksstruct tle62x0_state { 30447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks struct spi_device *us; 31447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks struct mutex lock; 32447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks unsigned int nr_gpio; 33447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks unsigned int gpio_state; 34447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 35447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks unsigned char tx_buff[4]; 36447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks unsigned char rx_buff[4]; 37447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks}; 38447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 39447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooksstatic int to_gpio_num(struct device_attribute *attr); 40447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 41447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooksstatic inline int tle62x0_write(struct tle62x0_state *st) 42447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks{ 43447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks unsigned char *buff = st->tx_buff; 44447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks unsigned int gpio_state = st->gpio_state; 45447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 46447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks buff[0] = CMD_SET; 47447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 48447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks if (st->nr_gpio == 16) { 49447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks buff[1] = gpio_state >> 8; 50447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks buff[2] = gpio_state; 51447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks } else { 52447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks buff[1] = gpio_state; 53447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks } 54447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 55447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks dev_dbg(&st->us->dev, "buff %02x,%02x,%02x\n", 56447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks buff[0], buff[1], buff[2]); 57447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 58447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks return spi_write(st->us, buff, (st->nr_gpio == 16) ? 3 : 2); 59447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks} 60447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 61447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooksstatic inline int tle62x0_read(struct tle62x0_state *st) 62447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks{ 63447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks unsigned char *txbuff = st->tx_buff; 64447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks struct spi_transfer xfer = { 65447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks .tx_buf = txbuff, 66447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks .rx_buf = st->rx_buff, 67447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks .len = (st->nr_gpio * 2) / 8, 68447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks }; 69447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks struct spi_message msg; 70447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 71447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks txbuff[0] = CMD_READ; 72447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks txbuff[1] = 0x00; 73447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks txbuff[2] = 0x00; 74447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks txbuff[3] = 0x00; 75447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 76447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks spi_message_init(&msg); 77447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks spi_message_add_tail(&xfer, &msg); 78447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 79447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks return spi_sync(st->us, &msg); 80447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks} 81447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 82447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooksstatic unsigned char *decode_fault(unsigned int fault_code) 83447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks{ 84447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks fault_code &= 3; 85447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 86447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks switch (fault_code) { 87447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks case DIAG_NORMAL: 88447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks return "N"; 89447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks case DIAG_OVERLOAD: 90447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks return "V"; 91447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks case DIAG_OPEN: 92447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks return "O"; 93447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks case DIAG_SHORTGND: 94447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks return "G"; 95447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks } 96447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 97447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks return "?"; 98447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks} 99447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 100447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooksstatic ssize_t tle62x0_status_show(struct device *dev, 101447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks struct device_attribute *attr, char *buf) 102447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks{ 103447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks struct tle62x0_state *st = dev_get_drvdata(dev); 104447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks char *bp = buf; 105447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks unsigned char *buff = st->rx_buff; 106447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks unsigned long fault = 0; 107447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks int ptr; 108447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks int ret; 109447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 110447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks mutex_lock(&st->lock); 111447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks ret = tle62x0_read(st); 112447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks dev_dbg(dev, "tle62x0_read() returned %d\n", ret); 113822bd5aa2b8e8fa1d328f03bf5b9c75701481bf0David Brownell if (ret < 0) { 114822bd5aa2b8e8fa1d328f03bf5b9c75701481bf0David Brownell mutex_unlock(&st->lock); 115822bd5aa2b8e8fa1d328f03bf5b9c75701481bf0David Brownell return ret; 116822bd5aa2b8e8fa1d328f03bf5b9c75701481bf0David Brownell } 117447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 118447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks for (ptr = 0; ptr < (st->nr_gpio * 2)/8; ptr += 1) { 119447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks fault <<= 8; 120447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks fault |= ((unsigned long)buff[ptr]); 121447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 122447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks dev_dbg(dev, "byte %d is %02x\n", ptr, buff[ptr]); 123447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks } 124447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 125447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks for (ptr = 0; ptr < st->nr_gpio; ptr++) { 126447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks bp += sprintf(bp, "%s ", decode_fault(fault >> (ptr * 2))); 127447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks } 128447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 129447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks *bp++ = '\n'; 130447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 131447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks mutex_unlock(&st->lock); 132447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks return bp - buf; 133447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks} 134447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 135447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooksstatic DEVICE_ATTR(status_show, S_IRUGO, tle62x0_status_show, NULL); 136447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 137447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooksstatic ssize_t tle62x0_gpio_show(struct device *dev, 138447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks struct device_attribute *attr, char *buf) 139447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks{ 140447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks struct tle62x0_state *st = dev_get_drvdata(dev); 141447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks int gpio_num = to_gpio_num(attr); 142447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks int value; 143447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 144447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks mutex_lock(&st->lock); 145447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks value = (st->gpio_state >> gpio_num) & 1; 146447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks mutex_unlock(&st->lock); 147447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 148447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks return snprintf(buf, PAGE_SIZE, "%d", value); 149447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks} 150447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 151447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooksstatic ssize_t tle62x0_gpio_store(struct device *dev, 152447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks struct device_attribute *attr, 153447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks const char *buf, size_t len) 154447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks{ 155447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks struct tle62x0_state *st = dev_get_drvdata(dev); 156447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks int gpio_num = to_gpio_num(attr); 157447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks unsigned long val; 158447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks char *endp; 159447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 160447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks val = simple_strtoul(buf, &endp, 0); 161447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks if (buf == endp) 162447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks return -EINVAL; 163447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 164447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks dev_dbg(dev, "setting gpio %d to %ld\n", gpio_num, val); 165447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 166447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks mutex_lock(&st->lock); 167447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 168447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks if (val) 169447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks st->gpio_state |= 1 << gpio_num; 170447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks else 171447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks st->gpio_state &= ~(1 << gpio_num); 172447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 173447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks tle62x0_write(st); 174447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks mutex_unlock(&st->lock); 175447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 176447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks return len; 177447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks} 178447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 179447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooksstatic DEVICE_ATTR(gpio1, S_IWUSR|S_IRUGO, 180447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks tle62x0_gpio_show, tle62x0_gpio_store); 181447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooksstatic DEVICE_ATTR(gpio2, S_IWUSR|S_IRUGO, 182447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks tle62x0_gpio_show, tle62x0_gpio_store); 183447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooksstatic DEVICE_ATTR(gpio3, S_IWUSR|S_IRUGO, 184447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks tle62x0_gpio_show, tle62x0_gpio_store); 185447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooksstatic DEVICE_ATTR(gpio4, S_IWUSR|S_IRUGO, 186447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks tle62x0_gpio_show, tle62x0_gpio_store); 187447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooksstatic DEVICE_ATTR(gpio5, S_IWUSR|S_IRUGO, 188447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks tle62x0_gpio_show, tle62x0_gpio_store); 189447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooksstatic DEVICE_ATTR(gpio6, S_IWUSR|S_IRUGO, 190447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks tle62x0_gpio_show, tle62x0_gpio_store); 191447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooksstatic DEVICE_ATTR(gpio7, S_IWUSR|S_IRUGO, 192447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks tle62x0_gpio_show, tle62x0_gpio_store); 193447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooksstatic DEVICE_ATTR(gpio8, S_IWUSR|S_IRUGO, 194447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks tle62x0_gpio_show, tle62x0_gpio_store); 195447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooksstatic DEVICE_ATTR(gpio9, S_IWUSR|S_IRUGO, 196447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks tle62x0_gpio_show, tle62x0_gpio_store); 197447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooksstatic DEVICE_ATTR(gpio10, S_IWUSR|S_IRUGO, 198447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks tle62x0_gpio_show, tle62x0_gpio_store); 199447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooksstatic DEVICE_ATTR(gpio11, S_IWUSR|S_IRUGO, 200447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks tle62x0_gpio_show, tle62x0_gpio_store); 201447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooksstatic DEVICE_ATTR(gpio12, S_IWUSR|S_IRUGO, 202447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks tle62x0_gpio_show, tle62x0_gpio_store); 203447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooksstatic DEVICE_ATTR(gpio13, S_IWUSR|S_IRUGO, 204447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks tle62x0_gpio_show, tle62x0_gpio_store); 205447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooksstatic DEVICE_ATTR(gpio14, S_IWUSR|S_IRUGO, 206447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks tle62x0_gpio_show, tle62x0_gpio_store); 207447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooksstatic DEVICE_ATTR(gpio15, S_IWUSR|S_IRUGO, 208447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks tle62x0_gpio_show, tle62x0_gpio_store); 209447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooksstatic DEVICE_ATTR(gpio16, S_IWUSR|S_IRUGO, 210447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks tle62x0_gpio_show, tle62x0_gpio_store); 211447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 212447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooksstatic struct device_attribute *gpio_attrs[] = { 213447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks [0] = &dev_attr_gpio1, 214447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks [1] = &dev_attr_gpio2, 215447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks [2] = &dev_attr_gpio3, 216447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks [3] = &dev_attr_gpio4, 217447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks [4] = &dev_attr_gpio5, 218447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks [5] = &dev_attr_gpio6, 219447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks [6] = &dev_attr_gpio7, 220447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks [7] = &dev_attr_gpio8, 221447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks [8] = &dev_attr_gpio9, 222447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks [9] = &dev_attr_gpio10, 223447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks [10] = &dev_attr_gpio11, 224447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks [11] = &dev_attr_gpio12, 225447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks [12] = &dev_attr_gpio13, 226447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks [13] = &dev_attr_gpio14, 227447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks [14] = &dev_attr_gpio15, 228447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks [15] = &dev_attr_gpio16 229447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks}; 230447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 231447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooksstatic int to_gpio_num(struct device_attribute *attr) 232447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks{ 233447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks int ptr; 234447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 235447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks for (ptr = 0; ptr < ARRAY_SIZE(gpio_attrs); ptr++) { 236447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks if (gpio_attrs[ptr] == attr) 237447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks return ptr; 238447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks } 239447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 240447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks return -1; 241447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks} 242447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 243447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooksstatic int __devinit tle62x0_probe(struct spi_device *spi) 244447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks{ 245447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks struct tle62x0_state *st; 246447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks struct tle62x0_pdata *pdata; 247447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks int ptr; 248447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks int ret; 249447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 250447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks pdata = spi->dev.platform_data; 251447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks if (pdata == NULL) { 252447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks dev_err(&spi->dev, "no device data specified\n"); 253447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks return -EINVAL; 254447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks } 255447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 256447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks st = kzalloc(sizeof(struct tle62x0_state), GFP_KERNEL); 257447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks if (st == NULL) { 258447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks dev_err(&spi->dev, "no memory for device state\n"); 259447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks return -ENOMEM; 260447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks } 261447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 262447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks st->us = spi; 263447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks st->nr_gpio = pdata->gpio_count; 264447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks st->gpio_state = pdata->init_state; 265447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 266447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks mutex_init(&st->lock); 267447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 268447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks ret = device_create_file(&spi->dev, &dev_attr_status_show); 269447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks if (ret) { 270447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks dev_err(&spi->dev, "cannot create status attribute\n"); 271447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks goto err_status; 272447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks } 273447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 274447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks for (ptr = 0; ptr < pdata->gpio_count; ptr++) { 275447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks ret = device_create_file(&spi->dev, gpio_attrs[ptr]); 276447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks if (ret) { 277447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks dev_err(&spi->dev, "cannot create gpio attribute\n"); 278447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks goto err_gpios; 279447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks } 280447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks } 281447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 282447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks /* tle62x0_write(st); */ 283447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks spi_set_drvdata(spi, st); 284447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks return 0; 285447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 286447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks err_gpios: 28780b4037033c2dae31e73810d506ce93b3783be05Axel Lin while (--ptr >= 0) 288447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks device_remove_file(&spi->dev, gpio_attrs[ptr]); 289447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 290447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks device_remove_file(&spi->dev, &dev_attr_status_show); 291447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 292447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks err_status: 293447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks kfree(st); 294447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks return ret; 295447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks} 296447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 297447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooksstatic int __devexit tle62x0_remove(struct spi_device *spi) 298447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks{ 299447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks struct tle62x0_state *st = spi_get_drvdata(spi); 300447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks int ptr; 301447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 302447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks for (ptr = 0; ptr < st->nr_gpio; ptr++) 303447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks device_remove_file(&spi->dev, gpio_attrs[ptr]); 304447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 30580b4037033c2dae31e73810d506ce93b3783be05Axel Lin device_remove_file(&spi->dev, &dev_attr_status_show); 306447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks kfree(st); 307447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks return 0; 308447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks} 309447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 310447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooksstatic struct spi_driver tle62x0_driver = { 311447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks .driver = { 312447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks .name = "tle62x0", 313447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks .owner = THIS_MODULE, 314447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks }, 315447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks .probe = tle62x0_probe, 316447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks .remove = __devexit_p(tle62x0_remove), 317447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks}; 318447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 319447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooksstatic __init int tle62x0_init(void) 320447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks{ 321447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks return spi_register_driver(&tle62x0_driver); 322447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks} 323447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 324447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooksstatic __exit void tle62x0_exit(void) 325447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks{ 326447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks spi_unregister_driver(&tle62x0_driver); 327447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks} 328447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 329447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooksmodule_init(tle62x0_init); 330447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooksmodule_exit(tle62x0_exit); 331447aef1a19135a69bfd725c33f7e753740cb8447Ben Dooks 332447aef1a19135a69bfd725c33f7e753740cb8447Ben DooksMODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); 333447aef1a19135a69bfd725c33f7e753740cb8447Ben DooksMODULE_DESCRIPTION("TLE62x0 SPI driver"); 334447aef1a19135a69bfd725c33f7e753740cb8447Ben DooksMODULE_LICENSE("GPL v2"); 335e0626e3844e8f430fc1a4417f523a00797df7ca6Anton VorontsovMODULE_ALIAS("spi:tle62x0"); 336