18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * GPIO driver for LPC32xx SoC 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author: Kevin Wells <kevin.wells@nxp.com> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 2010 NXP Semiconductors 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/init.h> 128c2ecf20Sopenharmony_ci#include <linux/io.h> 138c2ecf20Sopenharmony_ci#include <linux/errno.h> 148c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h> 158c2ecf20Sopenharmony_ci#include <linux/of.h> 168c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define LPC32XX_GPIO_P3_INP_STATE (0x000) 208c2ecf20Sopenharmony_ci#define LPC32XX_GPIO_P3_OUTP_SET (0x004) 218c2ecf20Sopenharmony_ci#define LPC32XX_GPIO_P3_OUTP_CLR (0x008) 228c2ecf20Sopenharmony_ci#define LPC32XX_GPIO_P3_OUTP_STATE (0x00C) 238c2ecf20Sopenharmony_ci#define LPC32XX_GPIO_P2_DIR_SET (0x010) 248c2ecf20Sopenharmony_ci#define LPC32XX_GPIO_P2_DIR_CLR (0x014) 258c2ecf20Sopenharmony_ci#define LPC32XX_GPIO_P2_DIR_STATE (0x018) 268c2ecf20Sopenharmony_ci#define LPC32XX_GPIO_P2_INP_STATE (0x01C) 278c2ecf20Sopenharmony_ci#define LPC32XX_GPIO_P2_OUTP_SET (0x020) 288c2ecf20Sopenharmony_ci#define LPC32XX_GPIO_P2_OUTP_CLR (0x024) 298c2ecf20Sopenharmony_ci#define LPC32XX_GPIO_P2_MUX_SET (0x028) 308c2ecf20Sopenharmony_ci#define LPC32XX_GPIO_P2_MUX_CLR (0x02C) 318c2ecf20Sopenharmony_ci#define LPC32XX_GPIO_P2_MUX_STATE (0x030) 328c2ecf20Sopenharmony_ci#define LPC32XX_GPIO_P0_INP_STATE (0x040) 338c2ecf20Sopenharmony_ci#define LPC32XX_GPIO_P0_OUTP_SET (0x044) 348c2ecf20Sopenharmony_ci#define LPC32XX_GPIO_P0_OUTP_CLR (0x048) 358c2ecf20Sopenharmony_ci#define LPC32XX_GPIO_P0_OUTP_STATE (0x04C) 368c2ecf20Sopenharmony_ci#define LPC32XX_GPIO_P0_DIR_SET (0x050) 378c2ecf20Sopenharmony_ci#define LPC32XX_GPIO_P0_DIR_CLR (0x054) 388c2ecf20Sopenharmony_ci#define LPC32XX_GPIO_P0_DIR_STATE (0x058) 398c2ecf20Sopenharmony_ci#define LPC32XX_GPIO_P1_INP_STATE (0x060) 408c2ecf20Sopenharmony_ci#define LPC32XX_GPIO_P1_OUTP_SET (0x064) 418c2ecf20Sopenharmony_ci#define LPC32XX_GPIO_P1_OUTP_CLR (0x068) 428c2ecf20Sopenharmony_ci#define LPC32XX_GPIO_P1_OUTP_STATE (0x06C) 438c2ecf20Sopenharmony_ci#define LPC32XX_GPIO_P1_DIR_SET (0x070) 448c2ecf20Sopenharmony_ci#define LPC32XX_GPIO_P1_DIR_CLR (0x074) 458c2ecf20Sopenharmony_ci#define LPC32XX_GPIO_P1_DIR_STATE (0x078) 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#define GPIO012_PIN_TO_BIT(x) (1 << (x)) 488c2ecf20Sopenharmony_ci#define GPIO3_PIN_TO_BIT(x) (1 << ((x) + 25)) 498c2ecf20Sopenharmony_ci#define GPO3_PIN_TO_BIT(x) (1 << (x)) 508c2ecf20Sopenharmony_ci#define GPIO012_PIN_IN_SEL(x, y) (((x) >> (y)) & 1) 518c2ecf20Sopenharmony_ci#define GPIO3_PIN_IN_SHIFT(x) ((x) == 5 ? 24 : 10 + (x)) 528c2ecf20Sopenharmony_ci#define GPIO3_PIN_IN_SEL(x, y) (((x) >> GPIO3_PIN_IN_SHIFT(y)) & 1) 538c2ecf20Sopenharmony_ci#define GPIO3_PIN5_IN_SEL(x) (((x) >> 24) & 1) 548c2ecf20Sopenharmony_ci#define GPI3_PIN_IN_SEL(x, y) (((x) >> (y)) & 1) 558c2ecf20Sopenharmony_ci#define GPO3_PIN_IN_SEL(x, y) (((x) >> (y)) & 1) 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#define LPC32XX_GPIO_P0_MAX 8 588c2ecf20Sopenharmony_ci#define LPC32XX_GPIO_P1_MAX 24 598c2ecf20Sopenharmony_ci#define LPC32XX_GPIO_P2_MAX 13 608c2ecf20Sopenharmony_ci#define LPC32XX_GPIO_P3_MAX 6 618c2ecf20Sopenharmony_ci#define LPC32XX_GPI_P3_MAX 29 628c2ecf20Sopenharmony_ci#define LPC32XX_GPO_P3_MAX 24 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#define LPC32XX_GPIO_P0_GRP 0 658c2ecf20Sopenharmony_ci#define LPC32XX_GPIO_P1_GRP (LPC32XX_GPIO_P0_GRP + LPC32XX_GPIO_P0_MAX) 668c2ecf20Sopenharmony_ci#define LPC32XX_GPIO_P2_GRP (LPC32XX_GPIO_P1_GRP + LPC32XX_GPIO_P1_MAX) 678c2ecf20Sopenharmony_ci#define LPC32XX_GPIO_P3_GRP (LPC32XX_GPIO_P2_GRP + LPC32XX_GPIO_P2_MAX) 688c2ecf20Sopenharmony_ci#define LPC32XX_GPI_P3_GRP (LPC32XX_GPIO_P3_GRP + LPC32XX_GPIO_P3_MAX) 698c2ecf20Sopenharmony_ci#define LPC32XX_GPO_P3_GRP (LPC32XX_GPI_P3_GRP + LPC32XX_GPI_P3_MAX) 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistruct gpio_regs { 728c2ecf20Sopenharmony_ci unsigned long inp_state; 738c2ecf20Sopenharmony_ci unsigned long outp_state; 748c2ecf20Sopenharmony_ci unsigned long outp_set; 758c2ecf20Sopenharmony_ci unsigned long outp_clr; 768c2ecf20Sopenharmony_ci unsigned long dir_set; 778c2ecf20Sopenharmony_ci unsigned long dir_clr; 788c2ecf20Sopenharmony_ci}; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci/* 818c2ecf20Sopenharmony_ci * GPIO names 828c2ecf20Sopenharmony_ci */ 838c2ecf20Sopenharmony_cistatic const char *gpio_p0_names[LPC32XX_GPIO_P0_MAX] = { 848c2ecf20Sopenharmony_ci "p0.0", "p0.1", "p0.2", "p0.3", 858c2ecf20Sopenharmony_ci "p0.4", "p0.5", "p0.6", "p0.7" 868c2ecf20Sopenharmony_ci}; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic const char *gpio_p1_names[LPC32XX_GPIO_P1_MAX] = { 898c2ecf20Sopenharmony_ci "p1.0", "p1.1", "p1.2", "p1.3", 908c2ecf20Sopenharmony_ci "p1.4", "p1.5", "p1.6", "p1.7", 918c2ecf20Sopenharmony_ci "p1.8", "p1.9", "p1.10", "p1.11", 928c2ecf20Sopenharmony_ci "p1.12", "p1.13", "p1.14", "p1.15", 938c2ecf20Sopenharmony_ci "p1.16", "p1.17", "p1.18", "p1.19", 948c2ecf20Sopenharmony_ci "p1.20", "p1.21", "p1.22", "p1.23", 958c2ecf20Sopenharmony_ci}; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic const char *gpio_p2_names[LPC32XX_GPIO_P2_MAX] = { 988c2ecf20Sopenharmony_ci "p2.0", "p2.1", "p2.2", "p2.3", 998c2ecf20Sopenharmony_ci "p2.4", "p2.5", "p2.6", "p2.7", 1008c2ecf20Sopenharmony_ci "p2.8", "p2.9", "p2.10", "p2.11", 1018c2ecf20Sopenharmony_ci "p2.12" 1028c2ecf20Sopenharmony_ci}; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic const char *gpio_p3_names[LPC32XX_GPIO_P3_MAX] = { 1058c2ecf20Sopenharmony_ci "gpio00", "gpio01", "gpio02", "gpio03", 1068c2ecf20Sopenharmony_ci "gpio04", "gpio05" 1078c2ecf20Sopenharmony_ci}; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic const char *gpi_p3_names[LPC32XX_GPI_P3_MAX] = { 1108c2ecf20Sopenharmony_ci "gpi00", "gpi01", "gpi02", "gpi03", 1118c2ecf20Sopenharmony_ci "gpi04", "gpi05", "gpi06", "gpi07", 1128c2ecf20Sopenharmony_ci "gpi08", "gpi09", NULL, NULL, 1138c2ecf20Sopenharmony_ci NULL, NULL, NULL, "gpi15", 1148c2ecf20Sopenharmony_ci "gpi16", "gpi17", "gpi18", "gpi19", 1158c2ecf20Sopenharmony_ci "gpi20", "gpi21", "gpi22", "gpi23", 1168c2ecf20Sopenharmony_ci "gpi24", "gpi25", "gpi26", "gpi27", 1178c2ecf20Sopenharmony_ci "gpi28" 1188c2ecf20Sopenharmony_ci}; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic const char *gpo_p3_names[LPC32XX_GPO_P3_MAX] = { 1218c2ecf20Sopenharmony_ci "gpo00", "gpo01", "gpo02", "gpo03", 1228c2ecf20Sopenharmony_ci "gpo04", "gpo05", "gpo06", "gpo07", 1238c2ecf20Sopenharmony_ci "gpo08", "gpo09", "gpo10", "gpo11", 1248c2ecf20Sopenharmony_ci "gpo12", "gpo13", "gpo14", "gpo15", 1258c2ecf20Sopenharmony_ci "gpo16", "gpo17", "gpo18", "gpo19", 1268c2ecf20Sopenharmony_ci "gpo20", "gpo21", "gpo22", "gpo23" 1278c2ecf20Sopenharmony_ci}; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic struct gpio_regs gpio_grp_regs_p0 = { 1308c2ecf20Sopenharmony_ci .inp_state = LPC32XX_GPIO_P0_INP_STATE, 1318c2ecf20Sopenharmony_ci .outp_set = LPC32XX_GPIO_P0_OUTP_SET, 1328c2ecf20Sopenharmony_ci .outp_clr = LPC32XX_GPIO_P0_OUTP_CLR, 1338c2ecf20Sopenharmony_ci .dir_set = LPC32XX_GPIO_P0_DIR_SET, 1348c2ecf20Sopenharmony_ci .dir_clr = LPC32XX_GPIO_P0_DIR_CLR, 1358c2ecf20Sopenharmony_ci}; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic struct gpio_regs gpio_grp_regs_p1 = { 1388c2ecf20Sopenharmony_ci .inp_state = LPC32XX_GPIO_P1_INP_STATE, 1398c2ecf20Sopenharmony_ci .outp_set = LPC32XX_GPIO_P1_OUTP_SET, 1408c2ecf20Sopenharmony_ci .outp_clr = LPC32XX_GPIO_P1_OUTP_CLR, 1418c2ecf20Sopenharmony_ci .dir_set = LPC32XX_GPIO_P1_DIR_SET, 1428c2ecf20Sopenharmony_ci .dir_clr = LPC32XX_GPIO_P1_DIR_CLR, 1438c2ecf20Sopenharmony_ci}; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic struct gpio_regs gpio_grp_regs_p2 = { 1468c2ecf20Sopenharmony_ci .inp_state = LPC32XX_GPIO_P2_INP_STATE, 1478c2ecf20Sopenharmony_ci .outp_set = LPC32XX_GPIO_P2_OUTP_SET, 1488c2ecf20Sopenharmony_ci .outp_clr = LPC32XX_GPIO_P2_OUTP_CLR, 1498c2ecf20Sopenharmony_ci .dir_set = LPC32XX_GPIO_P2_DIR_SET, 1508c2ecf20Sopenharmony_ci .dir_clr = LPC32XX_GPIO_P2_DIR_CLR, 1518c2ecf20Sopenharmony_ci}; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic struct gpio_regs gpio_grp_regs_p3 = { 1548c2ecf20Sopenharmony_ci .inp_state = LPC32XX_GPIO_P3_INP_STATE, 1558c2ecf20Sopenharmony_ci .outp_state = LPC32XX_GPIO_P3_OUTP_STATE, 1568c2ecf20Sopenharmony_ci .outp_set = LPC32XX_GPIO_P3_OUTP_SET, 1578c2ecf20Sopenharmony_ci .outp_clr = LPC32XX_GPIO_P3_OUTP_CLR, 1588c2ecf20Sopenharmony_ci .dir_set = LPC32XX_GPIO_P2_DIR_SET, 1598c2ecf20Sopenharmony_ci .dir_clr = LPC32XX_GPIO_P2_DIR_CLR, 1608c2ecf20Sopenharmony_ci}; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistruct lpc32xx_gpio_chip { 1638c2ecf20Sopenharmony_ci struct gpio_chip chip; 1648c2ecf20Sopenharmony_ci struct gpio_regs *gpio_grp; 1658c2ecf20Sopenharmony_ci void __iomem *reg_base; 1668c2ecf20Sopenharmony_ci}; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic inline u32 gpreg_read(struct lpc32xx_gpio_chip *group, unsigned long offset) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci return __raw_readl(group->reg_base + offset); 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic inline void gpreg_write(struct lpc32xx_gpio_chip *group, u32 val, unsigned long offset) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci __raw_writel(val, group->reg_base + offset); 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistatic void __set_gpio_dir_p012(struct lpc32xx_gpio_chip *group, 1798c2ecf20Sopenharmony_ci unsigned pin, int input) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci if (input) 1828c2ecf20Sopenharmony_ci gpreg_write(group, GPIO012_PIN_TO_BIT(pin), 1838c2ecf20Sopenharmony_ci group->gpio_grp->dir_clr); 1848c2ecf20Sopenharmony_ci else 1858c2ecf20Sopenharmony_ci gpreg_write(group, GPIO012_PIN_TO_BIT(pin), 1868c2ecf20Sopenharmony_ci group->gpio_grp->dir_set); 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic void __set_gpio_dir_p3(struct lpc32xx_gpio_chip *group, 1908c2ecf20Sopenharmony_ci unsigned pin, int input) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci u32 u = GPIO3_PIN_TO_BIT(pin); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (input) 1958c2ecf20Sopenharmony_ci gpreg_write(group, u, group->gpio_grp->dir_clr); 1968c2ecf20Sopenharmony_ci else 1978c2ecf20Sopenharmony_ci gpreg_write(group, u, group->gpio_grp->dir_set); 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic void __set_gpio_level_p012(struct lpc32xx_gpio_chip *group, 2018c2ecf20Sopenharmony_ci unsigned pin, int high) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci if (high) 2048c2ecf20Sopenharmony_ci gpreg_write(group, GPIO012_PIN_TO_BIT(pin), 2058c2ecf20Sopenharmony_ci group->gpio_grp->outp_set); 2068c2ecf20Sopenharmony_ci else 2078c2ecf20Sopenharmony_ci gpreg_write(group, GPIO012_PIN_TO_BIT(pin), 2088c2ecf20Sopenharmony_ci group->gpio_grp->outp_clr); 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic void __set_gpio_level_p3(struct lpc32xx_gpio_chip *group, 2128c2ecf20Sopenharmony_ci unsigned pin, int high) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci u32 u = GPIO3_PIN_TO_BIT(pin); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci if (high) 2178c2ecf20Sopenharmony_ci gpreg_write(group, u, group->gpio_grp->outp_set); 2188c2ecf20Sopenharmony_ci else 2198c2ecf20Sopenharmony_ci gpreg_write(group, u, group->gpio_grp->outp_clr); 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cistatic void __set_gpo_level_p3(struct lpc32xx_gpio_chip *group, 2238c2ecf20Sopenharmony_ci unsigned pin, int high) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci if (high) 2268c2ecf20Sopenharmony_ci gpreg_write(group, GPO3_PIN_TO_BIT(pin), group->gpio_grp->outp_set); 2278c2ecf20Sopenharmony_ci else 2288c2ecf20Sopenharmony_ci gpreg_write(group, GPO3_PIN_TO_BIT(pin), group->gpio_grp->outp_clr); 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic int __get_gpio_state_p012(struct lpc32xx_gpio_chip *group, 2328c2ecf20Sopenharmony_ci unsigned pin) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci return GPIO012_PIN_IN_SEL(gpreg_read(group, group->gpio_grp->inp_state), 2358c2ecf20Sopenharmony_ci pin); 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic int __get_gpio_state_p3(struct lpc32xx_gpio_chip *group, 2398c2ecf20Sopenharmony_ci unsigned pin) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci int state = gpreg_read(group, group->gpio_grp->inp_state); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci /* 2448c2ecf20Sopenharmony_ci * P3 GPIO pin input mapping is not contiguous, GPIOP3-0..4 is mapped 2458c2ecf20Sopenharmony_ci * to bits 10..14, while GPIOP3-5 is mapped to bit 24. 2468c2ecf20Sopenharmony_ci */ 2478c2ecf20Sopenharmony_ci return GPIO3_PIN_IN_SEL(state, pin); 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic int __get_gpi_state_p3(struct lpc32xx_gpio_chip *group, 2518c2ecf20Sopenharmony_ci unsigned pin) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci return GPI3_PIN_IN_SEL(gpreg_read(group, group->gpio_grp->inp_state), pin); 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistatic int __get_gpo_state_p3(struct lpc32xx_gpio_chip *group, 2578c2ecf20Sopenharmony_ci unsigned pin) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci return GPO3_PIN_IN_SEL(gpreg_read(group, group->gpio_grp->outp_state), pin); 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci/* 2638c2ecf20Sopenharmony_ci * GPIO primitives. 2648c2ecf20Sopenharmony_ci */ 2658c2ecf20Sopenharmony_cistatic int lpc32xx_gpio_dir_input_p012(struct gpio_chip *chip, 2668c2ecf20Sopenharmony_ci unsigned pin) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci __set_gpio_dir_p012(group, pin, 1); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci return 0; 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic int lpc32xx_gpio_dir_input_p3(struct gpio_chip *chip, 2768c2ecf20Sopenharmony_ci unsigned pin) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci __set_gpio_dir_p3(group, pin, 1); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci return 0; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic int lpc32xx_gpio_dir_in_always(struct gpio_chip *chip, 2868c2ecf20Sopenharmony_ci unsigned pin) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci return 0; 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic int lpc32xx_gpio_get_value_p012(struct gpio_chip *chip, unsigned pin) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci return !!__get_gpio_state_p012(group, pin); 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cistatic int lpc32xx_gpio_get_value_p3(struct gpio_chip *chip, unsigned pin) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci return !!__get_gpio_state_p3(group, pin); 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic int lpc32xx_gpi_get_value(struct gpio_chip *chip, unsigned pin) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci return !!__get_gpi_state_p3(group, pin); 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cistatic int lpc32xx_gpio_dir_output_p012(struct gpio_chip *chip, unsigned pin, 3138c2ecf20Sopenharmony_ci int value) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci __set_gpio_level_p012(group, pin, value); 3188c2ecf20Sopenharmony_ci __set_gpio_dir_p012(group, pin, 0); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci return 0; 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_cistatic int lpc32xx_gpio_dir_output_p3(struct gpio_chip *chip, unsigned pin, 3248c2ecf20Sopenharmony_ci int value) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci __set_gpio_level_p3(group, pin, value); 3298c2ecf20Sopenharmony_ci __set_gpio_dir_p3(group, pin, 0); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci return 0; 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_cistatic int lpc32xx_gpio_dir_out_always(struct gpio_chip *chip, unsigned pin, 3358c2ecf20Sopenharmony_ci int value) 3368c2ecf20Sopenharmony_ci{ 3378c2ecf20Sopenharmony_ci struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci __set_gpo_level_p3(group, pin, value); 3408c2ecf20Sopenharmony_ci return 0; 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_cistatic void lpc32xx_gpio_set_value_p012(struct gpio_chip *chip, unsigned pin, 3448c2ecf20Sopenharmony_ci int value) 3458c2ecf20Sopenharmony_ci{ 3468c2ecf20Sopenharmony_ci struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci __set_gpio_level_p012(group, pin, value); 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_cistatic void lpc32xx_gpio_set_value_p3(struct gpio_chip *chip, unsigned pin, 3528c2ecf20Sopenharmony_ci int value) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci __set_gpio_level_p3(group, pin, value); 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic void lpc32xx_gpo_set_value(struct gpio_chip *chip, unsigned pin, 3608c2ecf20Sopenharmony_ci int value) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci __set_gpo_level_p3(group, pin, value); 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_cistatic int lpc32xx_gpo_get_value(struct gpio_chip *chip, unsigned pin) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci return !!__get_gpo_state_p3(group, pin); 3728c2ecf20Sopenharmony_ci} 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_cistatic int lpc32xx_gpio_request(struct gpio_chip *chip, unsigned pin) 3758c2ecf20Sopenharmony_ci{ 3768c2ecf20Sopenharmony_ci if (pin < chip->ngpio) 3778c2ecf20Sopenharmony_ci return 0; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci return -EINVAL; 3808c2ecf20Sopenharmony_ci} 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_cistatic int lpc32xx_gpio_to_irq_p01(struct gpio_chip *chip, unsigned offset) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci return -ENXIO; 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic int lpc32xx_gpio_to_irq_gpio_p3(struct gpio_chip *chip, unsigned offset) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci return -ENXIO; 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_cistatic int lpc32xx_gpio_to_irq_gpi_p3(struct gpio_chip *chip, unsigned offset) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci return -ENXIO; 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cistatic struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = { 3988c2ecf20Sopenharmony_ci { 3998c2ecf20Sopenharmony_ci .chip = { 4008c2ecf20Sopenharmony_ci .label = "gpio_p0", 4018c2ecf20Sopenharmony_ci .direction_input = lpc32xx_gpio_dir_input_p012, 4028c2ecf20Sopenharmony_ci .get = lpc32xx_gpio_get_value_p012, 4038c2ecf20Sopenharmony_ci .direction_output = lpc32xx_gpio_dir_output_p012, 4048c2ecf20Sopenharmony_ci .set = lpc32xx_gpio_set_value_p012, 4058c2ecf20Sopenharmony_ci .request = lpc32xx_gpio_request, 4068c2ecf20Sopenharmony_ci .to_irq = lpc32xx_gpio_to_irq_p01, 4078c2ecf20Sopenharmony_ci .base = LPC32XX_GPIO_P0_GRP, 4088c2ecf20Sopenharmony_ci .ngpio = LPC32XX_GPIO_P0_MAX, 4098c2ecf20Sopenharmony_ci .names = gpio_p0_names, 4108c2ecf20Sopenharmony_ci .can_sleep = false, 4118c2ecf20Sopenharmony_ci }, 4128c2ecf20Sopenharmony_ci .gpio_grp = &gpio_grp_regs_p0, 4138c2ecf20Sopenharmony_ci }, 4148c2ecf20Sopenharmony_ci { 4158c2ecf20Sopenharmony_ci .chip = { 4168c2ecf20Sopenharmony_ci .label = "gpio_p1", 4178c2ecf20Sopenharmony_ci .direction_input = lpc32xx_gpio_dir_input_p012, 4188c2ecf20Sopenharmony_ci .get = lpc32xx_gpio_get_value_p012, 4198c2ecf20Sopenharmony_ci .direction_output = lpc32xx_gpio_dir_output_p012, 4208c2ecf20Sopenharmony_ci .set = lpc32xx_gpio_set_value_p012, 4218c2ecf20Sopenharmony_ci .request = lpc32xx_gpio_request, 4228c2ecf20Sopenharmony_ci .to_irq = lpc32xx_gpio_to_irq_p01, 4238c2ecf20Sopenharmony_ci .base = LPC32XX_GPIO_P1_GRP, 4248c2ecf20Sopenharmony_ci .ngpio = LPC32XX_GPIO_P1_MAX, 4258c2ecf20Sopenharmony_ci .names = gpio_p1_names, 4268c2ecf20Sopenharmony_ci .can_sleep = false, 4278c2ecf20Sopenharmony_ci }, 4288c2ecf20Sopenharmony_ci .gpio_grp = &gpio_grp_regs_p1, 4298c2ecf20Sopenharmony_ci }, 4308c2ecf20Sopenharmony_ci { 4318c2ecf20Sopenharmony_ci .chip = { 4328c2ecf20Sopenharmony_ci .label = "gpio_p2", 4338c2ecf20Sopenharmony_ci .direction_input = lpc32xx_gpio_dir_input_p012, 4348c2ecf20Sopenharmony_ci .get = lpc32xx_gpio_get_value_p012, 4358c2ecf20Sopenharmony_ci .direction_output = lpc32xx_gpio_dir_output_p012, 4368c2ecf20Sopenharmony_ci .set = lpc32xx_gpio_set_value_p012, 4378c2ecf20Sopenharmony_ci .request = lpc32xx_gpio_request, 4388c2ecf20Sopenharmony_ci .base = LPC32XX_GPIO_P2_GRP, 4398c2ecf20Sopenharmony_ci .ngpio = LPC32XX_GPIO_P2_MAX, 4408c2ecf20Sopenharmony_ci .names = gpio_p2_names, 4418c2ecf20Sopenharmony_ci .can_sleep = false, 4428c2ecf20Sopenharmony_ci }, 4438c2ecf20Sopenharmony_ci .gpio_grp = &gpio_grp_regs_p2, 4448c2ecf20Sopenharmony_ci }, 4458c2ecf20Sopenharmony_ci { 4468c2ecf20Sopenharmony_ci .chip = { 4478c2ecf20Sopenharmony_ci .label = "gpio_p3", 4488c2ecf20Sopenharmony_ci .direction_input = lpc32xx_gpio_dir_input_p3, 4498c2ecf20Sopenharmony_ci .get = lpc32xx_gpio_get_value_p3, 4508c2ecf20Sopenharmony_ci .direction_output = lpc32xx_gpio_dir_output_p3, 4518c2ecf20Sopenharmony_ci .set = lpc32xx_gpio_set_value_p3, 4528c2ecf20Sopenharmony_ci .request = lpc32xx_gpio_request, 4538c2ecf20Sopenharmony_ci .to_irq = lpc32xx_gpio_to_irq_gpio_p3, 4548c2ecf20Sopenharmony_ci .base = LPC32XX_GPIO_P3_GRP, 4558c2ecf20Sopenharmony_ci .ngpio = LPC32XX_GPIO_P3_MAX, 4568c2ecf20Sopenharmony_ci .names = gpio_p3_names, 4578c2ecf20Sopenharmony_ci .can_sleep = false, 4588c2ecf20Sopenharmony_ci }, 4598c2ecf20Sopenharmony_ci .gpio_grp = &gpio_grp_regs_p3, 4608c2ecf20Sopenharmony_ci }, 4618c2ecf20Sopenharmony_ci { 4628c2ecf20Sopenharmony_ci .chip = { 4638c2ecf20Sopenharmony_ci .label = "gpi_p3", 4648c2ecf20Sopenharmony_ci .direction_input = lpc32xx_gpio_dir_in_always, 4658c2ecf20Sopenharmony_ci .get = lpc32xx_gpi_get_value, 4668c2ecf20Sopenharmony_ci .request = lpc32xx_gpio_request, 4678c2ecf20Sopenharmony_ci .to_irq = lpc32xx_gpio_to_irq_gpi_p3, 4688c2ecf20Sopenharmony_ci .base = LPC32XX_GPI_P3_GRP, 4698c2ecf20Sopenharmony_ci .ngpio = LPC32XX_GPI_P3_MAX, 4708c2ecf20Sopenharmony_ci .names = gpi_p3_names, 4718c2ecf20Sopenharmony_ci .can_sleep = false, 4728c2ecf20Sopenharmony_ci }, 4738c2ecf20Sopenharmony_ci .gpio_grp = &gpio_grp_regs_p3, 4748c2ecf20Sopenharmony_ci }, 4758c2ecf20Sopenharmony_ci { 4768c2ecf20Sopenharmony_ci .chip = { 4778c2ecf20Sopenharmony_ci .label = "gpo_p3", 4788c2ecf20Sopenharmony_ci .direction_output = lpc32xx_gpio_dir_out_always, 4798c2ecf20Sopenharmony_ci .set = lpc32xx_gpo_set_value, 4808c2ecf20Sopenharmony_ci .get = lpc32xx_gpo_get_value, 4818c2ecf20Sopenharmony_ci .request = lpc32xx_gpio_request, 4828c2ecf20Sopenharmony_ci .base = LPC32XX_GPO_P3_GRP, 4838c2ecf20Sopenharmony_ci .ngpio = LPC32XX_GPO_P3_MAX, 4848c2ecf20Sopenharmony_ci .names = gpo_p3_names, 4858c2ecf20Sopenharmony_ci .can_sleep = false, 4868c2ecf20Sopenharmony_ci }, 4878c2ecf20Sopenharmony_ci .gpio_grp = &gpio_grp_regs_p3, 4888c2ecf20Sopenharmony_ci }, 4898c2ecf20Sopenharmony_ci}; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_cistatic int lpc32xx_of_xlate(struct gpio_chip *gc, 4928c2ecf20Sopenharmony_ci const struct of_phandle_args *gpiospec, u32 *flags) 4938c2ecf20Sopenharmony_ci{ 4948c2ecf20Sopenharmony_ci /* Is this the correct bank? */ 4958c2ecf20Sopenharmony_ci u32 bank = gpiospec->args[0]; 4968c2ecf20Sopenharmony_ci if ((bank >= ARRAY_SIZE(lpc32xx_gpiochip) || 4978c2ecf20Sopenharmony_ci (gc != &lpc32xx_gpiochip[bank].chip))) 4988c2ecf20Sopenharmony_ci return -EINVAL; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci if (flags) 5018c2ecf20Sopenharmony_ci *flags = gpiospec->args[2]; 5028c2ecf20Sopenharmony_ci return gpiospec->args[1]; 5038c2ecf20Sopenharmony_ci} 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_cistatic int lpc32xx_gpio_probe(struct platform_device *pdev) 5068c2ecf20Sopenharmony_ci{ 5078c2ecf20Sopenharmony_ci int i; 5088c2ecf20Sopenharmony_ci void __iomem *reg_base; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci reg_base = devm_platform_ioremap_resource(pdev, 0); 5118c2ecf20Sopenharmony_ci if (IS_ERR(reg_base)) 5128c2ecf20Sopenharmony_ci return PTR_ERR(reg_base); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(lpc32xx_gpiochip); i++) { 5158c2ecf20Sopenharmony_ci if (pdev->dev.of_node) { 5168c2ecf20Sopenharmony_ci lpc32xx_gpiochip[i].chip.of_xlate = lpc32xx_of_xlate; 5178c2ecf20Sopenharmony_ci lpc32xx_gpiochip[i].chip.of_gpio_n_cells = 3; 5188c2ecf20Sopenharmony_ci lpc32xx_gpiochip[i].chip.of_node = pdev->dev.of_node; 5198c2ecf20Sopenharmony_ci lpc32xx_gpiochip[i].reg_base = reg_base; 5208c2ecf20Sopenharmony_ci } 5218c2ecf20Sopenharmony_ci devm_gpiochip_add_data(&pdev->dev, &lpc32xx_gpiochip[i].chip, 5228c2ecf20Sopenharmony_ci &lpc32xx_gpiochip[i]); 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci return 0; 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 5298c2ecf20Sopenharmony_cistatic const struct of_device_id lpc32xx_gpio_of_match[] = { 5308c2ecf20Sopenharmony_ci { .compatible = "nxp,lpc3220-gpio", }, 5318c2ecf20Sopenharmony_ci { }, 5328c2ecf20Sopenharmony_ci}; 5338c2ecf20Sopenharmony_ci#endif 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_cistatic struct platform_driver lpc32xx_gpio_driver = { 5368c2ecf20Sopenharmony_ci .driver = { 5378c2ecf20Sopenharmony_ci .name = "lpc32xx-gpio", 5388c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(lpc32xx_gpio_of_match), 5398c2ecf20Sopenharmony_ci }, 5408c2ecf20Sopenharmony_ci .probe = lpc32xx_gpio_probe, 5418c2ecf20Sopenharmony_ci}; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_cimodule_platform_driver(lpc32xx_gpio_driver); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ciMODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com>"); 5468c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 5478c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("GPIO driver for LPC32xx SoC"); 548