162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * PPC4xx gpio driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2008 Harris Corporation 662306a36Sopenharmony_ci * Copyright (c) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix 762306a36Sopenharmony_ci * Copyright (c) MontaVista Software, Inc. 2008. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Author: Steve Falco <sfalco@harris.com> 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/kernel.h> 1362306a36Sopenharmony_ci#include <linux/init.h> 1462306a36Sopenharmony_ci#include <linux/spinlock.h> 1562306a36Sopenharmony_ci#include <linux/io.h> 1662306a36Sopenharmony_ci#include <linux/of.h> 1762306a36Sopenharmony_ci#include <linux/gpio/legacy-of-mm-gpiochip.h> 1862306a36Sopenharmony_ci#include <linux/gpio/driver.h> 1962306a36Sopenharmony_ci#include <linux/types.h> 2062306a36Sopenharmony_ci#include <linux/slab.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define GPIO_MASK(gpio) (0x80000000 >> (gpio)) 2362306a36Sopenharmony_ci#define GPIO_MASK2(gpio) (0xc0000000 >> ((gpio) * 2)) 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/* Physical GPIO register layout */ 2662306a36Sopenharmony_cistruct ppc4xx_gpio { 2762306a36Sopenharmony_ci __be32 or; 2862306a36Sopenharmony_ci __be32 tcr; 2962306a36Sopenharmony_ci __be32 osrl; 3062306a36Sopenharmony_ci __be32 osrh; 3162306a36Sopenharmony_ci __be32 tsrl; 3262306a36Sopenharmony_ci __be32 tsrh; 3362306a36Sopenharmony_ci __be32 odr; 3462306a36Sopenharmony_ci __be32 ir; 3562306a36Sopenharmony_ci __be32 rr1; 3662306a36Sopenharmony_ci __be32 rr2; 3762306a36Sopenharmony_ci __be32 rr3; 3862306a36Sopenharmony_ci __be32 reserved1; 3962306a36Sopenharmony_ci __be32 isr1l; 4062306a36Sopenharmony_ci __be32 isr1h; 4162306a36Sopenharmony_ci __be32 isr2l; 4262306a36Sopenharmony_ci __be32 isr2h; 4362306a36Sopenharmony_ci __be32 isr3l; 4462306a36Sopenharmony_ci __be32 isr3h; 4562306a36Sopenharmony_ci}; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistruct ppc4xx_gpio_chip { 4862306a36Sopenharmony_ci struct of_mm_gpio_chip mm_gc; 4962306a36Sopenharmony_ci spinlock_t lock; 5062306a36Sopenharmony_ci}; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci/* 5362306a36Sopenharmony_ci * GPIO LIB API implementation for GPIOs 5462306a36Sopenharmony_ci * 5562306a36Sopenharmony_ci * There are a maximum of 32 gpios in each gpio controller. 5662306a36Sopenharmony_ci */ 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic int ppc4xx_gpio_get(struct gpio_chip *gc, unsigned int gpio) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); 6162306a36Sopenharmony_ci struct ppc4xx_gpio __iomem *regs = mm_gc->regs; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci return !!(in_be32(®s->ir) & GPIO_MASK(gpio)); 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic inline void 6762306a36Sopenharmony_ci__ppc4xx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); 7062306a36Sopenharmony_ci struct ppc4xx_gpio __iomem *regs = mm_gc->regs; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci if (val) 7362306a36Sopenharmony_ci setbits32(®s->or, GPIO_MASK(gpio)); 7462306a36Sopenharmony_ci else 7562306a36Sopenharmony_ci clrbits32(®s->or, GPIO_MASK(gpio)); 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic void 7962306a36Sopenharmony_cippc4xx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci struct ppc4xx_gpio_chip *chip = gpiochip_get_data(gc); 8262306a36Sopenharmony_ci unsigned long flags; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci spin_lock_irqsave(&chip->lock, flags); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci __ppc4xx_gpio_set(gc, gpio, val); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci spin_unlock_irqrestore(&chip->lock, flags); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val); 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic int ppc4xx_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); 9662306a36Sopenharmony_ci struct ppc4xx_gpio_chip *chip = gpiochip_get_data(gc); 9762306a36Sopenharmony_ci struct ppc4xx_gpio __iomem *regs = mm_gc->regs; 9862306a36Sopenharmony_ci unsigned long flags; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci spin_lock_irqsave(&chip->lock, flags); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci /* Disable open-drain function */ 10362306a36Sopenharmony_ci clrbits32(®s->odr, GPIO_MASK(gpio)); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci /* Float the pin */ 10662306a36Sopenharmony_ci clrbits32(®s->tcr, GPIO_MASK(gpio)); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci /* Bits 0-15 use TSRL/OSRL, bits 16-31 use TSRH/OSRH */ 10962306a36Sopenharmony_ci if (gpio < 16) { 11062306a36Sopenharmony_ci clrbits32(®s->osrl, GPIO_MASK2(gpio)); 11162306a36Sopenharmony_ci clrbits32(®s->tsrl, GPIO_MASK2(gpio)); 11262306a36Sopenharmony_ci } else { 11362306a36Sopenharmony_ci clrbits32(®s->osrh, GPIO_MASK2(gpio)); 11462306a36Sopenharmony_ci clrbits32(®s->tsrh, GPIO_MASK2(gpio)); 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci spin_unlock_irqrestore(&chip->lock, flags); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci return 0; 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic int 12362306a36Sopenharmony_cippc4xx_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); 12662306a36Sopenharmony_ci struct ppc4xx_gpio_chip *chip = gpiochip_get_data(gc); 12762306a36Sopenharmony_ci struct ppc4xx_gpio __iomem *regs = mm_gc->regs; 12862306a36Sopenharmony_ci unsigned long flags; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci spin_lock_irqsave(&chip->lock, flags); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci /* First set initial value */ 13362306a36Sopenharmony_ci __ppc4xx_gpio_set(gc, gpio, val); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci /* Disable open-drain function */ 13662306a36Sopenharmony_ci clrbits32(®s->odr, GPIO_MASK(gpio)); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci /* Drive the pin */ 13962306a36Sopenharmony_ci setbits32(®s->tcr, GPIO_MASK(gpio)); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci /* Bits 0-15 use TSRL, bits 16-31 use TSRH */ 14262306a36Sopenharmony_ci if (gpio < 16) { 14362306a36Sopenharmony_ci clrbits32(®s->osrl, GPIO_MASK2(gpio)); 14462306a36Sopenharmony_ci clrbits32(®s->tsrl, GPIO_MASK2(gpio)); 14562306a36Sopenharmony_ci } else { 14662306a36Sopenharmony_ci clrbits32(®s->osrh, GPIO_MASK2(gpio)); 14762306a36Sopenharmony_ci clrbits32(®s->tsrh, GPIO_MASK2(gpio)); 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci spin_unlock_irqrestore(&chip->lock, flags); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci return 0; 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic int __init ppc4xx_add_gpiochips(void) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci struct device_node *np; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci for_each_compatible_node(np, NULL, "ibm,ppc4xx-gpio") { 16262306a36Sopenharmony_ci int ret; 16362306a36Sopenharmony_ci struct ppc4xx_gpio_chip *ppc4xx_gc; 16462306a36Sopenharmony_ci struct of_mm_gpio_chip *mm_gc; 16562306a36Sopenharmony_ci struct gpio_chip *gc; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci ppc4xx_gc = kzalloc(sizeof(*ppc4xx_gc), GFP_KERNEL); 16862306a36Sopenharmony_ci if (!ppc4xx_gc) { 16962306a36Sopenharmony_ci ret = -ENOMEM; 17062306a36Sopenharmony_ci goto err; 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci spin_lock_init(&ppc4xx_gc->lock); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci mm_gc = &ppc4xx_gc->mm_gc; 17662306a36Sopenharmony_ci gc = &mm_gc->gc; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci gc->ngpio = 32; 17962306a36Sopenharmony_ci gc->direction_input = ppc4xx_gpio_dir_in; 18062306a36Sopenharmony_ci gc->direction_output = ppc4xx_gpio_dir_out; 18162306a36Sopenharmony_ci gc->get = ppc4xx_gpio_get; 18262306a36Sopenharmony_ci gc->set = ppc4xx_gpio_set; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci ret = of_mm_gpiochip_add_data(np, mm_gc, ppc4xx_gc); 18562306a36Sopenharmony_ci if (ret) 18662306a36Sopenharmony_ci goto err; 18762306a36Sopenharmony_ci continue; 18862306a36Sopenharmony_cierr: 18962306a36Sopenharmony_ci pr_err("%pOF: registration failed with status %d\n", np, ret); 19062306a36Sopenharmony_ci kfree(ppc4xx_gc); 19162306a36Sopenharmony_ci /* try others anyway */ 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci return 0; 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ciarch_initcall(ppc4xx_add_gpiochips); 196