18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * QUICC Engine GPIOs 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) MontaVista Software, Inc. 2008. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Anton Vorontsov <avorontsov@ru.mvista.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/init.h> 128c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 138c2ecf20Sopenharmony_ci#include <linux/err.h> 148c2ecf20Sopenharmony_ci#include <linux/io.h> 158c2ecf20Sopenharmony_ci#include <linux/of.h> 168c2ecf20Sopenharmony_ci#include <linux/of_gpio.h> 178c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h> 188c2ecf20Sopenharmony_ci/* FIXME: needed for gpio_to_chip() get rid of this */ 198c2ecf20Sopenharmony_ci#include <linux/gpio.h> 208c2ecf20Sopenharmony_ci#include <linux/slab.h> 218c2ecf20Sopenharmony_ci#include <linux/export.h> 228c2ecf20Sopenharmony_ci#include <soc/fsl/qe/qe.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistruct qe_gpio_chip { 258c2ecf20Sopenharmony_ci struct of_mm_gpio_chip mm_gc; 268c2ecf20Sopenharmony_ci spinlock_t lock; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci unsigned long pin_flags[QE_PIO_PINS]; 298c2ecf20Sopenharmony_ci#define QE_PIN_REQUESTED 0 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci /* shadowed data register to clear/set bits safely */ 328c2ecf20Sopenharmony_ci u32 cpdata; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci /* saved_regs used to restore dedicated functions */ 358c2ecf20Sopenharmony_ci struct qe_pio_regs saved_regs; 368c2ecf20Sopenharmony_ci}; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic void qe_gpio_save_regs(struct of_mm_gpio_chip *mm_gc) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci struct qe_gpio_chip *qe_gc = 418c2ecf20Sopenharmony_ci container_of(mm_gc, struct qe_gpio_chip, mm_gc); 428c2ecf20Sopenharmony_ci struct qe_pio_regs __iomem *regs = mm_gc->regs; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci qe_gc->cpdata = qe_ioread32be(®s->cpdata); 458c2ecf20Sopenharmony_ci qe_gc->saved_regs.cpdata = qe_gc->cpdata; 468c2ecf20Sopenharmony_ci qe_gc->saved_regs.cpdir1 = qe_ioread32be(®s->cpdir1); 478c2ecf20Sopenharmony_ci qe_gc->saved_regs.cpdir2 = qe_ioread32be(®s->cpdir2); 488c2ecf20Sopenharmony_ci qe_gc->saved_regs.cppar1 = qe_ioread32be(®s->cppar1); 498c2ecf20Sopenharmony_ci qe_gc->saved_regs.cppar2 = qe_ioread32be(®s->cppar2); 508c2ecf20Sopenharmony_ci qe_gc->saved_regs.cpodr = qe_ioread32be(®s->cpodr); 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic int qe_gpio_get(struct gpio_chip *gc, unsigned int gpio) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); 568c2ecf20Sopenharmony_ci struct qe_pio_regs __iomem *regs = mm_gc->regs; 578c2ecf20Sopenharmony_ci u32 pin_mask = 1 << (QE_PIO_PINS - 1 - gpio); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci return !!(qe_ioread32be(®s->cpdata) & pin_mask); 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic void qe_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); 658c2ecf20Sopenharmony_ci struct qe_gpio_chip *qe_gc = gpiochip_get_data(gc); 668c2ecf20Sopenharmony_ci struct qe_pio_regs __iomem *regs = mm_gc->regs; 678c2ecf20Sopenharmony_ci unsigned long flags; 688c2ecf20Sopenharmony_ci u32 pin_mask = 1 << (QE_PIO_PINS - 1 - gpio); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci spin_lock_irqsave(&qe_gc->lock, flags); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci if (val) 738c2ecf20Sopenharmony_ci qe_gc->cpdata |= pin_mask; 748c2ecf20Sopenharmony_ci else 758c2ecf20Sopenharmony_ci qe_gc->cpdata &= ~pin_mask; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci qe_iowrite32be(qe_gc->cpdata, ®s->cpdata); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qe_gc->lock, flags); 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic void qe_gpio_set_multiple(struct gpio_chip *gc, 838c2ecf20Sopenharmony_ci unsigned long *mask, unsigned long *bits) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); 868c2ecf20Sopenharmony_ci struct qe_gpio_chip *qe_gc = gpiochip_get_data(gc); 878c2ecf20Sopenharmony_ci struct qe_pio_regs __iomem *regs = mm_gc->regs; 888c2ecf20Sopenharmony_ci unsigned long flags; 898c2ecf20Sopenharmony_ci int i; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci spin_lock_irqsave(&qe_gc->lock, flags); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci for (i = 0; i < gc->ngpio; i++) { 948c2ecf20Sopenharmony_ci if (*mask == 0) 958c2ecf20Sopenharmony_ci break; 968c2ecf20Sopenharmony_ci if (__test_and_clear_bit(i, mask)) { 978c2ecf20Sopenharmony_ci if (test_bit(i, bits)) 988c2ecf20Sopenharmony_ci qe_gc->cpdata |= (1U << (QE_PIO_PINS - 1 - i)); 998c2ecf20Sopenharmony_ci else 1008c2ecf20Sopenharmony_ci qe_gc->cpdata &= ~(1U << (QE_PIO_PINS - 1 - i)); 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci qe_iowrite32be(qe_gc->cpdata, ®s->cpdata); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qe_gc->lock, flags); 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic int qe_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); 1128c2ecf20Sopenharmony_ci struct qe_gpio_chip *qe_gc = gpiochip_get_data(gc); 1138c2ecf20Sopenharmony_ci unsigned long flags; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci spin_lock_irqsave(&qe_gc->lock, flags); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci __par_io_config_pin(mm_gc->regs, gpio, QE_PIO_DIR_IN, 0, 0, 0); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qe_gc->lock, flags); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci return 0; 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic int qe_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); 1278c2ecf20Sopenharmony_ci struct qe_gpio_chip *qe_gc = gpiochip_get_data(gc); 1288c2ecf20Sopenharmony_ci unsigned long flags; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci qe_gpio_set(gc, gpio, val); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci spin_lock_irqsave(&qe_gc->lock, flags); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci __par_io_config_pin(mm_gc->regs, gpio, QE_PIO_DIR_OUT, 0, 0, 0); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qe_gc->lock, flags); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci return 0; 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistruct qe_pin { 1428c2ecf20Sopenharmony_ci /* 1438c2ecf20Sopenharmony_ci * The qe_gpio_chip name is unfortunate, we should change that to 1448c2ecf20Sopenharmony_ci * something like qe_pio_controller. Someday. 1458c2ecf20Sopenharmony_ci */ 1468c2ecf20Sopenharmony_ci struct qe_gpio_chip *controller; 1478c2ecf20Sopenharmony_ci int num; 1488c2ecf20Sopenharmony_ci}; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci/** 1518c2ecf20Sopenharmony_ci * qe_pin_request - Request a QE pin 1528c2ecf20Sopenharmony_ci * @np: device node to get a pin from 1538c2ecf20Sopenharmony_ci * @index: index of a pin in the device tree 1548c2ecf20Sopenharmony_ci * Context: non-atomic 1558c2ecf20Sopenharmony_ci * 1568c2ecf20Sopenharmony_ci * This function return qe_pin so that you could use it with the rest of 1578c2ecf20Sopenharmony_ci * the QE Pin Multiplexing API. 1588c2ecf20Sopenharmony_ci */ 1598c2ecf20Sopenharmony_cistruct qe_pin *qe_pin_request(struct device_node *np, int index) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci struct qe_pin *qe_pin; 1628c2ecf20Sopenharmony_ci struct gpio_chip *gc; 1638c2ecf20Sopenharmony_ci struct qe_gpio_chip *qe_gc; 1648c2ecf20Sopenharmony_ci int err; 1658c2ecf20Sopenharmony_ci unsigned long flags; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci qe_pin = kzalloc(sizeof(*qe_pin), GFP_KERNEL); 1688c2ecf20Sopenharmony_ci if (!qe_pin) { 1698c2ecf20Sopenharmony_ci pr_debug("%s: can't allocate memory\n", __func__); 1708c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci err = of_get_gpio(np, index); 1748c2ecf20Sopenharmony_ci if (err < 0) 1758c2ecf20Sopenharmony_ci goto err0; 1768c2ecf20Sopenharmony_ci gc = gpio_to_chip(err); 1778c2ecf20Sopenharmony_ci if (WARN_ON(!gc)) { 1788c2ecf20Sopenharmony_ci err = -ENODEV; 1798c2ecf20Sopenharmony_ci goto err0; 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci if (!of_device_is_compatible(gc->of_node, "fsl,mpc8323-qe-pario-bank")) { 1838c2ecf20Sopenharmony_ci pr_debug("%s: tried to get a non-qe pin\n", __func__); 1848c2ecf20Sopenharmony_ci err = -EINVAL; 1858c2ecf20Sopenharmony_ci goto err0; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci qe_gc = gpiochip_get_data(gc); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci spin_lock_irqsave(&qe_gc->lock, flags); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci err -= gc->base; 1938c2ecf20Sopenharmony_ci if (test_and_set_bit(QE_PIN_REQUESTED, &qe_gc->pin_flags[err]) == 0) { 1948c2ecf20Sopenharmony_ci qe_pin->controller = qe_gc; 1958c2ecf20Sopenharmony_ci qe_pin->num = err; 1968c2ecf20Sopenharmony_ci err = 0; 1978c2ecf20Sopenharmony_ci } else { 1988c2ecf20Sopenharmony_ci err = -EBUSY; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qe_gc->lock, flags); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci if (!err) 2048c2ecf20Sopenharmony_ci return qe_pin; 2058c2ecf20Sopenharmony_cierr0: 2068c2ecf20Sopenharmony_ci kfree(qe_pin); 2078c2ecf20Sopenharmony_ci pr_debug("%s failed with status %d\n", __func__, err); 2088c2ecf20Sopenharmony_ci return ERR_PTR(err); 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ciEXPORT_SYMBOL(qe_pin_request); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci/** 2138c2ecf20Sopenharmony_ci * qe_pin_free - Free a pin 2148c2ecf20Sopenharmony_ci * @qe_pin: pointer to the qe_pin structure 2158c2ecf20Sopenharmony_ci * Context: any 2168c2ecf20Sopenharmony_ci * 2178c2ecf20Sopenharmony_ci * This function frees the qe_pin structure and makes a pin available 2188c2ecf20Sopenharmony_ci * for further qe_pin_request() calls. 2198c2ecf20Sopenharmony_ci */ 2208c2ecf20Sopenharmony_civoid qe_pin_free(struct qe_pin *qe_pin) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci struct qe_gpio_chip *qe_gc = qe_pin->controller; 2238c2ecf20Sopenharmony_ci unsigned long flags; 2248c2ecf20Sopenharmony_ci const int pin = qe_pin->num; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci spin_lock_irqsave(&qe_gc->lock, flags); 2278c2ecf20Sopenharmony_ci test_and_clear_bit(QE_PIN_REQUESTED, &qe_gc->pin_flags[pin]); 2288c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qe_gc->lock, flags); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci kfree(qe_pin); 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ciEXPORT_SYMBOL(qe_pin_free); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci/** 2358c2ecf20Sopenharmony_ci * qe_pin_set_dedicated - Revert a pin to a dedicated peripheral function mode 2368c2ecf20Sopenharmony_ci * @qe_pin: pointer to the qe_pin structure 2378c2ecf20Sopenharmony_ci * Context: any 2388c2ecf20Sopenharmony_ci * 2398c2ecf20Sopenharmony_ci * This function resets a pin to a dedicated peripheral function that 2408c2ecf20Sopenharmony_ci * has been set up by the firmware. 2418c2ecf20Sopenharmony_ci */ 2428c2ecf20Sopenharmony_civoid qe_pin_set_dedicated(struct qe_pin *qe_pin) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci struct qe_gpio_chip *qe_gc = qe_pin->controller; 2458c2ecf20Sopenharmony_ci struct qe_pio_regs __iomem *regs = qe_gc->mm_gc.regs; 2468c2ecf20Sopenharmony_ci struct qe_pio_regs *sregs = &qe_gc->saved_regs; 2478c2ecf20Sopenharmony_ci int pin = qe_pin->num; 2488c2ecf20Sopenharmony_ci u32 mask1 = 1 << (QE_PIO_PINS - (pin + 1)); 2498c2ecf20Sopenharmony_ci u32 mask2 = 0x3 << (QE_PIO_PINS - (pin % (QE_PIO_PINS / 2) + 1) * 2); 2508c2ecf20Sopenharmony_ci bool second_reg = pin > (QE_PIO_PINS / 2) - 1; 2518c2ecf20Sopenharmony_ci unsigned long flags; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci spin_lock_irqsave(&qe_gc->lock, flags); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci if (second_reg) { 2568c2ecf20Sopenharmony_ci qe_clrsetbits_be32(®s->cpdir2, mask2, 2578c2ecf20Sopenharmony_ci sregs->cpdir2 & mask2); 2588c2ecf20Sopenharmony_ci qe_clrsetbits_be32(®s->cppar2, mask2, 2598c2ecf20Sopenharmony_ci sregs->cppar2 & mask2); 2608c2ecf20Sopenharmony_ci } else { 2618c2ecf20Sopenharmony_ci qe_clrsetbits_be32(®s->cpdir1, mask2, 2628c2ecf20Sopenharmony_ci sregs->cpdir1 & mask2); 2638c2ecf20Sopenharmony_ci qe_clrsetbits_be32(®s->cppar1, mask2, 2648c2ecf20Sopenharmony_ci sregs->cppar1 & mask2); 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (sregs->cpdata & mask1) 2688c2ecf20Sopenharmony_ci qe_gc->cpdata |= mask1; 2698c2ecf20Sopenharmony_ci else 2708c2ecf20Sopenharmony_ci qe_gc->cpdata &= ~mask1; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci qe_iowrite32be(qe_gc->cpdata, ®s->cpdata); 2738c2ecf20Sopenharmony_ci qe_clrsetbits_be32(®s->cpodr, mask1, sregs->cpodr & mask1); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qe_gc->lock, flags); 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ciEXPORT_SYMBOL(qe_pin_set_dedicated); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci/** 2808c2ecf20Sopenharmony_ci * qe_pin_set_gpio - Set a pin to the GPIO mode 2818c2ecf20Sopenharmony_ci * @qe_pin: pointer to the qe_pin structure 2828c2ecf20Sopenharmony_ci * Context: any 2838c2ecf20Sopenharmony_ci * 2848c2ecf20Sopenharmony_ci * This function sets a pin to the GPIO mode. 2858c2ecf20Sopenharmony_ci */ 2868c2ecf20Sopenharmony_civoid qe_pin_set_gpio(struct qe_pin *qe_pin) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci struct qe_gpio_chip *qe_gc = qe_pin->controller; 2898c2ecf20Sopenharmony_ci struct qe_pio_regs __iomem *regs = qe_gc->mm_gc.regs; 2908c2ecf20Sopenharmony_ci unsigned long flags; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci spin_lock_irqsave(&qe_gc->lock, flags); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci /* Let's make it input by default, GPIO API is able to change that. */ 2958c2ecf20Sopenharmony_ci __par_io_config_pin(regs, qe_pin->num, QE_PIO_DIR_IN, 0, 0, 0); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qe_gc->lock, flags); 2988c2ecf20Sopenharmony_ci} 2998c2ecf20Sopenharmony_ciEXPORT_SYMBOL(qe_pin_set_gpio); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic int __init qe_add_gpiochips(void) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci struct device_node *np; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci for_each_compatible_node(np, NULL, "fsl,mpc8323-qe-pario-bank") { 3068c2ecf20Sopenharmony_ci int ret; 3078c2ecf20Sopenharmony_ci struct qe_gpio_chip *qe_gc; 3088c2ecf20Sopenharmony_ci struct of_mm_gpio_chip *mm_gc; 3098c2ecf20Sopenharmony_ci struct gpio_chip *gc; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci qe_gc = kzalloc(sizeof(*qe_gc), GFP_KERNEL); 3128c2ecf20Sopenharmony_ci if (!qe_gc) { 3138c2ecf20Sopenharmony_ci ret = -ENOMEM; 3148c2ecf20Sopenharmony_ci goto err; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci spin_lock_init(&qe_gc->lock); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci mm_gc = &qe_gc->mm_gc; 3208c2ecf20Sopenharmony_ci gc = &mm_gc->gc; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci mm_gc->save_regs = qe_gpio_save_regs; 3238c2ecf20Sopenharmony_ci gc->ngpio = QE_PIO_PINS; 3248c2ecf20Sopenharmony_ci gc->direction_input = qe_gpio_dir_in; 3258c2ecf20Sopenharmony_ci gc->direction_output = qe_gpio_dir_out; 3268c2ecf20Sopenharmony_ci gc->get = qe_gpio_get; 3278c2ecf20Sopenharmony_ci gc->set = qe_gpio_set; 3288c2ecf20Sopenharmony_ci gc->set_multiple = qe_gpio_set_multiple; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci ret = of_mm_gpiochip_add_data(np, mm_gc, qe_gc); 3318c2ecf20Sopenharmony_ci if (ret) 3328c2ecf20Sopenharmony_ci goto err; 3338c2ecf20Sopenharmony_ci continue; 3348c2ecf20Sopenharmony_cierr: 3358c2ecf20Sopenharmony_ci pr_err("%pOF: registration failed with status %d\n", 3368c2ecf20Sopenharmony_ci np, ret); 3378c2ecf20Sopenharmony_ci kfree(qe_gc); 3388c2ecf20Sopenharmony_ci /* try others anyway */ 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci return 0; 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ciarch_initcall(qe_add_gpiochips); 343