18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci// Copyright (C) 2018 ROHM Semiconductors 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h> 58c2ecf20Sopenharmony_ci#include <linux/mfd/rohm-bd71828.h> 68c2ecf20Sopenharmony_ci#include <linux/module.h> 78c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 88c2ecf20Sopenharmony_ci#include <linux/regmap.h> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#define GPIO_OUT_REG(off) (BD71828_REG_GPIO_CTRL1 + (off)) 118c2ecf20Sopenharmony_ci#define HALL_GPIO_OFFSET 3 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_cistruct bd71828_gpio { 148c2ecf20Sopenharmony_ci struct rohm_regmap_dev chip; 158c2ecf20Sopenharmony_ci struct gpio_chip gpio; 168c2ecf20Sopenharmony_ci}; 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistatic void bd71828_gpio_set(struct gpio_chip *chip, unsigned int offset, 198c2ecf20Sopenharmony_ci int value) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci int ret; 228c2ecf20Sopenharmony_ci struct bd71828_gpio *bdgpio = gpiochip_get_data(chip); 238c2ecf20Sopenharmony_ci u8 val = (value) ? BD71828_GPIO_OUT_HI : BD71828_GPIO_OUT_LO; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci /* 268c2ecf20Sopenharmony_ci * The HALL input pin can only be used as input. If this is the pin 278c2ecf20Sopenharmony_ci * we are dealing with - then we are done 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_ci if (offset == HALL_GPIO_OFFSET) 308c2ecf20Sopenharmony_ci return; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci ret = regmap_update_bits(bdgpio->chip.regmap, GPIO_OUT_REG(offset), 338c2ecf20Sopenharmony_ci BD71828_GPIO_OUT_MASK, val); 348c2ecf20Sopenharmony_ci if (ret) 358c2ecf20Sopenharmony_ci dev_err(bdgpio->chip.dev, "Could not set gpio to %d\n", value); 368c2ecf20Sopenharmony_ci} 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic int bd71828_gpio_get(struct gpio_chip *chip, unsigned int offset) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci int ret; 418c2ecf20Sopenharmony_ci unsigned int val; 428c2ecf20Sopenharmony_ci struct bd71828_gpio *bdgpio = gpiochip_get_data(chip); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci if (offset == HALL_GPIO_OFFSET) 458c2ecf20Sopenharmony_ci ret = regmap_read(bdgpio->chip.regmap, BD71828_REG_IO_STAT, 468c2ecf20Sopenharmony_ci &val); 478c2ecf20Sopenharmony_ci else 488c2ecf20Sopenharmony_ci ret = regmap_read(bdgpio->chip.regmap, GPIO_OUT_REG(offset), 498c2ecf20Sopenharmony_ci &val); 508c2ecf20Sopenharmony_ci if (!ret) 518c2ecf20Sopenharmony_ci ret = (val & BD71828_GPIO_OUT_MASK); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci return ret; 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic int bd71828_gpio_set_config(struct gpio_chip *chip, unsigned int offset, 578c2ecf20Sopenharmony_ci unsigned long config) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci struct bd71828_gpio *bdgpio = gpiochip_get_data(chip); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci if (offset == HALL_GPIO_OFFSET) 628c2ecf20Sopenharmony_ci return -ENOTSUPP; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci switch (pinconf_to_config_param(config)) { 658c2ecf20Sopenharmony_ci case PIN_CONFIG_DRIVE_OPEN_DRAIN: 668c2ecf20Sopenharmony_ci return regmap_update_bits(bdgpio->chip.regmap, 678c2ecf20Sopenharmony_ci GPIO_OUT_REG(offset), 688c2ecf20Sopenharmony_ci BD71828_GPIO_DRIVE_MASK, 698c2ecf20Sopenharmony_ci BD71828_GPIO_OPEN_DRAIN); 708c2ecf20Sopenharmony_ci case PIN_CONFIG_DRIVE_PUSH_PULL: 718c2ecf20Sopenharmony_ci return regmap_update_bits(bdgpio->chip.regmap, 728c2ecf20Sopenharmony_ci GPIO_OUT_REG(offset), 738c2ecf20Sopenharmony_ci BD71828_GPIO_DRIVE_MASK, 748c2ecf20Sopenharmony_ci BD71828_GPIO_PUSH_PULL); 758c2ecf20Sopenharmony_ci default: 768c2ecf20Sopenharmony_ci break; 778c2ecf20Sopenharmony_ci } 788c2ecf20Sopenharmony_ci return -ENOTSUPP; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic int bd71828_get_direction(struct gpio_chip *chip, unsigned int offset) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci /* 848c2ecf20Sopenharmony_ci * Pin usage is selected by OTP data. We can't read it runtime. Hence 858c2ecf20Sopenharmony_ci * we trust that if the pin is not excluded by "gpio-reserved-ranges" 868c2ecf20Sopenharmony_ci * the OTP configuration is set to OUT. (Other pins but HALL input pin 878c2ecf20Sopenharmony_ci * on BD71828 can't really be used for general purpose input - input 888c2ecf20Sopenharmony_ci * states are used for specific cases like regulator control or 898c2ecf20Sopenharmony_ci * PMIC_ON_REQ. 908c2ecf20Sopenharmony_ci */ 918c2ecf20Sopenharmony_ci if (offset == HALL_GPIO_OFFSET) 928c2ecf20Sopenharmony_ci return GPIO_LINE_DIRECTION_IN; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci return GPIO_LINE_DIRECTION_OUT; 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic int bd71828_probe(struct platform_device *pdev) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci struct bd71828_gpio *bdgpio; 1008c2ecf20Sopenharmony_ci struct rohm_regmap_dev *bd71828; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci bd71828 = dev_get_drvdata(pdev->dev.parent); 1038c2ecf20Sopenharmony_ci if (!bd71828) { 1048c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "No MFD driver data\n"); 1058c2ecf20Sopenharmony_ci return -EINVAL; 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci bdgpio = devm_kzalloc(&pdev->dev, sizeof(*bdgpio), 1098c2ecf20Sopenharmony_ci GFP_KERNEL); 1108c2ecf20Sopenharmony_ci if (!bdgpio) 1118c2ecf20Sopenharmony_ci return -ENOMEM; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci bdgpio->chip.dev = &pdev->dev; 1148c2ecf20Sopenharmony_ci bdgpio->gpio.parent = pdev->dev.parent; 1158c2ecf20Sopenharmony_ci bdgpio->gpio.label = "bd71828-gpio"; 1168c2ecf20Sopenharmony_ci bdgpio->gpio.owner = THIS_MODULE; 1178c2ecf20Sopenharmony_ci bdgpio->gpio.get_direction = bd71828_get_direction; 1188c2ecf20Sopenharmony_ci bdgpio->gpio.set_config = bd71828_gpio_set_config; 1198c2ecf20Sopenharmony_ci bdgpio->gpio.can_sleep = true; 1208c2ecf20Sopenharmony_ci bdgpio->gpio.get = bd71828_gpio_get; 1218c2ecf20Sopenharmony_ci bdgpio->gpio.set = bd71828_gpio_set; 1228c2ecf20Sopenharmony_ci bdgpio->gpio.base = -1; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci /* 1258c2ecf20Sopenharmony_ci * See if we need some implementation to mark some PINs as 1268c2ecf20Sopenharmony_ci * not controllable based on DT info or if core can handle 1278c2ecf20Sopenharmony_ci * "gpio-reserved-ranges" and exclude them from control 1288c2ecf20Sopenharmony_ci */ 1298c2ecf20Sopenharmony_ci bdgpio->gpio.ngpio = 4; 1308c2ecf20Sopenharmony_ci bdgpio->gpio.of_node = pdev->dev.parent->of_node; 1318c2ecf20Sopenharmony_ci bdgpio->chip.regmap = bd71828->regmap; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci return devm_gpiochip_add_data(&pdev->dev, &bdgpio->gpio, 1348c2ecf20Sopenharmony_ci bdgpio); 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic struct platform_driver bd71828_gpio = { 1388c2ecf20Sopenharmony_ci .driver = { 1398c2ecf20Sopenharmony_ci .name = "bd71828-gpio" 1408c2ecf20Sopenharmony_ci }, 1418c2ecf20Sopenharmony_ci .probe = bd71828_probe, 1428c2ecf20Sopenharmony_ci}; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cimodule_platform_driver(bd71828_gpio); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ciMODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); 1478c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("BD71828 voltage regulator driver"); 1488c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1498c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:bd71828-gpio"); 150