linux/drivers/gpio/gpio-74x164.c
<<
>>
Prefs
   1/*
   2 *  74Hx164 - Generic serial-in/parallel-out 8-bits shift register GPIO driver
   3 *
   4 *  Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
   5 *  Copyright (C) 2010 Miguel Gaio <miguel.gaio@efixo.com>
   6 *
   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.
  10 */
  11
  12#include <linux/init.h>
  13#include <linux/mutex.h>
  14#include <linux/spi/spi.h>
  15#include <linux/spi/74x164.h>
  16#include <linux/gpio.h>
  17#include <linux/of_gpio.h>
  18#include <linux/slab.h>
  19#include <linux/module.h>
  20
  21#define GEN_74X164_NUMBER_GPIOS 8
  22
  23struct gen_74x164_chip {
  24        struct spi_device       *spi;
  25        u8                      *buffer;
  26        struct gpio_chip        gpio_chip;
  27        struct mutex            lock;
  28        u32                     registers;
  29};
  30
  31static struct gen_74x164_chip *gpio_to_74x164_chip(struct gpio_chip *gc)
  32{
  33        return container_of(gc, struct gen_74x164_chip, gpio_chip);
  34}
  35
  36static int __gen_74x164_write_config(struct gen_74x164_chip *chip)
  37{
  38        struct spi_message message;
  39        struct spi_transfer *msg_buf;
  40        int i, ret = 0;
  41
  42        msg_buf = kzalloc(chip->registers * sizeof(struct spi_transfer),
  43                        GFP_KERNEL);
  44        if (!msg_buf)
  45                return -ENOMEM;
  46
  47        spi_message_init(&message);
  48
  49        /*
  50         * Since the registers are chained, every byte sent will make
  51         * the previous byte shift to the next register in the
  52         * chain. Thus, the first byte send will end up in the last
  53         * register at the end of the transfer. So, to have a logical
  54         * numbering, send the bytes in reverse order so that the last
  55         * byte of the buffer will end up in the last register.
  56         */
  57        for (i = chip->registers - 1; i >= 0; i--) {
  58                msg_buf[i].tx_buf = chip->buffer +i;
  59                msg_buf[i].len = sizeof(u8);
  60                spi_message_add_tail(msg_buf + i, &message);
  61        }
  62
  63        ret = spi_sync(chip->spi, &message);
  64
  65        kfree(msg_buf);
  66
  67        return ret;
  68}
  69
  70static int gen_74x164_get_value(struct gpio_chip *gc, unsigned offset)
  71{
  72        struct gen_74x164_chip *chip = gpio_to_74x164_chip(gc);
  73        u8 bank = offset / 8;
  74        u8 pin = offset % 8;
  75        int ret;
  76
  77        mutex_lock(&chip->lock);
  78        ret = (chip->buffer[bank] >> pin) & 0x1;
  79        mutex_unlock(&chip->lock);
  80
  81        return ret;
  82}
  83
  84static void gen_74x164_set_value(struct gpio_chip *gc,
  85                unsigned offset, int val)
  86{
  87        struct gen_74x164_chip *chip = gpio_to_74x164_chip(gc);
  88        u8 bank = offset / 8;
  89        u8 pin = offset % 8;
  90
  91        mutex_lock(&chip->lock);
  92        if (val)
  93                chip->buffer[bank] |= (1 << pin);
  94        else
  95                chip->buffer[bank] &= ~(1 << pin);
  96
  97        __gen_74x164_write_config(chip);
  98        mutex_unlock(&chip->lock);
  99}
 100
 101static int gen_74x164_direction_output(struct gpio_chip *gc,
 102                unsigned offset, int val)
 103{
 104        gen_74x164_set_value(gc, offset, val);
 105        return 0;
 106}
 107
 108static int gen_74x164_probe(struct spi_device *spi)
 109{
 110        struct gen_74x164_chip *chip;
 111        struct gen_74x164_chip_platform_data *pdata;
 112        int ret;
 113
 114        if (!spi->dev.of_node) {
 115                dev_err(&spi->dev, "No device tree data available.\n");
 116                return -EINVAL;
 117        }
 118
 119        /*
 120         * bits_per_word cannot be configured in platform data
 121         */
 122        spi->bits_per_word = 8;
 123
 124        ret = spi_setup(spi);
 125        if (ret < 0)
 126                return ret;
 127
 128        chip = devm_kzalloc(&spi->dev, sizeof(*chip), GFP_KERNEL);
 129        if (!chip)
 130                return -ENOMEM;
 131
 132        pdata = dev_get_platdata(&spi->dev);
 133        if (pdata && pdata->base)
 134                chip->gpio_chip.base = pdata->base;
 135        else
 136                chip->gpio_chip.base = -1;
 137
 138        mutex_init(&chip->lock);
 139
 140        spi_set_drvdata(spi, chip);
 141
 142        chip->spi = spi;
 143
 144        chip->gpio_chip.label = spi->modalias;
 145        chip->gpio_chip.direction_output = gen_74x164_direction_output;
 146        chip->gpio_chip.get = gen_74x164_get_value;
 147        chip->gpio_chip.set = gen_74x164_set_value;
 148
 149        if (of_property_read_u32(spi->dev.of_node, "registers-number", &chip->registers)) {
 150                dev_err(&spi->dev, "Missing registers-number property in the DT.\n");
 151                ret = -EINVAL;
 152                goto exit_destroy;
 153        }
 154
 155        chip->gpio_chip.ngpio = GEN_74X164_NUMBER_GPIOS * chip->registers;
 156        chip->buffer = devm_kzalloc(&spi->dev, chip->registers, GFP_KERNEL);
 157        if (!chip->buffer) {
 158                ret = -ENOMEM;
 159                goto exit_destroy;
 160        }
 161
 162        chip->gpio_chip.can_sleep = 1;
 163        chip->gpio_chip.dev = &spi->dev;
 164        chip->gpio_chip.owner = THIS_MODULE;
 165
 166        ret = __gen_74x164_write_config(chip);
 167        if (ret) {
 168                dev_err(&spi->dev, "Failed writing: %d\n", ret);
 169                goto exit_destroy;
 170        }
 171
 172        ret = gpiochip_add(&chip->gpio_chip);
 173        if (ret)
 174                goto exit_destroy;
 175
 176        return ret;
 177
 178exit_destroy:
 179        spi_set_drvdata(spi, NULL);
 180        mutex_destroy(&chip->lock);
 181        return ret;
 182}
 183
 184static int gen_74x164_remove(struct spi_device *spi)
 185{
 186        struct gen_74x164_chip *chip;
 187        int ret;
 188
 189        chip = spi_get_drvdata(spi);
 190        if (chip == NULL)
 191                return -ENODEV;
 192
 193        spi_set_drvdata(spi, NULL);
 194
 195        ret = gpiochip_remove(&chip->gpio_chip);
 196        if (!ret)
 197                mutex_destroy(&chip->lock);
 198        else
 199                dev_err(&spi->dev, "Failed to remove the GPIO controller: %d\n",
 200                                ret);
 201
 202        return ret;
 203}
 204
 205static const struct of_device_id gen_74x164_dt_ids[] = {
 206        { .compatible = "fairchild,74hc595" },
 207        {},
 208};
 209MODULE_DEVICE_TABLE(of, gen_74x164_dt_ids);
 210
 211static struct spi_driver gen_74x164_driver = {
 212        .driver = {
 213                .name           = "74x164",
 214                .owner          = THIS_MODULE,
 215                .of_match_table = of_match_ptr(gen_74x164_dt_ids),
 216        },
 217        .probe          = gen_74x164_probe,
 218        .remove         = gen_74x164_remove,
 219};
 220module_spi_driver(gen_74x164_driver);
 221
 222MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
 223MODULE_AUTHOR("Miguel Gaio <miguel.gaio@efixo.com>");
 224MODULE_DESCRIPTION("GPIO expander driver for 74X164 8-bits shift register");
 225MODULE_LICENSE("GPL v2");
 226
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.