Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | // SPDX-License-Identifier: GPL-2.0-only /* * PPC4xx gpio driver * * Copyright (c) 2008 Harris Corporation * Copyright (c) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix * Copyright (c) MontaVista Software, Inc. 2008. * * Author: Steve Falco <sfalco@harris.com> */ #include <linux/kernel.h> #include <linux/init.h> #include <linux/spinlock.h> #include <linux/io.h> #include <linux/of.h> #include <linux/of_gpio.h> #include <linux/gpio/driver.h> #include <linux/types.h> #include <linux/slab.h> #define GPIO_MASK(gpio) (0x80000000 >> (gpio)) #define GPIO_MASK2(gpio) (0xc0000000 >> ((gpio) * 2)) /* Physical GPIO register layout */ struct ppc4xx_gpio { __be32 or; __be32 tcr; __be32 osrl; __be32 osrh; __be32 tsrl; __be32 tsrh; __be32 odr; __be32 ir; __be32 rr1; __be32 rr2; __be32 rr3; __be32 reserved1; __be32 isr1l; __be32 isr1h; __be32 isr2l; __be32 isr2h; __be32 isr3l; __be32 isr3h; }; struct ppc4xx_gpio_chip { struct of_mm_gpio_chip mm_gc; spinlock_t lock; }; /* * GPIO LIB API implementation for GPIOs * * There are a maximum of 32 gpios in each gpio controller. */ static int ppc4xx_gpio_get(struct gpio_chip *gc, unsigned int gpio) { struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); struct ppc4xx_gpio __iomem *regs = mm_gc->regs; return !!(in_be32(®s->ir) & GPIO_MASK(gpio)); } static inline void __ppc4xx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) { struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); struct ppc4xx_gpio __iomem *regs = mm_gc->regs; if (val) setbits32(®s->or, GPIO_MASK(gpio)); else clrbits32(®s->or, GPIO_MASK(gpio)); } static void ppc4xx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) { struct ppc4xx_gpio_chip *chip = gpiochip_get_data(gc); unsigned long flags; spin_lock_irqsave(&chip->lock, flags); __ppc4xx_gpio_set(gc, gpio, val); spin_unlock_irqrestore(&chip->lock, flags); pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val); } static int ppc4xx_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio) { struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); struct ppc4xx_gpio_chip *chip = gpiochip_get_data(gc); struct ppc4xx_gpio __iomem *regs = mm_gc->regs; unsigned long flags; spin_lock_irqsave(&chip->lock, flags); /* Disable open-drain function */ clrbits32(®s->odr, GPIO_MASK(gpio)); /* Float the pin */ clrbits32(®s->tcr, GPIO_MASK(gpio)); /* Bits 0-15 use TSRL/OSRL, bits 16-31 use TSRH/OSRH */ if (gpio < 16) { clrbits32(®s->osrl, GPIO_MASK2(gpio)); clrbits32(®s->tsrl, GPIO_MASK2(gpio)); } else { clrbits32(®s->osrh, GPIO_MASK2(gpio)); clrbits32(®s->tsrh, GPIO_MASK2(gpio)); } spin_unlock_irqrestore(&chip->lock, flags); return 0; } static int ppc4xx_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) { struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); struct ppc4xx_gpio_chip *chip = gpiochip_get_data(gc); struct ppc4xx_gpio __iomem *regs = mm_gc->regs; unsigned long flags; spin_lock_irqsave(&chip->lock, flags); /* First set initial value */ __ppc4xx_gpio_set(gc, gpio, val); /* Disable open-drain function */ clrbits32(®s->odr, GPIO_MASK(gpio)); /* Drive the pin */ setbits32(®s->tcr, GPIO_MASK(gpio)); /* Bits 0-15 use TSRL, bits 16-31 use TSRH */ if (gpio < 16) { clrbits32(®s->osrl, GPIO_MASK2(gpio)); clrbits32(®s->tsrl, GPIO_MASK2(gpio)); } else { clrbits32(®s->osrh, GPIO_MASK2(gpio)); clrbits32(®s->tsrh, GPIO_MASK2(gpio)); } spin_unlock_irqrestore(&chip->lock, flags); pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val); return 0; } static int __init ppc4xx_add_gpiochips(void) { struct device_node *np; for_each_compatible_node(np, NULL, "ibm,ppc4xx-gpio") { int ret; struct ppc4xx_gpio_chip *ppc4xx_gc; struct of_mm_gpio_chip *mm_gc; struct gpio_chip *gc; ppc4xx_gc = kzalloc(sizeof(*ppc4xx_gc), GFP_KERNEL); if (!ppc4xx_gc) { ret = -ENOMEM; goto err; } spin_lock_init(&ppc4xx_gc->lock); mm_gc = &ppc4xx_gc->mm_gc; gc = &mm_gc->gc; gc->ngpio = 32; gc->direction_input = ppc4xx_gpio_dir_in; gc->direction_output = ppc4xx_gpio_dir_out; gc->get = ppc4xx_gpio_get; gc->set = ppc4xx_gpio_set; ret = of_mm_gpiochip_add_data(np, mm_gc, ppc4xx_gc); if (ret) goto err; continue; err: pr_err("%pOF: registration failed with status %d\n", np, ret); kfree(ppc4xx_gc); /* try others anyway */ } return 0; } arch_initcall(ppc4xx_add_gpiochips); |