2021-04-11 13:36:29

by Peter Geis

[permalink] [raw]
Subject: [PATCH v2 0/7] gpio-rockchip driver

Separate gpio driver from pinctrl driver, and support v2 controller.

Tested on rk3566-quartz64 prototype board.

Patch History:
V2 - Rebase to latest linux-next.

Tested-by: Peter Geis <[email protected]>

Jianqun Xu (7):
pinctrl/rockchip: separate struct rockchip_pin_bank to a head file
pinctrl/pinctrl-rockchip.h: add pinctrl device to gpio bank struct
gpio: separate gpio driver from pinctrl-rockchip driver
gpio/rockchip: use struct rockchip_gpio_regs for gpio controller
gpio/rockchip: support next version gpio controller
gpio/rockchip: always enable clock for gpio controller
gpio/rockchip: drop irq_gc_lock/irq_gc_unlock for irq set type

drivers/gpio/Kconfig | 8 +
drivers/gpio/Makefile | 1 +
drivers/gpio/gpio-rockchip.c | 758 ++++++++++++++++++++++++
drivers/pinctrl/pinctrl-rockchip.c | 911 +----------------------------
drivers/pinctrl/pinctrl-rockchip.h | 287 +++++++++
5 files changed, 1073 insertions(+), 892 deletions(-)
create mode 100644 drivers/gpio/gpio-rockchip.c
create mode 100644 drivers/pinctrl/pinctrl-rockchip.h

--
2.25.1


2021-04-11 13:44:49

by Peter Geis

[permalink] [raw]
Subject: [PATCH v2 6/7] gpio/rockchip: always enable clock for gpio controller

From: Jianqun Xu <[email protected]>

Since gate and ungate pclk of gpio has very litte benifit for system
power consumption, just keep it always ungate.

Signed-off-by: Jianqun Xu <[email protected]>
---
drivers/gpio/gpio-rockchip.c | 68 +++++-------------------------------
1 file changed, 9 insertions(+), 59 deletions(-)

diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c
index 92aaf1848449..048e7eecddba 100644
--- a/drivers/gpio/gpio-rockchip.c
+++ b/drivers/gpio/gpio-rockchip.c
@@ -139,17 +139,8 @@ static int rockchip_gpio_get_direction(struct gpio_chip *chip,
{
struct rockchip_pin_bank *bank = gpiochip_get_data(chip);
u32 data;
- int ret;

- ret = clk_enable(bank->clk);
- if (ret < 0) {
- dev_err(bank->drvdata->dev,
- "failed to enable clock for bank %s\n", bank->name);
- return ret;
- }
data = rockchip_gpio_readl_bit(bank, offset, bank->gpio_regs->port_ddr);
- clk_disable(bank->clk);
-
if (data & BIT(offset))
return GPIO_LINE_DIRECTION_OUT;

@@ -163,11 +154,9 @@ static int rockchip_gpio_set_direction(struct gpio_chip *chip,
unsigned long flags;
u32 data = input ? 0 : 1;

- clk_enable(bank->clk);
raw_spin_lock_irqsave(&bank->slock, flags);
rockchip_gpio_writel_bit(bank, offset, data, bank->gpio_regs->port_ddr);
raw_spin_unlock_irqrestore(&bank->slock, flags);
- clk_disable(bank->clk);

return 0;
}
@@ -178,11 +167,9 @@ static void rockchip_gpio_set(struct gpio_chip *gc, unsigned int offset,
struct rockchip_pin_bank *bank = gpiochip_get_data(gc);
unsigned long flags;

- clk_enable(bank->clk);
raw_spin_lock_irqsave(&bank->slock, flags);
rockchip_gpio_writel_bit(bank, offset, value, bank->gpio_regs->port_dr);
raw_spin_unlock_irqrestore(&bank->slock, flags);
- clk_disable(bank->clk);
}

static int rockchip_gpio_get(struct gpio_chip *gc, unsigned int offset)
@@ -190,11 +177,10 @@ static int rockchip_gpio_get(struct gpio_chip *gc, unsigned int offset)
struct rockchip_pin_bank *bank = gpiochip_get_data(gc);
u32 data;

- clk_enable(bank->clk);
data = readl(bank->reg_base + bank->gpio_regs->ext_port);
- clk_disable(bank->clk);
data >>= offset;
data &= 1;
+
return data;
}

@@ -315,9 +301,7 @@ static int rockchip_gpio_to_irq(struct gpio_chip *gc, unsigned int offset)
if (!bank->domain)
return -ENXIO;

- clk_enable(bank->clk);
virq = irq_create_mapping(bank->domain, offset);
- clk_disable(bank->clk);

return (virq) ? : -ENXIO;
}
@@ -409,7 +393,6 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type)
unsigned long flags;
int ret = 0;

- clk_enable(bank->clk);
raw_spin_lock_irqsave(&bank->slock, flags);

rockchip_gpio_writel_bit(bank, d->hwirq, 0,
@@ -480,7 +463,6 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type)
out:
irq_gc_unlock(gc);
raw_spin_unlock_irqrestore(&bank->slock, flags);
- clk_disable(bank->clk);

return ret;
}
@@ -490,10 +472,8 @@ static void rockchip_irq_suspend(struct irq_data *d)
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct rockchip_pin_bank *bank = gc->private;

- clk_enable(bank->clk);
bank->saved_masks = irq_reg_readl(gc, bank->gpio_regs->int_mask);
irq_reg_writel(gc, ~gc->wake_active, bank->gpio_regs->int_mask);
- clk_disable(bank->clk);
}

static void rockchip_irq_resume(struct irq_data *d)
@@ -501,27 +481,7 @@ static void rockchip_irq_resume(struct irq_data *d)
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct rockchip_pin_bank *bank = gc->private;

- clk_enable(bank->clk);
irq_reg_writel(gc, bank->saved_masks, bank->gpio_regs->int_mask);
- clk_disable(bank->clk);
-}
-
-static void rockchip_irq_enable(struct irq_data *d)
-{
- struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
- struct rockchip_pin_bank *bank = gc->private;
-
- clk_enable(bank->clk);
- irq_gc_mask_clr_bit(d);
-}
-
-static void rockchip_irq_disable(struct irq_data *d)
-{
- struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
- struct rockchip_pin_bank *bank = gc->private;
-
- irq_gc_mask_set_bit(d);
- clk_disable(bank->clk);
}

static int rockchip_interrupts_register(struct rockchip_pin_bank *bank)
@@ -530,19 +490,11 @@ static int rockchip_interrupts_register(struct rockchip_pin_bank *bank)
struct irq_chip_generic *gc;
int ret;

- ret = clk_enable(bank->clk);
- if (ret) {
- dev_err(bank->dev, "failed to enable clock for bank %s\n",
- bank->name);
- return -EINVAL;
- }
-
bank->domain = irq_domain_add_linear(bank->of_node, 32,
&irq_generic_chip_ops, NULL);
if (!bank->domain) {
dev_warn(bank->dev, "could not init irq domain for bank %s\n",
bank->name);
- clk_disable(bank->clk);
return -EINVAL;
}

@@ -554,7 +506,6 @@ static int rockchip_interrupts_register(struct rockchip_pin_bank *bank)
dev_err(bank->dev, "could not alloc generic chips for bank %s\n",
bank->name);
irq_domain_remove(bank->domain);
- clk_disable(bank->clk);
return -EINVAL;
}

@@ -571,8 +522,8 @@ static int rockchip_interrupts_register(struct rockchip_pin_bank *bank)
gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit;
gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit;
gc->chip_types[0].chip.irq_unmask = irq_gc_mask_clr_bit;
- gc->chip_types[0].chip.irq_enable = rockchip_irq_enable;
- gc->chip_types[0].chip.irq_disable = rockchip_irq_disable;
+ gc->chip_types[0].chip.irq_enable = irq_gc_mask_clr_bit;
+ gc->chip_types[0].chip.irq_disable = irq_gc_mask_set_bit;
gc->chip_types[0].chip.irq_set_wake = irq_gc_set_wake;
gc->chip_types[0].chip.irq_suspend = rockchip_irq_suspend;
gc->chip_types[0].chip.irq_resume = rockchip_irq_resume;
@@ -591,7 +542,6 @@ static int rockchip_interrupts_register(struct rockchip_pin_bank *bank)

irq_set_chained_handler_and_data(bank->irq,
rockchip_irq_demux, bank);
- clk_disable(bank->clk);

