1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright Intel Corporation (C) 2014-2016. All Rights Reserved 4 * 5 * GPIO driver for Altera Arria10 MAX5 System Resource Chip 6 * 7 * Adapted from gpio-tps65910.c 8 */ 9 10 #include <linux/gpio/driver.h> 11 #include <linux/mfd/altera-a10sr.h> 12 #include <linux/mod_devicetable.h> 13 #include <linux/module.h> 14 #include <linux/property.h> 15 16 /** 17 * struct altr_a10sr_gpio - Altera Max5 GPIO device private data structure 18 * @gp: : instance of the gpio_chip 19 * @regmap: the regmap from the parent device. 20 */ 21 struct altr_a10sr_gpio { 22 struct gpio_chip gp; 23 struct regmap *regmap; 24 }; 25 26 static int altr_a10sr_gpio_get(struct gpio_chip *chip, unsigned int offset) 27 { 28 struct altr_a10sr_gpio *gpio = gpiochip_get_data(chip); 29 int ret, val; 30 31 ret = regmap_read(gpio->regmap, ALTR_A10SR_PBDSW_REG, &val); 32 if (ret < 0) 33 return ret; 34 35 return !!(val & BIT(offset - ALTR_A10SR_LED_VALID_SHIFT)); 36 } 37 38 static void altr_a10sr_gpio_set(struct gpio_chip *chip, unsigned int offset, 39 int value) 40 { 41 struct altr_a10sr_gpio *gpio = gpiochip_get_data(chip); 42 43 regmap_update_bits(gpio->regmap, ALTR_A10SR_LED_REG, 44 BIT(ALTR_A10SR_LED_VALID_SHIFT + offset), 45 value ? BIT(ALTR_A10SR_LED_VALID_SHIFT + offset) 46 : 0); 47 } 48 49 static int altr_a10sr_gpio_direction_input(struct gpio_chip *gc, 50 unsigned int nr) 51 { 52 if (nr < (ALTR_A10SR_IN_VALID_RANGE_LO - ALTR_A10SR_LED_VALID_SHIFT)) 53 return -EINVAL; 54 55 return 0; 56 } 57 58 static int altr_a10sr_gpio_direction_output(struct gpio_chip *gc, 59 unsigned int nr, int value) 60 { 61 if (nr > (ALTR_A10SR_OUT_VALID_RANGE_HI - ALTR_A10SR_LED_VALID_SHIFT)) 62 return -EINVAL; 63 64 altr_a10sr_gpio_set(gc, nr, value); 65 return 0; 66 } 67 68 static const struct gpio_chip altr_a10sr_gc = { 69 .label = "altr_a10sr_gpio", 70 .owner = THIS_MODULE, 71 .get = altr_a10sr_gpio_get, 72 .set = altr_a10sr_gpio_set, 73 .direction_input = altr_a10sr_gpio_direction_input, 74 .direction_output = altr_a10sr_gpio_direction_output, 75 .can_sleep = true, 76 .ngpio = 12, 77 .base = -1, 78 }; 79 80 static int altr_a10sr_gpio_probe(struct platform_device *pdev) 81 { 82 struct altr_a10sr_gpio *gpio; 83 struct altr_a10sr *a10sr = dev_get_drvdata(pdev->dev.parent); 84 85 gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); 86 if (!gpio) 87 return -ENOMEM; 88 89 gpio->regmap = a10sr->regmap; 90 91 gpio->gp = altr_a10sr_gc; 92 gpio->gp.parent = pdev->dev.parent; 93 gpio->gp.fwnode = dev_fwnode(&pdev->dev); 94 95 return devm_gpiochip_add_data(&pdev->dev, &gpio->gp, gpio); 96 } 97 98 static const struct of_device_id altr_a10sr_gpio_of_match[] = { 99 { .compatible = "altr,a10sr-gpio" }, 100 { }, 101 }; 102 MODULE_DEVICE_TABLE(of, altr_a10sr_gpio_of_match); 103 104 static struct platform_driver altr_a10sr_gpio_driver = { 105 .probe = altr_a10sr_gpio_probe, 106 .driver = { 107 .name = "altr_a10sr_gpio", 108 .of_match_table = altr_a10sr_gpio_of_match, 109 }, 110 }; 111 module_platform_driver(altr_a10sr_gpio_driver); 112 113 MODULE_LICENSE("GPL v2"); 114 MODULE_AUTHOR("Thor Thayer <tthayer@opensource.altera.com>"); 115 MODULE_DESCRIPTION("Altera Arria10 System Resource Chip GPIO"); 116