237 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2006 Juergen Beisert, Pengutronix4 * Copyright (C) 2008 Guennadi Liakhovetski, Pengutronix5 * Copyright (C) 2009 Wolfram Sang, Pengutronix6 *7 * The Maxim MAX7300/1 device is an I2C/SPI driven GPIO expander. There are8 * 28 GPIOs. 8 of them can trigger an interrupt. See datasheet for more9 * details10 * Note:11 * - DIN must be stable at the rising edge of clock.12 * - when writing:13 * - always clock in 16 clocks at once14 * - at DIN: D15 first, D0 last15 * - D0..D7 = databyte, D8..D14 = commandbyte16 * - D15 = low -> write command17 * - when reading18 * - always clock in 16 clocks at once19 * - at DIN: D15 first, D0 last20 * - D0..D7 = dummy, D8..D14 = register address21 * - D15 = high -> read command22 * - raise CS and assert it again23 * - always clock in 16 clocks at once24 * - at DOUT: D15 first, D0 last25 * - D0..D7 contains the data from the first cycle26 *27 * The driver exports a standard gpiochip interface28 */29 30#include <linux/module.h>31#include <linux/init.h>32#include <linux/platform_device.h>33#include <linux/mutex.h>34#include <linux/spi/max7301.h>35#include <linux/gpio/driver.h>36#include <linux/slab.h>37 38/*39 * Pin configurations, see MAX7301 datasheet page 640 */41#define PIN_CONFIG_MASK 0x0342#define PIN_CONFIG_IN_PULLUP 0x0343#define PIN_CONFIG_IN_WO_PULLUP 0x0244#define PIN_CONFIG_OUT 0x0145 46#define PIN_NUMBER 2847 48static int max7301_direction_input(struct gpio_chip *chip, unsigned offset)49{50 struct max7301 *ts = container_of(chip, struct max7301, chip);51 u8 *config;52 u8 offset_bits, pin_config;53 int ret;54 55 /* First 4 pins are unused in the controller */56 offset += 4;57 offset_bits = (offset & 3) << 1;58 59 config = &ts->port_config[offset >> 2];60 61 if (ts->input_pullup_active & BIT(offset))62 pin_config = PIN_CONFIG_IN_PULLUP;63 else64 pin_config = PIN_CONFIG_IN_WO_PULLUP;65 66 mutex_lock(&ts->lock);67 68 *config = (*config & ~(PIN_CONFIG_MASK << offset_bits))69 | (pin_config << offset_bits);70 71 ret = ts->write(ts->dev, 0x08 + (offset >> 2), *config);72 73 mutex_unlock(&ts->lock);74 75 return ret;76}77 78static int __max7301_set(struct max7301 *ts, unsigned offset, int value)79{80 if (value) {81 ts->out_level |= 1 << offset;82 return ts->write(ts->dev, 0x20 + offset, 0x01);83 } else {84 ts->out_level &= ~(1 << offset);85 return ts->write(ts->dev, 0x20 + offset, 0x00);86 }87}88 89static int max7301_direction_output(struct gpio_chip *chip, unsigned offset,90 int value)91{92 struct max7301 *ts = container_of(chip, struct max7301, chip);93 u8 *config;94 u8 offset_bits;95 int ret;96 97 /* First 4 pins are unused in the controller */98 offset += 4;99 offset_bits = (offset & 3) << 1;100 101 config = &ts->port_config[offset >> 2];102 103 mutex_lock(&ts->lock);104 105 *config = (*config & ~(PIN_CONFIG_MASK << offset_bits))106 | (PIN_CONFIG_OUT << offset_bits);107 108 ret = __max7301_set(ts, offset, value);109 110 if (!ret)111 ret = ts->write(ts->dev, 0x08 + (offset >> 2), *config);112 113 mutex_unlock(&ts->lock);114 115 return ret;116}117 118static int max7301_get(struct gpio_chip *chip, unsigned offset)119{120 struct max7301 *ts = gpiochip_get_data(chip);121 int config, level = -EINVAL;122 123 /* First 4 pins are unused in the controller */124 offset += 4;125 126 mutex_lock(&ts->lock);127 128 config = (ts->port_config[offset >> 2] >> ((offset & 3) << 1))129 & PIN_CONFIG_MASK;130 131 switch (config) {132 case PIN_CONFIG_OUT:133 /* Output: return cached level */134 level = !!(ts->out_level & (1 << offset));135 break;136 case PIN_CONFIG_IN_WO_PULLUP:137 case PIN_CONFIG_IN_PULLUP:138 /* Input: read out */139 level = ts->read(ts->dev, 0x20 + offset) & 0x01;140 }141 mutex_unlock(&ts->lock);142 143 return level;144}145 146static void max7301_set(struct gpio_chip *chip, unsigned offset, int value)147{148 struct max7301 *ts = gpiochip_get_data(chip);149 150 /* First 4 pins are unused in the controller */151 offset += 4;152 153 mutex_lock(&ts->lock);154 155 __max7301_set(ts, offset, value);156 157 mutex_unlock(&ts->lock);158}159 160int __max730x_probe(struct max7301 *ts)161{162 struct device *dev = ts->dev;163 struct max7301_platform_data *pdata;164 int i, ret;165 166 pdata = dev_get_platdata(dev);167 168 mutex_init(&ts->lock);169 dev_set_drvdata(dev, ts);170 171 /* Power up the chip and disable IRQ output */172 ts->write(dev, 0x04, 0x01);173 174 if (pdata) {175 ts->input_pullup_active = pdata->input_pullup_active;176 ts->chip.base = pdata->base;177 } else {178 ts->chip.base = -1;179 }180 ts->chip.label = dev->driver->name;181 182 ts->chip.direction_input = max7301_direction_input;183 ts->chip.get = max7301_get;184 ts->chip.direction_output = max7301_direction_output;185 ts->chip.set = max7301_set;186 187 ts->chip.ngpio = PIN_NUMBER;188 ts->chip.can_sleep = true;189 ts->chip.parent = dev;190 ts->chip.owner = THIS_MODULE;191 192 /*193 * initialize pullups according to platform data and cache the194 * register values for later use.195 */196 for (i = 1; i < 8; i++) {197 int j;198 /*199 * initialize port_config with "0xAA", which means200 * input with internal pullup disabled. This is needed201 * to avoid writing zeros (in the inner for loop),202 * which is not allowed according to the datasheet.203 */204 ts->port_config[i] = 0xAA;205 for (j = 0; j < 4; j++) {206 int offset = (i - 1) * 4 + j;207 ret = max7301_direction_input(&ts->chip, offset);208 if (ret)209 goto exit_destroy;210 }211 }212 213 ret = gpiochip_add_data(&ts->chip, ts);214 if (!ret)215 return ret;216 217exit_destroy:218 mutex_destroy(&ts->lock);219 return ret;220}221EXPORT_SYMBOL_GPL(__max730x_probe);222 223void __max730x_remove(struct device *dev)224{225 struct max7301 *ts = dev_get_drvdata(dev);226 227 /* Power down the chip and disable IRQ output */228 ts->write(dev, 0x04, 0x00);229 gpiochip_remove(&ts->chip);230 mutex_destroy(&ts->lock);231}232EXPORT_SYMBOL_GPL(__max730x_remove);233 234MODULE_AUTHOR("Juergen Beisert, Wolfram Sang");235MODULE_LICENSE("GPL v2");236MODULE_DESCRIPTION("MAX730x GPIO-Expanders, generic parts");237