return 0;
}
@@ -695,7 +645,6 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank)
if (IS_ERR(bank->db_clk)) {
dev_err(bank->dev, "cannot find debounce clk\n");
bank->db_clk = NULL;
- clk_disable(bank->clk);
return -EINVAL;
}
} else {
@@ -703,7 +652,6 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank)
bank->gpio_type = GPIO_TYPE_V1;
}

- clk_disable(bank->clk);
return 0;
}

@@ -756,15 +704,17 @@ static int rockchip_gpio_probe(struct platform_device *pdev)
return ret;

ret = rockchip_gpiolib_register(bank);
- if (ret) {
- clk_disable_unprepare(bank->clk);
- return ret;
- }
+ if (ret)
+ goto err_clk;

platform_set_drvdata(pdev, bank);
dev_info(dev, "probed %pOF\n", np);

return 0;
+err_clk:
+ clk_disable_unprepare(bank->clk);
+
+ return ret;
}

static int rockchip_gpio_remove(struct platform_device *pdev)
--
2.25.1

2021-04-11 14:03:22

by Peter Geis

[permalink] [raw]
Subject: [PATCH v2 2/7] pinctrl/pinctrl-rockchip.h: add pinctrl device to gpio bank struct

From: Jianqun Xu <[email protected]>

Store a pointer from the pinctrl device for the gpio bank.

Signed-off-by: Jianqun Xu <[email protected]>
---
drivers/pinctrl/pinctrl-rockchip.h | 2 ++
1 file changed, 2 insertions(+)

