1139826Simp// SPDX-License-Identifier: GPL-2.0-only
253541Sshin/*
353541Sshin *  linux/drivers/gpio/gpio-mb86s7x.c
453541Sshin *
553541Sshin *  Copyright (C) 2015 Fujitsu Semiconductor Limited
653541Sshin *  Copyright (C) 2015 Linaro Ltd.
753541Sshin */
853541Sshin
953541Sshin#include <linux/acpi.h>
1053541Sshin#include <linux/io.h>
1153541Sshin#include <linux/init.h>
1253541Sshin#include <linux/clk.h>
1353541Sshin#include <linux/mod_devicetable.h>
1453541Sshin#include <linux/module.h>
1553541Sshin#include <linux/err.h>
1653541Sshin#include <linux/errno.h>
1753541Sshin#include <linux/ioport.h>
1853541Sshin#include <linux/gpio/driver.h>
1953541Sshin#include <linux/platform_device.h>
2053541Sshin#include <linux/spinlock.h>
2153541Sshin#include <linux/slab.h>
2253541Sshin
2353541Sshin#include "gpiolib-acpi.h"
2453541Sshin
2553541Sshin/*
2653541Sshin * Only first 8bits of a register correspond to each pin,
2753541Sshin * so there are 4 registers for 32 pins.
2853541Sshin */
2953541Sshin#define PDR(x)	(0x0 + x / 8 * 4)
30139826Simp#define DDR(x)	(0x10 + x / 8 * 4)
3153541Sshin#define PFR(x)	(0x20 + x / 8 * 4)
32180305Srwatson
33180305Srwatson#define OFFSET(x)	BIT((x) % 8)
3453541Sshin
3553541Sshinstruct mb86s70_gpio_chip {
3653541Sshin	struct gpio_chip gc;
3753541Sshin	void __iomem *base;
3853541Sshin	struct clk *clk;
3953541Sshin	spinlock_t lock;
4053541Sshin};
4153541Sshin
4253541Sshinstatic int mb86s70_gpio_request(struct gpio_chip *gc, unsigned gpio)
4353541Sshin{
4453541Sshin	struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
4553541Sshin	unsigned long flags;
4653541Sshin	u32 val;
4753541Sshin
4853541Sshin	spin_lock_irqsave(&gchip->lock, flags);
4953541Sshin
5053541Sshin	val = readl(gchip->base + PFR(gpio));
5153541Sshin	val &= ~OFFSET(gpio);
5253541Sshin	writel(val, gchip->base + PFR(gpio));
5353541Sshin
5453541Sshin	spin_unlock_irqrestore(&gchip->lock, flags);
5553541Sshin
5653541Sshin	return 0;
5753541Sshin}
5853541Sshin
5953541Sshinstatic void mb86s70_gpio_free(struct gpio_chip *gc, unsigned gpio)
6053541Sshin{
6153541Sshin	struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
62174510Sobrien	unsigned long flags;
63174510Sobrien	u32 val;
64174510Sobrien
6555009Sshin	spin_lock_irqsave(&gchip->lock, flags);
6678064Sume
6755009Sshin	val = readl(gchip->base + PFR(gpio));
6853541Sshin	val |= OFFSET(gpio);
6995759Stanimura	writel(val, gchip->base + PFR(gpio));
70185435Sbz
7195759Stanimura	spin_unlock_irqrestore(&gchip->lock, flags);
7253541Sshin}
7395759Stanimura
74170689Srwatsonstatic int mb86s70_gpio_direction_input(struct gpio_chip *gc, unsigned gpio)
7553541Sshin{
7695759Stanimura	struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
7795759Stanimura	unsigned long flags;
7853541Sshin	unsigned char val;
7953541Sshin
8095759Stanimura	spin_lock_irqsave(&gchip->lock, flags);
81148385Sume
8253541Sshin	val = readl(gchip->base + DDR(gpio));
8353541Sshin	val &= ~OFFSET(gpio);
8495759Stanimura	writel(val, gchip->base + DDR(gpio));
8553541Sshin
86185571Sbz	spin_unlock_irqrestore(&gchip->lock, flags);
8753541Sshin
8853541Sshin	return 0;
8953541Sshin}
9053541Sshin
91185571Sbzstatic int mb86s70_gpio_direction_output(struct gpio_chip *gc,
92185571Sbz					 unsigned gpio, int value)
9395759Stanimura{
9462587Sitojun	struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
95211501Sanchie	unsigned long flags;
9695759Stanimura	unsigned char val;
9756723Sshin
9853541Sshin	spin_lock_irqsave(&gchip->lock, flags);
9995759Stanimura
10053541Sshin	val = readl(gchip->base + PDR(gpio));
10195759Stanimura	if (value)
10262587Sitojun		val |= OFFSET(gpio);
103211501Sanchie	else
10453541Sshin		val &= ~OFFSET(gpio);
105171167Sgnn	writel(val, gchip->base + PDR(gpio));
106105199Ssam
107105199Ssam	val = readl(gchip->base + DDR(gpio));
108171167Sgnn	val |= OFFSET(gpio);
109105199Ssam	writel(val, gchip->base + DDR(gpio));
11053541Sshin
11153541Sshin	spin_unlock_irqrestore(&gchip->lock, flags);
11253541Sshin
11353541Sshin	return 0;
11453541Sshin}
11553541Sshin
11653541Sshinstatic int mb86s70_gpio_get(struct gpio_chip *gc, unsigned gpio)
11753541Sshin{
11853541Sshin	struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
119195699Srwatson
120195699Srwatson	return !!(readl(gchip->base + PDR(gpio)) & OFFSET(gpio));
121195727Srwatson}
122195727Srwatson
123185348Szecstatic void mb86s70_gpio_set(struct gpio_chip *gc, unsigned gpio, int value)
12453541Sshin{
12553541Sshin	struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
12653541Sshin	unsigned long flags;
127207369Sbz	unsigned char val;
128207369Sbz
12953541Sshin	spin_lock_irqsave(&gchip->lock, flags);
130191672Sbms
131191672Sbms	val = readl(gchip->base + PDR(gpio));
132166938Sbms	if (value)
133191672Sbms		val |= OFFSET(gpio);
134191672Sbms	else
135191672Sbms		val &= ~OFFSET(gpio);
136191672Sbms	writel(val, gchip->base + PDR(gpio));
137195699Srwatson
138191672Sbms	spin_unlock_irqrestore(&gchip->lock, flags);
139191672Sbms}
140191672Sbms
141191672Sbmsstatic int mb86s70_gpio_to_irq(struct gpio_chip *gc, unsigned int offset)
142166938Sbms{
143166938Sbms	int irq, index;
144166938Sbms
145166938Sbms	for (index = 0;; index++) {
146194581Srdivacky		irq = platform_get_irq(to_platform_device(gc->parent), index);
147166938Sbms		if (irq < 0)
148166938Sbms			return irq;
149180305Srwatson		if (irq == 0)
150180305Srwatson			break;
15153541Sshin		if (irq_get_irq_data(irq)->hwirq == offset)
15253541Sshin			return irq;
153171259Sdelphij	}
15453541Sshin	return -EINVAL;
155191672Sbms}
15653541Sshin
15753541Sshinstatic int mb86s70_gpio_probe(struct platform_device *pdev)
15853541Sshin{
15953541Sshin	struct mb86s70_gpio_chip *gchip;
16078064Sume	int ret;
161121901Sume
16253541Sshin	gchip = devm_kzalloc(&pdev->dev, sizeof(*gchip), GFP_KERNEL);
163181803Sbz	if (gchip == NULL)
16478064Sume		return -ENOMEM;
16583934Sbrooks
166180305Srwatson	platform_set_drvdata(pdev, gchip);
16778064Sume
168180305Srwatson	gchip->base = devm_platform_ioremap_resource(pdev, 0);
16953541Sshin	if (IS_ERR(gchip->base))
17078064Sume		return PTR_ERR(gchip->base);
171121901Sume
17253541Sshin	gchip->clk = devm_clk_get_optional(&pdev->dev, NULL);
173191672Sbms	if (IS_ERR(gchip->clk))
174191672Sbms		return PTR_ERR(gchip->clk);
175181803Sbz
176181803Sbz	ret = clk_prepare_enable(gchip->clk);
177185435Sbz	if (ret)
178186141Sbz		return ret;
17953541Sshin
180186141Sbz	spin_lock_init(&gchip->lock);
181186141Sbz
182180850Smav	gchip->gc.direction_output = mb86s70_gpio_direction_output;
18353541Sshin	gchip->gc.direction_input = mb86s70_gpio_direction_input;
18453541Sshin	gchip->gc.request = mb86s70_gpio_request;
185180850Smav	gchip->gc.free = mb86s70_gpio_free;
18653541Sshin	gchip->gc.get = mb86s70_gpio_get;
18753541Sshin	gchip->gc.set = mb86s70_gpio_set;
188180850Smav	gchip->gc.to_irq = mb86s70_gpio_to_irq;
189200473Sbz	gchip->gc.label = dev_name(&pdev->dev);
190191672Sbms	gchip->gc.ngpio = 32;
191191672Sbms	gchip->gc.owner = THIS_MODULE;
192191672Sbms	gchip->gc.parent = &pdev->dev;
193191672Sbms	gchip->gc.base = -1;
194191672Sbms
195191672Sbms	ret = gpiochip_add_data(&gchip->gc, gchip);
196191672Sbms	if (ret) {
197191672Sbms		dev_err(&pdev->dev, "couldn't register gpio driver\n");
198191672Sbms		clk_disable_unprepare(gchip->clk);
199191672Sbms		return ret;
20078064Sume	}
201181803Sbz
202151459Ssuz	acpi_gpiochip_request_interrupts(&gchip->gc);
20378064Sume
204180932Smav	return 0;
205181803Sbz}
206180850Smav
20778064Sumestatic void mb86s70_gpio_remove(struct platform_device *pdev)
20853541Sshin{
209191672Sbms	struct mb86s70_gpio_chip *gchip = platform_get_drvdata(pdev);
210191672Sbms
211191672Sbms	acpi_gpiochip_free_interrupts(&gchip->gc);
212191672Sbms	gpiochip_remove(&gchip->gc);
213191672Sbms	clk_disable_unprepare(gchip->clk);
214191672Sbms}
215191672Sbms
216191672Sbmsstatic const struct of_device_id mb86s70_gpio_dt_ids[] = {
217191672Sbms	{ .compatible = "fujitsu,mb86s70-gpio" },
218199518Sbms	{ /* sentinel */ }
219199518Sbms};
220199518SbmsMODULE_DEVICE_TABLE(of, mb86s70_gpio_dt_ids);
221199518Sbms
222199518Sbms#ifdef CONFIG_ACPI
223199518Sbmsstatic const struct acpi_device_id mb86s70_gpio_acpi_ids[] = {
224199518Sbms	{ "SCX0007" },
225199518Sbms	{ /* sentinel */ }
226199518Sbms};
227199518SbmsMODULE_DEVICE_TABLE(acpi, mb86s70_gpio_acpi_ids);
228199518Sbms#endif
229199518Sbms
230199518Sbmsstatic struct platform_driver mb86s70_gpio_driver = {
231199518Sbms	.driver = {
232199518Sbms		.name = "mb86s70-gpio",
233199518Sbms		.of_match_table = mb86s70_gpio_dt_ids,
234199518Sbms		.acpi_match_table = ACPI_PTR(mb86s70_gpio_acpi_ids),
235191672Sbms	},
236191672Sbms	.probe = mb86s70_gpio_probe,
237199518Sbms	.remove_new = mb86s70_gpio_remove,
238199518Sbms};
239199518Sbmsmodule_platform_driver(mb86s70_gpio_driver);
240191672Sbms
241199518SbmsMODULE_DESCRIPTION("MB86S7x GPIO Driver");
242199518SbmsMODULE_ALIAS("platform:mb86s70-gpio");
243199518SbmsMODULE_LICENSE("GPL");
244199518Sbms