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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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