1/* 2 * GPIO Driver for Dialog DA9052 PMICs. 3 * 4 * Copyright(c) 2011 Dialog Semiconductor Ltd. 5 * 6 * Author: David Dajun Chen <dchen@diasemi.com> 7 * 8 * This program is free software; you can redistribute it and/or modify it 9 * under the terms of the GNU General Public License as published by the 10 * Free Software Foundation; either version 2 of the License, or (at your 11 * option) any later version. 12 * 13 */ 14#include <linux/module.h> 15#include <linux/fs.h> 16#include <linux/uaccess.h> 17#include <linux/platform_device.h> 18#include <linux/gpio.h> 19#include <linux/syscalls.h> 20#include <linux/seq_file.h> 21 22#include <linux/mfd/da9052/da9052.h> 23#include <linux/mfd/da9052/reg.h> 24#include <linux/mfd/da9052/pdata.h> 25 26#define DA9052_INPUT 1 27#define DA9052_OUTPUT_OPENDRAIN 2 28#define DA9052_OUTPUT_PUSHPULL 3 29 30#define DA9052_SUPPLY_VDD_IO1 0 31 32#define DA9052_DEBOUNCING_OFF 0 33#define DA9052_DEBOUNCING_ON 1 34 35#define DA9052_OUTPUT_LOWLEVEL 0 36 37#define DA9052_ACTIVE_LOW 0 38#define DA9052_ACTIVE_HIGH 1 39 40#define DA9052_GPIO_MAX_PORTS_PER_REGISTER 8 41#define DA9052_GPIO_SHIFT_COUNT(no) (no%8) 42#define DA9052_GPIO_MASK_UPPER_NIBBLE 0xF0 43#define DA9052_GPIO_MASK_LOWER_NIBBLE 0x0F 44#define DA9052_GPIO_NIBBLE_SHIFT 4 45#define DA9052_IRQ_GPI0 16 46#define DA9052_GPIO_ODD_SHIFT 7 47#define DA9052_GPIO_EVEN_SHIFT 3 48 49struct da9052_gpio { 50 struct da9052 *da9052; 51 struct gpio_chip gp; 52}; 53 54static inline struct da9052_gpio *to_da9052_gpio(struct gpio_chip *chip) 55{ 56 return container_of(chip, struct da9052_gpio, gp); 57} 58 59static unsigned char da9052_gpio_port_odd(unsigned offset) 60{ 61 return offset % 2; 62} 63 64static int da9052_gpio_get(struct gpio_chip *gc, unsigned offset) 65{ 66 struct da9052_gpio *gpio = to_da9052_gpio(gc); 67 int da9052_port_direction = 0; 68 int ret; 69 70 ret = da9052_reg_read(gpio->da9052, 71 DA9052_GPIO_0_1_REG + (offset >> 1)); 72 if (ret < 0) 73 return ret; 74 75 if (da9052_gpio_port_odd(offset)) { 76 da9052_port_direction = ret & DA9052_GPIO_ODD_PORT_PIN; 77 da9052_port_direction >>= 4; 78 } else { 79 da9052_port_direction = ret & DA9052_GPIO_EVEN_PORT_PIN; 80 } 81 82 switch (da9052_port_direction) { 83 case DA9052_INPUT: 84 if (offset < DA9052_GPIO_MAX_PORTS_PER_REGISTER) 85 ret = da9052_reg_read(gpio->da9052, 86 DA9052_STATUS_C_REG); 87 else 88 ret = da9052_reg_read(gpio->da9052, 89 DA9052_STATUS_D_REG); 90 if (ret < 0) 91 return ret; 92 if (ret & (1 << DA9052_GPIO_SHIFT_COUNT(offset))) 93 return 1; 94 else 95 return 0; 96 case DA9052_OUTPUT_PUSHPULL: 97 if (da9052_gpio_port_odd(offset)) 98 return ret & DA9052_GPIO_ODD_PORT_MODE; 99 else 100 return ret & DA9052_GPIO_EVEN_PORT_MODE; 101 default: 102 return -EINVAL; 103 } 104} 105 106static void da9052_gpio_set(struct gpio_chip *gc, unsigned offset, int value) 107{ 108 struct da9052_gpio *gpio = to_da9052_gpio(gc); 109 int ret; 110 111 if (da9052_gpio_port_odd(offset)) { 112 ret = da9052_reg_update(gpio->da9052, (offset >> 1) + 113 DA9052_GPIO_0_1_REG, 114 DA9052_GPIO_ODD_PORT_MODE, 115 value << DA9052_GPIO_ODD_SHIFT); 116 if (ret != 0) 117 dev_err(gpio->da9052->dev, 118 "Failed to updated gpio odd reg,%d", 119 ret); 120 } else { 121 ret = da9052_reg_update(gpio->da9052, (offset >> 1) + 122 DA9052_GPIO_0_1_REG, 123 DA9052_GPIO_EVEN_PORT_MODE, 124 value << DA9052_GPIO_EVEN_SHIFT); 125 if (ret != 0) 126 dev_err(gpio->da9052->dev, 127 "Failed to updated gpio even reg,%d", 128 ret); 129 } 130} 131 132static int da9052_gpio_direction_input(struct gpio_chip *gc, unsigned offset) 133{ 134 struct da9052_gpio *gpio = to_da9052_gpio(gc); 135 unsigned char register_value; 136 int ret; 137 138 /* Format: function - 2 bits type - 1 bit mode - 1 bit */ 139 register_value = DA9052_INPUT | DA9052_ACTIVE_LOW << 2 | 140 DA9052_DEBOUNCING_ON << 3; 141 142 if (da9052_gpio_port_odd(offset)) 143 ret = da9052_reg_update(gpio->da9052, (offset >> 1) + 144 DA9052_GPIO_0_1_REG, 145 DA9052_GPIO_MASK_UPPER_NIBBLE, 146 (register_value << 147 DA9052_GPIO_NIBBLE_SHIFT)); 148 else 149 ret = da9052_reg_update(gpio->da9052, (offset >> 1) + 150 DA9052_GPIO_0_1_REG, 151 DA9052_GPIO_MASK_LOWER_NIBBLE, 152 register_value); 153 154 return ret; 155} 156 157static int da9052_gpio_direction_output(struct gpio_chip *gc, 158 unsigned offset, int value) 159{ 160 struct da9052_gpio *gpio = to_da9052_gpio(gc); 161 unsigned char register_value; 162 int ret; 163 164 /* Format: Function - 2 bits Type - 1 bit Mode - 1 bit */ 165 register_value = DA9052_OUTPUT_PUSHPULL | DA9052_SUPPLY_VDD_IO1 << 2 | 166 value << 3; 167 168 if (da9052_gpio_port_odd(offset)) 169 ret = da9052_reg_update(gpio->da9052, (offset >> 1) + 170 DA9052_GPIO_0_1_REG, 171 DA9052_GPIO_MASK_UPPER_NIBBLE, 172 (register_value << 173 DA9052_GPIO_NIBBLE_SHIFT)); 174 else 175 ret = da9052_reg_update(gpio->da9052, (offset >> 1) + 176 DA9052_GPIO_0_1_REG, 177 DA9052_GPIO_MASK_LOWER_NIBBLE, 178 register_value); 179 180 return ret; 181} 182 183static int da9052_gpio_to_irq(struct gpio_chip *gc, u32 offset) 184{ 185 struct da9052_gpio *gpio = to_da9052_gpio(gc); 186 struct da9052 *da9052 = gpio->da9052; 187 188 int irq; 189 190 irq = regmap_irq_get_virq(da9052->irq_data, DA9052_IRQ_GPI0 + offset); 191 192 return irq; 193} 194 195static struct gpio_chip reference_gp = { 196 .label = "da9052-gpio", 197 .owner = THIS_MODULE, 198 .get = da9052_gpio_get, 199 .set = da9052_gpio_set, 200 .direction_input = da9052_gpio_direction_input, 201 .direction_output = da9052_gpio_direction_output, 202 .to_irq = da9052_gpio_to_irq, 203 .can_sleep = true, 204 .ngpio = 16, 205 .base = -1, 206}; 207 208static int da9052_gpio_probe(struct platform_device *pdev) 209{ 210 struct da9052_gpio *gpio; 211 struct da9052_pdata *pdata; 212 int ret; 213 214 gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); 215 if (!gpio) 216 return -ENOMEM; 217 218 gpio->da9052 = dev_get_drvdata(pdev->dev.parent); 219 pdata = dev_get_platdata(gpio->da9052->dev); 220 221 gpio->gp = reference_gp; 222 if (pdata && pdata->gpio_base) 223 gpio->gp.base = pdata->gpio_base; 224 225 ret = gpiochip_add(&gpio->gp); 226 if (ret < 0) { 227 dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret); 228 return ret; 229 } 230 231 platform_set_drvdata(pdev, gpio); 232 233 return 0; 234} 235 236static int da9052_gpio_remove(struct platform_device *pdev) 237{ 238 struct da9052_gpio *gpio = platform_get_drvdata(pdev); 239 240 gpiochip_remove(&gpio->gp); 241 return 0; 242} 243 244static struct platform_driver da9052_gpio_driver = { 245 .probe = da9052_gpio_probe, 246 .remove = da9052_gpio_remove, 247 .driver = { 248 .name = "da9052-gpio", 249 }, 250}; 251 252module_platform_driver(da9052_gpio_driver); 253 254MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); 255MODULE_DESCRIPTION("DA9052 GPIO Device Driver"); 256MODULE_LICENSE("GPL"); 257MODULE_ALIAS("platform:da9052-gpio"); 258