diff --git a/drivers/pinctrl/pinctrl-rockchip.h b/drivers/pinctrl/pinctrl-rockchip.h
index dba9e9540633..4aa3d2f1fa67 100644
--- a/drivers/pinctrl/pinctrl-rockchip.h
+++ b/drivers/pinctrl/pinctrl-rockchip.h
@@ -81,6 +81,7 @@ struct rockchip_drv {

/**
* struct rockchip_pin_bank
+ * @dev: the pinctrl device bind to the bank
* @reg_base: register base of the gpio bank
* @regmap_pull: optional separate register for additional pull settings
* @clk: clock of the gpio bank
@@ -105,6 +106,7 @@ struct rockchip_drv {
* @route_mask: bits describing the routing pins of per bank
*/
struct rockchip_pin_bank {
+ struct device *dev;
void __iomem *reg_base;
struct regmap *regmap_pull;
struct clk *clk;
--
2.25.1

2021-04-11 14:03:45

by Peter Geis

[permalink] [raw]
Subject: [PATCH v2 1/7] pinctrl/rockchip: separate struct rockchip_pin_bank to a head file

From: Jianqun Xu <[email protected]>

Separate struct rockchip_pin_bank to pinctrl-rockchip.h file, which will
be used by gpio-rockchip driver in the future.

Signed-off-by: Jianqun Xu <[email protected]>
---
drivers/pinctrl/pinctrl-rockchip.c | 226 +-------------------------
drivers/pinctrl/pinctrl-rockchip.h | 245 +++++++++++++++++++++++++++++
2 files changed, 246 insertions(+), 225 deletions(-)
create mode 100644 drivers/pinctrl/pinctrl-rockchip.h

diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
index 2eb51ddfca02..dd6c7489c35c 100644
--- a/drivers/pinctrl/pinctrl-rockchip.c
+++ b/drivers/pinctrl/pinctrl-rockchip.c
@@ -37,6 +37,7 @@

#include "core.h"
#include "pinconf.h"
+#include "pinctrl-rockchip.h"

/* GPIO control registers */
#define GPIO_SWPORT_DR 0x00
@@ -52,21 +53,6 @@
#define GPIO_EXT_PORT 0x50
#define GPIO_LS_SYNC 0x60

-enum rockchip_pinctrl_type {
- PX30,
- RV1108,
- RK2928,
- RK3066B,
- RK3128,
- RK3188,
- RK3288,
- RK3308,
- RK3368,
- RK3399,
- RK3568,
-};
-
-
/**
* Generate a bitmask for setting a value (v) with a write mask bit in hiword
* register 31:16 area.
@@ -84,103 +70,6 @@ enum rockchip_pinctrl_type {
#define IOMUX_WIDTH_3BIT BIT(4)
#define IOMUX_WIDTH_2BIT BIT(5)

-/**
- * struct rockchip_iomux
- * @type: iomux variant using IOMUX_* constants
- * @offset: if initialized to -1 it will be autocalculated, by specifying
- * an initial offset value the relevant source offset can be reset
- * to a new value for autocalculating the following iomux registers.
- */
-struct rockchip_iomux {
- int type;
- int offset;
-};
-
-/*
- * enum type index corresponding to rockchip_perpin_drv_list arrays index.
- */
-enum rockchip_pin_drv_type {
- DRV_TYPE_IO_DEFAULT = 0,
- DRV_TYPE_IO_1V8_OR_3V0,
- DRV_TYPE_IO_1V8_ONLY,
- DRV_TYPE_IO_1V8_3V0_AUTO,
- DRV_TYPE_IO_3V3_ONLY,
- DRV_TYPE_MAX
-};
-
-/*
- * enum type index corresponding to rockchip_pull_list arrays index.
- */
-enum rockchip_pin_pull_type {
- PULL_TYPE_IO_DEFAULT = 0,
- PULL_TYPE_IO_1V8_ONLY,
- PULL_TYPE_MAX
-};
-
-/**
- * struct rockchip_drv
- * @drv_type: drive strength variant using rockchip_perpin_drv_type
- * @offset: if initialized to -1 it will be autocalculated, by specifying
- * an initial offset value the relevant source offset can be reset
- * to a new value for autocalculating the following drive strength
- * registers. if used chips own cal_drv func instead to calculate
- * registers offset, the variant could be ignored.
- */
-struct rockchip_drv {
- enum rockchip_pin_drv_type drv_type;
- int offset;
-};
-
-/**
- * struct rockchip_pin_bank
- * @reg_base: register base of the gpio bank
- * @regmap_pull: optional separate register for additional pull settings
- * @clk: clock of the gpio bank
- * @irq: interrupt of the gpio bank
- * @saved_masks: Saved content of GPIO_INTEN at suspend time.
- * @pin_base: first pin number
- * @nr_pins: number of pins in this bank
- * @name: name of the bank
- * @bank_num: number of the bank, to account for holes
- * @iomux: array describing the 4 iomux sources of the bank
- * @drv: array describing the 4 drive strength sources of the bank
- * @pull_type: array describing the 4 pull type sources of the bank
- * @valid: is all necessary information present
- * @of_node: dt node of this bank
- * @drvdata: common pinctrl basedata
- * @domain: irqdomain of the gpio bank
- * @gpio_chip: gpiolib chip
- * @grange: gpio range
- * @slock: spinlock for the gpio bank
- * @toggle_edge_mode: bit mask to toggle (falling/rising) edge mode
- * @recalced_mask: bit mask to indicate a need to recalulate the mask
- * @route_mask: bits describing the routing pins of per bank
- */
-struct rockchip_pin_bank {
- void __iomem *reg_base;
- struct regmap *regmap_pull;
- struct clk *clk;
- int irq;
- u32 saved_masks;
- u32 pin_base;
- u8 nr_pins;
- char *name;
- u8 bank_num;
- struct rockchip_iomux iomux[4];
- struct rockchip_drv drv[4];
- enum rockchip_pin_pull_type pull_type[4];
- bool valid;
- struct device_node *of_node;
- struct rockchip_pinctrl *drvdata;
- struct irq_domain *domain;
- struct gpio_chip gpio_chip;
- struct pinctrl_gpio_range grange;
- raw_spinlock_t slock;
- u32 toggle_edge_mode;
- u32 recalced_mask;
- u32 route_mask;
-};
-
#define PIN_BANK(id, pins, label) \
{ \
.bank_num = id, \
@@ -320,119 +209,6 @@ struct rockchip_pin_bank {
#define RK_MUXROUTE_PMU(ID, PIN, FUNC, REG, VAL) \
PIN_BANK_MUX_ROUTE_FLAGS(ID, PIN, FUNC, REG, VAL, ROCKCHIP_ROUTE_PMU)

-/**
- * struct rockchip_mux_recalced_data: represent a pin iomux data.
- * @num: bank number.
- * @pin: pin number.
- * @bit: index at register.
- * @reg: register offset.
- * @mask: mask bit
- */
-struct rockchip_mux_recalced_data {
- u8 num;
- u8 pin;
- u32 reg;
- u8 bit;
- u8 mask;
-};
-
-enum rockchip_mux_route_location {
- ROCKCHIP_ROUTE_SAME = 0,
- ROCKCHIP_ROUTE_PMU,
- ROCKCHIP_ROUTE_GRF,
-};
-
-/**
- * struct rockchip_mux_recalced_data: represent a pin iomux data.
- * @bank_num: bank number.
- * @pin: index at register or used to calc index.
- * @func: the min pin.
- * @route_location: the mux route location (same, pmu, grf).
- * @route_offset: the max pin.
- * @route_val: the register offset.
- */
-struct rockchip_mux_route_data {
- u8 bank_num;
- u8 pin;
- u8 func;
- enum rockchip_mux_route_location route_location;
- u32 route_offset;
- u32 route_val;
-};
-
-struct rockchip_pin_ctrl {
- struct rockchip_pin_bank *pin_banks;
- u32 nr_banks;
- u32 nr_pins;
- char *label;
- enum rockchip_pinctrl_type type;
- int grf_mux_offset;
- int pmu_mux_offset;
- int grf_drv_offset;
- int pmu_drv_offset;
- struct rockchip_mux_recalced_data *iomux_recalced;
- u32 niomux_recalced;
- struct rockchip_mux_route_data *iomux_routes;
- u32 niomux_routes;
-
- void (*pull_calc_reg)(struct rockchip_pin_bank *bank,
- int pin_num, struct regmap **regmap,
- int *reg, u8 *bit);
- void (*drv_calc_reg)(struct rockchip_pin_bank *bank,
- int pin_num, struct regmap **regmap,
- int *reg, u8 *bit);
- int (*schmitt_calc_reg)(struct rockchip_pin_bank *bank,
- int pin_num, struct regmap **regmap,
- int *reg, u8 *bit);
-};
-
-struct rockchip_pin_config {
- unsigned int func;
- unsigned long *configs;
- unsigned int nconfigs;
-};
-
-/**
- * struct rockchip_pin_group: represent group of pins of a pinmux function.
- * @name: name of the pin group, used to lookup the group.
- * @pins: the pins included in this group.
- * @npins: number of pins included in this group.
- * @data: local pin configuration
- */
-struct rockchip_pin_group {
- const char *name;
- unsigned int npins;
- unsigned int *pins;
- struct rockchip_pin_config *data;
-};
-
-/**
- * struct rockchip_pmx_func: represent a pin function.
- * @name: name of the pin function, used to lookup the function.
- * @groups: one or more names of pin groups that provide this function.
- * @ngroups: number of groups included in @groups.
- */
-struct rockchip_pmx_func {
- const char *name;
- const char **groups;
- u8 ngroups;
-};
-
-struct rockchip_pinctrl {
- struct regmap *regmap_base;
- int reg_size;
- struct regmap *regmap_pull;
- struct regmap *regmap_pmu;
- struct device *dev;
- struct rockchip_pin_ctrl *ctrl;
- struct pinctrl_desc pctl;
- struct pinctrl_dev *pctl_dev;
- struct rockchip_pin_group *groups;
- unsigned int ngroups;
- struct rockchip_pmx_func *functions;
- unsigned int nfunctions;
-};
-
static struct regmap_config rockchip_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
diff --git a/drivers/pinctrl/pinctrl-rockchip.h b/drivers/pinctrl/pinctrl-rockchip.h
new file mode 100644
index 000000000000..dba9e9540633
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-rockchip.h
@@ -0,0 +1,245 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2021 Rockchip Electronics Co. Ltd.
+ *
+ * Copyright (c) 2013 MundoReader S.L.
+ * Author: Heiko Stuebner <[email protected]>
+ *
+ * With some ideas taken from pinctrl-samsung:
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ * Copyright (c) 2012 Linaro Ltd
+ * https://www.linaro.org
+ *
+ * and pinctrl-at91:
+ * Copyright (C) 2011-2012 Jean-Christophe PLAGNIOL-VILLARD <[email protected]>
+ */
+
+#ifndef _PINCTRL_ROCKCHIP_H
+#define _PINCTRL_ROCKCHIP_H
+
+enum rockchip_pinctrl_type {
+ PX30,
+ RV1108,
+ RK2928,
+ RK3066B,
+ RK3128,
+ RK3188,
+ RK3288,
+ RK3308,
+ RK3368,
+ RK3399,
+ RK3568,
+};
+
+/**
+ * struct rockchip_iomux
+ * @type: iomux variant using IOMUX_* constants
+ * @offset: if initialized to -1 it will be autocalculated, by specifying
+ * an initial offset value the relevant source offset can be reset
+ * to a new value for autocalculating the following iomux registers.
+ */
+struct rockchip_iomux {
+ int type;
+ int offset;
+};
+
+/*
+ * enum type index corresponding to rockchip_perpin_drv_list arrays index.
+ */
+enum rockchip_pin_drv_type {
+ DRV_TYPE_IO_DEFAULT = 0,
+ DRV_TYPE_IO_1V8_OR_3V0,
+ DRV_TYPE_IO_1V8_ONLY,
+ DRV_TYPE_IO_1V8_3V0_AUTO,
+ DRV_TYPE_IO_3V3_ONLY,
+ DRV_TYPE_MAX
+};
+
+/*
+ * enum type index corresponding to rockchip_pull_list arrays index.
+ */
+enum rockchip_pin_pull_type {
+ PULL_TYPE_IO_DEFAULT = 0,
+ PULL_TYPE_IO_1V8_ONLY,
+ PULL_TYPE_MAX
+};
+
+/**
+ * struct rockchip_drv
+ * @drv_type: drive strength variant using rockchip_perpin_drv_type
+ * @offset: if initialized to -1 it will be autocalculated, by specifying
+ * an initial offset value the relevant source offset can be reset
+ * to a new value for autocalculating the following drive strength
+ * registers. if used chips own cal_drv func instead to calculate
+ * registers offset, the variant could be ignored.
+ */
+struct rockchip_drv {
+ enum rockchip_pin_drv_type drv_type;
+ int offset;
+};
+
+/**
+ * struct rockchip_pin_bank
+ * @reg_base: register base of the gpio bank
+ * @regmap_pull: optional separate register for additional pull settings
+ * @clk: clock of the gpio bank
+ * @irq: interrupt of the gpio bank
+ * @saved_masks: Saved content of GPIO_INTEN at suspend time.
+ * @pin_base: first pin number
+ * @nr_pins: number of pins in this bank
+ * @name: name of the bank
+ * @bank_num: number of the bank, to account for holes
+ * @iomux: array describing the 4 iomux sources of the bank
+ * @drv: array describing the 4 drive strength sources of the bank
+ * @pull_type: array describing the 4 pull type sources of the bank
+ * @valid: is all necessary information present
+ * @of_node: dt node of this bank
+ * @drvdata: common pinctrl basedata
+ * @domain: irqdomain of the gpio bank
+ * @gpio_chip: gpiolib chip
+ * @grange: gpio range
+ * @slock: spinlock for the gpio bank
+ * @toggle_edge_mode: bit mask to toggle (falling/rising) edge mode
+ * @recalced_mask: bit mask to indicate a need to recalulate the mask
+ * @route_mask: bits describing the routing pins of per bank
+ */
+struct rockchip_pin_bank {
+ void __iomem *reg_base;
+ struct regmap *regmap_pull;
+ struct clk *clk;
+ int irq;
+ u32 saved_masks;
+ u32 pin_base;
+ u8 nr_pins;
+ char *name;
+ u8 bank_num;
+ struct rockchip_iomux iomux[4];
+ struct rockchip_drv drv[4];
+ enum rockchip_pin_pull_type pull_type[4];
+ bool valid;
+ struct device_node *of_node;
+ struct rockchip_pinctrl *drvdata;
+ struct irq_domain *domain;
+ struct gpio_chip gpio_chip;
+ struct pinctrl_gpio_range grange;
+ raw_spinlock_t slock;
+ u32 toggle_edge_mode;
+ u32 recalced_mask;
+ u32 route_mask;
+};
+
+/**
+ * struct rockchip_mux_recalced_data: represent a pin iomux data.
+ * @num: bank number.
+ * @pin: pin number.
+ * @bit: index at register.
+ * @reg: register offset.
+ * @mask: mask bit
+ */
+struct rockchip_mux_recalced_data {
+ u8 num;
+ u8 pin;
+ u32 reg;
+ u8 bit;
+ u8 mask;
+};
+
+enum rockchip_mux_route_location {
+ ROCKCHIP_ROUTE_SAME = 0,
+ ROCKCHIP_ROUTE_PMU,
+ ROCKCHIP_ROUTE_GRF,
+};
+
+/**
+ * struct rockchip_mux_recalced_data: represent a pin iomux data.
+ * @bank_num: bank number.
+ * @pin: index at register or used to calc index.
+ * @func: the min pin.
+ * @route_location: the mux route location (same, pmu, grf).
+ * @route_offset: the max pin.
+ * @route_val: the register offset.
+ */
+struct rockchip_mux_route_data {
+ u8 bank_num;
+ u8 pin;
+ u8 func;
+ enum rockchip_mux_route_location route_location;
+ u32 route_offset;
+ u32 route_val;
+};
+
+struct rockchip_pin_ctrl {
+ struct rockchip_pin_bank *pin_banks;
+ u32 nr_banks;
+ u32 nr_pins;
+ char *label;
+ enum rockchip_pinctrl_type type;
+ int grf_mux_offset;
+ int pmu_mux_offset;
+ int grf_drv_offset;
+ int pmu_drv_offset;
+ struct rockchip_mux_recalced_data *iomux_recalced;
+ u32 niomux_recalced;
+ struct rockchip_mux_route_data *iomux_routes;
+ u32 niomux_routes;
+
+ void (*pull_calc_reg)(struct rockchip_pin_bank *bank,
+ int pin_num, struct regmap **regmap,
+ int *reg, u8 *bit);
+ void (*drv_calc_reg)(struct rockchip_pin_bank *bank,
+ int pin_num, struct regmap **regmap,
+ int *reg, u8 *bit);
+ int (*schmitt_calc_reg)(struct rockchip_pin_bank *bank,
+ int pin_num, struct regmap **regmap,
+ int *reg, u8 *bit);
+};
+
+struct rockchip_pin_config {
+ unsigned int func;
+ unsigned long *configs;
+ unsigned int nconfigs;
+};
+
+/**
+ * struct rockchip_pin_group: represent group of pins of a pinmux function.
+ * @name: name of the pin group, used to lookup the group.
+ * @pins: the pins included in this group.
+ * @npins: number of pins included in this group.
+ * @data: local pin configuration
+ */
+struct rockchip_pin_group {
+ const char *name;
+ unsigned int npins;
+ unsigned int *pins;
+ struct rockchip_pin_config *data;
+};
+
+/**
+ * struct rockchip_pmx_func: represent a pin function.
+ * @name: name of the pin function, used to lookup the function.
+ * @groups: one or more names of pin groups that provide this function.
+ * @ngroups: number of groups included in @groups.
+ */
+struct rockchip_pmx_func {
+ const char *name;
+ const char **groups;
+ u8 ngroups;
+};
+
+struct rockchip_pinctrl {
+ struct regmap *regmap_base;
+ int reg_size;
+ struct regmap *regmap_pull;
+ struct regmap *regmap_pmu;
+ struct device *dev;
+ struct rockchip_pin_ctrl *ctrl;
+ struct pinctrl_desc pctl;
+ struct pinctrl_dev *pctl_dev;
+ struct rockchip_pin_group *groups;
+ unsigned int ngroups;
+ struct rockchip_pmx_func *functions;
+ unsigned int nfunctions;
+};
+
+#endif
--
2.25.1

2021-04-11 14:10:11

by Peter Geis

[permalink] [raw]
Subject: [PATCH v2 4/7] gpio/rockchip: use struct rockchip_gpio_regs for gpio controller

From: Jianqun Xu <[email protected]>

Store register offsets in the struct rockchip_gpio_regs, this patch
prepare for the driver update for new gpio controller.

Signed-off-by: Jianqun Xu <[email protected]>
---
drivers/gpio/gpio-rockchip.c | 85 ++++++++++++++++--------------
drivers/pinctrl/pinctrl-rockchip.h | 38 +++++++++++++
2 files changed, 84 insertions(+), 39 deletions(-)

diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c
index 03a3d251faae..b12db3a523d0 100644
--- a/drivers/gpio/gpio-rockchip.c
+++ b/drivers/gpio/gpio-rockchip.c
@@ -24,19 +24,21 @@
#include "../pinctrl/core.h"
#include "../pinctrl/pinctrl-rockchip.h"

-/* GPIO control registers */
-#define GPIO_SWPORT_DR 0x00
-#define GPIO_SWPORT_DDR 0x04
-#define GPIO_INTEN 0x30
-#define GPIO_INTMASK 0x34
-#define GPIO_INTTYPE_LEVEL 0x38
-#define GPIO_INT_POLARITY 0x3c
-#define GPIO_INT_STATUS 0x40
-#define GPIO_INT_RAWSTATUS 0x44
-#define GPIO_DEBOUNCE 0x48
-#define GPIO_PORTS_EOI 0x4c
-#define GPIO_EXT_PORT 0x50
-#define GPIO_LS_SYNC 0x60
+#define GPIO_TYPE_V1 (0) /* GPIO Version ID reserved */
+
+static const struct rockchip_gpio_regs gpio_regs_v1 = {
+ .port_dr = 0x00,
+ .port_ddr = 0x04,
+ .int_en = 0x30,
+ .int_mask = 0x34,
+ .int_type = 0x38,
+ .int_polarity = 0x3c,
+ .int_status = 0x40,
+ .int_rawstatus = 0x44,
+ .debounce = 0x48,
+ .port_eoi = 0x4c,
+ .ext_port = 0x50,
+};

static int rockchip_gpio_get_direction(struct gpio_chip *chip,
unsigned int offset)
@@ -51,7 +53,7 @@ static int rockchip_gpio_get_direction(struct gpio_chip *chip,
"failed to enable clock for bank %s\n", bank->name);
return ret;
}
- data = readl_relaxed(bank->reg_base + GPIO_SWPORT_DDR);
+ data = readl_relaxed(bank->reg_base + bank->gpio_regs->port_ddr);
clk_disable(bank->clk);

if (data & BIT(offset))
@@ -70,13 +72,13 @@ static int rockchip_gpio_set_direction(struct gpio_chip *chip,
clk_enable(bank->clk);
raw_spin_lock_irqsave(&bank->slock, flags);

- data = readl_relaxed(bank->reg_base + GPIO_SWPORT_DDR);
+ data = readl_relaxed(bank->reg_base + bank->gpio_regs->port_ddr);
/* set bit to 1 for output, 0 for input */
if (!input)
data |= BIT(offset);
else
data &= ~BIT(offset);
- writel_relaxed(data, bank->reg_base + GPIO_SWPORT_DDR);
+ writel_relaxed(data, bank->reg_base + bank->gpio_regs->port_ddr);

raw_spin_unlock_irqrestore(&bank->slock, flags);
clk_disable(bank->clk);
@@ -88,7 +90,7 @@ static void rockchip_gpio_set(struct gpio_chip *gc, unsigned int offset,
int value)
{
struct rockchip_pin_bank *bank = gpiochip_get_data(gc);
- void __iomem *reg = bank->reg_base + GPIO_SWPORT_DR;
+ void __iomem *reg = bank->reg_base + bank->gpio_regs->port_dr;
unsigned long flags;
u32 data;

@@ -111,7 +113,7 @@ static int rockchip_gpio_get(struct gpio_chip *gc, unsigned int offset)
u32 data;

clk_enable(bank->clk);
- data = readl(bank->reg_base + GPIO_EXT_PORT);
+ data = readl(bank->reg_base + bank->gpio_regs->ext_port);
clk_disable(bank->clk);
data >>= offset;
data &= 1;
@@ -122,7 +124,7 @@ static void rockchip_gpio_set_debounce(struct gpio_chip *gc,
unsigned int offset, bool enable)
{
struct rockchip_pin_bank *bank = gpiochip_get_data(gc);
- void __iomem *reg = bank->reg_base + GPIO_DEBOUNCE;
+ void __iomem *reg = bank->reg_base + bank->gpio_regs->debounce;
unsigned long flags;
u32 data;

@@ -226,7 +228,7 @@ static void rockchip_irq_demux(struct irq_desc *desc)

chained_irq_enter(chip, desc);

- pend = readl_relaxed(bank->reg_base + GPIO_INT_STATUS);
+ pend = readl_relaxed(bank->reg_base + bank->gpio_regs->int_status);

while (pend) {
unsigned int irq, virq;
@@ -250,24 +252,26 @@ static void rockchip_irq_demux(struct irq_desc *desc)
u32 data, data_old, polarity;
unsigned long flags;

- data = readl_relaxed(bank->reg_base + GPIO_EXT_PORT);
+ data = readl_relaxed(bank->reg_base +
+ bank->gpio_regs->ext_port);
do {
raw_spin_lock_irqsave(&bank->slock, flags);

polarity = readl_relaxed(bank->reg_base +
- GPIO_INT_POLARITY);
+ bank->gpio_regs->int_polarity);
if (data & BIT(irq))
polarity &= ~BIT(irq);
else
polarity |= BIT(irq);
writel(polarity,
- bank->reg_base + GPIO_INT_POLARITY);
+ bank->reg_base +
+ bank->gpio_regs->int_polarity);

raw_spin_unlock_irqrestore(&bank->slock, flags);

data_old = data;
data = readl_relaxed(bank->reg_base +
- GPIO_EXT_PORT);
+ bank->gpio_regs->ext_port);
} while ((data & BIT(irq)) != (data_old & BIT(irq)));
}

@@ -290,9 +294,9 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type)
clk_enable(bank->clk);
raw_spin_lock_irqsave(&bank->slock, flags);

- data = readl_relaxed(bank->reg_base + GPIO_SWPORT_DDR);
+ data = readl_relaxed(bank->reg_base + bank->gpio_regs->port_ddr);
data &= ~mask;
- writel_relaxed(data, bank->reg_base + GPIO_SWPORT_DDR);
+ writel_relaxed(data, bank->reg_base + bank->gpio_regs->port_ddr);

raw_spin_unlock_irqrestore(&bank->slock, flags);

@@ -304,8 +308,8 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type)
raw_spin_lock_irqsave(&bank->slock, flags);
irq_gc_lock(gc);

- level = readl_relaxed(gc->reg_base + GPIO_INTTYPE_LEVEL);
- polarity = readl_relaxed(gc->reg_base + GPIO_INT_POLARITY);
+ level = readl_relaxed(gc->reg_base + bank->gpio_regs->int_type);
+ polarity = readl_relaxed(gc->reg_base + bank->gpio_regs->int_polarity);

switch (type) {
case IRQ_TYPE_EDGE_BOTH:
@@ -316,7 +320,7 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type)
* Determine gpio state. If 1 next interrupt should be falling
* otherwise rising.
*/
- data = readl(bank->reg_base + GPIO_EXT_PORT);
+ data = readl(bank->reg_base + bank->gpio_regs->ext_port);
if (data & mask)
polarity &= ~mask;
else
@@ -349,8 +353,8 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type)
return -EINVAL;
}

