18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2013 STMicroelectronics (R&D) Limited. 48c2ecf20Sopenharmony_ci * Authors: 58c2ecf20Sopenharmony_ci * Srinivas Kandagatla <srinivas.kandagatla@st.com> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/init.h> 98c2ecf20Sopenharmony_ci#include <linux/module.h> 108c2ecf20Sopenharmony_ci#include <linux/slab.h> 118c2ecf20Sopenharmony_ci#include <linux/err.h> 128c2ecf20Sopenharmony_ci#include <linux/io.h> 138c2ecf20Sopenharmony_ci#include <linux/of.h> 148c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 158c2ecf20Sopenharmony_ci#include <linux/of_gpio.h> /* of_get_named_gpio() */ 168c2ecf20Sopenharmony_ci#include <linux/of_address.h> 178c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h> 188c2ecf20Sopenharmony_ci#include <linux/regmap.h> 198c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 208c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinctrl.h> 218c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinmux.h> 228c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinconf.h> 238c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 248c2ecf20Sopenharmony_ci#include "core.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* PIO Block registers */ 278c2ecf20Sopenharmony_ci/* PIO output */ 288c2ecf20Sopenharmony_ci#define REG_PIO_POUT 0x00 298c2ecf20Sopenharmony_ci/* Set bits of POUT */ 308c2ecf20Sopenharmony_ci#define REG_PIO_SET_POUT 0x04 318c2ecf20Sopenharmony_ci/* Clear bits of POUT */ 328c2ecf20Sopenharmony_ci#define REG_PIO_CLR_POUT 0x08 338c2ecf20Sopenharmony_ci/* PIO input */ 348c2ecf20Sopenharmony_ci#define REG_PIO_PIN 0x10 358c2ecf20Sopenharmony_ci/* PIO configuration */ 368c2ecf20Sopenharmony_ci#define REG_PIO_PC(n) (0x20 + (n) * 0x10) 378c2ecf20Sopenharmony_ci/* Set bits of PC[2:0] */ 388c2ecf20Sopenharmony_ci#define REG_PIO_SET_PC(n) (0x24 + (n) * 0x10) 398c2ecf20Sopenharmony_ci/* Clear bits of PC[2:0] */ 408c2ecf20Sopenharmony_ci#define REG_PIO_CLR_PC(n) (0x28 + (n) * 0x10) 418c2ecf20Sopenharmony_ci/* PIO input comparison */ 428c2ecf20Sopenharmony_ci#define REG_PIO_PCOMP 0x50 438c2ecf20Sopenharmony_ci/* Set bits of PCOMP */ 448c2ecf20Sopenharmony_ci#define REG_PIO_SET_PCOMP 0x54 458c2ecf20Sopenharmony_ci/* Clear bits of PCOMP */ 468c2ecf20Sopenharmony_ci#define REG_PIO_CLR_PCOMP 0x58 478c2ecf20Sopenharmony_ci/* PIO input comparison mask */ 488c2ecf20Sopenharmony_ci#define REG_PIO_PMASK 0x60 498c2ecf20Sopenharmony_ci/* Set bits of PMASK */ 508c2ecf20Sopenharmony_ci#define REG_PIO_SET_PMASK 0x64 518c2ecf20Sopenharmony_ci/* Clear bits of PMASK */ 528c2ecf20Sopenharmony_ci#define REG_PIO_CLR_PMASK 0x68 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#define ST_GPIO_DIRECTION_BIDIR 0x1 558c2ecf20Sopenharmony_ci#define ST_GPIO_DIRECTION_OUT 0x2 568c2ecf20Sopenharmony_ci#define ST_GPIO_DIRECTION_IN 0x4 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/** 598c2ecf20Sopenharmony_ci * Packed style retime configuration. 608c2ecf20Sopenharmony_ci * There are two registers cfg0 and cfg1 in this style for each bank. 618c2ecf20Sopenharmony_ci * Each field in this register is 8 bit corresponding to 8 pins in the bank. 628c2ecf20Sopenharmony_ci */ 638c2ecf20Sopenharmony_ci#define RT_P_CFGS_PER_BANK 2 648c2ecf20Sopenharmony_ci#define RT_P_CFG0_CLK1NOTCLK0_FIELD(reg) REG_FIELD(reg, 0, 7) 658c2ecf20Sopenharmony_ci#define RT_P_CFG0_DELAY_0_FIELD(reg) REG_FIELD(reg, 16, 23) 668c2ecf20Sopenharmony_ci#define RT_P_CFG0_DELAY_1_FIELD(reg) REG_FIELD(reg, 24, 31) 678c2ecf20Sopenharmony_ci#define RT_P_CFG1_INVERTCLK_FIELD(reg) REG_FIELD(reg, 0, 7) 688c2ecf20Sopenharmony_ci#define RT_P_CFG1_RETIME_FIELD(reg) REG_FIELD(reg, 8, 15) 698c2ecf20Sopenharmony_ci#define RT_P_CFG1_CLKNOTDATA_FIELD(reg) REG_FIELD(reg, 16, 23) 708c2ecf20Sopenharmony_ci#define RT_P_CFG1_DOUBLE_EDGE_FIELD(reg) REG_FIELD(reg, 24, 31) 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/** 738c2ecf20Sopenharmony_ci * Dedicated style retime Configuration register 748c2ecf20Sopenharmony_ci * each register is dedicated per pin. 758c2ecf20Sopenharmony_ci */ 768c2ecf20Sopenharmony_ci#define RT_D_CFGS_PER_BANK 8 778c2ecf20Sopenharmony_ci#define RT_D_CFG_CLK_SHIFT 0 788c2ecf20Sopenharmony_ci#define RT_D_CFG_CLK_MASK (0x3 << 0) 798c2ecf20Sopenharmony_ci#define RT_D_CFG_CLKNOTDATA_SHIFT 2 808c2ecf20Sopenharmony_ci#define RT_D_CFG_CLKNOTDATA_MASK BIT(2) 818c2ecf20Sopenharmony_ci#define RT_D_CFG_DELAY_SHIFT 3 828c2ecf20Sopenharmony_ci#define RT_D_CFG_DELAY_MASK (0xf << 3) 838c2ecf20Sopenharmony_ci#define RT_D_CFG_DELAY_INNOTOUT_SHIFT 7 848c2ecf20Sopenharmony_ci#define RT_D_CFG_DELAY_INNOTOUT_MASK BIT(7) 858c2ecf20Sopenharmony_ci#define RT_D_CFG_DOUBLE_EDGE_SHIFT 8 868c2ecf20Sopenharmony_ci#define RT_D_CFG_DOUBLE_EDGE_MASK BIT(8) 878c2ecf20Sopenharmony_ci#define RT_D_CFG_INVERTCLK_SHIFT 9 888c2ecf20Sopenharmony_ci#define RT_D_CFG_INVERTCLK_MASK BIT(9) 898c2ecf20Sopenharmony_ci#define RT_D_CFG_RETIME_SHIFT 10 908c2ecf20Sopenharmony_ci#define RT_D_CFG_RETIME_MASK BIT(10) 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci/* 938c2ecf20Sopenharmony_ci * Pinconf is represented in an opaque unsigned long variable. 948c2ecf20Sopenharmony_ci * Below is the bit allocation details for each possible configuration. 958c2ecf20Sopenharmony_ci * All the bit fields can be encapsulated into four variables 968c2ecf20Sopenharmony_ci * (direction, retime-type, retime-clk, retime-delay) 978c2ecf20Sopenharmony_ci * 988c2ecf20Sopenharmony_ci * +----------------+ 998c2ecf20Sopenharmony_ci *[31:28]| reserved-3 | 1008c2ecf20Sopenharmony_ci * +----------------+------------- 1018c2ecf20Sopenharmony_ci *[27] | oe | | 1028c2ecf20Sopenharmony_ci * +----------------+ v 1038c2ecf20Sopenharmony_ci *[26] | pu | [Direction ] 1048c2ecf20Sopenharmony_ci * +----------------+ ^ 1058c2ecf20Sopenharmony_ci *[25] | od | | 1068c2ecf20Sopenharmony_ci * +----------------+------------- 1078c2ecf20Sopenharmony_ci *[24] | reserved-2 | 1088c2ecf20Sopenharmony_ci * +----------------+------------- 1098c2ecf20Sopenharmony_ci *[23] | retime | | 1108c2ecf20Sopenharmony_ci * +----------------+ | 1118c2ecf20Sopenharmony_ci *[22] | retime-invclk | | 1128c2ecf20Sopenharmony_ci * +----------------+ v 1138c2ecf20Sopenharmony_ci *[21] |retime-clknotdat| [Retime-type ] 1148c2ecf20Sopenharmony_ci * +----------------+ ^ 1158c2ecf20Sopenharmony_ci *[20] | retime-de | | 1168c2ecf20Sopenharmony_ci * +----------------+------------- 1178c2ecf20Sopenharmony_ci *[19:18]| retime-clk |------>[Retime-Clk ] 1188c2ecf20Sopenharmony_ci * +----------------+ 1198c2ecf20Sopenharmony_ci *[17:16]| reserved-1 | 1208c2ecf20Sopenharmony_ci * +----------------+ 1218c2ecf20Sopenharmony_ci *[15..0]| retime-delay |------>[Retime Delay] 1228c2ecf20Sopenharmony_ci * +----------------+ 1238c2ecf20Sopenharmony_ci */ 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci#define ST_PINCONF_UNPACK(conf, param)\ 1268c2ecf20Sopenharmony_ci ((conf >> ST_PINCONF_ ##param ##_SHIFT) \ 1278c2ecf20Sopenharmony_ci & ST_PINCONF_ ##param ##_MASK) 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci#define ST_PINCONF_PACK(conf, val, param) (conf |=\ 1308c2ecf20Sopenharmony_ci ((val & ST_PINCONF_ ##param ##_MASK) << \ 1318c2ecf20Sopenharmony_ci ST_PINCONF_ ##param ##_SHIFT)) 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci/* Output enable */ 1348c2ecf20Sopenharmony_ci#define ST_PINCONF_OE_MASK 0x1 1358c2ecf20Sopenharmony_ci#define ST_PINCONF_OE_SHIFT 27 1368c2ecf20Sopenharmony_ci#define ST_PINCONF_OE BIT(27) 1378c2ecf20Sopenharmony_ci#define ST_PINCONF_UNPACK_OE(conf) ST_PINCONF_UNPACK(conf, OE) 1388c2ecf20Sopenharmony_ci#define ST_PINCONF_PACK_OE(conf) ST_PINCONF_PACK(conf, 1, OE) 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci/* Pull Up */ 1418c2ecf20Sopenharmony_ci#define ST_PINCONF_PU_MASK 0x1 1428c2ecf20Sopenharmony_ci#define ST_PINCONF_PU_SHIFT 26 1438c2ecf20Sopenharmony_ci#define ST_PINCONF_PU BIT(26) 1448c2ecf20Sopenharmony_ci#define ST_PINCONF_UNPACK_PU(conf) ST_PINCONF_UNPACK(conf, PU) 1458c2ecf20Sopenharmony_ci#define ST_PINCONF_PACK_PU(conf) ST_PINCONF_PACK(conf, 1, PU) 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci/* Open Drain */ 1488c2ecf20Sopenharmony_ci#define ST_PINCONF_OD_MASK 0x1 1498c2ecf20Sopenharmony_ci#define ST_PINCONF_OD_SHIFT 25 1508c2ecf20Sopenharmony_ci#define ST_PINCONF_OD BIT(25) 1518c2ecf20Sopenharmony_ci#define ST_PINCONF_UNPACK_OD(conf) ST_PINCONF_UNPACK(conf, OD) 1528c2ecf20Sopenharmony_ci#define ST_PINCONF_PACK_OD(conf) ST_PINCONF_PACK(conf, 1, OD) 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci#define ST_PINCONF_RT_MASK 0x1 1558c2ecf20Sopenharmony_ci#define ST_PINCONF_RT_SHIFT 23 1568c2ecf20Sopenharmony_ci#define ST_PINCONF_RT BIT(23) 1578c2ecf20Sopenharmony_ci#define ST_PINCONF_UNPACK_RT(conf) ST_PINCONF_UNPACK(conf, RT) 1588c2ecf20Sopenharmony_ci#define ST_PINCONF_PACK_RT(conf) ST_PINCONF_PACK(conf, 1, RT) 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci#define ST_PINCONF_RT_INVERTCLK_MASK 0x1 1618c2ecf20Sopenharmony_ci#define ST_PINCONF_RT_INVERTCLK_SHIFT 22 1628c2ecf20Sopenharmony_ci#define ST_PINCONF_RT_INVERTCLK BIT(22) 1638c2ecf20Sopenharmony_ci#define ST_PINCONF_UNPACK_RT_INVERTCLK(conf) \ 1648c2ecf20Sopenharmony_ci ST_PINCONF_UNPACK(conf, RT_INVERTCLK) 1658c2ecf20Sopenharmony_ci#define ST_PINCONF_PACK_RT_INVERTCLK(conf) \ 1668c2ecf20Sopenharmony_ci ST_PINCONF_PACK(conf, 1, RT_INVERTCLK) 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci#define ST_PINCONF_RT_CLKNOTDATA_MASK 0x1 1698c2ecf20Sopenharmony_ci#define ST_PINCONF_RT_CLKNOTDATA_SHIFT 21 1708c2ecf20Sopenharmony_ci#define ST_PINCONF_RT_CLKNOTDATA BIT(21) 1718c2ecf20Sopenharmony_ci#define ST_PINCONF_UNPACK_RT_CLKNOTDATA(conf) \ 1728c2ecf20Sopenharmony_ci ST_PINCONF_UNPACK(conf, RT_CLKNOTDATA) 1738c2ecf20Sopenharmony_ci#define ST_PINCONF_PACK_RT_CLKNOTDATA(conf) \ 1748c2ecf20Sopenharmony_ci ST_PINCONF_PACK(conf, 1, RT_CLKNOTDATA) 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci#define ST_PINCONF_RT_DOUBLE_EDGE_MASK 0x1 1778c2ecf20Sopenharmony_ci#define ST_PINCONF_RT_DOUBLE_EDGE_SHIFT 20 1788c2ecf20Sopenharmony_ci#define ST_PINCONF_RT_DOUBLE_EDGE BIT(20) 1798c2ecf20Sopenharmony_ci#define ST_PINCONF_UNPACK_RT_DOUBLE_EDGE(conf) \ 1808c2ecf20Sopenharmony_ci ST_PINCONF_UNPACK(conf, RT_DOUBLE_EDGE) 1818c2ecf20Sopenharmony_ci#define ST_PINCONF_PACK_RT_DOUBLE_EDGE(conf) \ 1828c2ecf20Sopenharmony_ci ST_PINCONF_PACK(conf, 1, RT_DOUBLE_EDGE) 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci#define ST_PINCONF_RT_CLK_MASK 0x3 1858c2ecf20Sopenharmony_ci#define ST_PINCONF_RT_CLK_SHIFT 18 1868c2ecf20Sopenharmony_ci#define ST_PINCONF_RT_CLK BIT(18) 1878c2ecf20Sopenharmony_ci#define ST_PINCONF_UNPACK_RT_CLK(conf) ST_PINCONF_UNPACK(conf, RT_CLK) 1888c2ecf20Sopenharmony_ci#define ST_PINCONF_PACK_RT_CLK(conf, val) ST_PINCONF_PACK(conf, val, RT_CLK) 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci/* RETIME_DELAY in Pico Secs */ 1918c2ecf20Sopenharmony_ci#define ST_PINCONF_RT_DELAY_MASK 0xffff 1928c2ecf20Sopenharmony_ci#define ST_PINCONF_RT_DELAY_SHIFT 0 1938c2ecf20Sopenharmony_ci#define ST_PINCONF_UNPACK_RT_DELAY(conf) ST_PINCONF_UNPACK(conf, RT_DELAY) 1948c2ecf20Sopenharmony_ci#define ST_PINCONF_PACK_RT_DELAY(conf, val) \ 1958c2ecf20Sopenharmony_ci ST_PINCONF_PACK(conf, val, RT_DELAY) 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci#define ST_GPIO_PINS_PER_BANK (8) 1988c2ecf20Sopenharmony_ci#define OF_GPIO_ARGS_MIN (4) 1998c2ecf20Sopenharmony_ci#define OF_RT_ARGS_MIN (2) 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci#define gpio_range_to_bank(chip) \ 2028c2ecf20Sopenharmony_ci container_of(chip, struct st_gpio_bank, range) 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci#define pc_to_bank(pc) \ 2058c2ecf20Sopenharmony_ci container_of(pc, struct st_gpio_bank, pc) 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cienum st_retime_style { 2088c2ecf20Sopenharmony_ci st_retime_style_none, 2098c2ecf20Sopenharmony_ci st_retime_style_packed, 2108c2ecf20Sopenharmony_ci st_retime_style_dedicated, 2118c2ecf20Sopenharmony_ci}; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_cistruct st_retime_dedicated { 2148c2ecf20Sopenharmony_ci struct regmap_field *rt[ST_GPIO_PINS_PER_BANK]; 2158c2ecf20Sopenharmony_ci}; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_cistruct st_retime_packed { 2188c2ecf20Sopenharmony_ci struct regmap_field *clk1notclk0; 2198c2ecf20Sopenharmony_ci struct regmap_field *delay_0; 2208c2ecf20Sopenharmony_ci struct regmap_field *delay_1; 2218c2ecf20Sopenharmony_ci struct regmap_field *invertclk; 2228c2ecf20Sopenharmony_ci struct regmap_field *retime; 2238c2ecf20Sopenharmony_ci struct regmap_field *clknotdata; 2248c2ecf20Sopenharmony_ci struct regmap_field *double_edge; 2258c2ecf20Sopenharmony_ci}; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistruct st_pio_control { 2288c2ecf20Sopenharmony_ci u32 rt_pin_mask; 2298c2ecf20Sopenharmony_ci struct regmap_field *alt, *oe, *pu, *od; 2308c2ecf20Sopenharmony_ci /* retiming */ 2318c2ecf20Sopenharmony_ci union { 2328c2ecf20Sopenharmony_ci struct st_retime_packed rt_p; 2338c2ecf20Sopenharmony_ci struct st_retime_dedicated rt_d; 2348c2ecf20Sopenharmony_ci } rt; 2358c2ecf20Sopenharmony_ci}; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistruct st_pctl_data { 2388c2ecf20Sopenharmony_ci const enum st_retime_style rt_style; 2398c2ecf20Sopenharmony_ci const unsigned int *input_delays; 2408c2ecf20Sopenharmony_ci const int ninput_delays; 2418c2ecf20Sopenharmony_ci const unsigned int *output_delays; 2428c2ecf20Sopenharmony_ci const int noutput_delays; 2438c2ecf20Sopenharmony_ci /* register offset information */ 2448c2ecf20Sopenharmony_ci const int alt, oe, pu, od, rt; 2458c2ecf20Sopenharmony_ci}; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistruct st_pinconf { 2488c2ecf20Sopenharmony_ci int pin; 2498c2ecf20Sopenharmony_ci const char *name; 2508c2ecf20Sopenharmony_ci unsigned long config; 2518c2ecf20Sopenharmony_ci int altfunc; 2528c2ecf20Sopenharmony_ci}; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistruct st_pmx_func { 2558c2ecf20Sopenharmony_ci const char *name; 2568c2ecf20Sopenharmony_ci const char **groups; 2578c2ecf20Sopenharmony_ci unsigned ngroups; 2588c2ecf20Sopenharmony_ci}; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistruct st_pctl_group { 2618c2ecf20Sopenharmony_ci const char *name; 2628c2ecf20Sopenharmony_ci unsigned int *pins; 2638c2ecf20Sopenharmony_ci unsigned npins; 2648c2ecf20Sopenharmony_ci struct st_pinconf *pin_conf; 2658c2ecf20Sopenharmony_ci}; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci/* 2688c2ecf20Sopenharmony_ci * Edge triggers are not supported at hardware level, it is supported by 2698c2ecf20Sopenharmony_ci * software by exploiting the level trigger support in hardware. 2708c2ecf20Sopenharmony_ci * Software uses a virtual register (EDGE_CONF) for edge trigger configuration 2718c2ecf20Sopenharmony_ci * of each gpio pin in a GPIO bank. 2728c2ecf20Sopenharmony_ci * 2738c2ecf20Sopenharmony_ci * Each bank has a 32 bit EDGE_CONF register which is divided in to 8 parts of 2748c2ecf20Sopenharmony_ci * 4-bits. Each 4-bit space is allocated for each pin in a gpio bank. 2758c2ecf20Sopenharmony_ci * 2768c2ecf20Sopenharmony_ci * bit allocation per pin is: 2778c2ecf20Sopenharmony_ci * Bits: [0 - 3] | [4 - 7] [8 - 11] ... ... ... ... [ 28 - 31] 2788c2ecf20Sopenharmony_ci * -------------------------------------------------------- 2798c2ecf20Sopenharmony_ci * | pin-0 | pin-2 | pin-3 | ... ... ... ... | pin -7 | 2808c2ecf20Sopenharmony_ci * -------------------------------------------------------- 2818c2ecf20Sopenharmony_ci * 2828c2ecf20Sopenharmony_ci * A pin can have one of following the values in its edge configuration field. 2838c2ecf20Sopenharmony_ci * 2848c2ecf20Sopenharmony_ci * ------- ---------------------------- 2858c2ecf20Sopenharmony_ci * [0-3] - Description 2868c2ecf20Sopenharmony_ci * ------- ---------------------------- 2878c2ecf20Sopenharmony_ci * 0000 - No edge IRQ. 2888c2ecf20Sopenharmony_ci * 0001 - Falling edge IRQ. 2898c2ecf20Sopenharmony_ci * 0010 - Rising edge IRQ. 2908c2ecf20Sopenharmony_ci * 0011 - Rising and Falling edge IRQ. 2918c2ecf20Sopenharmony_ci * ------- ---------------------------- 2928c2ecf20Sopenharmony_ci */ 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci#define ST_IRQ_EDGE_CONF_BITS_PER_PIN 4 2958c2ecf20Sopenharmony_ci#define ST_IRQ_EDGE_MASK 0xf 2968c2ecf20Sopenharmony_ci#define ST_IRQ_EDGE_FALLING BIT(0) 2978c2ecf20Sopenharmony_ci#define ST_IRQ_EDGE_RISING BIT(1) 2988c2ecf20Sopenharmony_ci#define ST_IRQ_EDGE_BOTH (BIT(0) | BIT(1)) 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci#define ST_IRQ_RISING_EDGE_CONF(pin) \ 3018c2ecf20Sopenharmony_ci (ST_IRQ_EDGE_RISING << (pin * ST_IRQ_EDGE_CONF_BITS_PER_PIN)) 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci#define ST_IRQ_FALLING_EDGE_CONF(pin) \ 3048c2ecf20Sopenharmony_ci (ST_IRQ_EDGE_FALLING << (pin * ST_IRQ_EDGE_CONF_BITS_PER_PIN)) 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci#define ST_IRQ_BOTH_EDGE_CONF(pin) \ 3078c2ecf20Sopenharmony_ci (ST_IRQ_EDGE_BOTH << (pin * ST_IRQ_EDGE_CONF_BITS_PER_PIN)) 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci#define ST_IRQ_EDGE_CONF(conf, pin) \ 3108c2ecf20Sopenharmony_ci (conf >> (pin * ST_IRQ_EDGE_CONF_BITS_PER_PIN) & ST_IRQ_EDGE_MASK) 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cistruct st_gpio_bank { 3138c2ecf20Sopenharmony_ci struct gpio_chip gpio_chip; 3148c2ecf20Sopenharmony_ci struct pinctrl_gpio_range range; 3158c2ecf20Sopenharmony_ci void __iomem *base; 3168c2ecf20Sopenharmony_ci struct st_pio_control pc; 3178c2ecf20Sopenharmony_ci unsigned long irq_edge_conf; 3188c2ecf20Sopenharmony_ci spinlock_t lock; 3198c2ecf20Sopenharmony_ci}; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_cistruct st_pinctrl { 3228c2ecf20Sopenharmony_ci struct device *dev; 3238c2ecf20Sopenharmony_ci struct pinctrl_dev *pctl; 3248c2ecf20Sopenharmony_ci struct st_gpio_bank *banks; 3258c2ecf20Sopenharmony_ci int nbanks; 3268c2ecf20Sopenharmony_ci struct st_pmx_func *functions; 3278c2ecf20Sopenharmony_ci int nfunctions; 3288c2ecf20Sopenharmony_ci struct st_pctl_group *groups; 3298c2ecf20Sopenharmony_ci int ngroups; 3308c2ecf20Sopenharmony_ci struct regmap *regmap; 3318c2ecf20Sopenharmony_ci const struct st_pctl_data *data; 3328c2ecf20Sopenharmony_ci void __iomem *irqmux_base; 3338c2ecf20Sopenharmony_ci}; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci/* SOC specific data */ 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_cistatic const unsigned int stih407_delays[] = {0, 300, 500, 750, 1000, 1250, 3388c2ecf20Sopenharmony_ci 1500, 1750, 2000, 2250, 2500, 2750, 3000, 3250 }; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistatic const struct st_pctl_data stih407_data = { 3418c2ecf20Sopenharmony_ci .rt_style = st_retime_style_dedicated, 3428c2ecf20Sopenharmony_ci .input_delays = stih407_delays, 3438c2ecf20Sopenharmony_ci .ninput_delays = ARRAY_SIZE(stih407_delays), 3448c2ecf20Sopenharmony_ci .output_delays = stih407_delays, 3458c2ecf20Sopenharmony_ci .noutput_delays = ARRAY_SIZE(stih407_delays), 3468c2ecf20Sopenharmony_ci .alt = 0, .oe = 40, .pu = 50, .od = 60, .rt = 100, 3478c2ecf20Sopenharmony_ci}; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic const struct st_pctl_data stih407_flashdata = { 3508c2ecf20Sopenharmony_ci .rt_style = st_retime_style_none, 3518c2ecf20Sopenharmony_ci .input_delays = stih407_delays, 3528c2ecf20Sopenharmony_ci .ninput_delays = ARRAY_SIZE(stih407_delays), 3538c2ecf20Sopenharmony_ci .output_delays = stih407_delays, 3548c2ecf20Sopenharmony_ci .noutput_delays = ARRAY_SIZE(stih407_delays), 3558c2ecf20Sopenharmony_ci .alt = 0, 3568c2ecf20Sopenharmony_ci .oe = -1, /* Not Available */ 3578c2ecf20Sopenharmony_ci .pu = -1, /* Not Available */ 3588c2ecf20Sopenharmony_ci .od = 60, 3598c2ecf20Sopenharmony_ci .rt = 100, 3608c2ecf20Sopenharmony_ci}; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cistatic struct st_pio_control *st_get_pio_control( 3638c2ecf20Sopenharmony_ci struct pinctrl_dev *pctldev, int pin) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci struct pinctrl_gpio_range *range = 3668c2ecf20Sopenharmony_ci pinctrl_find_gpio_range_from_pin(pctldev, pin); 3678c2ecf20Sopenharmony_ci struct st_gpio_bank *bank = gpio_range_to_bank(range); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci return &bank->pc; 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci/* Low level functions.. */ 3738c2ecf20Sopenharmony_cistatic inline int st_gpio_bank(int gpio) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci return gpio/ST_GPIO_PINS_PER_BANK; 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistatic inline int st_gpio_pin(int gpio) 3798c2ecf20Sopenharmony_ci{ 3808c2ecf20Sopenharmony_ci return gpio%ST_GPIO_PINS_PER_BANK; 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cistatic void st_pinconf_set_config(struct st_pio_control *pc, 3848c2ecf20Sopenharmony_ci int pin, unsigned long config) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci struct regmap_field *output_enable = pc->oe; 3878c2ecf20Sopenharmony_ci struct regmap_field *pull_up = pc->pu; 3888c2ecf20Sopenharmony_ci struct regmap_field *open_drain = pc->od; 3898c2ecf20Sopenharmony_ci unsigned int oe_value, pu_value, od_value; 3908c2ecf20Sopenharmony_ci unsigned long mask = BIT(pin); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci if (output_enable) { 3938c2ecf20Sopenharmony_ci regmap_field_read(output_enable, &oe_value); 3948c2ecf20Sopenharmony_ci oe_value &= ~mask; 3958c2ecf20Sopenharmony_ci if (config & ST_PINCONF_OE) 3968c2ecf20Sopenharmony_ci oe_value |= mask; 3978c2ecf20Sopenharmony_ci regmap_field_write(output_enable, oe_value); 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci if (pull_up) { 4018c2ecf20Sopenharmony_ci regmap_field_read(pull_up, &pu_value); 4028c2ecf20Sopenharmony_ci pu_value &= ~mask; 4038c2ecf20Sopenharmony_ci if (config & ST_PINCONF_PU) 4048c2ecf20Sopenharmony_ci pu_value |= mask; 4058c2ecf20Sopenharmony_ci regmap_field_write(pull_up, pu_value); 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci if (open_drain) { 4098c2ecf20Sopenharmony_ci regmap_field_read(open_drain, &od_value); 4108c2ecf20Sopenharmony_ci od_value &= ~mask; 4118c2ecf20Sopenharmony_ci if (config & ST_PINCONF_OD) 4128c2ecf20Sopenharmony_ci od_value |= mask; 4138c2ecf20Sopenharmony_ci regmap_field_write(open_drain, od_value); 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cistatic void st_pctl_set_function(struct st_pio_control *pc, 4188c2ecf20Sopenharmony_ci int pin_id, int function) 4198c2ecf20Sopenharmony_ci{ 4208c2ecf20Sopenharmony_ci struct regmap_field *alt = pc->alt; 4218c2ecf20Sopenharmony_ci unsigned int val; 4228c2ecf20Sopenharmony_ci int pin = st_gpio_pin(pin_id); 4238c2ecf20Sopenharmony_ci int offset = pin * 4; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci if (!alt) 4268c2ecf20Sopenharmony_ci return; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci regmap_field_read(alt, &val); 4298c2ecf20Sopenharmony_ci val &= ~(0xf << offset); 4308c2ecf20Sopenharmony_ci val |= function << offset; 4318c2ecf20Sopenharmony_ci regmap_field_write(alt, val); 4328c2ecf20Sopenharmony_ci} 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_cistatic unsigned int st_pctl_get_pin_function(struct st_pio_control *pc, int pin) 4358c2ecf20Sopenharmony_ci{ 4368c2ecf20Sopenharmony_ci struct regmap_field *alt = pc->alt; 4378c2ecf20Sopenharmony_ci unsigned int val; 4388c2ecf20Sopenharmony_ci int offset = pin * 4; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci if (!alt) 4418c2ecf20Sopenharmony_ci return 0; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci regmap_field_read(alt, &val); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci return (val >> offset) & 0xf; 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cistatic unsigned long st_pinconf_delay_to_bit(unsigned int delay, 4498c2ecf20Sopenharmony_ci const struct st_pctl_data *data, unsigned long config) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci const unsigned int *delay_times; 4528c2ecf20Sopenharmony_ci int num_delay_times, i, closest_index = -1; 4538c2ecf20Sopenharmony_ci unsigned int closest_divergence = UINT_MAX; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci if (ST_PINCONF_UNPACK_OE(config)) { 4568c2ecf20Sopenharmony_ci delay_times = data->output_delays; 4578c2ecf20Sopenharmony_ci num_delay_times = data->noutput_delays; 4588c2ecf20Sopenharmony_ci } else { 4598c2ecf20Sopenharmony_ci delay_times = data->input_delays; 4608c2ecf20Sopenharmony_ci num_delay_times = data->ninput_delays; 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci for (i = 0; i < num_delay_times; i++) { 4648c2ecf20Sopenharmony_ci unsigned int divergence = abs(delay - delay_times[i]); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci if (divergence == 0) 4678c2ecf20Sopenharmony_ci return i; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci if (divergence < closest_divergence) { 4708c2ecf20Sopenharmony_ci closest_divergence = divergence; 4718c2ecf20Sopenharmony_ci closest_index = i; 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci pr_warn("Attempt to set delay %d, closest available %d\n", 4768c2ecf20Sopenharmony_ci delay, delay_times[closest_index]); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci return closest_index; 4798c2ecf20Sopenharmony_ci} 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_cistatic unsigned long st_pinconf_bit_to_delay(unsigned int index, 4828c2ecf20Sopenharmony_ci const struct st_pctl_data *data, unsigned long output) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci const unsigned int *delay_times; 4858c2ecf20Sopenharmony_ci int num_delay_times; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci if (output) { 4888c2ecf20Sopenharmony_ci delay_times = data->output_delays; 4898c2ecf20Sopenharmony_ci num_delay_times = data->noutput_delays; 4908c2ecf20Sopenharmony_ci } else { 4918c2ecf20Sopenharmony_ci delay_times = data->input_delays; 4928c2ecf20Sopenharmony_ci num_delay_times = data->ninput_delays; 4938c2ecf20Sopenharmony_ci } 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci if (index < num_delay_times) { 4968c2ecf20Sopenharmony_ci return delay_times[index]; 4978c2ecf20Sopenharmony_ci } else { 4988c2ecf20Sopenharmony_ci pr_warn("Delay not found in/out delay list\n"); 4998c2ecf20Sopenharmony_ci return 0; 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_cistatic void st_regmap_field_bit_set_clear_pin(struct regmap_field *field, 5048c2ecf20Sopenharmony_ci int enable, int pin) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci unsigned int val = 0; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci regmap_field_read(field, &val); 5098c2ecf20Sopenharmony_ci if (enable) 5108c2ecf20Sopenharmony_ci val |= BIT(pin); 5118c2ecf20Sopenharmony_ci else 5128c2ecf20Sopenharmony_ci val &= ~BIT(pin); 5138c2ecf20Sopenharmony_ci regmap_field_write(field, val); 5148c2ecf20Sopenharmony_ci} 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_cistatic void st_pinconf_set_retime_packed(struct st_pinctrl *info, 5178c2ecf20Sopenharmony_ci struct st_pio_control *pc, unsigned long config, int pin) 5188c2ecf20Sopenharmony_ci{ 5198c2ecf20Sopenharmony_ci const struct st_pctl_data *data = info->data; 5208c2ecf20Sopenharmony_ci struct st_retime_packed *rt_p = &pc->rt.rt_p; 5218c2ecf20Sopenharmony_ci unsigned int delay; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci st_regmap_field_bit_set_clear_pin(rt_p->clk1notclk0, 5248c2ecf20Sopenharmony_ci ST_PINCONF_UNPACK_RT_CLK(config), pin); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci st_regmap_field_bit_set_clear_pin(rt_p->clknotdata, 5278c2ecf20Sopenharmony_ci ST_PINCONF_UNPACK_RT_CLKNOTDATA(config), pin); 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci st_regmap_field_bit_set_clear_pin(rt_p->double_edge, 5308c2ecf20Sopenharmony_ci ST_PINCONF_UNPACK_RT_DOUBLE_EDGE(config), pin); 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci st_regmap_field_bit_set_clear_pin(rt_p->invertclk, 5338c2ecf20Sopenharmony_ci ST_PINCONF_UNPACK_RT_INVERTCLK(config), pin); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci st_regmap_field_bit_set_clear_pin(rt_p->retime, 5368c2ecf20Sopenharmony_ci ST_PINCONF_UNPACK_RT(config), pin); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci delay = st_pinconf_delay_to_bit(ST_PINCONF_UNPACK_RT_DELAY(config), 5398c2ecf20Sopenharmony_ci data, config); 5408c2ecf20Sopenharmony_ci /* 2 bit delay, lsb */ 5418c2ecf20Sopenharmony_ci st_regmap_field_bit_set_clear_pin(rt_p->delay_0, delay & 0x1, pin); 5428c2ecf20Sopenharmony_ci /* 2 bit delay, msb */ 5438c2ecf20Sopenharmony_ci st_regmap_field_bit_set_clear_pin(rt_p->delay_1, delay & 0x2, pin); 5448c2ecf20Sopenharmony_ci} 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_cistatic void st_pinconf_set_retime_dedicated(struct st_pinctrl *info, 5478c2ecf20Sopenharmony_ci struct st_pio_control *pc, unsigned long config, int pin) 5488c2ecf20Sopenharmony_ci{ 5498c2ecf20Sopenharmony_ci int input = ST_PINCONF_UNPACK_OE(config) ? 0 : 1; 5508c2ecf20Sopenharmony_ci int clk = ST_PINCONF_UNPACK_RT_CLK(config); 5518c2ecf20Sopenharmony_ci int clknotdata = ST_PINCONF_UNPACK_RT_CLKNOTDATA(config); 5528c2ecf20Sopenharmony_ci int double_edge = ST_PINCONF_UNPACK_RT_DOUBLE_EDGE(config); 5538c2ecf20Sopenharmony_ci int invertclk = ST_PINCONF_UNPACK_RT_INVERTCLK(config); 5548c2ecf20Sopenharmony_ci int retime = ST_PINCONF_UNPACK_RT(config); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci unsigned long delay = st_pinconf_delay_to_bit( 5578c2ecf20Sopenharmony_ci ST_PINCONF_UNPACK_RT_DELAY(config), 5588c2ecf20Sopenharmony_ci info->data, config); 5598c2ecf20Sopenharmony_ci struct st_retime_dedicated *rt_d = &pc->rt.rt_d; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci unsigned long retime_config = 5628c2ecf20Sopenharmony_ci ((clk) << RT_D_CFG_CLK_SHIFT) | 5638c2ecf20Sopenharmony_ci ((delay) << RT_D_CFG_DELAY_SHIFT) | 5648c2ecf20Sopenharmony_ci ((input) << RT_D_CFG_DELAY_INNOTOUT_SHIFT) | 5658c2ecf20Sopenharmony_ci ((retime) << RT_D_CFG_RETIME_SHIFT) | 5668c2ecf20Sopenharmony_ci ((clknotdata) << RT_D_CFG_CLKNOTDATA_SHIFT) | 5678c2ecf20Sopenharmony_ci ((invertclk) << RT_D_CFG_INVERTCLK_SHIFT) | 5688c2ecf20Sopenharmony_ci ((double_edge) << RT_D_CFG_DOUBLE_EDGE_SHIFT); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci regmap_field_write(rt_d->rt[pin], retime_config); 5718c2ecf20Sopenharmony_ci} 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_cistatic void st_pinconf_get_direction(struct st_pio_control *pc, 5748c2ecf20Sopenharmony_ci int pin, unsigned long *config) 5758c2ecf20Sopenharmony_ci{ 5768c2ecf20Sopenharmony_ci unsigned int oe_value, pu_value, od_value; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci if (pc->oe) { 5798c2ecf20Sopenharmony_ci regmap_field_read(pc->oe, &oe_value); 5808c2ecf20Sopenharmony_ci if (oe_value & BIT(pin)) 5818c2ecf20Sopenharmony_ci ST_PINCONF_PACK_OE(*config); 5828c2ecf20Sopenharmony_ci } 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci if (pc->pu) { 5858c2ecf20Sopenharmony_ci regmap_field_read(pc->pu, &pu_value); 5868c2ecf20Sopenharmony_ci if (pu_value & BIT(pin)) 5878c2ecf20Sopenharmony_ci ST_PINCONF_PACK_PU(*config); 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci if (pc->od) { 5918c2ecf20Sopenharmony_ci regmap_field_read(pc->od, &od_value); 5928c2ecf20Sopenharmony_ci if (od_value & BIT(pin)) 5938c2ecf20Sopenharmony_ci ST_PINCONF_PACK_OD(*config); 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci} 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_cistatic int st_pinconf_get_retime_packed(struct st_pinctrl *info, 5988c2ecf20Sopenharmony_ci struct st_pio_control *pc, int pin, unsigned long *config) 5998c2ecf20Sopenharmony_ci{ 6008c2ecf20Sopenharmony_ci const struct st_pctl_data *data = info->data; 6018c2ecf20Sopenharmony_ci struct st_retime_packed *rt_p = &pc->rt.rt_p; 6028c2ecf20Sopenharmony_ci unsigned int delay_bits, delay, delay0, delay1, val; 6038c2ecf20Sopenharmony_ci int output = ST_PINCONF_UNPACK_OE(*config); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci if (!regmap_field_read(rt_p->retime, &val) && (val & BIT(pin))) 6068c2ecf20Sopenharmony_ci ST_PINCONF_PACK_RT(*config); 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci if (!regmap_field_read(rt_p->clk1notclk0, &val) && (val & BIT(pin))) 6098c2ecf20Sopenharmony_ci ST_PINCONF_PACK_RT_CLK(*config, 1); 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci if (!regmap_field_read(rt_p->clknotdata, &val) && (val & BIT(pin))) 6128c2ecf20Sopenharmony_ci ST_PINCONF_PACK_RT_CLKNOTDATA(*config); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci if (!regmap_field_read(rt_p->double_edge, &val) && (val & BIT(pin))) 6158c2ecf20Sopenharmony_ci ST_PINCONF_PACK_RT_DOUBLE_EDGE(*config); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci if (!regmap_field_read(rt_p->invertclk, &val) && (val & BIT(pin))) 6188c2ecf20Sopenharmony_ci ST_PINCONF_PACK_RT_INVERTCLK(*config); 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci regmap_field_read(rt_p->delay_0, &delay0); 6218c2ecf20Sopenharmony_ci regmap_field_read(rt_p->delay_1, &delay1); 6228c2ecf20Sopenharmony_ci delay_bits = (((delay1 & BIT(pin)) ? 1 : 0) << 1) | 6238c2ecf20Sopenharmony_ci (((delay0 & BIT(pin)) ? 1 : 0)); 6248c2ecf20Sopenharmony_ci delay = st_pinconf_bit_to_delay(delay_bits, data, output); 6258c2ecf20Sopenharmony_ci ST_PINCONF_PACK_RT_DELAY(*config, delay); 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci return 0; 6288c2ecf20Sopenharmony_ci} 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_cistatic int st_pinconf_get_retime_dedicated(struct st_pinctrl *info, 6318c2ecf20Sopenharmony_ci struct st_pio_control *pc, int pin, unsigned long *config) 6328c2ecf20Sopenharmony_ci{ 6338c2ecf20Sopenharmony_ci unsigned int value; 6348c2ecf20Sopenharmony_ci unsigned long delay_bits, delay, rt_clk; 6358c2ecf20Sopenharmony_ci int output = ST_PINCONF_UNPACK_OE(*config); 6368c2ecf20Sopenharmony_ci struct st_retime_dedicated *rt_d = &pc->rt.rt_d; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci regmap_field_read(rt_d->rt[pin], &value); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci rt_clk = (value & RT_D_CFG_CLK_MASK) >> RT_D_CFG_CLK_SHIFT; 6418c2ecf20Sopenharmony_ci ST_PINCONF_PACK_RT_CLK(*config, rt_clk); 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci delay_bits = (value & RT_D_CFG_DELAY_MASK) >> RT_D_CFG_DELAY_SHIFT; 6448c2ecf20Sopenharmony_ci delay = st_pinconf_bit_to_delay(delay_bits, info->data, output); 6458c2ecf20Sopenharmony_ci ST_PINCONF_PACK_RT_DELAY(*config, delay); 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci if (value & RT_D_CFG_CLKNOTDATA_MASK) 6488c2ecf20Sopenharmony_ci ST_PINCONF_PACK_RT_CLKNOTDATA(*config); 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci if (value & RT_D_CFG_DOUBLE_EDGE_MASK) 6518c2ecf20Sopenharmony_ci ST_PINCONF_PACK_RT_DOUBLE_EDGE(*config); 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci if (value & RT_D_CFG_INVERTCLK_MASK) 6548c2ecf20Sopenharmony_ci ST_PINCONF_PACK_RT_INVERTCLK(*config); 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci if (value & RT_D_CFG_RETIME_MASK) 6578c2ecf20Sopenharmony_ci ST_PINCONF_PACK_RT(*config); 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci return 0; 6608c2ecf20Sopenharmony_ci} 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci/* GPIO related functions */ 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_cistatic inline void __st_gpio_set(struct st_gpio_bank *bank, 6658c2ecf20Sopenharmony_ci unsigned offset, int value) 6668c2ecf20Sopenharmony_ci{ 6678c2ecf20Sopenharmony_ci if (value) 6688c2ecf20Sopenharmony_ci writel(BIT(offset), bank->base + REG_PIO_SET_POUT); 6698c2ecf20Sopenharmony_ci else 6708c2ecf20Sopenharmony_ci writel(BIT(offset), bank->base + REG_PIO_CLR_POUT); 6718c2ecf20Sopenharmony_ci} 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_cistatic void st_gpio_direction(struct st_gpio_bank *bank, 6748c2ecf20Sopenharmony_ci unsigned int gpio, unsigned int direction) 6758c2ecf20Sopenharmony_ci{ 6768c2ecf20Sopenharmony_ci int offset = st_gpio_pin(gpio); 6778c2ecf20Sopenharmony_ci int i = 0; 6788c2ecf20Sopenharmony_ci /** 6798c2ecf20Sopenharmony_ci * There are three configuration registers (PIOn_PC0, PIOn_PC1 6808c2ecf20Sopenharmony_ci * and PIOn_PC2) for each port. These are used to configure the 6818c2ecf20Sopenharmony_ci * PIO port pins. Each pin can be configured as an input, output, 6828c2ecf20Sopenharmony_ci * bidirectional, or alternative function pin. Three bits, one bit 6838c2ecf20Sopenharmony_ci * from each of the three registers, configure the corresponding bit of 6848c2ecf20Sopenharmony_ci * the port. Valid bit settings is: 6858c2ecf20Sopenharmony_ci * 6868c2ecf20Sopenharmony_ci * PC2 PC1 PC0 Direction. 6878c2ecf20Sopenharmony_ci * 0 0 0 [Input Weak pull-up] 6888c2ecf20Sopenharmony_ci * 0 0 or 1 1 [Bidirection] 6898c2ecf20Sopenharmony_ci * 0 1 0 [Output] 6908c2ecf20Sopenharmony_ci * 1 0 0 [Input] 6918c2ecf20Sopenharmony_ci * 6928c2ecf20Sopenharmony_ci * PIOn_SET_PC and PIOn_CLR_PC registers are used to set and clear bits 6938c2ecf20Sopenharmony_ci * individually. 6948c2ecf20Sopenharmony_ci */ 6958c2ecf20Sopenharmony_ci for (i = 0; i <= 2; i++) { 6968c2ecf20Sopenharmony_ci if (direction & BIT(i)) 6978c2ecf20Sopenharmony_ci writel(BIT(offset), bank->base + REG_PIO_SET_PC(i)); 6988c2ecf20Sopenharmony_ci else 6998c2ecf20Sopenharmony_ci writel(BIT(offset), bank->base + REG_PIO_CLR_PC(i)); 7008c2ecf20Sopenharmony_ci } 7018c2ecf20Sopenharmony_ci} 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_cistatic int st_gpio_get(struct gpio_chip *chip, unsigned offset) 7048c2ecf20Sopenharmony_ci{ 7058c2ecf20Sopenharmony_ci struct st_gpio_bank *bank = gpiochip_get_data(chip); 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci return !!(readl(bank->base + REG_PIO_PIN) & BIT(offset)); 7088c2ecf20Sopenharmony_ci} 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_cistatic void st_gpio_set(struct gpio_chip *chip, unsigned offset, int value) 7118c2ecf20Sopenharmony_ci{ 7128c2ecf20Sopenharmony_ci struct st_gpio_bank *bank = gpiochip_get_data(chip); 7138c2ecf20Sopenharmony_ci __st_gpio_set(bank, offset, value); 7148c2ecf20Sopenharmony_ci} 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_cistatic int st_gpio_direction_input(struct gpio_chip *chip, unsigned offset) 7178c2ecf20Sopenharmony_ci{ 7188c2ecf20Sopenharmony_ci pinctrl_gpio_direction_input(chip->base + offset); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci return 0; 7218c2ecf20Sopenharmony_ci} 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_cistatic int st_gpio_direction_output(struct gpio_chip *chip, 7248c2ecf20Sopenharmony_ci unsigned offset, int value) 7258c2ecf20Sopenharmony_ci{ 7268c2ecf20Sopenharmony_ci struct st_gpio_bank *bank = gpiochip_get_data(chip); 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci __st_gpio_set(bank, offset, value); 7298c2ecf20Sopenharmony_ci pinctrl_gpio_direction_output(chip->base + offset); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci return 0; 7328c2ecf20Sopenharmony_ci} 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_cistatic int st_gpio_get_direction(struct gpio_chip *chip, unsigned offset) 7358c2ecf20Sopenharmony_ci{ 7368c2ecf20Sopenharmony_ci struct st_gpio_bank *bank = gpiochip_get_data(chip); 7378c2ecf20Sopenharmony_ci struct st_pio_control pc = bank->pc; 7388c2ecf20Sopenharmony_ci unsigned long config; 7398c2ecf20Sopenharmony_ci unsigned int direction = 0; 7408c2ecf20Sopenharmony_ci unsigned int function; 7418c2ecf20Sopenharmony_ci unsigned int value; 7428c2ecf20Sopenharmony_ci int i = 0; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci /* Alternate function direction is handled by Pinctrl */ 7458c2ecf20Sopenharmony_ci function = st_pctl_get_pin_function(&pc, offset); 7468c2ecf20Sopenharmony_ci if (function) { 7478c2ecf20Sopenharmony_ci st_pinconf_get_direction(&pc, offset, &config); 7488c2ecf20Sopenharmony_ci if (ST_PINCONF_UNPACK_OE(config)) 7498c2ecf20Sopenharmony_ci return GPIO_LINE_DIRECTION_OUT; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci return GPIO_LINE_DIRECTION_IN; 7528c2ecf20Sopenharmony_ci } 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci /* 7558c2ecf20Sopenharmony_ci * GPIO direction is handled differently 7568c2ecf20Sopenharmony_ci * - See st_gpio_direction() above for an explanation 7578c2ecf20Sopenharmony_ci */ 7588c2ecf20Sopenharmony_ci for (i = 0; i <= 2; i++) { 7598c2ecf20Sopenharmony_ci value = readl(bank->base + REG_PIO_PC(i)); 7608c2ecf20Sopenharmony_ci direction |= ((value >> offset) & 0x1) << i; 7618c2ecf20Sopenharmony_ci } 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci if (direction == ST_GPIO_DIRECTION_IN) 7648c2ecf20Sopenharmony_ci return GPIO_LINE_DIRECTION_IN; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci return GPIO_LINE_DIRECTION_OUT; 7678c2ecf20Sopenharmony_ci} 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci/* Pinctrl Groups */ 7708c2ecf20Sopenharmony_cistatic int st_pctl_get_groups_count(struct pinctrl_dev *pctldev) 7718c2ecf20Sopenharmony_ci{ 7728c2ecf20Sopenharmony_ci struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci return info->ngroups; 7758c2ecf20Sopenharmony_ci} 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_cistatic const char *st_pctl_get_group_name(struct pinctrl_dev *pctldev, 7788c2ecf20Sopenharmony_ci unsigned selector) 7798c2ecf20Sopenharmony_ci{ 7808c2ecf20Sopenharmony_ci struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci return info->groups[selector].name; 7838c2ecf20Sopenharmony_ci} 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_cistatic int st_pctl_get_group_pins(struct pinctrl_dev *pctldev, 7868c2ecf20Sopenharmony_ci unsigned selector, const unsigned **pins, unsigned *npins) 7878c2ecf20Sopenharmony_ci{ 7888c2ecf20Sopenharmony_ci struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci if (selector >= info->ngroups) 7918c2ecf20Sopenharmony_ci return -EINVAL; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci *pins = info->groups[selector].pins; 7948c2ecf20Sopenharmony_ci *npins = info->groups[selector].npins; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci return 0; 7978c2ecf20Sopenharmony_ci} 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_cistatic inline const struct st_pctl_group *st_pctl_find_group_by_name( 8008c2ecf20Sopenharmony_ci const struct st_pinctrl *info, const char *name) 8018c2ecf20Sopenharmony_ci{ 8028c2ecf20Sopenharmony_ci int i; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci for (i = 0; i < info->ngroups; i++) { 8058c2ecf20Sopenharmony_ci if (!strcmp(info->groups[i].name, name)) 8068c2ecf20Sopenharmony_ci return &info->groups[i]; 8078c2ecf20Sopenharmony_ci } 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci return NULL; 8108c2ecf20Sopenharmony_ci} 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_cistatic int st_pctl_dt_node_to_map(struct pinctrl_dev *pctldev, 8138c2ecf20Sopenharmony_ci struct device_node *np, struct pinctrl_map **map, unsigned *num_maps) 8148c2ecf20Sopenharmony_ci{ 8158c2ecf20Sopenharmony_ci struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); 8168c2ecf20Sopenharmony_ci const struct st_pctl_group *grp; 8178c2ecf20Sopenharmony_ci struct pinctrl_map *new_map; 8188c2ecf20Sopenharmony_ci struct device_node *parent; 8198c2ecf20Sopenharmony_ci int map_num, i; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci grp = st_pctl_find_group_by_name(info, np->name); 8228c2ecf20Sopenharmony_ci if (!grp) { 8238c2ecf20Sopenharmony_ci dev_err(info->dev, "unable to find group for node %pOFn\n", 8248c2ecf20Sopenharmony_ci np); 8258c2ecf20Sopenharmony_ci return -EINVAL; 8268c2ecf20Sopenharmony_ci } 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci map_num = grp->npins + 1; 8298c2ecf20Sopenharmony_ci new_map = devm_kcalloc(pctldev->dev, 8308c2ecf20Sopenharmony_ci map_num, sizeof(*new_map), GFP_KERNEL); 8318c2ecf20Sopenharmony_ci if (!new_map) 8328c2ecf20Sopenharmony_ci return -ENOMEM; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci parent = of_get_parent(np); 8358c2ecf20Sopenharmony_ci if (!parent) { 8368c2ecf20Sopenharmony_ci devm_kfree(pctldev->dev, new_map); 8378c2ecf20Sopenharmony_ci return -EINVAL; 8388c2ecf20Sopenharmony_ci } 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci *map = new_map; 8418c2ecf20Sopenharmony_ci *num_maps = map_num; 8428c2ecf20Sopenharmony_ci new_map[0].type = PIN_MAP_TYPE_MUX_GROUP; 8438c2ecf20Sopenharmony_ci new_map[0].data.mux.function = parent->name; 8448c2ecf20Sopenharmony_ci new_map[0].data.mux.group = np->name; 8458c2ecf20Sopenharmony_ci of_node_put(parent); 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci /* create config map per pin */ 8488c2ecf20Sopenharmony_ci new_map++; 8498c2ecf20Sopenharmony_ci for (i = 0; i < grp->npins; i++) { 8508c2ecf20Sopenharmony_ci new_map[i].type = PIN_MAP_TYPE_CONFIGS_PIN; 8518c2ecf20Sopenharmony_ci new_map[i].data.configs.group_or_pin = 8528c2ecf20Sopenharmony_ci pin_get_name(pctldev, grp->pins[i]); 8538c2ecf20Sopenharmony_ci new_map[i].data.configs.configs = &grp->pin_conf[i].config; 8548c2ecf20Sopenharmony_ci new_map[i].data.configs.num_configs = 1; 8558c2ecf20Sopenharmony_ci } 8568c2ecf20Sopenharmony_ci dev_info(pctldev->dev, "maps: function %s group %s num %d\n", 8578c2ecf20Sopenharmony_ci (*map)->data.mux.function, grp->name, map_num); 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci return 0; 8608c2ecf20Sopenharmony_ci} 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_cistatic void st_pctl_dt_free_map(struct pinctrl_dev *pctldev, 8638c2ecf20Sopenharmony_ci struct pinctrl_map *map, unsigned num_maps) 8648c2ecf20Sopenharmony_ci{ 8658c2ecf20Sopenharmony_ci} 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_cistatic const struct pinctrl_ops st_pctlops = { 8688c2ecf20Sopenharmony_ci .get_groups_count = st_pctl_get_groups_count, 8698c2ecf20Sopenharmony_ci .get_group_pins = st_pctl_get_group_pins, 8708c2ecf20Sopenharmony_ci .get_group_name = st_pctl_get_group_name, 8718c2ecf20Sopenharmony_ci .dt_node_to_map = st_pctl_dt_node_to_map, 8728c2ecf20Sopenharmony_ci .dt_free_map = st_pctl_dt_free_map, 8738c2ecf20Sopenharmony_ci}; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci/* Pinmux */ 8768c2ecf20Sopenharmony_cistatic int st_pmx_get_funcs_count(struct pinctrl_dev *pctldev) 8778c2ecf20Sopenharmony_ci{ 8788c2ecf20Sopenharmony_ci struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci return info->nfunctions; 8818c2ecf20Sopenharmony_ci} 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_cistatic const char *st_pmx_get_fname(struct pinctrl_dev *pctldev, 8848c2ecf20Sopenharmony_ci unsigned selector) 8858c2ecf20Sopenharmony_ci{ 8868c2ecf20Sopenharmony_ci struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci return info->functions[selector].name; 8898c2ecf20Sopenharmony_ci} 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_cistatic int st_pmx_get_groups(struct pinctrl_dev *pctldev, 8928c2ecf20Sopenharmony_ci unsigned selector, const char * const **grps, unsigned * const ngrps) 8938c2ecf20Sopenharmony_ci{ 8948c2ecf20Sopenharmony_ci struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); 8958c2ecf20Sopenharmony_ci *grps = info->functions[selector].groups; 8968c2ecf20Sopenharmony_ci *ngrps = info->functions[selector].ngroups; 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci return 0; 8998c2ecf20Sopenharmony_ci} 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_cistatic int st_pmx_set_mux(struct pinctrl_dev *pctldev, unsigned fselector, 9028c2ecf20Sopenharmony_ci unsigned group) 9038c2ecf20Sopenharmony_ci{ 9048c2ecf20Sopenharmony_ci struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); 9058c2ecf20Sopenharmony_ci struct st_pinconf *conf = info->groups[group].pin_conf; 9068c2ecf20Sopenharmony_ci struct st_pio_control *pc; 9078c2ecf20Sopenharmony_ci int i; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci for (i = 0; i < info->groups[group].npins; i++) { 9108c2ecf20Sopenharmony_ci pc = st_get_pio_control(pctldev, conf[i].pin); 9118c2ecf20Sopenharmony_ci st_pctl_set_function(pc, conf[i].pin, conf[i].altfunc); 9128c2ecf20Sopenharmony_ci } 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci return 0; 9158c2ecf20Sopenharmony_ci} 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_cistatic int st_pmx_set_gpio_direction(struct pinctrl_dev *pctldev, 9188c2ecf20Sopenharmony_ci struct pinctrl_gpio_range *range, unsigned gpio, 9198c2ecf20Sopenharmony_ci bool input) 9208c2ecf20Sopenharmony_ci{ 9218c2ecf20Sopenharmony_ci struct st_gpio_bank *bank = gpio_range_to_bank(range); 9228c2ecf20Sopenharmony_ci /* 9238c2ecf20Sopenharmony_ci * When a PIO bank is used in its primary function mode (altfunc = 0) 9248c2ecf20Sopenharmony_ci * Output Enable (OE), Open Drain(OD), and Pull Up (PU) 9258c2ecf20Sopenharmony_ci * for the primary PIO functions are driven by the related PIO block 9268c2ecf20Sopenharmony_ci */ 9278c2ecf20Sopenharmony_ci st_pctl_set_function(&bank->pc, gpio, 0); 9288c2ecf20Sopenharmony_ci st_gpio_direction(bank, gpio, input ? 9298c2ecf20Sopenharmony_ci ST_GPIO_DIRECTION_IN : ST_GPIO_DIRECTION_OUT); 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci return 0; 9328c2ecf20Sopenharmony_ci} 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_cistatic const struct pinmux_ops st_pmxops = { 9358c2ecf20Sopenharmony_ci .get_functions_count = st_pmx_get_funcs_count, 9368c2ecf20Sopenharmony_ci .get_function_name = st_pmx_get_fname, 9378c2ecf20Sopenharmony_ci .get_function_groups = st_pmx_get_groups, 9388c2ecf20Sopenharmony_ci .set_mux = st_pmx_set_mux, 9398c2ecf20Sopenharmony_ci .gpio_set_direction = st_pmx_set_gpio_direction, 9408c2ecf20Sopenharmony_ci .strict = true, 9418c2ecf20Sopenharmony_ci}; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci/* Pinconf */ 9448c2ecf20Sopenharmony_cistatic void st_pinconf_get_retime(struct st_pinctrl *info, 9458c2ecf20Sopenharmony_ci struct st_pio_control *pc, int pin, unsigned long *config) 9468c2ecf20Sopenharmony_ci{ 9478c2ecf20Sopenharmony_ci if (info->data->rt_style == st_retime_style_packed) 9488c2ecf20Sopenharmony_ci st_pinconf_get_retime_packed(info, pc, pin, config); 9498c2ecf20Sopenharmony_ci else if (info->data->rt_style == st_retime_style_dedicated) 9508c2ecf20Sopenharmony_ci if ((BIT(pin) & pc->rt_pin_mask)) 9518c2ecf20Sopenharmony_ci st_pinconf_get_retime_dedicated(info, pc, 9528c2ecf20Sopenharmony_ci pin, config); 9538c2ecf20Sopenharmony_ci} 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_cistatic void st_pinconf_set_retime(struct st_pinctrl *info, 9568c2ecf20Sopenharmony_ci struct st_pio_control *pc, int pin, unsigned long config) 9578c2ecf20Sopenharmony_ci{ 9588c2ecf20Sopenharmony_ci if (info->data->rt_style == st_retime_style_packed) 9598c2ecf20Sopenharmony_ci st_pinconf_set_retime_packed(info, pc, config, pin); 9608c2ecf20Sopenharmony_ci else if (info->data->rt_style == st_retime_style_dedicated) 9618c2ecf20Sopenharmony_ci if ((BIT(pin) & pc->rt_pin_mask)) 9628c2ecf20Sopenharmony_ci st_pinconf_set_retime_dedicated(info, pc, 9638c2ecf20Sopenharmony_ci config, pin); 9648c2ecf20Sopenharmony_ci} 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_cistatic int st_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin_id, 9678c2ecf20Sopenharmony_ci unsigned long *configs, unsigned num_configs) 9688c2ecf20Sopenharmony_ci{ 9698c2ecf20Sopenharmony_ci int pin = st_gpio_pin(pin_id); 9708c2ecf20Sopenharmony_ci struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); 9718c2ecf20Sopenharmony_ci struct st_pio_control *pc = st_get_pio_control(pctldev, pin_id); 9728c2ecf20Sopenharmony_ci int i; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci for (i = 0; i < num_configs; i++) { 9758c2ecf20Sopenharmony_ci st_pinconf_set_config(pc, pin, configs[i]); 9768c2ecf20Sopenharmony_ci st_pinconf_set_retime(info, pc, pin, configs[i]); 9778c2ecf20Sopenharmony_ci } /* for each config */ 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci return 0; 9808c2ecf20Sopenharmony_ci} 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_cistatic int st_pinconf_get(struct pinctrl_dev *pctldev, 9838c2ecf20Sopenharmony_ci unsigned pin_id, unsigned long *config) 9848c2ecf20Sopenharmony_ci{ 9858c2ecf20Sopenharmony_ci int pin = st_gpio_pin(pin_id); 9868c2ecf20Sopenharmony_ci struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); 9878c2ecf20Sopenharmony_ci struct st_pio_control *pc = st_get_pio_control(pctldev, pin_id); 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci *config = 0; 9908c2ecf20Sopenharmony_ci st_pinconf_get_direction(pc, pin, config); 9918c2ecf20Sopenharmony_ci st_pinconf_get_retime(info, pc, pin, config); 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci return 0; 9948c2ecf20Sopenharmony_ci} 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_cistatic void st_pinconf_dbg_show(struct pinctrl_dev *pctldev, 9978c2ecf20Sopenharmony_ci struct seq_file *s, unsigned pin_id) 9988c2ecf20Sopenharmony_ci{ 9998c2ecf20Sopenharmony_ci struct st_pio_control *pc; 10008c2ecf20Sopenharmony_ci unsigned long config; 10018c2ecf20Sopenharmony_ci unsigned int function; 10028c2ecf20Sopenharmony_ci int offset = st_gpio_pin(pin_id); 10038c2ecf20Sopenharmony_ci char f[16]; 10048c2ecf20Sopenharmony_ci int oe; 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci mutex_unlock(&pctldev->mutex); 10078c2ecf20Sopenharmony_ci pc = st_get_pio_control(pctldev, pin_id); 10088c2ecf20Sopenharmony_ci st_pinconf_get(pctldev, pin_id, &config); 10098c2ecf20Sopenharmony_ci mutex_lock(&pctldev->mutex); 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci function = st_pctl_get_pin_function(pc, offset); 10128c2ecf20Sopenharmony_ci if (function) 10138c2ecf20Sopenharmony_ci snprintf(f, 10, "Alt Fn %u", function); 10148c2ecf20Sopenharmony_ci else 10158c2ecf20Sopenharmony_ci snprintf(f, 5, "GPIO"); 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci oe = st_gpio_get_direction(&pc_to_bank(pc)->gpio_chip, offset); 10188c2ecf20Sopenharmony_ci seq_printf(s, "[OE:%d,PU:%ld,OD:%ld]\t%s\n" 10198c2ecf20Sopenharmony_ci "\t\t[retime:%ld,invclk:%ld,clknotdat:%ld," 10208c2ecf20Sopenharmony_ci "de:%ld,rt-clk:%ld,rt-delay:%ld]", 10218c2ecf20Sopenharmony_ci (oe == GPIO_LINE_DIRECTION_OUT), 10228c2ecf20Sopenharmony_ci ST_PINCONF_UNPACK_PU(config), 10238c2ecf20Sopenharmony_ci ST_PINCONF_UNPACK_OD(config), 10248c2ecf20Sopenharmony_ci f, 10258c2ecf20Sopenharmony_ci ST_PINCONF_UNPACK_RT(config), 10268c2ecf20Sopenharmony_ci ST_PINCONF_UNPACK_RT_INVERTCLK(config), 10278c2ecf20Sopenharmony_ci ST_PINCONF_UNPACK_RT_CLKNOTDATA(config), 10288c2ecf20Sopenharmony_ci ST_PINCONF_UNPACK_RT_DOUBLE_EDGE(config), 10298c2ecf20Sopenharmony_ci ST_PINCONF_UNPACK_RT_CLK(config), 10308c2ecf20Sopenharmony_ci ST_PINCONF_UNPACK_RT_DELAY(config)); 10318c2ecf20Sopenharmony_ci} 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_cistatic const struct pinconf_ops st_confops = { 10348c2ecf20Sopenharmony_ci .pin_config_get = st_pinconf_get, 10358c2ecf20Sopenharmony_ci .pin_config_set = st_pinconf_set, 10368c2ecf20Sopenharmony_ci .pin_config_dbg_show = st_pinconf_dbg_show, 10378c2ecf20Sopenharmony_ci}; 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_cistatic void st_pctl_dt_child_count(struct st_pinctrl *info, 10408c2ecf20Sopenharmony_ci struct device_node *np) 10418c2ecf20Sopenharmony_ci{ 10428c2ecf20Sopenharmony_ci struct device_node *child; 10438c2ecf20Sopenharmony_ci for_each_child_of_node(np, child) { 10448c2ecf20Sopenharmony_ci if (of_property_read_bool(child, "gpio-controller")) { 10458c2ecf20Sopenharmony_ci info->nbanks++; 10468c2ecf20Sopenharmony_ci } else { 10478c2ecf20Sopenharmony_ci info->nfunctions++; 10488c2ecf20Sopenharmony_ci info->ngroups += of_get_child_count(child); 10498c2ecf20Sopenharmony_ci } 10508c2ecf20Sopenharmony_ci } 10518c2ecf20Sopenharmony_ci} 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_cistatic int st_pctl_dt_setup_retime_packed(struct st_pinctrl *info, 10548c2ecf20Sopenharmony_ci int bank, struct st_pio_control *pc) 10558c2ecf20Sopenharmony_ci{ 10568c2ecf20Sopenharmony_ci struct device *dev = info->dev; 10578c2ecf20Sopenharmony_ci struct regmap *rm = info->regmap; 10588c2ecf20Sopenharmony_ci const struct st_pctl_data *data = info->data; 10598c2ecf20Sopenharmony_ci /* 2 registers per bank */ 10608c2ecf20Sopenharmony_ci int reg = (data->rt + bank * RT_P_CFGS_PER_BANK) * 4; 10618c2ecf20Sopenharmony_ci struct st_retime_packed *rt_p = &pc->rt.rt_p; 10628c2ecf20Sopenharmony_ci /* cfg0 */ 10638c2ecf20Sopenharmony_ci struct reg_field clk1notclk0 = RT_P_CFG0_CLK1NOTCLK0_FIELD(reg); 10648c2ecf20Sopenharmony_ci struct reg_field delay_0 = RT_P_CFG0_DELAY_0_FIELD(reg); 10658c2ecf20Sopenharmony_ci struct reg_field delay_1 = RT_P_CFG0_DELAY_1_FIELD(reg); 10668c2ecf20Sopenharmony_ci /* cfg1 */ 10678c2ecf20Sopenharmony_ci struct reg_field invertclk = RT_P_CFG1_INVERTCLK_FIELD(reg + 4); 10688c2ecf20Sopenharmony_ci struct reg_field retime = RT_P_CFG1_RETIME_FIELD(reg + 4); 10698c2ecf20Sopenharmony_ci struct reg_field clknotdata = RT_P_CFG1_CLKNOTDATA_FIELD(reg + 4); 10708c2ecf20Sopenharmony_ci struct reg_field double_edge = RT_P_CFG1_DOUBLE_EDGE_FIELD(reg + 4); 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci rt_p->clk1notclk0 = devm_regmap_field_alloc(dev, rm, clk1notclk0); 10738c2ecf20Sopenharmony_ci rt_p->delay_0 = devm_regmap_field_alloc(dev, rm, delay_0); 10748c2ecf20Sopenharmony_ci rt_p->delay_1 = devm_regmap_field_alloc(dev, rm, delay_1); 10758c2ecf20Sopenharmony_ci rt_p->invertclk = devm_regmap_field_alloc(dev, rm, invertclk); 10768c2ecf20Sopenharmony_ci rt_p->retime = devm_regmap_field_alloc(dev, rm, retime); 10778c2ecf20Sopenharmony_ci rt_p->clknotdata = devm_regmap_field_alloc(dev, rm, clknotdata); 10788c2ecf20Sopenharmony_ci rt_p->double_edge = devm_regmap_field_alloc(dev, rm, double_edge); 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci if (IS_ERR(rt_p->clk1notclk0) || IS_ERR(rt_p->delay_0) || 10818c2ecf20Sopenharmony_ci IS_ERR(rt_p->delay_1) || IS_ERR(rt_p->invertclk) || 10828c2ecf20Sopenharmony_ci IS_ERR(rt_p->retime) || IS_ERR(rt_p->clknotdata) || 10838c2ecf20Sopenharmony_ci IS_ERR(rt_p->double_edge)) 10848c2ecf20Sopenharmony_ci return -EINVAL; 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci return 0; 10878c2ecf20Sopenharmony_ci} 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_cistatic int st_pctl_dt_setup_retime_dedicated(struct st_pinctrl *info, 10908c2ecf20Sopenharmony_ci int bank, struct st_pio_control *pc) 10918c2ecf20Sopenharmony_ci{ 10928c2ecf20Sopenharmony_ci struct device *dev = info->dev; 10938c2ecf20Sopenharmony_ci struct regmap *rm = info->regmap; 10948c2ecf20Sopenharmony_ci const struct st_pctl_data *data = info->data; 10958c2ecf20Sopenharmony_ci /* 8 registers per bank */ 10968c2ecf20Sopenharmony_ci int reg_offset = (data->rt + bank * RT_D_CFGS_PER_BANK) * 4; 10978c2ecf20Sopenharmony_ci struct st_retime_dedicated *rt_d = &pc->rt.rt_d; 10988c2ecf20Sopenharmony_ci unsigned int j; 10998c2ecf20Sopenharmony_ci u32 pin_mask = pc->rt_pin_mask; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci for (j = 0; j < RT_D_CFGS_PER_BANK; j++) { 11028c2ecf20Sopenharmony_ci if (BIT(j) & pin_mask) { 11038c2ecf20Sopenharmony_ci struct reg_field reg = REG_FIELD(reg_offset, 0, 31); 11048c2ecf20Sopenharmony_ci rt_d->rt[j] = devm_regmap_field_alloc(dev, rm, reg); 11058c2ecf20Sopenharmony_ci if (IS_ERR(rt_d->rt[j])) 11068c2ecf20Sopenharmony_ci return -EINVAL; 11078c2ecf20Sopenharmony_ci reg_offset += 4; 11088c2ecf20Sopenharmony_ci } 11098c2ecf20Sopenharmony_ci } 11108c2ecf20Sopenharmony_ci return 0; 11118c2ecf20Sopenharmony_ci} 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_cistatic int st_pctl_dt_setup_retime(struct st_pinctrl *info, 11148c2ecf20Sopenharmony_ci int bank, struct st_pio_control *pc) 11158c2ecf20Sopenharmony_ci{ 11168c2ecf20Sopenharmony_ci const struct st_pctl_data *data = info->data; 11178c2ecf20Sopenharmony_ci if (data->rt_style == st_retime_style_packed) 11188c2ecf20Sopenharmony_ci return st_pctl_dt_setup_retime_packed(info, bank, pc); 11198c2ecf20Sopenharmony_ci else if (data->rt_style == st_retime_style_dedicated) 11208c2ecf20Sopenharmony_ci return st_pctl_dt_setup_retime_dedicated(info, bank, pc); 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci return -EINVAL; 11238c2ecf20Sopenharmony_ci} 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_cistatic struct regmap_field *st_pc_get_value(struct device *dev, 11278c2ecf20Sopenharmony_ci struct regmap *regmap, int bank, 11288c2ecf20Sopenharmony_ci int data, int lsb, int msb) 11298c2ecf20Sopenharmony_ci{ 11308c2ecf20Sopenharmony_ci struct reg_field reg = REG_FIELD((data + bank) * 4, lsb, msb); 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci if (data < 0) 11338c2ecf20Sopenharmony_ci return NULL; 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci return devm_regmap_field_alloc(dev, regmap, reg); 11368c2ecf20Sopenharmony_ci} 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_cistatic void st_parse_syscfgs(struct st_pinctrl *info, int bank, 11398c2ecf20Sopenharmony_ci struct device_node *np) 11408c2ecf20Sopenharmony_ci{ 11418c2ecf20Sopenharmony_ci const struct st_pctl_data *data = info->data; 11428c2ecf20Sopenharmony_ci /** 11438c2ecf20Sopenharmony_ci * For a given shared register like OE/PU/OD, there are 8 bits per bank 11448c2ecf20Sopenharmony_ci * 0:7 belongs to bank0, 8:15 belongs to bank1 ... 11458c2ecf20Sopenharmony_ci * So each register is shared across 4 banks. 11468c2ecf20Sopenharmony_ci */ 11478c2ecf20Sopenharmony_ci int lsb = (bank%4) * ST_GPIO_PINS_PER_BANK; 11488c2ecf20Sopenharmony_ci int msb = lsb + ST_GPIO_PINS_PER_BANK - 1; 11498c2ecf20Sopenharmony_ci struct st_pio_control *pc = &info->banks[bank].pc; 11508c2ecf20Sopenharmony_ci struct device *dev = info->dev; 11518c2ecf20Sopenharmony_ci struct regmap *regmap = info->regmap; 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci pc->alt = st_pc_get_value(dev, regmap, bank, data->alt, 0, 31); 11548c2ecf20Sopenharmony_ci pc->oe = st_pc_get_value(dev, regmap, bank/4, data->oe, lsb, msb); 11558c2ecf20Sopenharmony_ci pc->pu = st_pc_get_value(dev, regmap, bank/4, data->pu, lsb, msb); 11568c2ecf20Sopenharmony_ci pc->od = st_pc_get_value(dev, regmap, bank/4, data->od, lsb, msb); 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci /* retime avaiable for all pins by default */ 11598c2ecf20Sopenharmony_ci pc->rt_pin_mask = 0xff; 11608c2ecf20Sopenharmony_ci of_property_read_u32(np, "st,retime-pin-mask", &pc->rt_pin_mask); 11618c2ecf20Sopenharmony_ci st_pctl_dt_setup_retime(info, bank, pc); 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci return; 11648c2ecf20Sopenharmony_ci} 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci/* 11678c2ecf20Sopenharmony_ci * Each pin is represented in of the below forms. 11688c2ecf20Sopenharmony_ci * <bank offset mux direction rt_type rt_delay rt_clk> 11698c2ecf20Sopenharmony_ci */ 11708c2ecf20Sopenharmony_cistatic int st_pctl_dt_parse_groups(struct device_node *np, 11718c2ecf20Sopenharmony_ci struct st_pctl_group *grp, struct st_pinctrl *info, int idx) 11728c2ecf20Sopenharmony_ci{ 11738c2ecf20Sopenharmony_ci /* bank pad direction val altfunction */ 11748c2ecf20Sopenharmony_ci const __be32 *list; 11758c2ecf20Sopenharmony_ci struct property *pp; 11768c2ecf20Sopenharmony_ci struct st_pinconf *conf; 11778c2ecf20Sopenharmony_ci struct device_node *pins; 11788c2ecf20Sopenharmony_ci int i = 0, npins = 0, nr_props, ret = 0; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci pins = of_get_child_by_name(np, "st,pins"); 11818c2ecf20Sopenharmony_ci if (!pins) 11828c2ecf20Sopenharmony_ci return -ENODATA; 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci for_each_property_of_node(pins, pp) { 11858c2ecf20Sopenharmony_ci /* Skip those we do not want to proceed */ 11868c2ecf20Sopenharmony_ci if (!strcmp(pp->name, "name")) 11878c2ecf20Sopenharmony_ci continue; 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci if (pp->length / sizeof(__be32) >= OF_GPIO_ARGS_MIN) { 11908c2ecf20Sopenharmony_ci npins++; 11918c2ecf20Sopenharmony_ci } else { 11928c2ecf20Sopenharmony_ci pr_warn("Invalid st,pins in %pOFn node\n", np); 11938c2ecf20Sopenharmony_ci ret = -EINVAL; 11948c2ecf20Sopenharmony_ci goto out_put_node; 11958c2ecf20Sopenharmony_ci } 11968c2ecf20Sopenharmony_ci } 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci grp->npins = npins; 11998c2ecf20Sopenharmony_ci grp->name = np->name; 12008c2ecf20Sopenharmony_ci grp->pins = devm_kcalloc(info->dev, npins, sizeof(u32), GFP_KERNEL); 12018c2ecf20Sopenharmony_ci grp->pin_conf = devm_kcalloc(info->dev, 12028c2ecf20Sopenharmony_ci npins, sizeof(*conf), GFP_KERNEL); 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci if (!grp->pins || !grp->pin_conf) { 12058c2ecf20Sopenharmony_ci ret = -ENOMEM; 12068c2ecf20Sopenharmony_ci goto out_put_node; 12078c2ecf20Sopenharmony_ci } 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci /* <bank offset mux direction rt_type rt_delay rt_clk> */ 12108c2ecf20Sopenharmony_ci for_each_property_of_node(pins, pp) { 12118c2ecf20Sopenharmony_ci if (!strcmp(pp->name, "name")) 12128c2ecf20Sopenharmony_ci continue; 12138c2ecf20Sopenharmony_ci nr_props = pp->length/sizeof(u32); 12148c2ecf20Sopenharmony_ci list = pp->value; 12158c2ecf20Sopenharmony_ci conf = &grp->pin_conf[i]; 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci /* bank & offset */ 12188c2ecf20Sopenharmony_ci be32_to_cpup(list++); 12198c2ecf20Sopenharmony_ci be32_to_cpup(list++); 12208c2ecf20Sopenharmony_ci conf->pin = of_get_named_gpio(pins, pp->name, 0); 12218c2ecf20Sopenharmony_ci conf->name = pp->name; 12228c2ecf20Sopenharmony_ci grp->pins[i] = conf->pin; 12238c2ecf20Sopenharmony_ci /* mux */ 12248c2ecf20Sopenharmony_ci conf->altfunc = be32_to_cpup(list++); 12258c2ecf20Sopenharmony_ci conf->config = 0; 12268c2ecf20Sopenharmony_ci /* direction */ 12278c2ecf20Sopenharmony_ci conf->config |= be32_to_cpup(list++); 12288c2ecf20Sopenharmony_ci /* rt_type rt_delay rt_clk */ 12298c2ecf20Sopenharmony_ci if (nr_props >= OF_GPIO_ARGS_MIN + OF_RT_ARGS_MIN) { 12308c2ecf20Sopenharmony_ci /* rt_type */ 12318c2ecf20Sopenharmony_ci conf->config |= be32_to_cpup(list++); 12328c2ecf20Sopenharmony_ci /* rt_delay */ 12338c2ecf20Sopenharmony_ci conf->config |= be32_to_cpup(list++); 12348c2ecf20Sopenharmony_ci /* rt_clk */ 12358c2ecf20Sopenharmony_ci if (nr_props > OF_GPIO_ARGS_MIN + OF_RT_ARGS_MIN) 12368c2ecf20Sopenharmony_ci conf->config |= be32_to_cpup(list++); 12378c2ecf20Sopenharmony_ci } 12388c2ecf20Sopenharmony_ci i++; 12398c2ecf20Sopenharmony_ci } 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ciout_put_node: 12428c2ecf20Sopenharmony_ci of_node_put(pins); 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci return ret; 12458c2ecf20Sopenharmony_ci} 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_cistatic int st_pctl_parse_functions(struct device_node *np, 12488c2ecf20Sopenharmony_ci struct st_pinctrl *info, u32 index, int *grp_index) 12498c2ecf20Sopenharmony_ci{ 12508c2ecf20Sopenharmony_ci struct device_node *child; 12518c2ecf20Sopenharmony_ci struct st_pmx_func *func; 12528c2ecf20Sopenharmony_ci struct st_pctl_group *grp; 12538c2ecf20Sopenharmony_ci int ret, i; 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci func = &info->functions[index]; 12568c2ecf20Sopenharmony_ci func->name = np->name; 12578c2ecf20Sopenharmony_ci func->ngroups = of_get_child_count(np); 12588c2ecf20Sopenharmony_ci if (func->ngroups == 0) { 12598c2ecf20Sopenharmony_ci dev_err(info->dev, "No groups defined\n"); 12608c2ecf20Sopenharmony_ci return -EINVAL; 12618c2ecf20Sopenharmony_ci } 12628c2ecf20Sopenharmony_ci func->groups = devm_kcalloc(info->dev, 12638c2ecf20Sopenharmony_ci func->ngroups, sizeof(char *), GFP_KERNEL); 12648c2ecf20Sopenharmony_ci if (!func->groups) 12658c2ecf20Sopenharmony_ci return -ENOMEM; 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci i = 0; 12688c2ecf20Sopenharmony_ci for_each_child_of_node(np, child) { 12698c2ecf20Sopenharmony_ci func->groups[i] = child->name; 12708c2ecf20Sopenharmony_ci grp = &info->groups[*grp_index]; 12718c2ecf20Sopenharmony_ci *grp_index += 1; 12728c2ecf20Sopenharmony_ci ret = st_pctl_dt_parse_groups(child, grp, info, i++); 12738c2ecf20Sopenharmony_ci if (ret) { 12748c2ecf20Sopenharmony_ci of_node_put(child); 12758c2ecf20Sopenharmony_ci return ret; 12768c2ecf20Sopenharmony_ci } 12778c2ecf20Sopenharmony_ci } 12788c2ecf20Sopenharmony_ci dev_info(info->dev, "Function[%d\t name:%s,\tgroups:%d]\n", 12798c2ecf20Sopenharmony_ci index, func->name, func->ngroups); 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci return 0; 12828c2ecf20Sopenharmony_ci} 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_cistatic void st_gpio_irq_mask(struct irq_data *d) 12858c2ecf20Sopenharmony_ci{ 12868c2ecf20Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 12878c2ecf20Sopenharmony_ci struct st_gpio_bank *bank = gpiochip_get_data(gc); 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci writel(BIT(d->hwirq), bank->base + REG_PIO_CLR_PMASK); 12908c2ecf20Sopenharmony_ci} 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_cistatic void st_gpio_irq_unmask(struct irq_data *d) 12938c2ecf20Sopenharmony_ci{ 12948c2ecf20Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 12958c2ecf20Sopenharmony_ci struct st_gpio_bank *bank = gpiochip_get_data(gc); 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci writel(BIT(d->hwirq), bank->base + REG_PIO_SET_PMASK); 12988c2ecf20Sopenharmony_ci} 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_cistatic int st_gpio_irq_request_resources(struct irq_data *d) 13018c2ecf20Sopenharmony_ci{ 13028c2ecf20Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci st_gpio_direction_input(gc, d->hwirq); 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci return gpiochip_lock_as_irq(gc, d->hwirq); 13078c2ecf20Sopenharmony_ci} 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_cistatic void st_gpio_irq_release_resources(struct irq_data *d) 13108c2ecf20Sopenharmony_ci{ 13118c2ecf20Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci gpiochip_unlock_as_irq(gc, d->hwirq); 13148c2ecf20Sopenharmony_ci} 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_cistatic int st_gpio_irq_set_type(struct irq_data *d, unsigned type) 13178c2ecf20Sopenharmony_ci{ 13188c2ecf20Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 13198c2ecf20Sopenharmony_ci struct st_gpio_bank *bank = gpiochip_get_data(gc); 13208c2ecf20Sopenharmony_ci unsigned long flags; 13218c2ecf20Sopenharmony_ci int comp, pin = d->hwirq; 13228c2ecf20Sopenharmony_ci u32 val; 13238c2ecf20Sopenharmony_ci u32 pin_edge_conf = 0; 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci switch (type) { 13268c2ecf20Sopenharmony_ci case IRQ_TYPE_LEVEL_HIGH: 13278c2ecf20Sopenharmony_ci comp = 0; 13288c2ecf20Sopenharmony_ci break; 13298c2ecf20Sopenharmony_ci case IRQ_TYPE_EDGE_FALLING: 13308c2ecf20Sopenharmony_ci comp = 0; 13318c2ecf20Sopenharmony_ci pin_edge_conf = ST_IRQ_FALLING_EDGE_CONF(pin); 13328c2ecf20Sopenharmony_ci break; 13338c2ecf20Sopenharmony_ci case IRQ_TYPE_LEVEL_LOW: 13348c2ecf20Sopenharmony_ci comp = 1; 13358c2ecf20Sopenharmony_ci break; 13368c2ecf20Sopenharmony_ci case IRQ_TYPE_EDGE_RISING: 13378c2ecf20Sopenharmony_ci comp = 1; 13388c2ecf20Sopenharmony_ci pin_edge_conf = ST_IRQ_RISING_EDGE_CONF(pin); 13398c2ecf20Sopenharmony_ci break; 13408c2ecf20Sopenharmony_ci case IRQ_TYPE_EDGE_BOTH: 13418c2ecf20Sopenharmony_ci comp = st_gpio_get(&bank->gpio_chip, pin); 13428c2ecf20Sopenharmony_ci pin_edge_conf = ST_IRQ_BOTH_EDGE_CONF(pin); 13438c2ecf20Sopenharmony_ci break; 13448c2ecf20Sopenharmony_ci default: 13458c2ecf20Sopenharmony_ci return -EINVAL; 13468c2ecf20Sopenharmony_ci } 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci spin_lock_irqsave(&bank->lock, flags); 13498c2ecf20Sopenharmony_ci bank->irq_edge_conf &= ~(ST_IRQ_EDGE_MASK << ( 13508c2ecf20Sopenharmony_ci pin * ST_IRQ_EDGE_CONF_BITS_PER_PIN)); 13518c2ecf20Sopenharmony_ci bank->irq_edge_conf |= pin_edge_conf; 13528c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bank->lock, flags); 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci val = readl(bank->base + REG_PIO_PCOMP); 13558c2ecf20Sopenharmony_ci val &= ~BIT(pin); 13568c2ecf20Sopenharmony_ci val |= (comp << pin); 13578c2ecf20Sopenharmony_ci writel(val, bank->base + REG_PIO_PCOMP); 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci return 0; 13608c2ecf20Sopenharmony_ci} 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci/* 13638c2ecf20Sopenharmony_ci * As edge triggers are not supported at hardware level, it is supported by 13648c2ecf20Sopenharmony_ci * software by exploiting the level trigger support in hardware. 13658c2ecf20Sopenharmony_ci * 13668c2ecf20Sopenharmony_ci * Steps for detection raising edge interrupt in software. 13678c2ecf20Sopenharmony_ci * 13688c2ecf20Sopenharmony_ci * Step 1: CONFIGURE pin to detect level LOW interrupts. 13698c2ecf20Sopenharmony_ci * 13708c2ecf20Sopenharmony_ci * Step 2: DETECT level LOW interrupt and in irqmux/gpio bank interrupt handler, 13718c2ecf20Sopenharmony_ci * if the value of pin is low, then CONFIGURE pin for level HIGH interrupt. 13728c2ecf20Sopenharmony_ci * IGNORE calling the actual interrupt handler for the pin at this stage. 13738c2ecf20Sopenharmony_ci * 13748c2ecf20Sopenharmony_ci * Step 3: DETECT level HIGH interrupt and in irqmux/gpio-bank interrupt handler 13758c2ecf20Sopenharmony_ci * if the value of pin is HIGH, CONFIGURE pin for level LOW interrupt and then 13768c2ecf20Sopenharmony_ci * DISPATCH the interrupt to the interrupt handler of the pin. 13778c2ecf20Sopenharmony_ci * 13788c2ecf20Sopenharmony_ci * step-1 ________ __________ 13798c2ecf20Sopenharmony_ci * | | step - 3 13808c2ecf20Sopenharmony_ci * | | 13818c2ecf20Sopenharmony_ci * step -2 |_____| 13828c2ecf20Sopenharmony_ci * 13838c2ecf20Sopenharmony_ci * falling edge is also detected int the same way. 13848c2ecf20Sopenharmony_ci * 13858c2ecf20Sopenharmony_ci */ 13868c2ecf20Sopenharmony_cistatic void __gpio_irq_handler(struct st_gpio_bank *bank) 13878c2ecf20Sopenharmony_ci{ 13888c2ecf20Sopenharmony_ci unsigned long port_in, port_mask, port_comp, active_irqs; 13898c2ecf20Sopenharmony_ci unsigned long bank_edge_mask, flags; 13908c2ecf20Sopenharmony_ci int n, val, ecfg; 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci spin_lock_irqsave(&bank->lock, flags); 13938c2ecf20Sopenharmony_ci bank_edge_mask = bank->irq_edge_conf; 13948c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bank->lock, flags); 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci for (;;) { 13978c2ecf20Sopenharmony_ci port_in = readl(bank->base + REG_PIO_PIN); 13988c2ecf20Sopenharmony_ci port_comp = readl(bank->base + REG_PIO_PCOMP); 13998c2ecf20Sopenharmony_ci port_mask = readl(bank->base + REG_PIO_PMASK); 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci active_irqs = (port_in ^ port_comp) & port_mask; 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci if (active_irqs == 0) 14048c2ecf20Sopenharmony_ci break; 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci for_each_set_bit(n, &active_irqs, BITS_PER_LONG) { 14078c2ecf20Sopenharmony_ci /* check if we are detecting fake edges ... */ 14088c2ecf20Sopenharmony_ci ecfg = ST_IRQ_EDGE_CONF(bank_edge_mask, n); 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci if (ecfg) { 14118c2ecf20Sopenharmony_ci /* edge detection. */ 14128c2ecf20Sopenharmony_ci val = st_gpio_get(&bank->gpio_chip, n); 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci writel(BIT(n), 14158c2ecf20Sopenharmony_ci val ? bank->base + REG_PIO_SET_PCOMP : 14168c2ecf20Sopenharmony_ci bank->base + REG_PIO_CLR_PCOMP); 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci if (ecfg != ST_IRQ_EDGE_BOTH && 14198c2ecf20Sopenharmony_ci !((ecfg & ST_IRQ_EDGE_FALLING) ^ val)) 14208c2ecf20Sopenharmony_ci continue; 14218c2ecf20Sopenharmony_ci } 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci generic_handle_irq(irq_find_mapping(bank->gpio_chip.irq.domain, n)); 14248c2ecf20Sopenharmony_ci } 14258c2ecf20Sopenharmony_ci } 14268c2ecf20Sopenharmony_ci} 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_cistatic void st_gpio_irq_handler(struct irq_desc *desc) 14298c2ecf20Sopenharmony_ci{ 14308c2ecf20Sopenharmony_ci /* interrupt dedicated per bank */ 14318c2ecf20Sopenharmony_ci struct irq_chip *chip = irq_desc_get_chip(desc); 14328c2ecf20Sopenharmony_ci struct gpio_chip *gc = irq_desc_get_handler_data(desc); 14338c2ecf20Sopenharmony_ci struct st_gpio_bank *bank = gpiochip_get_data(gc); 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci chained_irq_enter(chip, desc); 14368c2ecf20Sopenharmony_ci __gpio_irq_handler(bank); 14378c2ecf20Sopenharmony_ci chained_irq_exit(chip, desc); 14388c2ecf20Sopenharmony_ci} 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_cistatic void st_gpio_irqmux_handler(struct irq_desc *desc) 14418c2ecf20Sopenharmony_ci{ 14428c2ecf20Sopenharmony_ci struct irq_chip *chip = irq_desc_get_chip(desc); 14438c2ecf20Sopenharmony_ci struct st_pinctrl *info = irq_desc_get_handler_data(desc); 14448c2ecf20Sopenharmony_ci unsigned long status; 14458c2ecf20Sopenharmony_ci int n; 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci chained_irq_enter(chip, desc); 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci status = readl(info->irqmux_base); 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci for_each_set_bit(n, &status, info->nbanks) 14528c2ecf20Sopenharmony_ci __gpio_irq_handler(&info->banks[n]); 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci chained_irq_exit(chip, desc); 14558c2ecf20Sopenharmony_ci} 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_cistatic const struct gpio_chip st_gpio_template = { 14588c2ecf20Sopenharmony_ci .request = gpiochip_generic_request, 14598c2ecf20Sopenharmony_ci .free = gpiochip_generic_free, 14608c2ecf20Sopenharmony_ci .get = st_gpio_get, 14618c2ecf20Sopenharmony_ci .set = st_gpio_set, 14628c2ecf20Sopenharmony_ci .direction_input = st_gpio_direction_input, 14638c2ecf20Sopenharmony_ci .direction_output = st_gpio_direction_output, 14648c2ecf20Sopenharmony_ci .get_direction = st_gpio_get_direction, 14658c2ecf20Sopenharmony_ci .ngpio = ST_GPIO_PINS_PER_BANK, 14668c2ecf20Sopenharmony_ci}; 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_cistatic struct irq_chip st_gpio_irqchip = { 14698c2ecf20Sopenharmony_ci .name = "GPIO", 14708c2ecf20Sopenharmony_ci .irq_request_resources = st_gpio_irq_request_resources, 14718c2ecf20Sopenharmony_ci .irq_release_resources = st_gpio_irq_release_resources, 14728c2ecf20Sopenharmony_ci .irq_disable = st_gpio_irq_mask, 14738c2ecf20Sopenharmony_ci .irq_mask = st_gpio_irq_mask, 14748c2ecf20Sopenharmony_ci .irq_unmask = st_gpio_irq_unmask, 14758c2ecf20Sopenharmony_ci .irq_set_type = st_gpio_irq_set_type, 14768c2ecf20Sopenharmony_ci .flags = IRQCHIP_SKIP_SET_WAKE, 14778c2ecf20Sopenharmony_ci}; 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_cistatic int st_gpiolib_register_bank(struct st_pinctrl *info, 14808c2ecf20Sopenharmony_ci int bank_nr, struct device_node *np) 14818c2ecf20Sopenharmony_ci{ 14828c2ecf20Sopenharmony_ci struct st_gpio_bank *bank = &info->banks[bank_nr]; 14838c2ecf20Sopenharmony_ci struct pinctrl_gpio_range *range = &bank->range; 14848c2ecf20Sopenharmony_ci struct device *dev = info->dev; 14858c2ecf20Sopenharmony_ci int bank_num = of_alias_get_id(np, "gpio"); 14868c2ecf20Sopenharmony_ci struct resource res, irq_res; 14878c2ecf20Sopenharmony_ci int err; 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_ci if (of_address_to_resource(np, 0, &res)) 14908c2ecf20Sopenharmony_ci return -ENODEV; 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci bank->base = devm_ioremap_resource(dev, &res); 14938c2ecf20Sopenharmony_ci if (IS_ERR(bank->base)) 14948c2ecf20Sopenharmony_ci return PTR_ERR(bank->base); 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci bank->gpio_chip = st_gpio_template; 14978c2ecf20Sopenharmony_ci bank->gpio_chip.base = bank_num * ST_GPIO_PINS_PER_BANK; 14988c2ecf20Sopenharmony_ci bank->gpio_chip.ngpio = ST_GPIO_PINS_PER_BANK; 14998c2ecf20Sopenharmony_ci bank->gpio_chip.of_node = np; 15008c2ecf20Sopenharmony_ci bank->gpio_chip.parent = dev; 15018c2ecf20Sopenharmony_ci spin_lock_init(&bank->lock); 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci of_property_read_string(np, "st,bank-name", &range->name); 15048c2ecf20Sopenharmony_ci bank->gpio_chip.label = range->name; 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci range->id = bank_num; 15078c2ecf20Sopenharmony_ci range->pin_base = range->base = range->id * ST_GPIO_PINS_PER_BANK; 15088c2ecf20Sopenharmony_ci range->npins = bank->gpio_chip.ngpio; 15098c2ecf20Sopenharmony_ci range->gc = &bank->gpio_chip; 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci /** 15128c2ecf20Sopenharmony_ci * GPIO bank can have one of the two possible types of 15138c2ecf20Sopenharmony_ci * interrupt-wirings. 15148c2ecf20Sopenharmony_ci * 15158c2ecf20Sopenharmony_ci * First type is via irqmux, single interrupt is used by multiple 15168c2ecf20Sopenharmony_ci * gpio banks. This reduces number of overall interrupts numbers 15178c2ecf20Sopenharmony_ci * required. All these banks belong to a single pincontroller. 15188c2ecf20Sopenharmony_ci * _________ 15198c2ecf20Sopenharmony_ci * | |----> [gpio-bank (n) ] 15208c2ecf20Sopenharmony_ci * | |----> [gpio-bank (n + 1)] 15218c2ecf20Sopenharmony_ci * [irqN]-- | irq-mux |----> [gpio-bank (n + 2)] 15228c2ecf20Sopenharmony_ci * | |----> [gpio-bank (... )] 15238c2ecf20Sopenharmony_ci * |_________|----> [gpio-bank (n + 7)] 15248c2ecf20Sopenharmony_ci * 15258c2ecf20Sopenharmony_ci * Second type has a dedicated interrupt per each gpio bank. 15268c2ecf20Sopenharmony_ci * 15278c2ecf20Sopenharmony_ci * [irqN]----> [gpio-bank (n)] 15288c2ecf20Sopenharmony_ci */ 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci if (of_irq_to_resource(np, 0, &irq_res) > 0) { 15318c2ecf20Sopenharmony_ci struct gpio_irq_chip *girq; 15328c2ecf20Sopenharmony_ci int gpio_irq = irq_res.start; 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci /* This is not a valid IRQ */ 15358c2ecf20Sopenharmony_ci if (gpio_irq <= 0) { 15368c2ecf20Sopenharmony_ci dev_err(dev, "invalid IRQ for %pOF bank\n", np); 15378c2ecf20Sopenharmony_ci goto skip_irq; 15388c2ecf20Sopenharmony_ci } 15398c2ecf20Sopenharmony_ci /* We need to have a mux as well */ 15408c2ecf20Sopenharmony_ci if (!info->irqmux_base) { 15418c2ecf20Sopenharmony_ci dev_err(dev, "no irqmux for %pOF bank\n", np); 15428c2ecf20Sopenharmony_ci goto skip_irq; 15438c2ecf20Sopenharmony_ci } 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci girq = &bank->gpio_chip.irq; 15468c2ecf20Sopenharmony_ci girq->chip = &st_gpio_irqchip; 15478c2ecf20Sopenharmony_ci girq->parent_handler = st_gpio_irq_handler; 15488c2ecf20Sopenharmony_ci girq->num_parents = 1; 15498c2ecf20Sopenharmony_ci girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents), 15508c2ecf20Sopenharmony_ci GFP_KERNEL); 15518c2ecf20Sopenharmony_ci if (!girq->parents) 15528c2ecf20Sopenharmony_ci return -ENOMEM; 15538c2ecf20Sopenharmony_ci girq->parents[0] = gpio_irq; 15548c2ecf20Sopenharmony_ci girq->default_type = IRQ_TYPE_NONE; 15558c2ecf20Sopenharmony_ci girq->handler = handle_simple_irq; 15568c2ecf20Sopenharmony_ci } 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ciskip_irq: 15598c2ecf20Sopenharmony_ci err = gpiochip_add_data(&bank->gpio_chip, bank); 15608c2ecf20Sopenharmony_ci if (err) { 15618c2ecf20Sopenharmony_ci dev_err(dev, "Failed to add gpiochip(%d)!\n", bank_num); 15628c2ecf20Sopenharmony_ci return err; 15638c2ecf20Sopenharmony_ci } 15648c2ecf20Sopenharmony_ci dev_info(dev, "%s bank added.\n", range->name); 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ci return 0; 15678c2ecf20Sopenharmony_ci} 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_cistatic const struct of_device_id st_pctl_of_match[] = { 15708c2ecf20Sopenharmony_ci { .compatible = "st,stih407-sbc-pinctrl", .data = &stih407_data}, 15718c2ecf20Sopenharmony_ci { .compatible = "st,stih407-front-pinctrl", .data = &stih407_data}, 15728c2ecf20Sopenharmony_ci { .compatible = "st,stih407-rear-pinctrl", .data = &stih407_data}, 15738c2ecf20Sopenharmony_ci { .compatible = "st,stih407-flash-pinctrl", .data = &stih407_flashdata}, 15748c2ecf20Sopenharmony_ci { /* sentinel */ } 15758c2ecf20Sopenharmony_ci}; 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_cistatic int st_pctl_probe_dt(struct platform_device *pdev, 15788c2ecf20Sopenharmony_ci struct pinctrl_desc *pctl_desc, struct st_pinctrl *info) 15798c2ecf20Sopenharmony_ci{ 15808c2ecf20Sopenharmony_ci int ret = 0; 15818c2ecf20Sopenharmony_ci int i = 0, j = 0, k = 0, bank; 15828c2ecf20Sopenharmony_ci struct pinctrl_pin_desc *pdesc; 15838c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 15848c2ecf20Sopenharmony_ci struct device_node *child; 15858c2ecf20Sopenharmony_ci int grp_index = 0; 15868c2ecf20Sopenharmony_ci int irq = 0; 15878c2ecf20Sopenharmony_ci struct resource *res; 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci st_pctl_dt_child_count(info, np); 15908c2ecf20Sopenharmony_ci if (!info->nbanks) { 15918c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "you need atleast one gpio bank\n"); 15928c2ecf20Sopenharmony_ci return -EINVAL; 15938c2ecf20Sopenharmony_ci } 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "nbanks = %d\n", info->nbanks); 15968c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "nfunctions = %d\n", info->nfunctions); 15978c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "ngroups = %d\n", info->ngroups); 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci info->functions = devm_kcalloc(&pdev->dev, 16008c2ecf20Sopenharmony_ci info->nfunctions, sizeof(*info->functions), GFP_KERNEL); 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_ci info->groups = devm_kcalloc(&pdev->dev, 16038c2ecf20Sopenharmony_ci info->ngroups, sizeof(*info->groups), 16048c2ecf20Sopenharmony_ci GFP_KERNEL); 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci info->banks = devm_kcalloc(&pdev->dev, 16078c2ecf20Sopenharmony_ci info->nbanks, sizeof(*info->banks), GFP_KERNEL); 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci if (!info->functions || !info->groups || !info->banks) 16108c2ecf20Sopenharmony_ci return -ENOMEM; 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci info->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg"); 16138c2ecf20Sopenharmony_ci if (IS_ERR(info->regmap)) { 16148c2ecf20Sopenharmony_ci dev_err(info->dev, "No syscfg phandle specified\n"); 16158c2ecf20Sopenharmony_ci return PTR_ERR(info->regmap); 16168c2ecf20Sopenharmony_ci } 16178c2ecf20Sopenharmony_ci info->data = of_match_node(st_pctl_of_match, np)->data; 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci irq = platform_get_irq(pdev, 0); 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci if (irq > 0) { 16228c2ecf20Sopenharmony_ci res = platform_get_resource_byname(pdev, 16238c2ecf20Sopenharmony_ci IORESOURCE_MEM, "irqmux"); 16248c2ecf20Sopenharmony_ci info->irqmux_base = devm_ioremap_resource(&pdev->dev, res); 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci if (IS_ERR(info->irqmux_base)) 16278c2ecf20Sopenharmony_ci return PTR_ERR(info->irqmux_base); 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci irq_set_chained_handler_and_data(irq, st_gpio_irqmux_handler, 16308c2ecf20Sopenharmony_ci info); 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci } 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_ci pctl_desc->npins = info->nbanks * ST_GPIO_PINS_PER_BANK; 16358c2ecf20Sopenharmony_ci pdesc = devm_kcalloc(&pdev->dev, 16368c2ecf20Sopenharmony_ci pctl_desc->npins, sizeof(*pdesc), GFP_KERNEL); 16378c2ecf20Sopenharmony_ci if (!pdesc) 16388c2ecf20Sopenharmony_ci return -ENOMEM; 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_ci pctl_desc->pins = pdesc; 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci bank = 0; 16438c2ecf20Sopenharmony_ci for_each_child_of_node(np, child) { 16448c2ecf20Sopenharmony_ci if (of_property_read_bool(child, "gpio-controller")) { 16458c2ecf20Sopenharmony_ci const char *bank_name = NULL; 16468c2ecf20Sopenharmony_ci ret = st_gpiolib_register_bank(info, bank, child); 16478c2ecf20Sopenharmony_ci if (ret) { 16488c2ecf20Sopenharmony_ci of_node_put(child); 16498c2ecf20Sopenharmony_ci return ret; 16508c2ecf20Sopenharmony_ci } 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci k = info->banks[bank].range.pin_base; 16538c2ecf20Sopenharmony_ci bank_name = info->banks[bank].range.name; 16548c2ecf20Sopenharmony_ci for (j = 0; j < ST_GPIO_PINS_PER_BANK; j++, k++) { 16558c2ecf20Sopenharmony_ci pdesc->number = k; 16568c2ecf20Sopenharmony_ci pdesc->name = kasprintf(GFP_KERNEL, "%s[%d]", 16578c2ecf20Sopenharmony_ci bank_name, j); 16588c2ecf20Sopenharmony_ci pdesc++; 16598c2ecf20Sopenharmony_ci } 16608c2ecf20Sopenharmony_ci st_parse_syscfgs(info, bank, child); 16618c2ecf20Sopenharmony_ci bank++; 16628c2ecf20Sopenharmony_ci } else { 16638c2ecf20Sopenharmony_ci ret = st_pctl_parse_functions(child, info, 16648c2ecf20Sopenharmony_ci i++, &grp_index); 16658c2ecf20Sopenharmony_ci if (ret) { 16668c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "No functions found.\n"); 16678c2ecf20Sopenharmony_ci of_node_put(child); 16688c2ecf20Sopenharmony_ci return ret; 16698c2ecf20Sopenharmony_ci } 16708c2ecf20Sopenharmony_ci } 16718c2ecf20Sopenharmony_ci } 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci return 0; 16748c2ecf20Sopenharmony_ci} 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_cistatic int st_pctl_probe(struct platform_device *pdev) 16778c2ecf20Sopenharmony_ci{ 16788c2ecf20Sopenharmony_ci struct st_pinctrl *info; 16798c2ecf20Sopenharmony_ci struct pinctrl_desc *pctl_desc; 16808c2ecf20Sopenharmony_ci int ret, i; 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci if (!pdev->dev.of_node) { 16838c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "device node not found.\n"); 16848c2ecf20Sopenharmony_ci return -EINVAL; 16858c2ecf20Sopenharmony_ci } 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci pctl_desc = devm_kzalloc(&pdev->dev, sizeof(*pctl_desc), GFP_KERNEL); 16888c2ecf20Sopenharmony_ci if (!pctl_desc) 16898c2ecf20Sopenharmony_ci return -ENOMEM; 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); 16928c2ecf20Sopenharmony_ci if (!info) 16938c2ecf20Sopenharmony_ci return -ENOMEM; 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci info->dev = &pdev->dev; 16968c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, info); 16978c2ecf20Sopenharmony_ci ret = st_pctl_probe_dt(pdev, pctl_desc, info); 16988c2ecf20Sopenharmony_ci if (ret) 16998c2ecf20Sopenharmony_ci return ret; 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci pctl_desc->owner = THIS_MODULE; 17028c2ecf20Sopenharmony_ci pctl_desc->pctlops = &st_pctlops; 17038c2ecf20Sopenharmony_ci pctl_desc->pmxops = &st_pmxops; 17048c2ecf20Sopenharmony_ci pctl_desc->confops = &st_confops; 17058c2ecf20Sopenharmony_ci pctl_desc->name = dev_name(&pdev->dev); 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_ci info->pctl = devm_pinctrl_register(&pdev->dev, pctl_desc, info); 17088c2ecf20Sopenharmony_ci if (IS_ERR(info->pctl)) { 17098c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed pinctrl registration\n"); 17108c2ecf20Sopenharmony_ci return PTR_ERR(info->pctl); 17118c2ecf20Sopenharmony_ci } 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci for (i = 0; i < info->nbanks; i++) 17148c2ecf20Sopenharmony_ci pinctrl_add_gpio_range(info->pctl, &info->banks[i].range); 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci return 0; 17178c2ecf20Sopenharmony_ci} 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_cistatic struct platform_driver st_pctl_driver = { 17208c2ecf20Sopenharmony_ci .driver = { 17218c2ecf20Sopenharmony_ci .name = "st-pinctrl", 17228c2ecf20Sopenharmony_ci .of_match_table = st_pctl_of_match, 17238c2ecf20Sopenharmony_ci }, 17248c2ecf20Sopenharmony_ci .probe = st_pctl_probe, 17258c2ecf20Sopenharmony_ci}; 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_cistatic int __init st_pctl_init(void) 17288c2ecf20Sopenharmony_ci{ 17298c2ecf20Sopenharmony_ci return platform_driver_register(&st_pctl_driver); 17308c2ecf20Sopenharmony_ci} 17318c2ecf20Sopenharmony_ciarch_initcall(st_pctl_init); 1732