1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * ROHM BD9571MWV-M and BD9574MWF-M GPIO driver 4 * 5 * Copyright (C) 2017 Marek Vasut <marek.vasut+renesas@gmail.com> 6 * 7 * Based on the TPS65086 driver 8 * 9 * NOTE: Interrupts are not supported yet. 10 */ 11 12 #include <linux/gpio/driver.h> 13 #include <linux/mfd/rohm-generic.h> 14 #include <linux/module.h> 15 #include <linux/platform_device.h> 16 17 #include <linux/mfd/bd9571mwv.h> 18 19 struct bd9571mwv_gpio { 20 struct regmap *regmap; 21 struct gpio_chip chip; 22 }; 23 24 static int bd9571mwv_gpio_get_direction(struct gpio_chip *chip, 25 unsigned int offset) 26 { 27 struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip); 28 int ret, val; 29 30 ret = regmap_read(gpio->regmap, BD9571MWV_GPIO_DIR, &val); 31 if (ret < 0) 32 return ret; 33 if (val & BIT(offset)) 34 return GPIO_LINE_DIRECTION_IN; 35 36 return GPIO_LINE_DIRECTION_OUT; 37 } 38 39 static int bd9571mwv_gpio_direction_input(struct gpio_chip *chip, 40 unsigned int offset) 41 { 42 struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip); 43 44 regmap_update_bits(gpio->regmap, BD9571MWV_GPIO_DIR, BIT(offset), 0); 45 46 return 0; 47 } 48 49 static int bd9571mwv_gpio_direction_output(struct gpio_chip *chip, 50 unsigned int offset, int value) 51 { 52 struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip); 53 54 /* Set the initial value */ 55 regmap_update_bits(gpio->regmap, BD9571MWV_GPIO_OUT, 56 BIT(offset), value ? BIT(offset) : 0); 57 regmap_update_bits(gpio->regmap, BD9571MWV_GPIO_DIR, 58 BIT(offset), BIT(offset)); 59 60 return 0; 61 } 62 63 static int bd9571mwv_gpio_get(struct gpio_chip *chip, unsigned int offset) 64 { 65 struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip); 66 int ret, val; 67 68 ret = regmap_read(gpio->regmap, BD9571MWV_GPIO_IN, &val); 69 if (ret < 0) 70 return ret; 71 72 return val & BIT(offset); 73 } 74 75 static void bd9571mwv_gpio_set(struct gpio_chip *chip, unsigned int offset, 76 int value) 77 { 78 struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip); 79 80 regmap_update_bits(gpio->regmap, BD9571MWV_GPIO_OUT, 81 BIT(offset), value ? BIT(offset) : 0); 82 } 83 84 static const struct gpio_chip template_chip = { 85 .label = "bd9571mwv-gpio", 86 .owner = THIS_MODULE, 87 .get_direction = bd9571mwv_gpio_get_direction, 88 .direction_input = bd9571mwv_gpio_direction_input, 89 .direction_output = bd9571mwv_gpio_direction_output, 90 .get = bd9571mwv_gpio_get, 91 .set = bd9571mwv_gpio_set, 92 .base = -1, 93 .ngpio = 2, 94 .can_sleep = true, 95 }; 96 97 static int bd9571mwv_gpio_probe(struct platform_device *pdev) 98 { 99 struct bd9571mwv_gpio *gpio; 100 int ret; 101 102 gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); 103 if (!gpio) 104 return -ENOMEM; 105 106 platform_set_drvdata(pdev, gpio); 107 108 gpio->regmap = dev_get_regmap(pdev->dev.parent, NULL); 109 gpio->chip = template_chip; 110 gpio->chip.parent = pdev->dev.parent; 111 112 ret = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio); 113 if (ret < 0) { 114 dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret); 115 return ret; 116 } 117 118 return 0; 119 } 120 121 static const struct platform_device_id bd9571mwv_gpio_id_table[] = { 122 { "bd9571mwv-gpio", ROHM_CHIP_TYPE_BD9571 }, 123 { "bd9574mwf-gpio", ROHM_CHIP_TYPE_BD9574 }, 124 { /* sentinel */ } 125 }; 126 MODULE_DEVICE_TABLE(platform, bd9571mwv_gpio_id_table); 127 128 static struct platform_driver bd9571mwv_gpio_driver = { 129 .driver = { 130 .name = "bd9571mwv-gpio", 131 }, 132 .probe = bd9571mwv_gpio_probe, 133 .id_table = bd9571mwv_gpio_id_table, 134 }; 135 module_platform_driver(bd9571mwv_gpio_driver); 136 137 MODULE_AUTHOR("Marek Vasut <marek.vasut+renesas@gmail.com>"); 138 MODULE_DESCRIPTION("BD9571MWV GPIO driver"); 139 MODULE_LICENSE("GPL v2"); 140