- writel_relaxed(level, gc->reg_base + GPIO_INTTYPE_LEVEL);
- writel_relaxed(polarity, gc->reg_base + GPIO_INT_POLARITY);
+ writel_relaxed(level, gc->reg_base + bank->gpio_regs->int_type);
+ writel_relaxed(polarity, gc->reg_base + bank->gpio_regs->int_polarity);

irq_gc_unlock(gc);
raw_spin_unlock_irqrestore(&bank->slock, flags);
@@ -365,8 +369,8 @@ static void rockchip_irq_suspend(struct irq_data *d)
struct rockchip_pin_bank *bank = gc->private;

clk_enable(bank->clk);
- bank->saved_masks = irq_reg_readl(gc, GPIO_INTMASK);
- irq_reg_writel(gc, ~gc->wake_active, GPIO_INTMASK);
+ bank->saved_masks = irq_reg_readl(gc, bank->gpio_regs->int_mask);
+ irq_reg_writel(gc, ~gc->wake_active, bank->gpio_regs->int_mask);
clk_disable(bank->clk);
}

@@ -376,7 +380,7 @@ static void rockchip_irq_resume(struct irq_data *d)
struct rockchip_pin_bank *bank = gc->private;

clk_enable(bank->clk);
- irq_reg_writel(gc, bank->saved_masks, GPIO_INTMASK);
+ irq_reg_writel(gc, bank->saved_masks, bank->gpio_regs->int_mask);
clk_disable(bank->clk);
}

