[Letux-kernel] [RFC 14/28] pinctrl/ingenic: Add pinctrl support for the JZ4730
H. Nikolaus Schaller
hns at goldelico.com
Sat Jan 23 17:28:40 CET 2021
From: Paul Boddie <paul at boddie.org.uk>
Add jz4730 pin groups and register definitions to the existing
driver.
Also add code to handle the jz4730 specific register offsets
and some register pairs have 2 bits for each GPIO pin.
Signed-off-by: Paul Boddie <paul at boddie.org.uk>
Signed-off-by: H. Nikolaus Schaller <hns at goldelico.com>
---
drivers/pinctrl/pinctrl-ingenic.c | 197 +++++++++++++++++++++++++++++-
1 file changed, 192 insertions(+), 5 deletions(-)
diff --git a/drivers/pinctrl/pinctrl-ingenic.c b/drivers/pinctrl/pinctrl-ingenic.c
index 53a6a24bd0527..c0d5c2ee82e11 100644
--- a/drivers/pinctrl/pinctrl-ingenic.c
+++ b/drivers/pinctrl/pinctrl-ingenic.c
@@ -4,7 +4,7 @@
*
* Copyright (c) 2017 Paul Cercueil <paul at crapouillou.net>
* Copyright (c) 2019 周琰杰 (Zhou Yanjie) <zhouyanjie at wanyeetech.com>
- * Copyright (c) 2017, 2019 Paul Boddie <paul at boddie.org.uk>
+ * Copyright (c) 2017, 2019, 2020 Paul Boddie <paul at boddie.org.uk>
*/
#include <linux/compiler.h>
@@ -29,6 +29,17 @@
#define GPIO_PIN 0x00
#define GPIO_MSK 0x20
+#define JZ4730_GPIO_DATA 0x00
+#define JZ4730_GPIO_GPDIR 0x04
+#define JZ4730_GPIO_GPPUR 0x0c
+#define JZ4730_GPIO_GPALR 0x10
+#define JZ4730_GPIO_GPAUR 0x14
+#define JZ4730_GPIO_GPIDLR 0x18
+#define JZ4730_GPIO_GPIDUR 0x1c
+#define JZ4730_GPIO_GPIER 0x20
+#define JZ4730_GPIO_GPIMR 0x24
+#define JZ4730_GPIO_GPFR 0x28
+
#define JZ4740_GPIO_DATA 0x10
#define JZ4740_GPIO_PULL_DIS 0x30
#define JZ4740_GPIO_FUNC 0x40
@@ -57,10 +68,12 @@
#define GPIO_PULL_DOWN 2
#define PINS_PER_GPIO_CHIP 32
+#define JZ4730_PINS_PER_PAIRED_REG 16
enum jz_version {
ID_JZ4740,
ID_JZ4725B,
+ ID_JZ4730,
ID_JZ4760,
ID_JZ4770,
ID_JZ4780,
@@ -322,6 +335,96 @@ static const struct ingenic_chip_info jz4725b_chip_info = {
.pull_downs = jz4740_pull_downs,
};
+static const u32 jz4730_pull_ups[4] = {
+ 0x3fa3320f, 0xf200ffff, 0xffffffff, 0xffffffff,
+};
+
+static const u32 jz4730_pull_downs[4] = {
+ 0x00000df0, 0x0dff0000, 0x00000000, 0x00000000,
+};
+
+static int jz4730_mmc_1bit_pins[] = { 0x27, 0x26, 0x22, };
+static int jz4730_mmc_4bit_pins[] = { 0x23, 0x24, 0x25, };
+static int jz4730_uart0_data_pins[] = { 0x7e, 0x7f, };
+static int jz4730_uart1_data_pins[] = { 0x18, 0x19, };
+static int jz4730_uart2_data_pins[] = { 0x6f, 0x7d, };
+static int jz4730_uart3_data_pins[] = { 0x10, 0x15, };
+static int jz4730_uart3_hwflow_pins[] = { 0x11, 0x17, };
+static int jz4730_lcd_8bit_pins[] = {
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x3a, 0x39, 0x38,
+};
+static int jz4730_lcd_16bit_pins[] = {
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x3b,
+};
+static int jz4730_lcd_16bit_tft_pins[] = { 0x3e, 0x3f, 0x3d, 0x3c, };
+static int jz4730_nand_cs1_pins[] = { 0x53, };
+static int jz4730_nand_cs2_pins[] = { 0x54, };
+static int jz4730_nand_cs3_pins[] = { 0x55, };
+static int jz4730_nand_cs4_pins[] = { 0x56, };
+static int jz4730_nand_cs5_pins[] = { 0x57, };
+static int jz4730_pwm_pwm0_pins[] = { 0x5e, };
+static int jz4730_pwm_pwm1_pins[] = { 0x5f, };
+
+static u8 jz4730_lcd_8bit_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, };
+
+static const struct group_desc jz4730_groups[] = {
+ INGENIC_PIN_GROUP("mmc-1bit", jz4730_mmc_1bit, 1),
+ INGENIC_PIN_GROUP("mmc-4bit", jz4730_mmc_4bit, 1),
+ INGENIC_PIN_GROUP("uart0-data", jz4730_uart0_data, 1),
+ INGENIC_PIN_GROUP("uart1-data", jz4730_uart1_data, 1),
+ INGENIC_PIN_GROUP("uart2-data", jz4730_uart2_data, 1),
+ INGENIC_PIN_GROUP("uart3-data", jz4730_uart3_data, 1),
+ INGENIC_PIN_GROUP("uart3-hwflow", jz4730_uart3_hwflow, 1),
+ INGENIC_PIN_GROUP_FUNCS("lcd-8bit", jz4730_lcd_8bit, jz4730_lcd_8bit_funcs),
+ INGENIC_PIN_GROUP("lcd-16bit", jz4730_lcd_16bit, 1),
+ INGENIC_PIN_GROUP("lcd-16bit-tft", jz4730_lcd_16bit_tft, 1),
+ { "lcd-no-pins", },
+ INGENIC_PIN_GROUP("nand-cs1", jz4730_nand_cs1, 1),
+ INGENIC_PIN_GROUP("nand-cs2", jz4730_nand_cs2, 1),
+ INGENIC_PIN_GROUP("nand-cs3", jz4730_nand_cs3, 1),
+ INGENIC_PIN_GROUP("nand-cs4", jz4730_nand_cs4, 1),
+ INGENIC_PIN_GROUP("nand-cs5", jz4730_nand_cs5, 1),
+ INGENIC_PIN_GROUP("pwm0", jz4730_pwm_pwm0, 1),
+ INGENIC_PIN_GROUP("pwm1", jz4730_pwm_pwm1, 1),
+};
+
+static const char *jz4730_mmc_groups[] = { "mmc-1bit", "mmc-4bit", };
+static const char *jz4730_uart0_groups[] = { "uart0-data", };
+static const char *jz4730_uart1_groups[] = { "uart1-data", };
+static const char *jz4730_uart2_groups[] = { "uart2-data", };
+static const char *jz4730_uart3_groups[] = { "uart3-data", "uart3-hwflow", };
+static const char *jz4730_lcd_groups[] = {
+ "lcd-8bit", "lcd-16bit", "lcd-16bit-tft", "lcd-no-pins",
+};
+static const char *jz4730_nand_groups[] = {
+ "nand-cs1", "nand-cs2", "nand-cs3", "nand-cs4", "nand-cs5",
+};
+static const char *jz4730_pwm0_groups[] = { "pwm0", };
+static const char *jz4730_pwm1_groups[] = { "pwm1", };
+
+static const struct function_desc jz4730_functions[] = {
+ { "mmc", jz4730_mmc_groups, ARRAY_SIZE(jz4730_mmc_groups), },
+ { "uart0", jz4730_uart0_groups, ARRAY_SIZE(jz4730_uart0_groups), },
+ { "uart1", jz4730_uart1_groups, ARRAY_SIZE(jz4730_uart1_groups), },
+ { "uart2", jz4730_uart2_groups, ARRAY_SIZE(jz4730_uart2_groups), },
+ { "uart3", jz4730_uart3_groups, ARRAY_SIZE(jz4730_uart3_groups), },
+ { "lcd", jz4730_lcd_groups, ARRAY_SIZE(jz4730_lcd_groups), },
+ { "nand", jz4730_nand_groups, ARRAY_SIZE(jz4730_nand_groups), },
+ { "pwm0", jz4730_pwm0_groups, ARRAY_SIZE(jz4730_pwm0_groups), },
+ { "pwm1", jz4730_pwm1_groups, ARRAY_SIZE(jz4730_pwm1_groups), },
+};
+
+static const struct ingenic_chip_info jz4730_chip_info = {
+ .num_chips = 4,
+ .reg_offset = 0x30,
+ .version = ID_JZ4730,
+ .groups = jz4730_groups,
+ .num_groups = ARRAY_SIZE(jz4730_groups),
+ .functions = jz4730_functions,
+ .num_functions = ARRAY_SIZE(jz4730_functions),
+ .pull_ups = jz4730_pull_ups,
+ .pull_downs = jz4730_pull_downs,
+};
static const u32 jz4760_pull_ups[6] = {
0xffffffff, 0xfffcf3ff, 0xffffffff, 0xffffcfff, 0xfffffb7c, 0xfffff00f,
};
@@ -1650,6 +1753,12 @@ static u32 ingenic_gpio_read_reg(struct ingenic_gpio_chip *jzgc, u8 reg)
static void ingenic_gpio_set_bit(struct ingenic_gpio_chip *jzgc,
u8 reg, u8 offset, bool set)
{
+ if (jzgc->jzpc->info->version == ID_JZ4730) {
+ regmap_update_bits(jzgc->jzpc->map, jzgc->reg_base + reg,
+ BIT(offset), set ? BIT(offset) : 0);
+ return;
+ }
+
if (set)
reg = REG_SET(reg);
else
@@ -1658,6 +1767,20 @@ static void ingenic_gpio_set_bit(struct ingenic_gpio_chip *jzgc,
regmap_write(jzgc->jzpc->map, jzgc->reg_base + reg, BIT(offset));
}
+static void ingenic_gpio_set_bits(struct ingenic_gpio_chip *jzgc,
+ u8 reg_upper, u8 reg_lower, u8 offset, u8 value)
+{
+ /* JZ4730 function and IRQ registers support two-bits-per-pin
+ * definitions, split into two groups of 16.
+ */
+
+ u8 reg = offset < JZ4730_PINS_PER_PAIRED_REG ? reg_lower : reg_upper;
+ unsigned int idx = offset % JZ4730_PINS_PER_PAIRED_REG;
+
+ regmap_update_bits(jzgc->jzpc->map, jzgc->reg_base + reg,
+ 3 << (idx * 2), value << (idx * 2));
+}
+
static void ingenic_gpio_shadow_set_bit(struct ingenic_gpio_chip *jzgc,
u8 reg, u8 offset, bool set)
{
@@ -1690,6 +1813,8 @@ static void ingenic_gpio_set_value(struct ingenic_gpio_chip *jzgc,
{
if (jzgc->jzpc->info->version >= ID_JZ4760)
ingenic_gpio_set_bit(jzgc, JZ4760_GPIO_PAT0, offset, !!value);
+ else if (jzgc->jzpc->info->version == ID_JZ4730)
+ ingenic_gpio_set_bit(jzgc, JZ4730_GPIO_DATA, offset, !!value);
else
ingenic_gpio_set_bit(jzgc, JZ4740_GPIO_DATA, offset, !!value);
}
@@ -1721,6 +1846,12 @@ static void irq_set_type(struct ingenic_gpio_chip *jzgc,
if (jzgc->jzpc->info->version >= ID_JZ4760) {
reg1 = JZ4760_GPIO_PAT1;
reg2 = JZ4760_GPIO_PAT0;
+ } else if (jzgc->jzpc->info->version == ID_JZ4730) {
+ ingenic_gpio_set_bit(jzgc, JZ4730_GPIO_GPDIR, offset, false);
+ ingenic_gpio_set_bits(jzgc, JZ4730_GPIO_GPIDUR,
+ JZ4730_GPIO_GPIDLR, offset,
+ (val2 ? 2 : 0) | (val1 ? 1 : 0));
+ return;
} else {
reg1 = JZ4740_GPIO_TRIG;
reg2 = JZ4740_GPIO_DIR;
@@ -1740,16 +1871,24 @@ static void ingenic_gpio_irq_mask(struct irq_data *irqd)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+ int irq = irqd->hwirq;
- ingenic_gpio_set_bit(jzgc, GPIO_MSK, irqd->hwirq, true);
+ if (jzgc->jzpc->info->version == ID_JZ4730)
+ ingenic_gpio_set_bit(jzgc, JZ4730_GPIO_GPIMR, irq, true);
+ else
+ ingenic_gpio_set_bit(jzgc, GPIO_MSK, irq, true);
}
static void ingenic_gpio_irq_unmask(struct irq_data *irqd)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+ int irq = irqd->hwirq;
- ingenic_gpio_set_bit(jzgc, GPIO_MSK, irqd->hwirq, false);
+ if (jzgc->jzpc->info->version == ID_JZ4730)
+ ingenic_gpio_set_bit(jzgc, JZ4730_GPIO_GPIMR, irq, false);
+ else
+ ingenic_gpio_set_bit(jzgc, GPIO_MSK, irq, false);
}
static void ingenic_gpio_irq_enable(struct irq_data *irqd)
@@ -1760,6 +1899,8 @@ static void ingenic_gpio_irq_enable(struct irq_data *irqd)
if (jzgc->jzpc->info->version >= ID_JZ4760)
ingenic_gpio_set_bit(jzgc, JZ4760_GPIO_INT, irq, true);
+ else if (jzgc->jzpc->info->version == ID_JZ4730)
+ ingenic_gpio_set_bit(jzgc, JZ4730_GPIO_GPIER, irq, true);
else
ingenic_gpio_set_bit(jzgc, JZ4740_GPIO_SELECT, irq, true);
@@ -1776,6 +1917,8 @@ static void ingenic_gpio_irq_disable(struct irq_data *irqd)
if (jzgc->jzpc->info->version >= ID_JZ4760)
ingenic_gpio_set_bit(jzgc, JZ4760_GPIO_INT, irq, false);
+ else if (jzgc->jzpc->info->version == ID_JZ4730)
+ ingenic_gpio_set_bit(jzgc, JZ4730_GPIO_GPIER, irq, false);
else
ingenic_gpio_set_bit(jzgc, JZ4740_GPIO_SELECT, irq, false);
}
@@ -1801,6 +1944,8 @@ static void ingenic_gpio_irq_ack(struct irq_data *irqd)
if (jzgc->jzpc->info->version >= ID_JZ4760)
ingenic_gpio_set_bit(jzgc, JZ4760_GPIO_FLAG, irq, false);
+ else if (jzgc->jzpc->info->version == ID_JZ4730)
+ ingenic_gpio_set_bit(jzgc, JZ4730_GPIO_GPFR, irq, false);
else
ingenic_gpio_set_bit(jzgc, JZ4740_GPIO_DATA, irq, true);
}
@@ -1858,6 +2003,8 @@ static void ingenic_gpio_irq_handler(struct irq_desc *desc)
if (jzgc->jzpc->info->version >= ID_JZ4760)
flag = ingenic_gpio_read_reg(jzgc, JZ4760_GPIO_FLAG);
+ else if (jzgc->jzpc->info->version == ID_JZ4730)
+ flag = ingenic_gpio_read_reg(jzgc, JZ4730_GPIO_GPFR);
else
flag = ingenic_gpio_read_reg(jzgc, JZ4740_GPIO_FLAG);
@@ -1900,8 +2047,27 @@ static inline void ingenic_config_pin(struct ingenic_pinctrl *jzpc,
unsigned int idx = pin % PINS_PER_GPIO_CHIP;
unsigned int offt = pin / PINS_PER_GPIO_CHIP;
- regmap_write(jzpc->map, offt * jzpc->info->reg_offset +
- (set ? REG_SET(reg) : REG_CLEAR(reg)), BIT(idx));
+ if (jzpc->info->version == ID_JZ4730)
+ regmap_update_bits(jzpc->map, offt * jzpc->info->reg_offset + reg,
+ BIT(idx), set ? BIT(idx) : 0);
+ else
+ regmap_write(jzpc->map, offt * jzpc->info->reg_offset +
+ (set ? REG_SET(reg) : REG_CLEAR(reg)), BIT(idx));
+}
+
+static inline void ingenic_config_pin_function(struct ingenic_pinctrl *jzpc,
+ unsigned int pin, u8 reg_upper, u8 reg_lower, u8 value)
+{
+ /* JZ4730 function and IRQ registers support two-bits-per-pin
+ * definitions, split into two groups of 16.
+ */
+
+ unsigned int idx = pin % JZ4730_PINS_PER_PAIRED_REG;
+ unsigned int offt = pin / PINS_PER_GPIO_CHIP;
+ u8 reg = (pin % PINS_PER_GPIO_CHIP) < JZ4730_PINS_PER_PAIRED_REG ? reg_lower : reg_upper;
+
+ regmap_update_bits(jzpc->map, offt * jzpc->info->reg_offset + reg,
+ 3 << (idx * 2), value << (idx * 2));
}
static inline void ingenic_shadow_config_pin(struct ingenic_pinctrl *jzpc,
@@ -1943,6 +2109,10 @@ static int ingenic_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
ingenic_get_pin_config(jzpc, pin, JZ4760_GPIO_PAT1))
return GPIO_LINE_DIRECTION_IN;
return GPIO_LINE_DIRECTION_OUT;
+ } else if (jzpc->info->version == ID_JZ4730) {
+ if (!ingenic_get_pin_config(jzpc, pin, JZ4730_GPIO_GPDIR))
+ return GPIO_LINE_DIRECTION_IN;
+ return GPIO_LINE_DIRECTION_OUT;
}
if (ingenic_get_pin_config(jzpc, pin, JZ4740_GPIO_SELECT))
@@ -2001,6 +2171,10 @@ static int ingenic_pinmux_set_pin_fn(struct ingenic_pinctrl *jzpc,
ingenic_config_pin(jzpc, pin, GPIO_MSK, false);
ingenic_config_pin(jzpc, pin, JZ4760_GPIO_PAT1, func & 0x2);
ingenic_config_pin(jzpc, pin, JZ4760_GPIO_PAT0, func & 0x1);
+ } else if (jzpc->info->version == ID_JZ4730) {
+ ingenic_config_pin(jzpc, pin, JZ4730_GPIO_GPIER, false);
+ ingenic_config_pin_function(jzpc, pin, JZ4730_GPIO_GPAUR,
+ JZ4730_GPIO_GPALR, func & 0x3);
} else {
ingenic_config_pin(jzpc, pin, JZ4740_GPIO_FUNC, true);
ingenic_config_pin(jzpc, pin, JZ4740_GPIO_TRIG, func & 0x2);
@@ -2065,6 +2239,11 @@ static int ingenic_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
ingenic_config_pin(jzpc, pin, JZ4760_GPIO_INT, false);
ingenic_config_pin(jzpc, pin, GPIO_MSK, true);
ingenic_config_pin(jzpc, pin, JZ4760_GPIO_PAT1, input);
+ } else if (jzpc->info->version == ID_JZ4730) {
+ ingenic_config_pin(jzpc, pin, JZ4730_GPIO_GPIER, false);
+ ingenic_config_pin(jzpc, pin, JZ4730_GPIO_GPDIR, !input);
+ ingenic_config_pin_function(jzpc, pin, JZ4730_GPIO_GPAUR,
+ JZ4730_GPIO_GPALR, 0);
} else {
ingenic_config_pin(jzpc, pin, JZ4740_GPIO_SELECT, false);
ingenic_config_pin(jzpc, pin, JZ4740_GPIO_DIR, !input);
@@ -2093,6 +2272,8 @@ static int ingenic_pinconf_get(struct pinctrl_dev *pctldev,
if (jzpc->info->version >= ID_JZ4760)
pull = !ingenic_get_pin_config(jzpc, pin, JZ4760_GPIO_PEN);
+ else if (jzpc->info->version == ID_JZ4730)
+ pull = ingenic_get_pin_config(jzpc, pin, JZ4730_GPIO_GPPUR);
else
pull = !ingenic_get_pin_config(jzpc, pin, JZ4740_GPIO_PULL_DIS);
@@ -2143,6 +2324,8 @@ static void ingenic_set_bias(struct ingenic_pinctrl *jzpc,
} else if (jzpc->info->version >= ID_JZ4760) {
ingenic_config_pin(jzpc, pin, JZ4760_GPIO_PEN, !bias);
+ } else if (jzpc->info->version == ID_JZ4730) {
+ ingenic_config_pin(jzpc, pin, JZ4730_GPIO_GPPUR, bias);
} else {
ingenic_config_pin(jzpc, pin, JZ4740_GPIO_PULL_DIS, !bias);
}
@@ -2153,6 +2336,8 @@ static void ingenic_set_output_level(struct ingenic_pinctrl *jzpc,
{
if (jzpc->info->version >= ID_JZ4760)
ingenic_config_pin(jzpc, pin, JZ4760_GPIO_PAT0, high);
+ else if (jzpc->info->version == ID_JZ4730)
+ ingenic_config_pin(jzpc, pin, JZ4730_GPIO_DATA, high);
else
ingenic_config_pin(jzpc, pin, JZ4740_GPIO_DATA, high);
}
@@ -2283,6 +2468,7 @@ static const struct regmap_config ingenic_pinctrl_regmap_config = {
};
static const struct of_device_id ingenic_gpio_of_match[] __initconst = {
+ { .compatible = "ingenic,jz4730-gpio", },
{ .compatible = "ingenic,jz4740-gpio", },
{ .compatible = "ingenic,jz4725b-gpio", },
{ .compatible = "ingenic,jz4760-gpio", },
@@ -2472,6 +2658,7 @@ static int __init ingenic_pinctrl_probe(struct platform_device *pdev)
static const struct of_device_id ingenic_pinctrl_of_match[] = {
{ .compatible = "ingenic,jz4740-pinctrl", .data = &jz4740_chip_info },
{ .compatible = "ingenic,jz4725b-pinctrl", .data = &jz4725b_chip_info },
+ { .compatible = "ingenic,jz4730-pinctrl", .data = &jz4730_chip_info },
{ .compatible = "ingenic,jz4760-pinctrl", .data = &jz4760_chip_info },
{ .compatible = "ingenic,jz4760b-pinctrl", .data = &jz4760_chip_info },
{ .compatible = "ingenic,jz4770-pinctrl", .data = &jz4770_chip_info },
--
2.26.2
More information about the Letux-kernel
mailing list