162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * TI TPS6586x GPIO driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
662306a36Sopenharmony_ci * Author: Laxman dewangan <ldewangan@nvidia.com>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Based on tps6586x.c
962306a36Sopenharmony_ci * Copyright (c) 2010 CompuLab Ltd.
1062306a36Sopenharmony_ci * Mike Rapoport <mike@compulab.co.il>
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/errno.h>
1462306a36Sopenharmony_ci#include <linux/gpio/driver.h>
1562306a36Sopenharmony_ci#include <linux/kernel.h>
1662306a36Sopenharmony_ci#include <linux/init.h>
1762306a36Sopenharmony_ci#include <linux/mfd/tps6586x.h>
1862306a36Sopenharmony_ci#include <linux/of.h>
1962306a36Sopenharmony_ci#include <linux/platform_device.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/* GPIO control registers */
2262306a36Sopenharmony_ci#define TPS6586X_GPIOSET1	0x5d
2362306a36Sopenharmony_ci#define TPS6586X_GPIOSET2	0x5e
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistruct tps6586x_gpio {
2662306a36Sopenharmony_ci	struct gpio_chip gpio_chip;
2762306a36Sopenharmony_ci	struct device *parent;
2862306a36Sopenharmony_ci};
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistatic int tps6586x_gpio_get(struct gpio_chip *gc, unsigned offset)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	struct tps6586x_gpio *tps6586x_gpio = gpiochip_get_data(gc);
3362306a36Sopenharmony_ci	uint8_t val;
3462306a36Sopenharmony_ci	int ret;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	ret = tps6586x_read(tps6586x_gpio->parent, TPS6586X_GPIOSET2, &val);
3762306a36Sopenharmony_ci	if (ret)
3862306a36Sopenharmony_ci		return ret;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	return !!(val & (1 << offset));
4162306a36Sopenharmony_ci}
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic void tps6586x_gpio_set(struct gpio_chip *gc, unsigned offset,
4462306a36Sopenharmony_ci			      int value)
4562306a36Sopenharmony_ci{
4662306a36Sopenharmony_ci	struct tps6586x_gpio *tps6586x_gpio = gpiochip_get_data(gc);
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	tps6586x_update(tps6586x_gpio->parent, TPS6586X_GPIOSET2,
4962306a36Sopenharmony_ci			value << offset, 1 << offset);
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic int tps6586x_gpio_output(struct gpio_chip *gc, unsigned offset,
5362306a36Sopenharmony_ci				int value)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	struct tps6586x_gpio *tps6586x_gpio = gpiochip_get_data(gc);
5662306a36Sopenharmony_ci	uint8_t val, mask;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	tps6586x_gpio_set(gc, offset, value);
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	val = 0x1 << (offset * 2);
6162306a36Sopenharmony_ci	mask = 0x3 << (offset * 2);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	return tps6586x_update(tps6586x_gpio->parent, TPS6586X_GPIOSET1,
6462306a36Sopenharmony_ci				val, mask);
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic int tps6586x_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	struct tps6586x_gpio *tps6586x_gpio = gpiochip_get_data(gc);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	return tps6586x_irq_get_virq(tps6586x_gpio->parent,
7262306a36Sopenharmony_ci				TPS6586X_INT_PLDO_0 + offset);
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic int tps6586x_gpio_probe(struct platform_device *pdev)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	struct tps6586x_platform_data *pdata;
7862306a36Sopenharmony_ci	struct tps6586x_gpio *tps6586x_gpio;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	device_set_node(&pdev->dev, dev_fwnode(pdev->dev.parent));
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	pdata = dev_get_platdata(pdev->dev.parent);
8362306a36Sopenharmony_ci	tps6586x_gpio = devm_kzalloc(&pdev->dev,
8462306a36Sopenharmony_ci				sizeof(*tps6586x_gpio), GFP_KERNEL);
8562306a36Sopenharmony_ci	if (!tps6586x_gpio)
8662306a36Sopenharmony_ci		return -ENOMEM;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	tps6586x_gpio->parent = pdev->dev.parent;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	tps6586x_gpio->gpio_chip.owner = THIS_MODULE;
9162306a36Sopenharmony_ci	tps6586x_gpio->gpio_chip.label = pdev->name;
9262306a36Sopenharmony_ci	tps6586x_gpio->gpio_chip.parent = &pdev->dev;
9362306a36Sopenharmony_ci	tps6586x_gpio->gpio_chip.ngpio = 4;
9462306a36Sopenharmony_ci	tps6586x_gpio->gpio_chip.can_sleep = true;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	/* FIXME: add handling of GPIOs as dedicated inputs */
9762306a36Sopenharmony_ci	tps6586x_gpio->gpio_chip.direction_output = tps6586x_gpio_output;
9862306a36Sopenharmony_ci	tps6586x_gpio->gpio_chip.set	= tps6586x_gpio_set;
9962306a36Sopenharmony_ci	tps6586x_gpio->gpio_chip.get	= tps6586x_gpio_get;
10062306a36Sopenharmony_ci	tps6586x_gpio->gpio_chip.to_irq	= tps6586x_gpio_to_irq;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	if (pdata && pdata->gpio_base)
10362306a36Sopenharmony_ci		tps6586x_gpio->gpio_chip.base = pdata->gpio_base;
10462306a36Sopenharmony_ci	else
10562306a36Sopenharmony_ci		tps6586x_gpio->gpio_chip.base = -1;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	return devm_gpiochip_add_data(&pdev->dev, &tps6586x_gpio->gpio_chip,
10862306a36Sopenharmony_ci				      tps6586x_gpio);
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistatic struct platform_driver tps6586x_gpio_driver = {
11262306a36Sopenharmony_ci	.driver.name	= "tps6586x-gpio",
11362306a36Sopenharmony_ci	.probe		= tps6586x_gpio_probe,
11462306a36Sopenharmony_ci};
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic int __init tps6586x_gpio_init(void)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	return platform_driver_register(&tps6586x_gpio_driver);
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_cisubsys_initcall(tps6586x_gpio_init);
121