@@ -435,8 +439,8 @@ static int rockchip_interrupts_register(struct rockchip_pin_bank *bank)
gc = irq_get_domain_generic_chip(bank->domain, 0);
gc->reg_base = bank->reg_base;
gc->private = bank;
- gc->chip_types[0].regs.mask = GPIO_INTMASK;
- gc->chip_types[0].regs.ack = GPIO_PORTS_EOI;
+ gc->chip_types[0].regs.mask = bank->gpio_regs->int_mask;
+ gc->chip_types[0].regs.ack = bank->gpio_regs->port_eoi;
gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit;
gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit;
gc->chip_types[0].chip.irq_unmask = irq_gc_mask_clr_bit;
@@ -453,9 +457,9 @@ static int rockchip_interrupts_register(struct rockchip_pin_bank *bank)
* Our driver only uses the concept of masked and always keeps
* things enabled, so for us that's all masked and all enabled.
*/
- writel_relaxed(0xffffffff, bank->reg_base + GPIO_INTMASK);
- writel_relaxed(0xffffffff, bank->reg_base + GPIO_PORTS_EOI);
- writel_relaxed(0xffffffff, bank->reg_base + GPIO_INTEN);
+ writel_relaxed(0xffffffff, bank->reg_base + bank->gpio_regs->int_mask);
+ writel_relaxed(0xffffffff, bank->reg_base + bank->gpio_regs->port_eoi);
+ writel_relaxed(0xffffffff, bank->reg_base + bank->gpio_regs->int_en);
gc->mask_cache = 0xffffffff;

irq_set_chained_handler_and_data(bank->irq,
@@ -546,6 +550,9 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank)

bank->irq = irq_of_parse_and_map(bank->of_node, 0);

+ bank->gpio_regs = &gpio_regs_v1;
+ bank->gpio_type = GPIO_TYPE_V1;
+
bank->clk = of_clk_get(bank->of_node, 0);
if (!IS_ERR(bank->clk))
return clk_prepare(bank->clk);
diff --git a/drivers/pinctrl/pinctrl-rockchip.h b/drivers/pinctrl/pinctrl-rockchip.h
index 4aa3d2f1fa67..1b774b6bbc3e 100644
--- a/drivers/pinctrl/pinctrl-rockchip.h
+++ b/drivers/pinctrl/pinctrl-rockchip.h
@@ -32,6 +32,42 @@ enum rockchip_pinctrl_type {
RK3568,
};

+/**
+ * struct rockchip_gpio_regs
+ * @port_dr: data register
+ * @port_ddr: data direction register
+ * @int_en: interrupt enable
+ * @int_mask: interrupt mask
+ * @int_type: interrupt trigger type, such as high, low, edge trriger type.
+ * @int_polarity: interrupt polarity enable register
+ * @int_bothedge: interrupt bothedge enable register
+ * @int_status: interrupt status register
+ * @int_rawstatus: int_status = int_rawstatus & int_mask
+ * @debounce: enable debounce for interrupt signal
+ * @dbclk_div_en: enable divider for debounce clock
+ * @dbclk_div_con: setting for divider of debounce clock
+ * @port_eoi: end of interrupt of the port
+ * @ext_port: port data from external
+ * @version_id: controller version register
+ */
+struct rockchip_gpio_regs {
+ u32 port_dr;
+ u32 port_ddr;
+ u32 int_en;
+ u32 int_mask;
+ u32 int_type;
+ u32 int_polarity;
+ u32 int_bothedge;
+ u32 int_status;
+ u32 int_rawstatus;
+ u32 debounce;
+ u32 dbclk_div_en;
+ u32 dbclk_div_con;
+ u32 port_eoi;
+ u32 ext_port;
+ u32 version_id;
+};
+
/**
* struct rockchip_iomux
* @type: iomux variant using IOMUX_* constants
@@ -126,6 +162,8 @@ struct rockchip_pin_bank {
struct gpio_chip gpio_chip;
struct pinctrl_gpio_range grange;
raw_spinlock_t slock;
+ const struct rockchip_gpio_regs *gpio_regs;
+ u32 gpio_type;
u32 toggle_edge_mode;
u32 recalced_mask;
u32 route_mask;
--
2.25.1

2021-04-11 14:10:11

by Peter Geis

[permalink] [raw]
Subject: [PATCH v2 5/7] gpio/rockchip: support next version gpio controller

From: Jianqun Xu <[email protected]>

The next version gpio controller on SoCs like rk3568 have more write
mask bits for registers.

Signed-off-by: Jianqun Xu <[email protected]>
---
drivers/gpio/gpio-rockchip.c | 280 ++++++++++++++++++++++-------
drivers/pinctrl/pinctrl-rockchip.h | 2 +
2 files changed, 215 insertions(+), 67 deletions(-)

diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c
index b12db3a523d0..92aaf1848449 100644
--- a/drivers/gpio/gpio-rockchip.c
+++ b/drivers/gpio/gpio-rockchip.c
@@ -25,6 +25,7 @@
#include "../pinctrl/pinctrl-rockchip.h"

#define GPIO_TYPE_V1 (0) /* GPIO Version ID reserved */
+#define GPIO_TYPE_V2 (0x01000C2B) /* GPIO Version ID 0x01000C2B */

