xref: /linux/drivers/gpio/gpio-ppc44x.c (revision 1200d84f4c0a929a0780180d25063d93773be79c)
166da1ae1SRosen Penev // SPDX-License-Identifier: GPL-2.0-only
266da1ae1SRosen Penev /*
3f9476e23SRosen Penev  * PPC44x gpio driver
466da1ae1SRosen Penev  *
566da1ae1SRosen Penev  * Copyright (c) 2008 Harris Corporation
666da1ae1SRosen Penev  * Copyright (c) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
766da1ae1SRosen Penev  * Copyright (c) MontaVista Software, Inc. 2008.
866da1ae1SRosen Penev  *
966da1ae1SRosen Penev  * Author: Steve Falco <sfalco@harris.com>
1066da1ae1SRosen Penev  */
1166da1ae1SRosen Penev 
1266da1ae1SRosen Penev #include <linux/kernel.h>
1366da1ae1SRosen Penev #include <linux/init.h>
1466da1ae1SRosen Penev #include <linux/io.h>
1566da1ae1SRosen Penev #include <linux/of.h>
16714d445aSRosen Penev #include <linux/gpio/generic.h>
1766da1ae1SRosen Penev #include <linux/types.h>
1866da1ae1SRosen Penev #include <linux/slab.h>
1966da1ae1SRosen Penev #include <linux/platform_device.h>
2066da1ae1SRosen Penev 
2166da1ae1SRosen Penev #define GPIO_MASK(gpio)		(0x80000000 >> (gpio))
229c4d539dSRosen Penev #define GPIO_MASK2(gpio)	(0xc0000000 >> (((gpio) % 16) * 2))
2366da1ae1SRosen Penev 
2466da1ae1SRosen Penev /* Physical GPIO register layout */
25f9476e23SRosen Penev struct ppc44x_gpio {
2666da1ae1SRosen Penev 	__be32 or;
2766da1ae1SRosen Penev 	__be32 tcr;
2866da1ae1SRosen Penev 	__be32 osrl;
2966da1ae1SRosen Penev 	__be32 osrh;
3066da1ae1SRosen Penev 	__be32 tsrl;
3166da1ae1SRosen Penev 	__be32 tsrh;
3266da1ae1SRosen Penev 	__be32 odr;
3366da1ae1SRosen Penev 	__be32 ir;
3466da1ae1SRosen Penev 	__be32 rr1;
3566da1ae1SRosen Penev 	__be32 rr2;
3666da1ae1SRosen Penev 	__be32 rr3;
3766da1ae1SRosen Penev 	__be32 reserved1;
3866da1ae1SRosen Penev 	__be32 isr1l;
3966da1ae1SRosen Penev 	__be32 isr1h;
4066da1ae1SRosen Penev 	__be32 isr2l;
4166da1ae1SRosen Penev 	__be32 isr2h;
4266da1ae1SRosen Penev 	__be32 isr3l;
4366da1ae1SRosen Penev 	__be32 isr3h;
4466da1ae1SRosen Penev };
4566da1ae1SRosen Penev 
46f9476e23SRosen Penev struct ppc44x_gpio_chip {
47714d445aSRosen Penev 	struct gpio_generic_chip chip;
4866da1ae1SRosen Penev 	void __iomem *regs;
4966da1ae1SRosen Penev };
5066da1ae1SRosen Penev 
51595f5f25SRosen Penev static inline void ppc44x_clrbits32(void __iomem *addr, u32 mask)
52595f5f25SRosen Penev {
53595f5f25SRosen Penev 	u32 val = ioread32be(addr);
54595f5f25SRosen Penev 
55595f5f25SRosen Penev 	val &= ~mask;
56595f5f25SRosen Penev 	iowrite32be(val, addr);
57595f5f25SRosen Penev }
58595f5f25SRosen Penev 
59595f5f25SRosen Penev static inline void ppc44x_setbits32(void __iomem *addr, u32 mask)
60595f5f25SRosen Penev {
61595f5f25SRosen Penev 	u32 val = ioread32be(addr);
62595f5f25SRosen Penev 
63595f5f25SRosen Penev 	val |= mask;
64595f5f25SRosen Penev 	iowrite32be(val, addr);
65595f5f25SRosen Penev }
66595f5f25SRosen Penev 
6766da1ae1SRosen Penev /*
6866da1ae1SRosen Penev  * GPIO LIB API implementation for GPIOs
6966da1ae1SRosen Penev  *
7066da1ae1SRosen Penev  * There are a maximum of 32 gpios in each gpio controller.
7166da1ae1SRosen Penev  */
7266da1ae1SRosen Penev 
7366da1ae1SRosen Penev static inline void
74f9476e23SRosen Penev __ppc44x_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
7566da1ae1SRosen Penev {
76f9476e23SRosen Penev 	struct ppc44x_gpio_chip *chip = gpiochip_get_data(gc);
77714d445aSRosen Penev 	struct gpio_generic_chip *gen_gc = &chip->chip;
7866da1ae1SRosen Penev 
7966da1ae1SRosen Penev 	if (val)
80714d445aSRosen Penev 		gen_gc->sdata |= GPIO_MASK(gpio);
8166da1ae1SRosen Penev 	else
82714d445aSRosen Penev 		gen_gc->sdata &= ~GPIO_MASK(gpio);
8366da1ae1SRosen Penev 
84714d445aSRosen Penev 	gpio_generic_write_reg(gen_gc, gen_gc->reg_set, gen_gc->sdata);
8566da1ae1SRosen Penev }
8666da1ae1SRosen Penev 
87f9476e23SRosen Penev static int ppc44x_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
8866da1ae1SRosen Penev {
89f9476e23SRosen Penev 	struct ppc44x_gpio_chip *chip = gpiochip_get_data(gc);
90714d445aSRosen Penev 	struct gpio_generic_chip *gen_gc = &chip->chip;
91f9476e23SRosen Penev 	struct ppc44x_gpio __iomem *regs = chip->regs;
9266da1ae1SRosen Penev 
93714d445aSRosen Penev 	guard(gpio_generic_lock_irqsave)(gen_gc);
9466da1ae1SRosen Penev 
9566da1ae1SRosen Penev 	/* Disable open-drain function */
96595f5f25SRosen Penev 	ppc44x_clrbits32(&regs->odr, GPIO_MASK(gpio));
9766da1ae1SRosen Penev 
9866da1ae1SRosen Penev 	/* Float the pin */
99595f5f25SRosen Penev 	ppc44x_clrbits32(&regs->tcr, GPIO_MASK(gpio));
100714d445aSRosen Penev 	gen_gc->sdir &= ~GPIO_MASK(gpio);
10166da1ae1SRosen Penev 
10266da1ae1SRosen Penev 	/* Bits 0-15 use TSRL/OSRL, bits 16-31 use TSRH/OSRH */
10366da1ae1SRosen Penev 	if (gpio < 16) {
104595f5f25SRosen Penev 		ppc44x_clrbits32(&regs->osrl, GPIO_MASK2(gpio));
105595f5f25SRosen Penev 		ppc44x_clrbits32(&regs->tsrl, GPIO_MASK2(gpio));
10666da1ae1SRosen Penev 	} else {
107595f5f25SRosen Penev 		ppc44x_clrbits32(&regs->osrh, GPIO_MASK2(gpio));
108595f5f25SRosen Penev 		ppc44x_clrbits32(&regs->tsrh, GPIO_MASK2(gpio));
10966da1ae1SRosen Penev 	}
11066da1ae1SRosen Penev 
11166da1ae1SRosen Penev 	return 0;
11266da1ae1SRosen Penev }
11366da1ae1SRosen Penev 
11466da1ae1SRosen Penev static int
115f9476e23SRosen Penev ppc44x_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
11666da1ae1SRosen Penev {
117f9476e23SRosen Penev 	struct ppc44x_gpio_chip *chip = gpiochip_get_data(gc);
118714d445aSRosen Penev 	struct gpio_generic_chip *gen_gc = &chip->chip;
119f9476e23SRosen Penev 	struct ppc44x_gpio __iomem *regs = chip->regs;
12066da1ae1SRosen Penev 
121714d445aSRosen Penev 	guard(gpio_generic_lock_irqsave)(gen_gc);
12266da1ae1SRosen Penev 
12366da1ae1SRosen Penev 	/* First set initial value */
124f9476e23SRosen Penev 	__ppc44x_gpio_set(gc, gpio, val);
12566da1ae1SRosen Penev 
12666da1ae1SRosen Penev 	/* Disable open-drain function */
127595f5f25SRosen Penev 	ppc44x_clrbits32(&regs->odr, GPIO_MASK(gpio));
12866da1ae1SRosen Penev 
12966da1ae1SRosen Penev 	/* Drive the pin */
130595f5f25SRosen Penev 	ppc44x_setbits32(&regs->tcr, GPIO_MASK(gpio));
131714d445aSRosen Penev 	gen_gc->sdir |= GPIO_MASK(gpio);
13266da1ae1SRosen Penev 
13366da1ae1SRosen Penev 	/* Bits 0-15 use TSRL, bits 16-31 use TSRH */
13466da1ae1SRosen Penev 	if (gpio < 16) {
135595f5f25SRosen Penev 		ppc44x_clrbits32(&regs->osrl, GPIO_MASK2(gpio));
136595f5f25SRosen Penev 		ppc44x_clrbits32(&regs->tsrl, GPIO_MASK2(gpio));
13766da1ae1SRosen Penev 	} else {
138595f5f25SRosen Penev 		ppc44x_clrbits32(&regs->osrh, GPIO_MASK2(gpio));
139595f5f25SRosen Penev 		ppc44x_clrbits32(&regs->tsrh, GPIO_MASK2(gpio));
14066da1ae1SRosen Penev 	}
14166da1ae1SRosen Penev 
14266da1ae1SRosen Penev 	pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val);
14366da1ae1SRosen Penev 
14466da1ae1SRosen Penev 	return 0;
14566da1ae1SRosen Penev }
14666da1ae1SRosen Penev 
147f9476e23SRosen Penev static int ppc44x_gpio_probe(struct platform_device *ofdev)
14866da1ae1SRosen Penev {
14966da1ae1SRosen Penev 	struct device *dev = &ofdev->dev;
1508ab2d98fSRosen Penev 	struct ppc44x_gpio __iomem *regs;
151f9476e23SRosen Penev 	struct ppc44x_gpio_chip *chip;
152714d445aSRosen Penev 	struct gpio_generic_chip_config config;
15366da1ae1SRosen Penev 	struct gpio_chip *gc;
154714d445aSRosen Penev 	int ret;
15566da1ae1SRosen Penev 
1568ab2d98fSRosen Penev 	regs = devm_platform_ioremap_resource(ofdev, 0);
1578ab2d98fSRosen Penev 	if (IS_ERR(regs))
1588ab2d98fSRosen Penev 		return PTR_ERR(regs);
1598ab2d98fSRosen Penev 
16066da1ae1SRosen Penev 	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
16166da1ae1SRosen Penev 	if (!chip)
16266da1ae1SRosen Penev 		return -ENOMEM;
16366da1ae1SRosen Penev 
1648ab2d98fSRosen Penev 	chip->regs = regs;
1658ab2d98fSRosen Penev 
166714d445aSRosen Penev 	config = (struct gpio_generic_chip_config) {
167714d445aSRosen Penev 		.dev = dev,
168714d445aSRosen Penev 		.sz = 4,
169714d445aSRosen Penev 		.dat = &regs->ir,
170714d445aSRosen Penev 		.set = &regs->or,
171714d445aSRosen Penev 		.dirout = &regs->tcr,
172714d445aSRosen Penev 		.flags = GPIO_GENERIC_BIG_ENDIAN |
173714d445aSRosen Penev 			 GPIO_GENERIC_BIG_ENDIAN_BYTE_ORDER,
174714d445aSRosen Penev 	};
17566da1ae1SRosen Penev 
176714d445aSRosen Penev 	ret = gpio_generic_chip_init(&chip->chip, &config);
177714d445aSRosen Penev 	if (ret)
178714d445aSRosen Penev 		return ret;
17966da1ae1SRosen Penev 
180714d445aSRosen Penev 	gc = &chip->chip.gc;
181*98a39710SRosen Penev 	gc->label = dev_name(dev);
18266da1ae1SRosen Penev 	gc->parent = dev;
183f9476e23SRosen Penev 	gc->direction_input = ppc44x_gpio_dir_in;
184f9476e23SRosen Penev 	gc->direction_output = ppc44x_gpio_dir_out;
18566da1ae1SRosen Penev 
18666da1ae1SRosen Penev 	return devm_gpiochip_add_data(dev, gc, chip);
18766da1ae1SRosen Penev }
18866da1ae1SRosen Penev 
189f9476e23SRosen Penev static const struct of_device_id ppc44x_gpio_match[] = {
19066da1ae1SRosen Penev 	{
19166da1ae1SRosen Penev 		.compatible = "ibm,ppc4xx-gpio",
19266da1ae1SRosen Penev 	},
19366da1ae1SRosen Penev 	{},
19466da1ae1SRosen Penev };
195f9476e23SRosen Penev MODULE_DEVICE_TABLE(of, ppc44x_gpio_match);
19666da1ae1SRosen Penev 
197f9476e23SRosen Penev static struct platform_driver ppc44x_gpio_driver = {
198f9476e23SRosen Penev 	.probe		= ppc44x_gpio_probe,
19966da1ae1SRosen Penev 	.driver		= {
200f9476e23SRosen Penev 		.name	= "ppc44x-gpio",
201f9476e23SRosen Penev 		.of_match_table	= ppc44x_gpio_match,
20266da1ae1SRosen Penev 	},
20366da1ae1SRosen Penev };
20466da1ae1SRosen Penev 
205f17b0ef8SRosen Penev MODULE_DESCRIPTION("PPC44x gpio driver");
206f17b0ef8SRosen Penev MODULE_LICENSE("GPL");
207f17b0ef8SRosen Penev 
208f17b0ef8SRosen Penev module_platform_driver(ppc44x_gpio_driver);
209