Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.11-rc1 229 lines 5.6 kB view raw
1/* 2 * TI/National Semiconductor LP3943 GPIO driver 3 * 4 * Copyright 2013 Texas Instruments 5 * 6 * Author: Milo Kim <milo.kim@ti.com> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; version 2. 11 */ 12 13#include <linux/bitops.h> 14#include <linux/err.h> 15#include <linux/gpio.h> 16#include <linux/i2c.h> 17#include <linux/mfd/lp3943.h> 18#include <linux/module.h> 19#include <linux/platform_device.h> 20#include <linux/slab.h> 21 22enum lp3943_gpios { 23 LP3943_GPIO1, 24 LP3943_GPIO2, 25 LP3943_GPIO3, 26 LP3943_GPIO4, 27 LP3943_GPIO5, 28 LP3943_GPIO6, 29 LP3943_GPIO7, 30 LP3943_GPIO8, 31 LP3943_GPIO9, 32 LP3943_GPIO10, 33 LP3943_GPIO11, 34 LP3943_GPIO12, 35 LP3943_GPIO13, 36 LP3943_GPIO14, 37 LP3943_GPIO15, 38 LP3943_GPIO16, 39 LP3943_MAX_GPIO, 40}; 41 42struct lp3943_gpio { 43 struct gpio_chip chip; 44 struct lp3943 *lp3943; 45 u16 input_mask; /* 1 = GPIO is input direction, 0 = output */ 46}; 47 48static int lp3943_gpio_request(struct gpio_chip *chip, unsigned offset) 49{ 50 struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip); 51 struct lp3943 *lp3943 = lp3943_gpio->lp3943; 52 53 /* Return an error if the pin is already assigned */ 54 if (test_and_set_bit(offset, &lp3943->pin_used)) 55 return -EBUSY; 56 57 return 0; 58} 59 60static void lp3943_gpio_free(struct gpio_chip *chip, unsigned offset) 61{ 62 struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip); 63 struct lp3943 *lp3943 = lp3943_gpio->lp3943; 64 65 clear_bit(offset, &lp3943->pin_used); 66} 67 68static int lp3943_gpio_set_mode(struct lp3943_gpio *lp3943_gpio, u8 offset, 69 u8 val) 70{ 71 struct lp3943 *lp3943 = lp3943_gpio->lp3943; 72 const struct lp3943_reg_cfg *mux = lp3943->mux_cfg; 73 74 return lp3943_update_bits(lp3943, mux[offset].reg, mux[offset].mask, 75 val << mux[offset].shift); 76} 77 78static int lp3943_gpio_direction_input(struct gpio_chip *chip, unsigned offset) 79{ 80 struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip); 81 82 lp3943_gpio->input_mask |= BIT(offset); 83 84 return lp3943_gpio_set_mode(lp3943_gpio, offset, LP3943_GPIO_IN); 85} 86 87static int lp3943_get_gpio_in_status(struct lp3943_gpio *lp3943_gpio, 88 struct gpio_chip *chip, unsigned offset) 89{ 90 u8 addr, read; 91 int err; 92 93 switch (offset) { 94 case LP3943_GPIO1 ... LP3943_GPIO8: 95 addr = LP3943_REG_GPIO_A; 96 break; 97 case LP3943_GPIO9 ... LP3943_GPIO16: 98 addr = LP3943_REG_GPIO_B; 99 offset = offset - 8; 100 break; 101 default: 102 return -EINVAL; 103 } 104 105 err = lp3943_read_byte(lp3943_gpio->lp3943, addr, &read); 106 if (err) 107 return err; 108 109 return !!(read & BIT(offset)); 110} 111 112static int lp3943_get_gpio_out_status(struct lp3943_gpio *lp3943_gpio, 113 struct gpio_chip *chip, unsigned offset) 114{ 115 struct lp3943 *lp3943 = lp3943_gpio->lp3943; 116 const struct lp3943_reg_cfg *mux = lp3943->mux_cfg; 117 u8 read; 118 int err; 119 120 err = lp3943_read_byte(lp3943, mux[offset].reg, &read); 121 if (err) 122 return err; 123 124 read = (read & mux[offset].mask) >> mux[offset].shift; 125 126 if (read == LP3943_GPIO_OUT_HIGH) 127 return 1; 128 else if (read == LP3943_GPIO_OUT_LOW) 129 return 0; 130 else 131 return -EINVAL; 132} 133 134static int lp3943_gpio_get(struct gpio_chip *chip, unsigned offset) 135{ 136 struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip); 137 138 /* 139 * Limitation: 140 * LP3943 doesn't have the GPIO direction register. It provides 141 * only input and output status registers. 142 * So, direction info is required to handle the 'get' operation. 143 * This variable is updated whenever the direction is changed and 144 * it is used here. 145 */ 146 147 if (lp3943_gpio->input_mask & BIT(offset)) 148 return lp3943_get_gpio_in_status(lp3943_gpio, chip, offset); 149 else 150 return lp3943_get_gpio_out_status(lp3943_gpio, chip, offset); 151} 152 153static void lp3943_gpio_set(struct gpio_chip *chip, unsigned offset, int value) 154{ 155 struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip); 156 u8 data; 157 158 if (value) 159 data = LP3943_GPIO_OUT_HIGH; 160 else 161 data = LP3943_GPIO_OUT_LOW; 162 163 lp3943_gpio_set_mode(lp3943_gpio, offset, data); 164} 165 166static int lp3943_gpio_direction_output(struct gpio_chip *chip, unsigned offset, 167 int value) 168{ 169 struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip); 170 171 lp3943_gpio_set(chip, offset, value); 172 lp3943_gpio->input_mask &= ~BIT(offset); 173 174 return 0; 175} 176 177static const struct gpio_chip lp3943_gpio_chip = { 178 .label = "lp3943", 179 .owner = THIS_MODULE, 180 .request = lp3943_gpio_request, 181 .free = lp3943_gpio_free, 182 .direction_input = lp3943_gpio_direction_input, 183 .get = lp3943_gpio_get, 184 .direction_output = lp3943_gpio_direction_output, 185 .set = lp3943_gpio_set, 186 .base = -1, 187 .ngpio = LP3943_MAX_GPIO, 188 .can_sleep = 1, 189}; 190 191static int lp3943_gpio_probe(struct platform_device *pdev) 192{ 193 struct lp3943 *lp3943 = dev_get_drvdata(pdev->dev.parent); 194 struct lp3943_gpio *lp3943_gpio; 195 196 lp3943_gpio = devm_kzalloc(&pdev->dev, sizeof(*lp3943_gpio), 197 GFP_KERNEL); 198 if (!lp3943_gpio) 199 return -ENOMEM; 200 201 lp3943_gpio->lp3943 = lp3943; 202 lp3943_gpio->chip = lp3943_gpio_chip; 203 lp3943_gpio->chip.parent = &pdev->dev; 204 205 platform_set_drvdata(pdev, lp3943_gpio); 206 207 return devm_gpiochip_add_data(&pdev->dev, &lp3943_gpio->chip, 208 lp3943_gpio); 209} 210 211static const struct of_device_id lp3943_gpio_of_match[] = { 212 { .compatible = "ti,lp3943-gpio", }, 213 { } 214}; 215MODULE_DEVICE_TABLE(of, lp3943_gpio_of_match); 216 217static struct platform_driver lp3943_gpio_driver = { 218 .probe = lp3943_gpio_probe, 219 .driver = { 220 .name = "lp3943-gpio", 221 .of_match_table = lp3943_gpio_of_match, 222 }, 223}; 224module_platform_driver(lp3943_gpio_driver); 225 226MODULE_DESCRIPTION("LP3943 GPIO driver"); 227MODULE_ALIAS("platform:lp3943-gpio"); 228MODULE_AUTHOR("Milo Kim"); 229MODULE_LICENSE("GPL");