static const struct rockchip_gpio_regs gpio_regs_v1 = {
.port_dr = 0x00,
@@ -40,6 +41,99 @@ static const struct rockchip_gpio_regs gpio_regs_v1 = {
.ext_port = 0x50,
};

+static const struct rockchip_gpio_regs gpio_regs_v2 = {
+ .port_dr = 0x00,
+ .port_ddr = 0x08,
+ .int_en = 0x10,
+ .int_mask = 0x18,
+ .int_type = 0x20,
+ .int_polarity = 0x28,
+ .int_bothedge = 0x30,
+ .int_status = 0x50,
+ .int_rawstatus = 0x58,
+ .debounce = 0x38,
+ .dbclk_div_en = 0x40,
+ .dbclk_div_con = 0x48,
+ .port_eoi = 0x60,
+ .ext_port = 0x70,
+ .version_id = 0x78,
+};
+
+static inline void gpio_writel_v2(u32 val, void __iomem *reg)
+{
+ writel((val & 0xffff) | 0xffff0000, reg);
+ writel((val >> 16) | 0xffff0000, reg + 0x4);
+}
+
+static inline u32 gpio_readl_v2(void __iomem *reg)
+{
+ return readl(reg + 0x4) << 16 | readl(reg);
+}
+
+static inline void rockchip_gpio_writel(struct rockchip_pin_bank *bank,
+ u32 value, unsigned int offset)
+{
+ void __iomem *reg = bank->reg_base + offset;
+
+ if (bank->gpio_type == GPIO_TYPE_V2)
+ gpio_writel_v2(value, reg);
+ else
+ writel(value, reg);
+}
+
+static inline u32 rockchip_gpio_readl(struct rockchip_pin_bank *bank,
+ unsigned int offset)
+{
+ void __iomem *reg = bank->reg_base + offset;
+ u32 value;
+
+ if (bank->gpio_type == GPIO_TYPE_V2)
+ value = gpio_readl_v2(reg);
+ else
+ value = readl(reg);
+
+ return value;
+}
+
+static inline void rockchip_gpio_writel_bit(struct rockchip_pin_bank *bank,
+ u32 bit, u32 value,
+ unsigned int offset)
+{
+ void __iomem *reg = bank->reg_base + offset;
+ u32 data;
+
+ if (bank->gpio_type == GPIO_TYPE_V2) {
+ if (value)
+ data = BIT(bit % 16) | BIT(bit % 16 + 16);
+ else
+ data = BIT(bit % 16 + 16);
+ writel(data, bit >= 16 ? reg + 0x4 : reg);
+ } else {
+ data = readl(reg);
+ data &= ~BIT(bit);
+ if (value)
+ data |= BIT(bit);
+ writel(data, reg);
+ }
+}
+
+static inline u32 rockchip_gpio_readl_bit(struct rockchip_pin_bank *bank,
+ u32 bit, unsigned int offset)
+{
+ void __iomem *reg = bank->reg_base + offset;
+ u32 data;
+
+ if (bank->gpio_type == GPIO_TYPE_V2) {
+ data = readl(bit >= 16 ? reg + 0x4 : reg);
+ data >>= bit % 16;
+ } else {
+ data = readl(reg);
+ data >>= bit;
+ }
+
+ return data & (0x1);
+}
+
static int rockchip_gpio_get_direction(struct gpio_chip *chip,
unsigned int offset)
{
@@ -53,7 +147,7 @@ static int rockchip_gpio_get_direction(struct gpio_chip *chip,
"failed to enable clock for bank %s\n", bank->name);
return ret;
}
- data = readl_relaxed(bank->reg_base + bank->gpio_regs->port_ddr);
+ data = rockchip_gpio_readl_bit(bank, offset, bank->gpio_regs->port_ddr);
clk_disable(bank->clk);

if (data & BIT(offset))
@@ -67,19 +161,11 @@ static int rockchip_gpio_set_direction(struct gpio_chip *chip,
{
struct rockchip_pin_bank *bank = gpiochip_get_data(chip);
unsigned long flags;
- u32 data;
+ u32 data = input ? 0 : 1;

clk_enable(bank->clk);
raw_spin_lock_irqsave(&bank->slock, flags);
-
- data = readl_relaxed(bank->reg_base + bank->gpio_regs->port_ddr);
- /* set bit to 1 for output, 0 for input */
- if (!input)
- data |= BIT(offset);
- else
- data &= ~BIT(offset);
- writel_relaxed(data, bank->reg_base + bank->gpio_regs->port_ddr);
-
+ rockchip_gpio_writel_bit(bank, offset, data, bank->gpio_regs->port_ddr);
raw_spin_unlock_irqrestore(&bank->slock, flags);
clk_disable(bank->clk);

@@ -90,19 +176,11 @@ static void rockchip_gpio_set(struct gpio_chip *gc, unsigned int offset,
int value)
{
struct rockchip_pin_bank *bank = gpiochip_get_data(gc);
- void __iomem *reg = bank->reg_base + bank->gpio_regs->port_dr;
unsigned long flags;
- u32 data;

clk_enable(bank->clk);
raw_spin_lock_irqsave(&bank->slock, flags);
-
- data = readl(reg);
- data &= ~BIT(offset);
- if (value)
- data |= BIT(offset);
- writel(data, reg);
-
+ rockchip_gpio_writel_bit(bank, offset, value, bank->gpio_regs->port_dr);
raw_spin_unlock_irqrestore(&bank->slock, flags);
clk_disable(bank->clk);
}
@@ -120,26 +198,65 @@ static int rockchip_gpio_get(struct gpio_chip *gc, unsigned int offset)
return data;
}

-static void rockchip_gpio_set_debounce(struct gpio_chip *gc,
- unsigned int offset, bool enable)
+static int rockchip_gpio_set_debounce(struct gpio_chip *gc,
+ unsigned int offset,
+ unsigned int debounce)
{
struct rockchip_pin_bank *bank = gpiochip_get_data(gc);
- void __iomem *reg = bank->reg_base + bank->gpio_regs->debounce;
- unsigned long flags;
- u32 data;
+ const struct rockchip_gpio_regs *reg = bank->gpio_regs;
+ unsigned long flags, div_reg, freq, max_debounce;
+ bool div_debounce_support;
+ unsigned int cur_div_reg;
+ u64 div;
+
+ if (!IS_ERR(bank->db_clk)) {
+ div_debounce_support = true;
+ freq = clk_get_rate(bank->db_clk);
+ max_debounce = (GENMASK(23, 0) + 1) * 2 * 1000000 / freq;
+ if (debounce > max_debounce)
+ return -EINVAL;
+
+ div = debounce * freq;
+ div_reg = DIV_ROUND_CLOSEST_ULL(div, 2 * USEC_PER_SEC) - 1;
+ } else {
+ div_debounce_support = false;
+ }

- clk_enable(bank->clk);
raw_spin_lock_irqsave(&bank->slock, flags);

- data = readl(reg);
- if (enable)
- data |= BIT(offset);
- else
- data &= ~BIT(offset);
- writel(data, reg);
+ /* Only the v1 needs to configure div_en and div_con for dbclk */
+ if (debounce) {
+ if (div_debounce_support) {
+ /* Configure the max debounce from consumers */
+ cur_div_reg = readl(bank->reg_base +
+ reg->dbclk_div_con);
+ if (cur_div_reg < div_reg)
+ writel(div_reg, bank->reg_base +
+ reg->dbclk_div_con);
+ rockchip_gpio_writel_bit(bank, offset, 1,
+ reg->dbclk_div_en);
+ }
+
+ rockchip_gpio_writel_bit(bank, offset, 1, reg->debounce);
+ } else {
+ if (div_debounce_support)
+ rockchip_gpio_writel_bit(bank, offset, 0,
+ reg->dbclk_div_en);
+
+ rockchip_gpio_writel_bit(bank, offset, 0, reg->debounce);
+ }

raw_spin_unlock_irqrestore(&bank->slock, flags);
- clk_disable(bank->clk);
+
+ /* Enable or disable dbclk at last */
+ if (div_debounce_support) {
+ if (debounce)
+ clk_prepare_enable(bank->db_clk);
+ else
+ clk_disable_unprepare(bank->db_clk);
+ }
+
+ return 0;
}

static int rockchip_gpio_direction_input(struct gpio_chip *gc,
@@ -290,13 +407,13 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type)
u32 level;
u32 data;
unsigned long flags;
+ int ret = 0;

clk_enable(bank->clk);
raw_spin_lock_irqsave(&bank->slock, flags);

- data = readl_relaxed(bank->reg_base + bank->gpio_regs->port_ddr);
- data &= ~mask;
- writel_relaxed(data, bank->reg_base + bank->gpio_regs->port_ddr);
+ rockchip_gpio_writel_bit(bank, d->hwirq, 0,
+ bank->gpio_regs->port_ddr);

raw_spin_unlock_irqrestore(&bank->slock, flags);

@@ -308,23 +425,30 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type)
raw_spin_lock_irqsave(&bank->slock, flags);
irq_gc_lock(gc);

- level = readl_relaxed(gc->reg_base + bank->gpio_regs->int_type);
- polarity = readl_relaxed(gc->reg_base + bank->gpio_regs->int_polarity);
+ level = rockchip_gpio_readl(bank, bank->gpio_regs->int_type);
+ polarity = rockchip_gpio_readl(bank, bank->gpio_regs->int_polarity);

switch (type) {
case IRQ_TYPE_EDGE_BOTH:
- bank->toggle_edge_mode |= mask;
- level |= mask;
-
- /*
- * Determine gpio state. If 1 next interrupt should be falling
- * otherwise rising.
- */
- data = readl(bank->reg_base + bank->gpio_regs->ext_port);
- if (data & mask)
- polarity &= ~mask;
- else
- polarity |= mask;
+ if (bank->gpio_type == GPIO_TYPE_V2) {
+ bank->toggle_edge_mode &= ~mask;
+ rockchip_gpio_writel_bit(bank, d->hwirq, 1,
+ bank->gpio_regs->int_bothedge);
+ goto out;
+ } else {
+ bank->toggle_edge_mode |= mask;
+ level |= mask;
+
+ /*
+ * Determine gpio state. If 1 next interrupt should be
+ * falling otherwise rising.
+ */
+ data = readl(bank->reg_base + bank->gpio_regs->ext_port);
+ if (data & mask)
+ polarity &= ~mask;
+ else
+ polarity |= mask;
+ }
break;
case IRQ_TYPE_EDGE_RISING:
bank->toggle_edge_mode &= ~mask;
@@ -347,20 +471,18 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type)
polarity &= ~mask;
break;
default:
- irq_gc_unlock(gc);
- raw_spin_unlock_irqrestore(&bank->slock, flags);
- clk_disable(bank->clk);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}

