162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * SP7021 Pin Controller Driver. 462306a36Sopenharmony_ci * Copyright (C) Sunplus Tech / Tibbo Tech. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/bitfield.h> 862306a36Sopenharmony_ci#include <linux/device.h> 962306a36Sopenharmony_ci#include <linux/err.h> 1062306a36Sopenharmony_ci#include <linux/gpio/driver.h> 1162306a36Sopenharmony_ci#include <linux/init.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/of.h> 1462306a36Sopenharmony_ci#include <linux/overflow.h> 1562306a36Sopenharmony_ci#include <linux/platform_device.h> 1662306a36Sopenharmony_ci#include <linux/seq_file.h> 1762306a36Sopenharmony_ci#include <linux/slab.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <linux/pinctrl/pinconf.h> 2062306a36Sopenharmony_ci#include <linux/pinctrl/pinconf-generic.h> 2162306a36Sopenharmony_ci#include <linux/pinctrl/pinmux.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include <dt-bindings/pinctrl/sppctl-sp7021.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include "../core.h" 2662306a36Sopenharmony_ci#include "../pinctrl-utils.h" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#include "sppctl.h" 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistruct sppctl_gpio_chip { 3162306a36Sopenharmony_ci void __iomem *gpioxt_base; /* MASTER, OE, OUT, IN, I_INV, O_INV, OD */ 3262306a36Sopenharmony_ci void __iomem *first_base; /* GPIO_FIRST */ 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci struct gpio_chip chip; 3562306a36Sopenharmony_ci spinlock_t lock; /* lock for accessing OE register */ 3662306a36Sopenharmony_ci}; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic inline u32 sppctl_first_readl(struct sppctl_gpio_chip *spp_gchip, u32 off) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci return readl(spp_gchip->first_base + SPPCTL_GPIO_OFF_FIRST + off); 4162306a36Sopenharmony_ci} 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic inline void sppctl_first_writel(struct sppctl_gpio_chip *spp_gchip, u32 val, u32 off) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci writel(val, spp_gchip->first_base + SPPCTL_GPIO_OFF_FIRST + off); 4662306a36Sopenharmony_ci} 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic inline u32 sppctl_gpio_master_readl(struct sppctl_gpio_chip *spp_gchip, u32 off) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci return readl(spp_gchip->gpioxt_base + SPPCTL_GPIO_OFF_MASTER + off); 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic inline void sppctl_gpio_master_writel(struct sppctl_gpio_chip *spp_gchip, u32 val, 5462306a36Sopenharmony_ci u32 off) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci writel(val, spp_gchip->gpioxt_base + SPPCTL_GPIO_OFF_MASTER + off); 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic inline u32 sppctl_gpio_oe_readl(struct sppctl_gpio_chip *spp_gchip, u32 off) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci return readl(spp_gchip->gpioxt_base + SPPCTL_GPIO_OFF_OE + off); 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic inline void sppctl_gpio_oe_writel(struct sppctl_gpio_chip *spp_gchip, u32 val, u32 off) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci writel(val, spp_gchip->gpioxt_base + SPPCTL_GPIO_OFF_OE + off); 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic inline void sppctl_gpio_out_writel(struct sppctl_gpio_chip *spp_gchip, u32 val, u32 off) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci writel(val, spp_gchip->gpioxt_base + SPPCTL_GPIO_OFF_OUT + off); 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic inline u32 sppctl_gpio_in_readl(struct sppctl_gpio_chip *spp_gchip, u32 off) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci return readl(spp_gchip->gpioxt_base + SPPCTL_GPIO_OFF_IN + off); 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic inline u32 sppctl_gpio_iinv_readl(struct sppctl_gpio_chip *spp_gchip, u32 off) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci return readl(spp_gchip->gpioxt_base + SPPCTL_GPIO_OFF_IINV + off); 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic inline void sppctl_gpio_iinv_writel(struct sppctl_gpio_chip *spp_gchip, u32 val, 8562306a36Sopenharmony_ci u32 off) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci writel(val, spp_gchip->gpioxt_base + SPPCTL_GPIO_OFF_IINV + off); 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic inline u32 sppctl_gpio_oinv_readl(struct sppctl_gpio_chip *spp_gchip, u32 off) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci return readl(spp_gchip->gpioxt_base + SPPCTL_GPIO_OFF_OINV + off); 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic inline void sppctl_gpio_oinv_writel(struct sppctl_gpio_chip *spp_gchip, u32 val, 9662306a36Sopenharmony_ci u32 off) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci writel(val, spp_gchip->gpioxt_base + SPPCTL_GPIO_OFF_OINV + off); 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic inline u32 sppctl_gpio_od_readl(struct sppctl_gpio_chip *spp_gchip, u32 off) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci return readl(spp_gchip->gpioxt_base + SPPCTL_GPIO_OFF_OD + off); 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic inline void sppctl_gpio_od_writel(struct sppctl_gpio_chip *spp_gchip, u32 val, u32 off) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci writel(val, spp_gchip->gpioxt_base + SPPCTL_GPIO_OFF_OD + off); 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic inline u32 sppctl_get_reg_and_bit_offset(unsigned int offset, u32 *reg_off) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci u32 bit_off; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci /* Each register has 32 bits. */ 11662306a36Sopenharmony_ci *reg_off = (offset / 32) * 4; 11762306a36Sopenharmony_ci bit_off = offset % 32; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci return bit_off; 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic inline u32 sppctl_get_moon_reg_and_bit_offset(unsigned int offset, u32 *reg_off) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci u32 bit_off; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci /* 12762306a36Sopenharmony_ci * Each MOON register has 32 bits. Upper 16-bit word are mask-fields. 12862306a36Sopenharmony_ci * The lower 16-bit word are the control-fields. The corresponding 12962306a36Sopenharmony_ci * bits in mask-field should be set then you can write something to 13062306a36Sopenharmony_ci * control-field. 13162306a36Sopenharmony_ci */ 13262306a36Sopenharmony_ci *reg_off = (offset / 16) * 4; 13362306a36Sopenharmony_ci bit_off = offset % 16; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci return bit_off; 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic inline u32 sppctl_prep_moon_reg_and_offset(unsigned int offset, u32 *reg_off, int val) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci u32 bit_off; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci bit_off = sppctl_get_moon_reg_and_bit_offset(offset, reg_off); 14362306a36Sopenharmony_ci if (val) 14462306a36Sopenharmony_ci return SPPCTL_SET_MOON_REG_BIT(bit_off); 14562306a36Sopenharmony_ci else 14662306a36Sopenharmony_ci return SPPCTL_CLR_MOON_REG_BIT(bit_off); 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci/** 15062306a36Sopenharmony_ci * sppctl_func_set() - Set pin of fully-pinmux function. 15162306a36Sopenharmony_ci * 15262306a36Sopenharmony_ci * Mask-fields and control-fields of fully-pinmux function of SP7021 are 15362306a36Sopenharmony_ci * arranged as shown below: 15462306a36Sopenharmony_ci * 15562306a36Sopenharmony_ci * func# | register | mask-field | control-field 15662306a36Sopenharmony_ci * -------+----------+--------------+--------------- 15762306a36Sopenharmony_ci * 0 | base[0] | (22 : 16) | ( 6 : 0) 15862306a36Sopenharmony_ci * 1 | base[0] | (30 : 24) | (14 : 8) 15962306a36Sopenharmony_ci * 2 | base[1] | (22 : 16) | ( 6 : 0) 16062306a36Sopenharmony_ci * 3 | baeg[1] | (30 : 24) | (14 : 8) 16162306a36Sopenharmony_ci * : | : | : | : 16262306a36Sopenharmony_ci * 16362306a36Sopenharmony_ci * where mask-fields are used to protect control-fields from write-in 16462306a36Sopenharmony_ci * accidentally. Set the corresponding bits in the mask-field before 16562306a36Sopenharmony_ci * you write a value into a control-field. 16662306a36Sopenharmony_ci * 16762306a36Sopenharmony_ci * Control-fields are used to set where the function pin is going to 16862306a36Sopenharmony_ci * be routed to. 16962306a36Sopenharmony_ci * 17062306a36Sopenharmony_ci * Note that mask-fields and control-fields of even number of 'func' 17162306a36Sopenharmony_ci * are located at bits (22:16) and (6:0), while odd number of 'func's 17262306a36Sopenharmony_ci * are located at bits (30:24) and (14:8). 17362306a36Sopenharmony_ci */ 17462306a36Sopenharmony_cistatic void sppctl_func_set(struct sppctl_pdata *pctl, u8 func, u8 val) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci u32 reg, offset; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci /* 17962306a36Sopenharmony_ci * Note that upper 16-bit word are mask-fields and lower 16-bit 18062306a36Sopenharmony_ci * word are the control-fields. Set corresponding bits in mask- 18162306a36Sopenharmony_ci * field before write to a control-field. 18262306a36Sopenharmony_ci */ 18362306a36Sopenharmony_ci reg = SPPCTL_FULLY_PINMUX_MASK_MASK | val; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci /* 18662306a36Sopenharmony_ci * MUXF_L2SW_CLK_OUT is the first fully-pinmux pin 18762306a36Sopenharmony_ci * and its register offset is 0. 18862306a36Sopenharmony_ci */ 18962306a36Sopenharmony_ci func -= MUXF_L2SW_CLK_OUT; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci /* 19262306a36Sopenharmony_ci * Check if 'func' is an odd number or not. Mask and control- 19362306a36Sopenharmony_ci * fields of odd number 'func' is located at upper portion of 19462306a36Sopenharmony_ci * a register. Extra shift is needed. 19562306a36Sopenharmony_ci */ 19662306a36Sopenharmony_ci if (func & BIT(0)) 19762306a36Sopenharmony_ci reg <<= SPPCTL_FULLY_PINMUX_UPPER_SHIFT; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci /* Convert func# to register offset w.r.t. base register. */ 20062306a36Sopenharmony_ci offset = func * 2; 20162306a36Sopenharmony_ci offset &= GENMASK(31, 2); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci writel(reg, pctl->moon2_base + offset); 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci/** 20762306a36Sopenharmony_ci * sppctl_gmx_set() - Set pin of group-pinmux. 20862306a36Sopenharmony_ci * 20962306a36Sopenharmony_ci * Mask-fields and control-fields of group-pinmux function of SP7021 are 21062306a36Sopenharmony_ci * arranged as shown below: 21162306a36Sopenharmony_ci * 21262306a36Sopenharmony_ci * register | mask-fields | control-fields 21362306a36Sopenharmony_ci * ----------+--------------+---------------- 21462306a36Sopenharmony_ci * base[0] | (31 : 16) | (15 : 0) 21562306a36Sopenharmony_ci * base[1] | (31 : 24) | (15 : 0) 21662306a36Sopenharmony_ci * base[2] | (31 : 24) | (15 : 0) 21762306a36Sopenharmony_ci * : | : | : 21862306a36Sopenharmony_ci * 21962306a36Sopenharmony_ci * where mask-fields are used to protect control-fields from write-in 22062306a36Sopenharmony_ci * accidentally. Set the corresponding bits in the mask-field before 22162306a36Sopenharmony_ci * you write a value into a control-field. 22262306a36Sopenharmony_ci * 22362306a36Sopenharmony_ci * Control-fields are used to set where the function pin is going to 22462306a36Sopenharmony_ci * be routed to. A control-field consists of one or more bits. 22562306a36Sopenharmony_ci */ 22662306a36Sopenharmony_cistatic void sppctl_gmx_set(struct sppctl_pdata *pctl, u8 reg_off, u8 bit_off, u8 bit_sz, 22762306a36Sopenharmony_ci u8 val) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci u32 mask, reg; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci /* 23262306a36Sopenharmony_ci * Note that upper 16-bit word are mask-fields and lower 16-bit 23362306a36Sopenharmony_ci * word are the control-fields. Set corresponding bits in mask- 23462306a36Sopenharmony_ci * field before write to a control-field. 23562306a36Sopenharmony_ci */ 23662306a36Sopenharmony_ci mask = GENMASK(bit_sz - 1, 0) << SPPCTL_MOON_REG_MASK_SHIFT; 23762306a36Sopenharmony_ci reg = (mask | val) << bit_off; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci writel(reg, pctl->moon1_base + reg_off * 4); 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci/** 24362306a36Sopenharmony_ci * sppctl_first_get() - get bit of FIRST register. 24462306a36Sopenharmony_ci * 24562306a36Sopenharmony_ci * There are 4 FIRST registers. Each has 32 control-bits. 24662306a36Sopenharmony_ci * Totally, there are 4 * 32 = 128 control-bits. 24762306a36Sopenharmony_ci * Control-bits are arranged as shown below: 24862306a36Sopenharmony_ci * 24962306a36Sopenharmony_ci * registers | control-bits 25062306a36Sopenharmony_ci * -----------+-------------- 25162306a36Sopenharmony_ci * first[0] | (31 : 0) 25262306a36Sopenharmony_ci * first[1] | (63 : 32) 25362306a36Sopenharmony_ci * first[2] | (95 : 64) 25462306a36Sopenharmony_ci * first[3] | (127 : 96) 25562306a36Sopenharmony_ci * 25662306a36Sopenharmony_ci * Each control-bit sets type of a GPIO pin. 25762306a36Sopenharmony_ci * 0: a fully-pinmux pin 25862306a36Sopenharmony_ci * 1: a GPIO or IOP pin 25962306a36Sopenharmony_ci */ 26062306a36Sopenharmony_cistatic int sppctl_first_get(struct gpio_chip *chip, unsigned int offset) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci struct sppctl_gpio_chip *spp_gchip = gpiochip_get_data(chip); 26362306a36Sopenharmony_ci u32 reg_off, bit_off, reg; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci bit_off = sppctl_get_reg_and_bit_offset(offset, ®_off); 26662306a36Sopenharmony_ci reg = sppctl_first_readl(spp_gchip, reg_off); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci return (reg & BIT(bit_off)) ? 1 : 0; 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci/** 27262306a36Sopenharmony_ci * sppctl_master_get() - get bit of MASTER register. 27362306a36Sopenharmony_ci * 27462306a36Sopenharmony_ci * There are 8 MASTER registers. Each has 16 mask-bits and 16 control-bits. 27562306a36Sopenharmony_ci * Upper 16-bit of MASTER registers are mask-bits while lower 16-bit are 27662306a36Sopenharmony_ci * control-bits. Totally, there are 128 mask-bits and 128 control-bits. 27762306a36Sopenharmony_ci * They are arranged as shown below: 27862306a36Sopenharmony_ci * 27962306a36Sopenharmony_ci * register | mask-bits | control-bits 28062306a36Sopenharmony_ci * -----------+-------------+-------------- 28162306a36Sopenharmony_ci * master[0] | (15 : 0) | (15 : 0) 28262306a36Sopenharmony_ci * master[1] | (31 : 16) | (31 : 16) 28362306a36Sopenharmony_ci * master[2] | (47 : 32) | (47 : 32) 28462306a36Sopenharmony_ci * : | : | : 28562306a36Sopenharmony_ci * master[7] | (127 : 112) | (127 : 112) 28662306a36Sopenharmony_ci * 28762306a36Sopenharmony_ci * where mask-bits are used to protect control-bits from write-in 28862306a36Sopenharmony_ci * accidentally. Set the corresponding mask-bit before you write 28962306a36Sopenharmony_ci * a value into a control-bit. 29062306a36Sopenharmony_ci * 29162306a36Sopenharmony_ci * Each control-bit sets type of a GPIO pin when FIRST bit is 1. 29262306a36Sopenharmony_ci * 0: a IOP pin 29362306a36Sopenharmony_ci * 1: a GPIO pin 29462306a36Sopenharmony_ci */ 29562306a36Sopenharmony_cistatic int sppctl_master_get(struct gpio_chip *chip, unsigned int offset) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci struct sppctl_gpio_chip *spp_gchip = gpiochip_get_data(chip); 29862306a36Sopenharmony_ci u32 reg_off, bit_off, reg; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci bit_off = sppctl_get_moon_reg_and_bit_offset(offset, ®_off); 30162306a36Sopenharmony_ci reg = sppctl_gpio_master_readl(spp_gchip, reg_off); 30262306a36Sopenharmony_ci return (reg & BIT(bit_off)) ? 1 : 0; 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cistatic void sppctl_first_master_set(struct gpio_chip *chip, unsigned int offset, 30662306a36Sopenharmony_ci enum mux_first_reg first, enum mux_master_reg master) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci struct sppctl_gpio_chip *spp_gchip = gpiochip_get_data(chip); 30962306a36Sopenharmony_ci u32 reg_off, bit_off, reg; 31062306a36Sopenharmony_ci enum mux_first_reg val; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci /* FIRST register */ 31362306a36Sopenharmony_ci if (first != mux_f_keep) { 31462306a36Sopenharmony_ci bit_off = sppctl_get_reg_and_bit_offset(offset, ®_off); 31562306a36Sopenharmony_ci reg = sppctl_first_readl(spp_gchip, reg_off); 31662306a36Sopenharmony_ci val = (reg & BIT(bit_off)) ? mux_f_gpio : mux_f_mux; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci if (first != val) 31962306a36Sopenharmony_ci switch (first) { 32062306a36Sopenharmony_ci case mux_f_gpio: 32162306a36Sopenharmony_ci reg |= BIT(bit_off); 32262306a36Sopenharmony_ci sppctl_first_writel(spp_gchip, reg, reg_off); 32362306a36Sopenharmony_ci break; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci case mux_f_mux: 32662306a36Sopenharmony_ci reg &= ~BIT(bit_off); 32762306a36Sopenharmony_ci sppctl_first_writel(spp_gchip, reg, reg_off); 32862306a36Sopenharmony_ci break; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci case mux_f_keep: 33162306a36Sopenharmony_ci break; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci /* MASTER register */ 33662306a36Sopenharmony_ci if (master != mux_m_keep) { 33762306a36Sopenharmony_ci reg = sppctl_prep_moon_reg_and_offset(offset, ®_off, (master == mux_m_gpio)); 33862306a36Sopenharmony_ci sppctl_gpio_master_writel(spp_gchip, reg, reg_off); 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cistatic void sppctl_gpio_input_inv_set(struct gpio_chip *chip, unsigned int offset) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci struct sppctl_gpio_chip *spp_gchip = gpiochip_get_data(chip); 34562306a36Sopenharmony_ci u32 reg_off, reg; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci reg = sppctl_prep_moon_reg_and_offset(offset, ®_off, 1); 34862306a36Sopenharmony_ci sppctl_gpio_iinv_writel(spp_gchip, reg, reg_off); 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cistatic void sppctl_gpio_output_inv_set(struct gpio_chip *chip, unsigned int offset) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci struct sppctl_gpio_chip *spp_gchip = gpiochip_get_data(chip); 35462306a36Sopenharmony_ci u32 reg_off, reg; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci reg = sppctl_prep_moon_reg_and_offset(offset, ®_off, 1); 35762306a36Sopenharmony_ci sppctl_gpio_oinv_writel(spp_gchip, reg, reg_off); 35862306a36Sopenharmony_ci} 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_cistatic int sppctl_gpio_output_od_get(struct gpio_chip *chip, unsigned int offset) 36162306a36Sopenharmony_ci{ 36262306a36Sopenharmony_ci struct sppctl_gpio_chip *spp_gchip = gpiochip_get_data(chip); 36362306a36Sopenharmony_ci u32 reg_off, bit_off, reg; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci bit_off = sppctl_get_moon_reg_and_bit_offset(offset, ®_off); 36662306a36Sopenharmony_ci reg = sppctl_gpio_od_readl(spp_gchip, reg_off); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci return (reg & BIT(bit_off)) ? 1 : 0; 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic void sppctl_gpio_output_od_set(struct gpio_chip *chip, unsigned int offset, 37262306a36Sopenharmony_ci unsigned int val) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci struct sppctl_gpio_chip *spp_gchip = gpiochip_get_data(chip); 37562306a36Sopenharmony_ci u32 reg_off, reg; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci reg = sppctl_prep_moon_reg_and_offset(offset, ®_off, val); 37862306a36Sopenharmony_ci sppctl_gpio_od_writel(spp_gchip, reg, reg_off); 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_cistatic int sppctl_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci struct sppctl_gpio_chip *spp_gchip = gpiochip_get_data(chip); 38462306a36Sopenharmony_ci u32 reg_off, bit_off, reg; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci bit_off = sppctl_get_moon_reg_and_bit_offset(offset, ®_off); 38762306a36Sopenharmony_ci reg = sppctl_gpio_oe_readl(spp_gchip, reg_off); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci return (reg & BIT(bit_off)) ? 0 : 1; 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_cistatic int sppctl_gpio_inv_get(struct gpio_chip *chip, unsigned int offset) 39362306a36Sopenharmony_ci{ 39462306a36Sopenharmony_ci struct sppctl_gpio_chip *spp_gchip = gpiochip_get_data(chip); 39562306a36Sopenharmony_ci u32 reg_off, bit_off, reg; 39662306a36Sopenharmony_ci unsigned long flags; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci bit_off = sppctl_get_moon_reg_and_bit_offset(offset, ®_off); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci spin_lock_irqsave(&spp_gchip->lock, flags); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci if (sppctl_gpio_get_direction(chip, offset)) 40362306a36Sopenharmony_ci reg = sppctl_gpio_iinv_readl(spp_gchip, reg_off); 40462306a36Sopenharmony_ci else 40562306a36Sopenharmony_ci reg = sppctl_gpio_oinv_readl(spp_gchip, reg_off); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci spin_unlock_irqrestore(&spp_gchip->lock, flags); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci return (reg & BIT(bit_off)) ? 1 : 0; 41062306a36Sopenharmony_ci} 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic int sppctl_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) 41362306a36Sopenharmony_ci{ 41462306a36Sopenharmony_ci struct sppctl_gpio_chip *spp_gchip = gpiochip_get_data(chip); 41562306a36Sopenharmony_ci unsigned long flags; 41662306a36Sopenharmony_ci u32 reg_off, reg; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci reg = sppctl_prep_moon_reg_and_offset(offset, ®_off, 0); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci spin_lock_irqsave(&spp_gchip->lock, flags); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci sppctl_gpio_oe_writel(spp_gchip, reg, reg_off); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci spin_unlock_irqrestore(&spp_gchip->lock, flags); 42562306a36Sopenharmony_ci return 0; 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic int sppctl_gpio_direction_output(struct gpio_chip *chip, unsigned int offset, int val) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci struct sppctl_gpio_chip *spp_gchip = gpiochip_get_data(chip); 43162306a36Sopenharmony_ci unsigned long flags; 43262306a36Sopenharmony_ci u32 reg_off, reg; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci reg = sppctl_prep_moon_reg_and_offset(offset, ®_off, 1); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci spin_lock_irqsave(&spp_gchip->lock, flags); 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci sppctl_gpio_oe_writel(spp_gchip, reg, reg_off); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci if (val < 0) { 44162306a36Sopenharmony_ci spin_unlock_irqrestore(&spp_gchip->lock, flags); 44262306a36Sopenharmony_ci return 0; 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci reg = sppctl_prep_moon_reg_and_offset(offset, ®_off, val); 44662306a36Sopenharmony_ci sppctl_gpio_out_writel(spp_gchip, reg, reg_off); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci spin_unlock_irqrestore(&spp_gchip->lock, flags); 44962306a36Sopenharmony_ci return 0; 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_cistatic int sppctl_gpio_get(struct gpio_chip *chip, unsigned int offset) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci struct sppctl_gpio_chip *spp_gchip = gpiochip_get_data(chip); 45562306a36Sopenharmony_ci u32 reg_off, bit_off, reg; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci bit_off = sppctl_get_reg_and_bit_offset(offset, ®_off); 45862306a36Sopenharmony_ci reg = sppctl_gpio_in_readl(spp_gchip, reg_off); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci return (reg & BIT(bit_off)) ? 1 : 0; 46162306a36Sopenharmony_ci} 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_cistatic void sppctl_gpio_set(struct gpio_chip *chip, unsigned int offset, int val) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci struct sppctl_gpio_chip *spp_gchip = gpiochip_get_data(chip); 46662306a36Sopenharmony_ci u32 reg_off, reg; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci reg = sppctl_prep_moon_reg_and_offset(offset, ®_off, val); 46962306a36Sopenharmony_ci sppctl_gpio_out_writel(spp_gchip, reg, reg_off); 47062306a36Sopenharmony_ci} 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_cistatic int sppctl_gpio_set_config(struct gpio_chip *chip, unsigned int offset, 47362306a36Sopenharmony_ci unsigned long config) 47462306a36Sopenharmony_ci{ 47562306a36Sopenharmony_ci enum pin_config_param param = pinconf_to_config_param(config); 47662306a36Sopenharmony_ci struct sppctl_gpio_chip *spp_gchip = gpiochip_get_data(chip); 47762306a36Sopenharmony_ci u32 reg_off, reg; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci switch (param) { 48062306a36Sopenharmony_ci case PIN_CONFIG_DRIVE_OPEN_DRAIN: 48162306a36Sopenharmony_ci reg = sppctl_prep_moon_reg_and_offset(offset, ®_off, 1); 48262306a36Sopenharmony_ci sppctl_gpio_od_writel(spp_gchip, reg, reg_off); 48362306a36Sopenharmony_ci break; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci case PIN_CONFIG_INPUT_ENABLE: 48662306a36Sopenharmony_ci break; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci case PIN_CONFIG_OUTPUT: 48962306a36Sopenharmony_ci return sppctl_gpio_direction_output(chip, offset, 0); 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci case PIN_CONFIG_PERSIST_STATE: 49262306a36Sopenharmony_ci return -ENOTSUPP; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci default: 49562306a36Sopenharmony_ci return -EINVAL; 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci return 0; 49962306a36Sopenharmony_ci} 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_cistatic void sppctl_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci const char *label; 50462306a36Sopenharmony_ci int i; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci for (i = 0; i < chip->ngpio; i++) { 50762306a36Sopenharmony_ci label = gpiochip_is_requested(chip, i); 50862306a36Sopenharmony_ci if (!label) 50962306a36Sopenharmony_ci label = ""; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci seq_printf(s, " gpio-%03d (%-16.16s | %-16.16s)", i + chip->base, 51262306a36Sopenharmony_ci chip->names[i], label); 51362306a36Sopenharmony_ci seq_printf(s, " %c", sppctl_gpio_get_direction(chip, i) ? 'I' : 'O'); 51462306a36Sopenharmony_ci seq_printf(s, ":%d", sppctl_gpio_get(chip, i)); 51562306a36Sopenharmony_ci seq_printf(s, " %s", sppctl_first_get(chip, i) ? "gpi" : "mux"); 51662306a36Sopenharmony_ci seq_printf(s, " %s", sppctl_master_get(chip, i) ? "gpi" : "iop"); 51762306a36Sopenharmony_ci seq_printf(s, " %s", sppctl_gpio_inv_get(chip, i) ? "inv" : " "); 51862306a36Sopenharmony_ci seq_printf(s, " %s", sppctl_gpio_output_od_get(chip, i) ? "oDr" : ""); 51962306a36Sopenharmony_ci seq_puts(s, "\n"); 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cistatic int sppctl_gpio_new(struct platform_device *pdev, struct sppctl_pdata *pctl) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci struct sppctl_gpio_chip *spp_gchip; 52662306a36Sopenharmony_ci struct gpio_chip *gchip; 52762306a36Sopenharmony_ci int err; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci spp_gchip = devm_kzalloc(&pdev->dev, sizeof(*spp_gchip), GFP_KERNEL); 53062306a36Sopenharmony_ci if (!spp_gchip) 53162306a36Sopenharmony_ci return -ENOMEM; 53262306a36Sopenharmony_ci pctl->spp_gchip = spp_gchip; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci spp_gchip->gpioxt_base = pctl->gpioxt_base; 53562306a36Sopenharmony_ci spp_gchip->first_base = pctl->first_base; 53662306a36Sopenharmony_ci spin_lock_init(&spp_gchip->lock); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci gchip = &spp_gchip->chip; 53962306a36Sopenharmony_ci gchip->label = SPPCTL_MODULE_NAME; 54062306a36Sopenharmony_ci gchip->parent = &pdev->dev; 54162306a36Sopenharmony_ci gchip->owner = THIS_MODULE; 54262306a36Sopenharmony_ci gchip->request = gpiochip_generic_request; 54362306a36Sopenharmony_ci gchip->free = gpiochip_generic_free; 54462306a36Sopenharmony_ci gchip->get_direction = sppctl_gpio_get_direction; 54562306a36Sopenharmony_ci gchip->direction_input = sppctl_gpio_direction_input; 54662306a36Sopenharmony_ci gchip->direction_output = sppctl_gpio_direction_output; 54762306a36Sopenharmony_ci gchip->get = sppctl_gpio_get; 54862306a36Sopenharmony_ci gchip->set = sppctl_gpio_set; 54962306a36Sopenharmony_ci gchip->set_config = sppctl_gpio_set_config; 55062306a36Sopenharmony_ci gchip->dbg_show = IS_ENABLED(CONFIG_DEBUG_FS) ? 55162306a36Sopenharmony_ci sppctl_gpio_dbg_show : NULL; 55262306a36Sopenharmony_ci gchip->base = -1; 55362306a36Sopenharmony_ci gchip->ngpio = sppctl_gpio_list_sz; 55462306a36Sopenharmony_ci gchip->names = sppctl_gpio_list_s; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci pctl->pctl_grange.npins = gchip->ngpio; 55762306a36Sopenharmony_ci pctl->pctl_grange.name = gchip->label; 55862306a36Sopenharmony_ci pctl->pctl_grange.gc = gchip; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci err = devm_gpiochip_add_data(&pdev->dev, gchip, spp_gchip); 56162306a36Sopenharmony_ci if (err) 56262306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, err, "Failed to add gpiochip!\n"); 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci return 0; 56562306a36Sopenharmony_ci} 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_cistatic int sppctl_pin_config_get(struct pinctrl_dev *pctldev, unsigned int pin, 56862306a36Sopenharmony_ci unsigned long *config) 56962306a36Sopenharmony_ci{ 57062306a36Sopenharmony_ci struct sppctl_pdata *pctl = pinctrl_dev_get_drvdata(pctldev); 57162306a36Sopenharmony_ci unsigned int param = pinconf_to_config_param(*config); 57262306a36Sopenharmony_ci unsigned int arg; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci switch (param) { 57562306a36Sopenharmony_ci case PIN_CONFIG_DRIVE_OPEN_DRAIN: 57662306a36Sopenharmony_ci if (!sppctl_gpio_output_od_get(&pctl->spp_gchip->chip, pin)) 57762306a36Sopenharmony_ci return -EINVAL; 57862306a36Sopenharmony_ci arg = 0; 57962306a36Sopenharmony_ci break; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci case PIN_CONFIG_OUTPUT: 58262306a36Sopenharmony_ci if (!sppctl_first_get(&pctl->spp_gchip->chip, pin)) 58362306a36Sopenharmony_ci return -EINVAL; 58462306a36Sopenharmony_ci if (!sppctl_master_get(&pctl->spp_gchip->chip, pin)) 58562306a36Sopenharmony_ci return -EINVAL; 58662306a36Sopenharmony_ci if (sppctl_gpio_get_direction(&pctl->spp_gchip->chip, pin)) 58762306a36Sopenharmony_ci return -EINVAL; 58862306a36Sopenharmony_ci arg = sppctl_gpio_get(&pctl->spp_gchip->chip, pin); 58962306a36Sopenharmony_ci break; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci default: 59262306a36Sopenharmony_ci return -EOPNOTSUPP; 59362306a36Sopenharmony_ci } 59462306a36Sopenharmony_ci *config = pinconf_to_config_packed(param, arg); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci return 0; 59762306a36Sopenharmony_ci} 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_cistatic int sppctl_pin_config_set(struct pinctrl_dev *pctldev, unsigned int pin, 60062306a36Sopenharmony_ci unsigned long *configs, unsigned int num_configs) 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci struct sppctl_pdata *pctl = pinctrl_dev_get_drvdata(pctldev); 60362306a36Sopenharmony_ci int i; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci /* Special handling for IOP pins */ 60662306a36Sopenharmony_ci if (configs[0] == SPPCTL_IOP_CONFIGS) { 60762306a36Sopenharmony_ci sppctl_first_master_set(&pctl->spp_gchip->chip, pin, mux_f_gpio, mux_m_iop); 60862306a36Sopenharmony_ci return 0; 60962306a36Sopenharmony_ci } 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci for (i = 0; i < num_configs; i++) { 61262306a36Sopenharmony_ci if (configs[i] & SPPCTL_PCTL_L_OUT) 61362306a36Sopenharmony_ci sppctl_gpio_direction_output(&pctl->spp_gchip->chip, pin, 0); 61462306a36Sopenharmony_ci if (configs[i] & SPPCTL_PCTL_L_OU1) 61562306a36Sopenharmony_ci sppctl_gpio_direction_output(&pctl->spp_gchip->chip, pin, 1); 61662306a36Sopenharmony_ci if (configs[i] & SPPCTL_PCTL_L_INV) 61762306a36Sopenharmony_ci sppctl_gpio_input_inv_set(&pctl->spp_gchip->chip, pin); 61862306a36Sopenharmony_ci if (configs[i] & SPPCTL_PCTL_L_ONV) 61962306a36Sopenharmony_ci sppctl_gpio_output_inv_set(&pctl->spp_gchip->chip, pin); 62062306a36Sopenharmony_ci if (configs[i] & SPPCTL_PCTL_L_ODR) 62162306a36Sopenharmony_ci sppctl_gpio_output_od_set(&pctl->spp_gchip->chip, pin, 1); 62262306a36Sopenharmony_ci } 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci return 0; 62562306a36Sopenharmony_ci} 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_cistatic const struct pinconf_ops sppctl_pconf_ops = { 62862306a36Sopenharmony_ci .is_generic = true, 62962306a36Sopenharmony_ci .pin_config_get = sppctl_pin_config_get, 63062306a36Sopenharmony_ci .pin_config_set = sppctl_pin_config_set, 63162306a36Sopenharmony_ci}; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_cistatic int sppctl_get_functions_count(struct pinctrl_dev *pctldev) 63462306a36Sopenharmony_ci{ 63562306a36Sopenharmony_ci return sppctl_list_funcs_sz; 63662306a36Sopenharmony_ci} 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_cistatic const char *sppctl_get_function_name(struct pinctrl_dev *pctldev, 63962306a36Sopenharmony_ci unsigned int selector) 64062306a36Sopenharmony_ci{ 64162306a36Sopenharmony_ci return sppctl_list_funcs[selector].name; 64262306a36Sopenharmony_ci} 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_cistatic int sppctl_get_function_groups(struct pinctrl_dev *pctldev, unsigned int selector, 64562306a36Sopenharmony_ci const char * const **groups, unsigned int *num_groups) 64662306a36Sopenharmony_ci{ 64762306a36Sopenharmony_ci struct sppctl_pdata *pctl = pinctrl_dev_get_drvdata(pctldev); 64862306a36Sopenharmony_ci const struct sppctl_func *f = &sppctl_list_funcs[selector]; 64962306a36Sopenharmony_ci int i; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci *num_groups = 0; 65262306a36Sopenharmony_ci switch (f->type) { 65362306a36Sopenharmony_ci case pinmux_type_fpmx: 65462306a36Sopenharmony_ci *num_groups = sppctl_pmux_list_sz; 65562306a36Sopenharmony_ci *groups = sppctl_pmux_list_s; 65662306a36Sopenharmony_ci break; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci case pinmux_type_grp: 65962306a36Sopenharmony_ci if (!f->grps) 66062306a36Sopenharmony_ci break; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci *num_groups = f->gnum; 66362306a36Sopenharmony_ci for (i = 0; i < pctl->unq_grps_sz; i++) 66462306a36Sopenharmony_ci if (pctl->g2fp_maps[i].f_idx == selector) 66562306a36Sopenharmony_ci break; 66662306a36Sopenharmony_ci *groups = &pctl->unq_grps[i]; 66762306a36Sopenharmony_ci break; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci default: 67062306a36Sopenharmony_ci dev_err(pctldev->dev, "Unknown pinmux (selector: %d, type: %d)\n", 67162306a36Sopenharmony_ci selector, f->type); 67262306a36Sopenharmony_ci break; 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci return 0; 67662306a36Sopenharmony_ci} 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci/** 67962306a36Sopenharmony_ci * sppctl_fully_pinmux_conv - Convert GPIO# to fully-pinmux control-field setting 68062306a36Sopenharmony_ci * 68162306a36Sopenharmony_ci * Each fully-pinmux function can be mapped to any of GPIO 8 ~ 71 by 68262306a36Sopenharmony_ci * settings its control-field. Refer to following table: 68362306a36Sopenharmony_ci * 68462306a36Sopenharmony_ci * control-field | GPIO 68562306a36Sopenharmony_ci * --------------+-------- 68662306a36Sopenharmony_ci * 0 | No map 68762306a36Sopenharmony_ci * 1 | 8 68862306a36Sopenharmony_ci * 2 | 9 68962306a36Sopenharmony_ci * 3 | 10 69062306a36Sopenharmony_ci * : | : 69162306a36Sopenharmony_ci * 65 | 71 69262306a36Sopenharmony_ci */ 69362306a36Sopenharmony_cistatic inline int sppctl_fully_pinmux_conv(unsigned int offset) 69462306a36Sopenharmony_ci{ 69562306a36Sopenharmony_ci return (offset < 8) ? 0 : offset - 7; 69662306a36Sopenharmony_ci} 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_cistatic int sppctl_set_mux(struct pinctrl_dev *pctldev, unsigned int func_selector, 69962306a36Sopenharmony_ci unsigned int group_selector) 70062306a36Sopenharmony_ci{ 70162306a36Sopenharmony_ci const struct sppctl_func *f = &sppctl_list_funcs[func_selector]; 70262306a36Sopenharmony_ci struct sppctl_pdata *pctl = pinctrl_dev_get_drvdata(pctldev); 70362306a36Sopenharmony_ci struct grp2fp_map g2fpm = pctl->g2fp_maps[group_selector]; 70462306a36Sopenharmony_ci int i; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci switch (f->type) { 70762306a36Sopenharmony_ci case pinmux_type_fpmx: 70862306a36Sopenharmony_ci sppctl_first_master_set(&pctl->spp_gchip->chip, group_selector, 70962306a36Sopenharmony_ci mux_f_mux, mux_m_keep); 71062306a36Sopenharmony_ci sppctl_func_set(pctl, func_selector, sppctl_fully_pinmux_conv(group_selector)); 71162306a36Sopenharmony_ci break; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci case pinmux_type_grp: 71462306a36Sopenharmony_ci for (i = 0; i < f->grps[g2fpm.g_idx].pnum; i++) 71562306a36Sopenharmony_ci sppctl_first_master_set(&pctl->spp_gchip->chip, 71662306a36Sopenharmony_ci f->grps[g2fpm.g_idx].pins[i], 71762306a36Sopenharmony_ci mux_f_mux, mux_m_keep); 71862306a36Sopenharmony_ci sppctl_gmx_set(pctl, f->roff, f->boff, f->blen, f->grps[g2fpm.g_idx].gval); 71962306a36Sopenharmony_ci break; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci default: 72262306a36Sopenharmony_ci dev_err(pctldev->dev, "Unknown pinmux type (func_selector: %d, type: %d)\n", 72362306a36Sopenharmony_ci func_selector, f->type); 72462306a36Sopenharmony_ci break; 72562306a36Sopenharmony_ci } 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci return 0; 72862306a36Sopenharmony_ci} 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_cistatic int sppctl_gpio_request_enable(struct pinctrl_dev *pctldev, 73162306a36Sopenharmony_ci struct pinctrl_gpio_range *range, unsigned int offset) 73262306a36Sopenharmony_ci{ 73362306a36Sopenharmony_ci struct sppctl_pdata *pctl = pinctrl_dev_get_drvdata(pctldev); 73462306a36Sopenharmony_ci int g_f, g_m; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci g_f = sppctl_first_get(&pctl->spp_gchip->chip, offset); 73762306a36Sopenharmony_ci g_m = sppctl_master_get(&pctl->spp_gchip->chip, offset); 73862306a36Sopenharmony_ci if (g_f == mux_f_gpio && g_m == mux_m_gpio) 73962306a36Sopenharmony_ci return 0; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci sppctl_first_master_set(&pctl->spp_gchip->chip, offset, mux_f_gpio, mux_m_gpio); 74262306a36Sopenharmony_ci return 0; 74362306a36Sopenharmony_ci} 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_cistatic const struct pinmux_ops sppctl_pinmux_ops = { 74662306a36Sopenharmony_ci .get_functions_count = sppctl_get_functions_count, 74762306a36Sopenharmony_ci .get_function_name = sppctl_get_function_name, 74862306a36Sopenharmony_ci .get_function_groups = sppctl_get_function_groups, 74962306a36Sopenharmony_ci .set_mux = sppctl_set_mux, 75062306a36Sopenharmony_ci .gpio_request_enable = sppctl_gpio_request_enable, 75162306a36Sopenharmony_ci .strict = true, 75262306a36Sopenharmony_ci}; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_cistatic int sppctl_get_groups_count(struct pinctrl_dev *pctldev) 75562306a36Sopenharmony_ci{ 75662306a36Sopenharmony_ci struct sppctl_pdata *pctl = pinctrl_dev_get_drvdata(pctldev); 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci return pctl->unq_grps_sz; 75962306a36Sopenharmony_ci} 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_cistatic const char *sppctl_get_group_name(struct pinctrl_dev *pctldev, unsigned int selector) 76262306a36Sopenharmony_ci{ 76362306a36Sopenharmony_ci struct sppctl_pdata *pctl = pinctrl_dev_get_drvdata(pctldev); 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci return pctl->unq_grps[selector]; 76662306a36Sopenharmony_ci} 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_cistatic int sppctl_get_group_pins(struct pinctrl_dev *pctldev, unsigned int selector, 76962306a36Sopenharmony_ci const unsigned int **pins, unsigned int *num_pins) 77062306a36Sopenharmony_ci{ 77162306a36Sopenharmony_ci struct sppctl_pdata *pctl = pinctrl_dev_get_drvdata(pctldev); 77262306a36Sopenharmony_ci struct grp2fp_map g2fpm = pctl->g2fp_maps[selector]; 77362306a36Sopenharmony_ci const struct sppctl_func *f; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci f = &sppctl_list_funcs[g2fpm.f_idx]; 77662306a36Sopenharmony_ci *num_pins = 0; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci /* Except group-pinmux, each group has 1 pin. */ 77962306a36Sopenharmony_ci if (f->type != pinmux_type_grp) { 78062306a36Sopenharmony_ci *num_pins = 1; 78162306a36Sopenharmony_ci *pins = &sppctl_pins_gpio[selector]; 78262306a36Sopenharmony_ci return 0; 78362306a36Sopenharmony_ci } 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci /* Group-pinmux may have more than one pin. */ 78662306a36Sopenharmony_ci if (!f->grps) 78762306a36Sopenharmony_ci return 0; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci if (f->gnum < 1) 79062306a36Sopenharmony_ci return 0; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci *num_pins = f->grps[g2fpm.g_idx].pnum; 79362306a36Sopenharmony_ci *pins = f->grps[g2fpm.g_idx].pins; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci return 0; 79662306a36Sopenharmony_ci} 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 79962306a36Sopenharmony_cistatic void sppctl_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, 80062306a36Sopenharmony_ci unsigned int offset) 80162306a36Sopenharmony_ci{ 80262306a36Sopenharmony_ci struct sppctl_pdata *pctl = pinctrl_dev_get_drvdata(pctldev); 80362306a36Sopenharmony_ci const char *pin_type; 80462306a36Sopenharmony_ci u8 first, master; 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci first = sppctl_first_get(&pctl->spp_gchip->chip, offset); 80762306a36Sopenharmony_ci master = sppctl_master_get(&pctl->spp_gchip->chip, offset); 80862306a36Sopenharmony_ci if (first) 80962306a36Sopenharmony_ci if (master) 81062306a36Sopenharmony_ci pin_type = "GPIO"; 81162306a36Sopenharmony_ci else 81262306a36Sopenharmony_ci pin_type = " IOP"; 81362306a36Sopenharmony_ci else 81462306a36Sopenharmony_ci pin_type = " MUX"; 81562306a36Sopenharmony_ci seq_printf(s, " %s", pin_type); 81662306a36Sopenharmony_ci} 81762306a36Sopenharmony_ci#endif 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_cistatic int sppctl_dt_node_to_map(struct pinctrl_dev *pctldev, struct device_node *np_config, 82062306a36Sopenharmony_ci struct pinctrl_map **map, unsigned int *num_maps) 82162306a36Sopenharmony_ci{ 82262306a36Sopenharmony_ci struct sppctl_pdata *pctl = pinctrl_dev_get_drvdata(pctldev); 82362306a36Sopenharmony_ci int nmG = of_property_count_strings(np_config, "groups"); 82462306a36Sopenharmony_ci const struct sppctl_func *f = NULL; 82562306a36Sopenharmony_ci u8 pin_num, pin_type, pin_func; 82662306a36Sopenharmony_ci struct device_node *parent; 82762306a36Sopenharmony_ci unsigned long *configs; 82862306a36Sopenharmony_ci struct property *prop; 82962306a36Sopenharmony_ci const char *s_f, *s_g; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci const __be32 *list; 83262306a36Sopenharmony_ci u32 dt_pin, dt_fun; 83362306a36Sopenharmony_ci int i, size = 0; 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci list = of_get_property(np_config, "sunplus,pins", &size); 83662306a36Sopenharmony_ci *num_maps = size / sizeof(*list); 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci /* 83962306a36Sopenharmony_ci * Process property: 84062306a36Sopenharmony_ci * sunplus,pins = < u32 u32 u32 ... >; 84162306a36Sopenharmony_ci * 84262306a36Sopenharmony_ci * Each 32-bit integer defines a individual pin in which: 84362306a36Sopenharmony_ci * 84462306a36Sopenharmony_ci * Bit 32~24: defines GPIO pin number. Its range is 0 ~ 98. 84562306a36Sopenharmony_ci * Bit 23~16: defines types: (1) fully-pinmux pins 84662306a36Sopenharmony_ci * (2) IO processor pins 84762306a36Sopenharmony_ci * (3) digital GPIO pins 84862306a36Sopenharmony_ci * Bit 15~8: defines pins of peripherals (which are defined in 84962306a36Sopenharmony_ci * 'include/dt-binging/pinctrl/sppctl.h'). 85062306a36Sopenharmony_ci * Bit 7~0: defines types or initial-state of digital GPIO pins. 85162306a36Sopenharmony_ci */ 85262306a36Sopenharmony_ci for (i = 0; i < (*num_maps); i++) { 85362306a36Sopenharmony_ci dt_pin = be32_to_cpu(list[i]); 85462306a36Sopenharmony_ci pin_num = FIELD_GET(GENMASK(31, 24), dt_pin); 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci if (pin_num >= sppctl_pins_all_sz) { 85762306a36Sopenharmony_ci dev_err(pctldev->dev, "Invalid pin property at index %d (0x%08x)\n", 85862306a36Sopenharmony_ci i, dt_pin); 85962306a36Sopenharmony_ci return -EINVAL; 86062306a36Sopenharmony_ci } 86162306a36Sopenharmony_ci } 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci if (nmG <= 0) 86462306a36Sopenharmony_ci nmG = 0; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci *map = kcalloc(*num_maps + nmG, sizeof(**map), GFP_KERNEL); 86762306a36Sopenharmony_ci if (!(*map)) 86862306a36Sopenharmony_ci return -ENOMEM; 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci parent = of_get_parent(np_config); 87162306a36Sopenharmony_ci for (i = 0; i < (*num_maps); i++) { 87262306a36Sopenharmony_ci dt_pin = be32_to_cpu(list[i]); 87362306a36Sopenharmony_ci pin_num = FIELD_GET(GENMASK(31, 24), dt_pin); 87462306a36Sopenharmony_ci pin_type = FIELD_GET(GENMASK(23, 16), dt_pin); 87562306a36Sopenharmony_ci pin_func = FIELD_GET(GENMASK(15, 8), dt_pin); 87662306a36Sopenharmony_ci (*map)[i].name = parent->name; 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci if (pin_type == SPPCTL_PCTL_G_GPIO) { 87962306a36Sopenharmony_ci /* A digital GPIO pin */ 88062306a36Sopenharmony_ci (*map)[i].type = PIN_MAP_TYPE_CONFIGS_PIN; 88162306a36Sopenharmony_ci (*map)[i].data.configs.num_configs = 1; 88262306a36Sopenharmony_ci (*map)[i].data.configs.group_or_pin = pin_get_name(pctldev, pin_num); 88362306a36Sopenharmony_ci configs = kmalloc(sizeof(*configs), GFP_KERNEL); 88462306a36Sopenharmony_ci if (!configs) 88562306a36Sopenharmony_ci goto sppctl_map_err; 88662306a36Sopenharmony_ci *configs = FIELD_GET(GENMASK(7, 0), dt_pin); 88762306a36Sopenharmony_ci (*map)[i].data.configs.configs = configs; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci dev_dbg(pctldev->dev, "%s: GPIO (%s)\n", 89062306a36Sopenharmony_ci (*map)[i].data.configs.group_or_pin, 89162306a36Sopenharmony_ci (*configs & (SPPCTL_PCTL_L_OUT | SPPCTL_PCTL_L_OU1)) ? 89262306a36Sopenharmony_ci "OUT" : "IN"); 89362306a36Sopenharmony_ci } else if (pin_type == SPPCTL_PCTL_G_IOPP) { 89462306a36Sopenharmony_ci /* A IO Processor (IOP) pin */ 89562306a36Sopenharmony_ci (*map)[i].type = PIN_MAP_TYPE_CONFIGS_PIN; 89662306a36Sopenharmony_ci (*map)[i].data.configs.num_configs = 1; 89762306a36Sopenharmony_ci (*map)[i].data.configs.group_or_pin = pin_get_name(pctldev, pin_num); 89862306a36Sopenharmony_ci configs = kmalloc(sizeof(*configs), GFP_KERNEL); 89962306a36Sopenharmony_ci if (!configs) 90062306a36Sopenharmony_ci goto sppctl_map_err; 90162306a36Sopenharmony_ci *configs = SPPCTL_IOP_CONFIGS; 90262306a36Sopenharmony_ci (*map)[i].data.configs.configs = configs; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci dev_dbg(pctldev->dev, "%s: IOP\n", 90562306a36Sopenharmony_ci (*map)[i].data.configs.group_or_pin); 90662306a36Sopenharmony_ci } else { 90762306a36Sopenharmony_ci /* A fully-pinmux pin */ 90862306a36Sopenharmony_ci (*map)[i].type = PIN_MAP_TYPE_MUX_GROUP; 90962306a36Sopenharmony_ci (*map)[i].data.mux.function = sppctl_list_funcs[pin_func].name; 91062306a36Sopenharmony_ci (*map)[i].data.mux.group = pin_get_name(pctldev, pin_num); 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci dev_dbg(pctldev->dev, "%s: %s\n", (*map)[i].data.mux.group, 91362306a36Sopenharmony_ci (*map)[i].data.mux.function); 91462306a36Sopenharmony_ci } 91562306a36Sopenharmony_ci } 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci /* 91862306a36Sopenharmony_ci * Process properties: 91962306a36Sopenharmony_ci * function = "xxx"; 92062306a36Sopenharmony_ci * groups = "yyy"; 92162306a36Sopenharmony_ci */ 92262306a36Sopenharmony_ci if (nmG > 0 && of_property_read_string(np_config, "function", &s_f) == 0) { 92362306a36Sopenharmony_ci of_property_for_each_string(np_config, "groups", prop, s_g) { 92462306a36Sopenharmony_ci (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP; 92562306a36Sopenharmony_ci (*map)[*num_maps].data.mux.function = s_f; 92662306a36Sopenharmony_ci (*map)[*num_maps].data.mux.group = s_g; 92762306a36Sopenharmony_ci (*num_maps)++; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci dev_dbg(pctldev->dev, "%s: %s\n", s_f, s_g); 93062306a36Sopenharmony_ci } 93162306a36Sopenharmony_ci } 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci /* 93462306a36Sopenharmony_ci * Process property: 93562306a36Sopenharmony_ci * sunplus,zerofunc = < u32 u32 u32 ...> 93662306a36Sopenharmony_ci */ 93762306a36Sopenharmony_ci list = of_get_property(np_config, "sunplus,zerofunc", &size); 93862306a36Sopenharmony_ci if (list) { 93962306a36Sopenharmony_ci for (i = 0; i < (size / sizeof(*list)); i++) { 94062306a36Sopenharmony_ci dt_fun = be32_to_cpu(list[i]); 94162306a36Sopenharmony_ci if (dt_fun >= sppctl_list_funcs_sz) { 94262306a36Sopenharmony_ci dev_err(pctldev->dev, "Zero-func %d out of range!\n", 94362306a36Sopenharmony_ci dt_fun); 94462306a36Sopenharmony_ci continue; 94562306a36Sopenharmony_ci } 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci f = &sppctl_list_funcs[dt_fun]; 94862306a36Sopenharmony_ci switch (f->type) { 94962306a36Sopenharmony_ci case pinmux_type_fpmx: 95062306a36Sopenharmony_ci sppctl_func_set(pctl, dt_fun, 0); 95162306a36Sopenharmony_ci dev_dbg(pctldev->dev, "%s: No map\n", f->name); 95262306a36Sopenharmony_ci break; 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci case pinmux_type_grp: 95562306a36Sopenharmony_ci sppctl_gmx_set(pctl, f->roff, f->boff, f->blen, 0); 95662306a36Sopenharmony_ci dev_dbg(pctldev->dev, "%s: No map\n", f->name); 95762306a36Sopenharmony_ci break; 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci default: 96062306a36Sopenharmony_ci dev_err(pctldev->dev, "Wrong zero-group: %d (%s)\n", 96162306a36Sopenharmony_ci dt_fun, f->name); 96262306a36Sopenharmony_ci break; 96362306a36Sopenharmony_ci } 96462306a36Sopenharmony_ci } 96562306a36Sopenharmony_ci } 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci of_node_put(parent); 96862306a36Sopenharmony_ci dev_dbg(pctldev->dev, "%d pins mapped\n", *num_maps); 96962306a36Sopenharmony_ci return 0; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_cisppctl_map_err: 97262306a36Sopenharmony_ci for (i = 0; i < (*num_maps); i++) 97362306a36Sopenharmony_ci if ((*map)[i].type == PIN_MAP_TYPE_CONFIGS_PIN) 97462306a36Sopenharmony_ci kfree((*map)[i].data.configs.configs); 97562306a36Sopenharmony_ci kfree(*map); 97662306a36Sopenharmony_ci of_node_put(parent); 97762306a36Sopenharmony_ci return -ENOMEM; 97862306a36Sopenharmony_ci} 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_cistatic const struct pinctrl_ops sppctl_pctl_ops = { 98162306a36Sopenharmony_ci .get_groups_count = sppctl_get_groups_count, 98262306a36Sopenharmony_ci .get_group_name = sppctl_get_group_name, 98362306a36Sopenharmony_ci .get_group_pins = sppctl_get_group_pins, 98462306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 98562306a36Sopenharmony_ci .pin_dbg_show = sppctl_pin_dbg_show, 98662306a36Sopenharmony_ci#endif 98762306a36Sopenharmony_ci .dt_node_to_map = sppctl_dt_node_to_map, 98862306a36Sopenharmony_ci .dt_free_map = pinctrl_utils_free_map, 98962306a36Sopenharmony_ci}; 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_cistatic int sppctl_group_groups(struct platform_device *pdev) 99262306a36Sopenharmony_ci{ 99362306a36Sopenharmony_ci struct sppctl_pdata *sppctl = platform_get_drvdata(pdev); 99462306a36Sopenharmony_ci int i, k, j; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci /* Calculate number of total group (GPIO + group-pinmux group). */ 99762306a36Sopenharmony_ci sppctl->unq_grps_sz = sppctl_gpio_list_sz; 99862306a36Sopenharmony_ci for (i = 0; i < sppctl_list_funcs_sz; i++) 99962306a36Sopenharmony_ci if (sppctl_list_funcs[i].type == pinmux_type_grp) 100062306a36Sopenharmony_ci sppctl->unq_grps_sz += sppctl_list_funcs[i].gnum; 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci sppctl->unq_grps = devm_kcalloc(&pdev->dev, sppctl->unq_grps_sz + 1, 100362306a36Sopenharmony_ci sizeof(*sppctl->unq_grps), GFP_KERNEL); 100462306a36Sopenharmony_ci if (!sppctl->unq_grps) 100562306a36Sopenharmony_ci return -ENOMEM; 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci sppctl->g2fp_maps = devm_kcalloc(&pdev->dev, sppctl->unq_grps_sz + 1, 100862306a36Sopenharmony_ci sizeof(*sppctl->g2fp_maps), GFP_KERNEL); 100962306a36Sopenharmony_ci if (!sppctl->g2fp_maps) 101062306a36Sopenharmony_ci return -ENOMEM; 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci /* Add GPIO pins. */ 101362306a36Sopenharmony_ci for (i = 0; i < sppctl_gpio_list_sz; i++) { 101462306a36Sopenharmony_ci sppctl->unq_grps[i] = sppctl_gpio_list_s[i]; 101562306a36Sopenharmony_ci sppctl->g2fp_maps[i].f_idx = 0; 101662306a36Sopenharmony_ci sppctl->g2fp_maps[i].g_idx = i; 101762306a36Sopenharmony_ci } 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci /* Add group-pinmux to end of GPIO pins. */ 102062306a36Sopenharmony_ci j = sppctl_gpio_list_sz; 102162306a36Sopenharmony_ci for (i = 0; i < sppctl_list_funcs_sz; i++) { 102262306a36Sopenharmony_ci if (sppctl_list_funcs[i].type != pinmux_type_grp) 102362306a36Sopenharmony_ci continue; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci for (k = 0; k < sppctl_list_funcs[i].gnum; k++) { 102662306a36Sopenharmony_ci sppctl->unq_grps[j] = sppctl_list_funcs[i].grps[k].name; 102762306a36Sopenharmony_ci sppctl->g2fp_maps[j].f_idx = i; 102862306a36Sopenharmony_ci sppctl->g2fp_maps[j].g_idx = k; 102962306a36Sopenharmony_ci j++; 103062306a36Sopenharmony_ci } 103162306a36Sopenharmony_ci } 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci return 0; 103462306a36Sopenharmony_ci} 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_cistatic int sppctl_pinctrl_init(struct platform_device *pdev) 103762306a36Sopenharmony_ci{ 103862306a36Sopenharmony_ci struct sppctl_pdata *sppctl = platform_get_drvdata(pdev); 103962306a36Sopenharmony_ci int err; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci sppctl->pctl_desc.owner = THIS_MODULE; 104262306a36Sopenharmony_ci sppctl->pctl_desc.name = dev_name(&pdev->dev); 104362306a36Sopenharmony_ci sppctl->pctl_desc.pins = sppctl_pins_all; 104462306a36Sopenharmony_ci sppctl->pctl_desc.npins = sppctl_pins_all_sz; 104562306a36Sopenharmony_ci sppctl->pctl_desc.pctlops = &sppctl_pctl_ops; 104662306a36Sopenharmony_ci sppctl->pctl_desc.confops = &sppctl_pconf_ops; 104762306a36Sopenharmony_ci sppctl->pctl_desc.pmxops = &sppctl_pinmux_ops; 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci err = sppctl_group_groups(pdev); 105062306a36Sopenharmony_ci if (err) 105162306a36Sopenharmony_ci return err; 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci err = devm_pinctrl_register_and_init(&pdev->dev, &sppctl->pctl_desc, 105462306a36Sopenharmony_ci sppctl, &sppctl->pctl_dev); 105562306a36Sopenharmony_ci if (err) 105662306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, err, "Failed to register pinctrl!\n"); 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci pinctrl_enable(sppctl->pctl_dev); 105962306a36Sopenharmony_ci return 0; 106062306a36Sopenharmony_ci} 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_cistatic int sppctl_resource_map(struct platform_device *pdev, struct sppctl_pdata *sppctl) 106362306a36Sopenharmony_ci{ 106462306a36Sopenharmony_ci sppctl->moon2_base = devm_platform_ioremap_resource_byname(pdev, "moon2"); 106562306a36Sopenharmony_ci if (IS_ERR(sppctl->moon2_base)) 106662306a36Sopenharmony_ci return PTR_ERR(sppctl->moon2_base); 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci sppctl->gpioxt_base = devm_platform_ioremap_resource_byname(pdev, "gpioxt"); 106962306a36Sopenharmony_ci if (IS_ERR(sppctl->gpioxt_base)) 107062306a36Sopenharmony_ci return PTR_ERR(sppctl->gpioxt_base); 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci sppctl->first_base = devm_platform_ioremap_resource_byname(pdev, "first"); 107362306a36Sopenharmony_ci if (IS_ERR(sppctl->first_base)) 107462306a36Sopenharmony_ci return PTR_ERR(sppctl->first_base); 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci sppctl->moon1_base = devm_platform_ioremap_resource_byname(pdev, "moon1"); 107762306a36Sopenharmony_ci if (IS_ERR(sppctl->moon1_base)) 107862306a36Sopenharmony_ci return PTR_ERR(sppctl->moon1_base); 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci return 0; 108162306a36Sopenharmony_ci} 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_cistatic int sppctl_probe(struct platform_device *pdev) 108462306a36Sopenharmony_ci{ 108562306a36Sopenharmony_ci struct sppctl_pdata *sppctl; 108662306a36Sopenharmony_ci int ret; 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci sppctl = devm_kzalloc(&pdev->dev, sizeof(*sppctl), GFP_KERNEL); 108962306a36Sopenharmony_ci if (!sppctl) 109062306a36Sopenharmony_ci return -ENOMEM; 109162306a36Sopenharmony_ci platform_set_drvdata(pdev, sppctl); 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci ret = sppctl_resource_map(pdev, sppctl); 109462306a36Sopenharmony_ci if (ret) 109562306a36Sopenharmony_ci return ret; 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci ret = sppctl_gpio_new(pdev, sppctl); 109862306a36Sopenharmony_ci if (ret) 109962306a36Sopenharmony_ci return ret; 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci ret = sppctl_pinctrl_init(pdev); 110262306a36Sopenharmony_ci if (ret) 110362306a36Sopenharmony_ci return ret; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci pinctrl_add_gpio_range(sppctl->pctl_dev, &sppctl->pctl_grange); 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci return 0; 110862306a36Sopenharmony_ci} 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_cistatic const struct of_device_id sppctl_match_table[] = { 111162306a36Sopenharmony_ci { .compatible = "sunplus,sp7021-pctl" }, 111262306a36Sopenharmony_ci { /* sentinel */ } 111362306a36Sopenharmony_ci}; 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_cistatic struct platform_driver sppctl_pinctrl_driver = { 111662306a36Sopenharmony_ci .driver = { 111762306a36Sopenharmony_ci .name = SPPCTL_MODULE_NAME, 111862306a36Sopenharmony_ci .of_match_table = sppctl_match_table, 111962306a36Sopenharmony_ci }, 112062306a36Sopenharmony_ci .probe = sppctl_probe, 112162306a36Sopenharmony_ci}; 112262306a36Sopenharmony_cibuiltin_platform_driver(sppctl_pinctrl_driver) 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ciMODULE_AUTHOR("Dvorkin Dmitry <dvorkin@tibbo.com>"); 112562306a36Sopenharmony_ciMODULE_AUTHOR("Wells Lu <wellslutw@gmail.com>"); 112662306a36Sopenharmony_ciMODULE_DESCRIPTION("Sunplus SP7021 Pin Control and GPIO driver"); 112762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1128