18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * ROHM BD9571MWV-M GPIO driver 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2017 Marek Vasut <marek.vasut+renesas@gmail.com> 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or 78c2ecf20Sopenharmony_ci * modify it under the terms of the GNU General Public License version 2 as 88c2ecf20Sopenharmony_ci * published by the Free Software Foundation. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * This program is distributed "as is" WITHOUT ANY WARRANTY of any 118c2ecf20Sopenharmony_ci * kind, whether expressed or implied; without even the implied warranty 128c2ecf20Sopenharmony_ci * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 138c2ecf20Sopenharmony_ci * GNU General Public License version 2 for more details. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * Based on the TPS65086 driver 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * NOTE: Interrupts are not supported yet. 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h> 218c2ecf20Sopenharmony_ci#include <linux/module.h> 228c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <linux/mfd/bd9571mwv.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistruct bd9571mwv_gpio { 278c2ecf20Sopenharmony_ci struct gpio_chip chip; 288c2ecf20Sopenharmony_ci struct bd9571mwv *bd; 298c2ecf20Sopenharmony_ci}; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic int bd9571mwv_gpio_get_direction(struct gpio_chip *chip, 328c2ecf20Sopenharmony_ci unsigned int offset) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip); 358c2ecf20Sopenharmony_ci int ret, val; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci ret = regmap_read(gpio->bd->regmap, BD9571MWV_GPIO_DIR, &val); 388c2ecf20Sopenharmony_ci if (ret < 0) 398c2ecf20Sopenharmony_ci return ret; 408c2ecf20Sopenharmony_ci if (val & BIT(offset)) 418c2ecf20Sopenharmony_ci return GPIO_LINE_DIRECTION_IN; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci return GPIO_LINE_DIRECTION_OUT; 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic int bd9571mwv_gpio_direction_input(struct gpio_chip *chip, 478c2ecf20Sopenharmony_ci unsigned int offset) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci regmap_update_bits(gpio->bd->regmap, BD9571MWV_GPIO_DIR, 528c2ecf20Sopenharmony_ci BIT(offset), 0); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci return 0; 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic int bd9571mwv_gpio_direction_output(struct gpio_chip *chip, 588c2ecf20Sopenharmony_ci unsigned int offset, int value) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci /* Set the initial value */ 638c2ecf20Sopenharmony_ci regmap_update_bits(gpio->bd->regmap, BD9571MWV_GPIO_OUT, 648c2ecf20Sopenharmony_ci BIT(offset), value ? BIT(offset) : 0); 658c2ecf20Sopenharmony_ci regmap_update_bits(gpio->bd->regmap, BD9571MWV_GPIO_DIR, 668c2ecf20Sopenharmony_ci BIT(offset), BIT(offset)); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci return 0; 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic int bd9571mwv_gpio_get(struct gpio_chip *chip, unsigned int offset) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip); 748c2ecf20Sopenharmony_ci int ret, val; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci ret = regmap_read(gpio->bd->regmap, BD9571MWV_GPIO_IN, &val); 778c2ecf20Sopenharmony_ci if (ret < 0) 788c2ecf20Sopenharmony_ci return ret; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci return val & BIT(offset); 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic void bd9571mwv_gpio_set(struct gpio_chip *chip, unsigned int offset, 848c2ecf20Sopenharmony_ci int value) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci regmap_update_bits(gpio->bd->regmap, BD9571MWV_GPIO_OUT, 898c2ecf20Sopenharmony_ci BIT(offset), value ? BIT(offset) : 0); 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic const struct gpio_chip template_chip = { 938c2ecf20Sopenharmony_ci .label = "bd9571mwv-gpio", 948c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 958c2ecf20Sopenharmony_ci .get_direction = bd9571mwv_gpio_get_direction, 968c2ecf20Sopenharmony_ci .direction_input = bd9571mwv_gpio_direction_input, 978c2ecf20Sopenharmony_ci .direction_output = bd9571mwv_gpio_direction_output, 988c2ecf20Sopenharmony_ci .get = bd9571mwv_gpio_get, 998c2ecf20Sopenharmony_ci .set = bd9571mwv_gpio_set, 1008c2ecf20Sopenharmony_ci .base = -1, 1018c2ecf20Sopenharmony_ci .ngpio = 2, 1028c2ecf20Sopenharmony_ci .can_sleep = true, 1038c2ecf20Sopenharmony_ci}; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic int bd9571mwv_gpio_probe(struct platform_device *pdev) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci struct bd9571mwv_gpio *gpio; 1088c2ecf20Sopenharmony_ci int ret; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); 1118c2ecf20Sopenharmony_ci if (!gpio) 1128c2ecf20Sopenharmony_ci return -ENOMEM; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, gpio); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci gpio->bd = dev_get_drvdata(pdev->dev.parent); 1178c2ecf20Sopenharmony_ci gpio->chip = template_chip; 1188c2ecf20Sopenharmony_ci gpio->chip.parent = gpio->bd->dev; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci ret = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio); 1218c2ecf20Sopenharmony_ci if (ret < 0) { 1228c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret); 1238c2ecf20Sopenharmony_ci return ret; 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci return 0; 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic const struct platform_device_id bd9571mwv_gpio_id_table[] = { 1308c2ecf20Sopenharmony_ci { "bd9571mwv-gpio", }, 1318c2ecf20Sopenharmony_ci { /* sentinel */ } 1328c2ecf20Sopenharmony_ci}; 1338c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(platform, bd9571mwv_gpio_id_table); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic struct platform_driver bd9571mwv_gpio_driver = { 1368c2ecf20Sopenharmony_ci .driver = { 1378c2ecf20Sopenharmony_ci .name = "bd9571mwv-gpio", 1388c2ecf20Sopenharmony_ci }, 1398c2ecf20Sopenharmony_ci .probe = bd9571mwv_gpio_probe, 1408c2ecf20Sopenharmony_ci .id_table = bd9571mwv_gpio_id_table, 1418c2ecf20Sopenharmony_ci}; 1428c2ecf20Sopenharmony_cimodule_platform_driver(bd9571mwv_gpio_driver); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ciMODULE_AUTHOR("Marek Vasut <marek.vasut+renesas@gmail.com>"); 1458c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("BD9571MWV GPIO driver"); 1468c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 147