- writel_relaxed(level, gc->reg_base + bank->gpio_regs->int_type);
- writel_relaxed(polarity, gc->reg_base + bank->gpio_regs->int_polarity);
-
+ rockchip_gpio_writel(bank, level, bank->gpio_regs->int_type);
+ rockchip_gpio_writel(bank, polarity, bank->gpio_regs->int_polarity);
+out:
irq_gc_unlock(gc);
raw_spin_unlock_irqrestore(&bank->slock, flags);
clk_disable(bank->clk);

- return 0;
+ return ret;
}

static void rockchip_irq_suspend(struct irq_data *d)
@@ -437,6 +559,11 @@ static int rockchip_interrupts_register(struct rockchip_pin_bank *bank)
}

gc = irq_get_domain_generic_chip(bank->domain, 0);
+ if (bank->gpio_type == GPIO_TYPE_V2) {
+ gc->reg_writel = gpio_writel_v2;
+ gc->reg_readl = gpio_readl_v2;
+ }
+
gc->reg_base = bank->reg_base;
gc->private = bank;
gc->chip_types[0].regs.mask = bank->gpio_regs->int_mask;
@@ -457,9 +584,9 @@ static int rockchip_interrupts_register(struct rockchip_pin_bank *bank)
* Our driver only uses the concept of masked and always keeps
* things enabled, so for us that's all masked and all enabled.
*/
- writel_relaxed(0xffffffff, bank->reg_base + bank->gpio_regs->int_mask);
- writel_relaxed(0xffffffff, bank->reg_base + bank->gpio_regs->port_eoi);
- writel_relaxed(0xffffffff, bank->reg_base + bank->gpio_regs->int_en);
+ rockchip_gpio_writel(bank, 0xffffffff, bank->gpio_regs->int_mask);
+ rockchip_gpio_writel(bank, 0xffffffff, bank->gpio_regs->port_eoi);
+ rockchip_gpio_writel(bank, 0xffffffff, bank->gpio_regs->int_en);
gc->mask_cache = 0xffffffff;

