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/driver.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 22 enum 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 42 struct lp3943_gpio { 43 struct gpio_chip chip; 44 struct lp3943 *lp3943; 45 u16 input_mask; /* 1 = GPIO is input direction, 0 = output */ 46 }; 47 48 static 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 60 static 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 68 static 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 78 static 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 87 static 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 112 static 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 134 static 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 153 static 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 166 static 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 177 static 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 191 static 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 211 static const struct of_device_id lp3943_gpio_of_match[] = { 212 { .compatible = "ti,lp3943-gpio", }, 213 { } 214 }; 215 MODULE_DEVICE_TABLE(of, lp3943_gpio_of_match); 216 217 static 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 }; 224 module_platform_driver(lp3943_gpio_driver); 225 226 MODULE_DESCRIPTION("LP3943 GPIO driver"); 227 MODULE_ALIAS("platform:lp3943-gpio"); 228 MODULE_AUTHOR("Milo Kim"); 229 MODULE_LICENSE("GPL"); 230