irq_set_chained_handler_and_data(bank->irq,
@@ -538,6 +665,7 @@ static int rockchip_gpiolib_register(struct rockchip_pin_bank *bank)
static int rockchip_get_bank_data(struct rockchip_pin_bank *bank)
{
struct resource res;
+ int id = 0;

if (of_address_to_resource(bank->of_node, 0, &res)) {
dev_err(bank->dev, "cannot find IO resource for bank\n");
@@ -549,15 +677,33 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank)
return PTR_ERR(bank->reg_base);

bank->irq = irq_of_parse_and_map(bank->of_node, 0);
-
- bank->gpio_regs = &gpio_regs_v1;
- bank->gpio_type = GPIO_TYPE_V1;
+ if (!bank->irq)
+ return -EINVAL;

bank->clk = of_clk_get(bank->of_node, 0);
- if (!IS_ERR(bank->clk))
- return clk_prepare(bank->clk);
+ if (IS_ERR(bank->clk))
+ return PTR_ERR(bank->clk);
+
+ clk_prepare_enable(bank->clk);
+ id = readl(bank->reg_base + gpio_regs_v2.version_id);
+
+ /* If not gpio v2, that is default to v1. */
+ if (id == GPIO_TYPE_V2) {
+ bank->gpio_regs = &gpio_regs_v2;
+ bank->gpio_type = GPIO_TYPE_V2;
+ bank->db_clk = of_clk_get(bank->of_node, 1);
+ if (IS_ERR(bank->db_clk)) {
+ dev_err(bank->dev, "cannot find debounce clk\n");
+ bank->db_clk = NULL;
+ clk_disable(bank->clk);
+ return -EINVAL;
+ }
+ } else {
+ bank->gpio_regs = &gpio_regs_v1;
+ bank->gpio_type = GPIO_TYPE_V1;
+ }

- bank->clk = NULL;
+ clk_disable(bank->clk);
return 0;
}

diff --git a/drivers/pinctrl/pinctrl-rockchip.h b/drivers/pinctrl/pinctrl-rockchip.h
index 1b774b6bbc3e..589d4d2a98c9 100644
--- a/drivers/pinctrl/pinctrl-rockchip.h
+++ b/drivers/pinctrl/pinctrl-rockchip.h
@@ -121,6 +121,7 @@ struct rockchip_drv {
* @reg_base: register base of the gpio bank
* @regmap_pull: optional separate register for additional pull settings
* @clk: clock of the gpio bank
+ * @db_clk: clock of the gpio debounce
* @irq: interrupt of the gpio bank
* @saved_masks: Saved content of GPIO_INTEN at suspend time.
* @pin_base: first pin number
@@ -146,6 +147,7 @@ struct rockchip_pin_bank {
void __iomem *reg_base;
struct regmap *regmap_pull;
struct clk *clk;
+ struct clk *db_clk;
int irq;
u32 saved_masks;
u32 pin_base;
--
2.25.1

2021-04-11 14:10:29

by Peter Geis

[permalink] [raw]
Subject: [PATCH v2 7/7] gpio/rockchip: drop irq_gc_lock/irq_gc_unlock for irq set type

From: Jianqun Xu <[email protected]>

There has spin lock for irq set type already, so drop irq_gc_lock and
irq_gc_unlock.

Signed-off-by: Jianqun Xu <[email protected]>
---
drivers/gpio/gpio-rockchip.c | 2 --
1 file changed, 2 deletions(-)

diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c
index 048e7eecddba..c9c55614bbef 100644
--- a/drivers/gpio/gpio-rockchip.c
+++ b/drivers/gpio/gpio-rockchip.c
@@ -406,7 +406,6 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type)
irq_set_handler_locked(d, handle_level_irq);

raw_spin_lock_irqsave(&bank->slock, flags);
- irq_gc_lock(gc);

level = rockchip_gpio_readl(bank, bank->gpio_regs->int_type);
polarity = rockchip_gpio_readl(bank, bank->gpio_regs->int_polarity);
@@ -461,7 +460,6 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type)
rockchip_gpio_writel(bank, level, bank->gpio_regs->int_type);
rockchip_gpio_writel(bank, polarity, bank->gpio_regs->int_polarity);
out:
- irq_gc_unlock(gc);
raw_spin_unlock_irqrestore(&bank->slock, flags);

return ret;
--
2.25.1

2021-04-12 13:33:56

by Heiko Stuebner

[permalink] [raw]
Subject: Re: [PATCH v2 0/7] gpio-rockchip driver

Am Montag, 12. April 2021, 14:13:37 CEST schrieb Andy Shevchenko:
> On Sun, Apr 11, 2021 at 4:35 PM Peter Geis <[email protected]> wrote:
> >
> > Separate gpio driver from pinctrl driver, and support v2 controller.
> >
> > Tested on rk3566-quartz64 prototype board.
>
> Can you give a bit more context?
> Usually separation means that hardware is represented by two different
> IP blocks that are (almost) independent to each other. Was it the case
> on the original platforms? Do you have different pin controller (or
> it's absent completely) on some new / old platform?

They are separate on all Rockchip SoCs.

I.e. the pinconfig (muxing, pulls, etc) is done via some registers inside
the "General Register Files" [area for misc registers]
and control for the gpio functionality is done in separate blocks
for each bank.

Lumping that stuff together into one driver, was a design-mistake
from younger-me back in 2013 ;-)


Heiko

> >
> > Patch History:
> > V2 - Rebase to latest linux-next.
> >
> > Tested-by: Peter Geis <[email protected]>
> >
> > Jianqun Xu (7):
> > pinctrl/rockchip: separate struct rockchip_pin_bank to a head file
> > pinctrl/pinctrl-rockchip.h: add pinctrl device to gpio bank struct
> > gpio: separate gpio driver from pinctrl-rockchip driver
> > gpio/rockchip: use struct rockchip_gpio_regs for gpio controller
> > gpio/rockchip: support next version gpio controller
> > gpio/rockchip: always enable clock for gpio controller
> > gpio/rockchip: drop irq_gc_lock/irq_gc_unlock for irq set type
> >
> > drivers/gpio/Kconfig | 8 +
> > drivers/gpio/Makefile | 1 +
> > drivers/gpio/gpio-rockchip.c | 758 ++++++++++++++++++++++++
> > drivers/pinctrl/pinctrl-rockchip.c | 911 +----------------------------
> > drivers/pinctrl/pinctrl-rockchip.h | 287 +++++++++
> > 5 files changed, 1073 insertions(+), 892 deletions(-)
> > create mode 100644 drivers/gpio/gpio-rockchip.c
> > create mode 100644 drivers/pinctrl/pinctrl-rockchip.h
> >
> > --
> > 2.25.1
> >
>
>
>




2021-04-12 13:35:21

by Andy Shevchenko

[permalink] [raw]
Subject: Re: [PATCH v2 0/7] gpio-rockchip driver

On Mon, Apr 12, 2021 at 4:30 PM Heiko Stübner <[email protected]> wrote:
> Am Montag, 12. April 2021, 14:13:37 CEST schrieb Andy Shevchenko:
> > On Sun, Apr 11, 2021 at 4:35 PM Peter Geis <[email protected]> wrote:
> > >
> > > Separate gpio driver from pinctrl driver, and support v2 controller.
> > >
> > > Tested on rk3566-quartz64 prototype board.
> >
> > Can you give a bit more context?
> > Usually separation means that hardware is represented by two different
> > IP blocks that are (almost) independent to each other. Was it the case
> > on the original platforms? Do you have different pin controller (or
> > it's absent completely) on some new / old platform?
>
> They are separate on all Rockchip SoCs.
>
> I.e. the pinconfig (muxing, pulls, etc) is done via some registers inside
> the "General Register Files" [area for misc registers]
> and control for the gpio functionality is done in separate blocks
> for each bank.
>
> Lumping that stuff together into one driver, was a design-mistake
> from younger-me back in 2013 ;-)

Thanks!

To the submitter: Just for the future, please elaborate such things in
the cover letter.

--
With Best Regards,
Andy Shevchenko

2021-04-12 15:02:20

by Peter Geis

[permalink] [raw]
Subject: Re: [PATCH v2 0/7] gpio-rockchip driver

On Mon, Apr 12, 2021 at 9:34 AM Andy Shevchenko
<[email protected]> wrote:
>
> On Mon, Apr 12, 2021 at 4:30 PM Heiko Stübner <[email protected]> wrote:
> > Am Montag, 12. April 2021, 14:13:37 CEST schrieb Andy Shevchenko:
> > > On Sun, Apr 11, 2021 at 4:35 PM Peter Geis <[email protected]> wrote:
> > > >
> > > > Separate gpio driver from pinctrl driver, and support v2 controller.
> > > >
> > > > Tested on rk3566-quartz64 prototype board.
> > >
> > > Can you give a bit more context?
> > > Usually separation means that hardware is represented by two different
> > > IP blocks that are (almost) independent to each other. Was it the case
> > > on the original platforms? Do you have different pin controller (or
> > > it's absent completely) on some new / old platform?
> >
> > They are separate on all Rockchip SoCs.
> >
> > I.e. the pinconfig (muxing, pulls, etc) is done via some registers inside
> > the "General Register Files" [area for misc registers]
> > and control for the gpio functionality is done in separate blocks
> > for each bank.
> >
> > Lumping that stuff together into one driver, was a design-mistake
> > from younger-me back in 2013 ;-)
>
> Thanks!
>
> To the submitter: Just for the future, please elaborate such things in
> the cover letter.

Apologies, I only rebased the work and reused the original cover letter.
I'll keep that in mind if this sort of situation arises again.

>
> --
> With Best Regards,
> Andy Shevchenko

2021-04-13 01:25:47

by Andy Shevchenko

[permalink] [raw]
Subject: Re: [PATCH v2 0/7] gpio-rockchip driver

On Sun, Apr 11, 2021 at 4:35 PM Peter Geis <[email protected]> wrote:
>
> Separate gpio driver from pinctrl driver, and support v2 controller.
>
> Tested on rk3566-quartz64 prototype board.

Can you give a bit more context?
Usually separation means that hardware is represented by two different
IP blocks that are (almost) independent to each other. Was it the case
on the original platforms? Do you have different pin controller (or
it's absent completely) on some new / old platform?

>
> Patch History:
> V2 - Rebase to latest linux-next.
>
> Tested-by: Peter Geis <[email protected]>
>
> Jianqun Xu (7):
> pinctrl/rockchip: separate struct rockchip_pin_bank to a head file
> pinctrl/pinctrl-rockchip.h: add pinctrl device to gpio bank struct
> gpio: separate gpio driver from pinctrl-rockchip driver
> gpio/rockchip: use struct rockchip_gpio_regs for gpio controller
> gpio/rockchip: support next version gpio controller
> gpio/rockchip: always enable clock for gpio controller
> gpio/rockchip: drop irq_gc_lock/irq_gc_unlock for irq set type
>
> drivers/gpio/Kconfig | 8 +
> drivers/gpio/Makefile | 1 +
> drivers/gpio/gpio-rockchip.c | 758 ++++++++++++++++++++++++
> drivers/pinctrl/pinctrl-rockchip.c | 911 +----------------------------
> drivers/pinctrl/pinctrl-rockchip.h | 287 +++++++++
> 5 files changed, 1073 insertions(+), 892 deletions(-)
> create mode 100644 drivers/gpio/gpio-rockchip.c
> create mode 100644 drivers/pinctrl/pinctrl-rockchip.h
>
> --
> 2.25.1
>


--
With Best Regards,
Andy Shevchenko

2021-04-14 20:23:35

by Linus Walleij

[permalink] [raw]
Subject: Re: [PATCH v2 0/7] gpio-rockchip driver

On Sun, Apr 11, 2021 at 3:30 PM Peter Geis <[email protected]> wrote:

> Separate gpio driver from pinctrl driver, and support v2 controller.
>
> Tested on rk3566-quartz64 prototype board.
>
> Patch History:
> V2 - Rebase to latest linux-next.
>
> Tested-by: Peter Geis <[email protected]>

This does not apply to the pin control tree, the problem with basing stuff
on -next is that it sometimes does not apply to any development tree
and now that happened (because of conflicts in the GPIO tree).

You can either resend this based on the pinctrl "devel" branch:
https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl.git/log/?h=devel
... or you can wait until kernel v5.13-rc1 is out and then we can merge
it, but it might even require rebasing after that.

Yours,
Linus Walleij