From 2ed4ba83fb8a1e32a91f4d289069a33d390f532b Mon Sep 17 00:00:00 2001 From: Sam Protsenko Date: Thu, 30 Nov 2023 14:13:49 -0600 Subject: [PATCH] pinctrl: exynos: Support different register types in pin banks Get rid of hard-coded register offsets and widths. Instead provide a way for pinctrl drivers to specify different pin bank register offsets and widths. This in turn makes it possible to add support for new SoCs that have registers with offset/width values different than generic ones already available in pinctrl-exynos driver. Offset constants (now unused in pinctrl-exynos.c) are moved to pinctrl-exynos7420 driver, which is the single user of those constants. The design of this patch follows Linux kernel pinctrl-exynos driver design, in terms of added data structures and types. This patch doesn't add support for any new SoCs and shouldn't introduce any functional changes. Signed-off-by: Sam Protsenko Signed-off-by: Minkyu Kang --- drivers/pinctrl/exynos/pinctrl-exynos.c | 42 ++++++++++++++------- drivers/pinctrl/exynos/pinctrl-exynos.h | 34 +++++++++++++++-- drivers/pinctrl/exynos/pinctrl-exynos7420.c | 2 + 3 files changed, 61 insertions(+), 17 deletions(-) diff --git a/drivers/pinctrl/exynos/pinctrl-exynos.c b/drivers/pinctrl/exynos/pinctrl-exynos.c index d908927135..9a51653be8 100644 --- a/drivers/pinctrl/exynos/pinctrl-exynos.c +++ b/drivers/pinctrl/exynos/pinctrl-exynos.c @@ -15,6 +15,12 @@ DECLARE_GLOBAL_DATA_PTR; +/* CON, DAT, PUD, DRV */ +const struct samsung_pin_bank_type bank_type_alive = { + .fld_width = { 4, 1, 2, 2, }, + .reg_offset = { 0x00, 0x04, 0x08, 0x0c, }, +}; + /** * exynos_pinctrl_setup_peri: setup pinctrl for a peripheral. * conf: soc specific pin configuration data array @@ -81,6 +87,22 @@ static const struct samsung_pin_bank_data *get_bank(struct udevice *dev, return NULL; } +static void exynos_pinctrl_set_pincfg(unsigned long reg_base, u32 pin_num, + u32 val, enum pincfg_type pincfg, + const struct samsung_pin_bank_type *type) +{ + u32 width = type->fld_width[pincfg]; + u32 reg_offset = type->reg_offset[pincfg]; + u32 mask = (1 << width) - 1; + u32 shift = pin_num * width; + u32 data; + + data = readl(reg_base + reg_offset); + data &= ~(mask << shift); + data |= val << shift; + writel(data, reg_base + reg_offset); +} + /** * exynos_pinctrl_set_state: configure a pin state. * dev: the pinctrl device to be configured. @@ -93,7 +115,7 @@ int exynos_pinctrl_set_state(struct udevice *dev, struct udevice *config) int node = dev_of_offset(config); unsigned int count, idx, pin_num; unsigned int pinfunc, pinpud, pindrv; - unsigned long reg, value; + unsigned long reg; const char *name; /* @@ -120,24 +142,18 @@ int exynos_pinctrl_set_state(struct udevice *dev, struct udevice *config) reg = priv->base + bank->offset; if (pinfunc != -1) { - value = readl(reg + PIN_CON); - value &= ~(0xf << (pin_num << 2)); - value |= (pinfunc << (pin_num << 2)); - writel(value, reg + PIN_CON); + exynos_pinctrl_set_pincfg(reg, pin_num, pinfunc, + PINCFG_TYPE_FUNC, bank->type); } if (pinpud != -1) { - value = readl(reg + PIN_PUD); - value &= ~(0x3 << (pin_num << 1)); - value |= (pinpud << (pin_num << 1)); - writel(value, reg + PIN_PUD); + exynos_pinctrl_set_pincfg(reg, pin_num, pinpud, + PINCFG_TYPE_PUD, bank->type); } if (pindrv != -1) { - value = readl(reg + PIN_DRV); - value &= ~(0x3 << (pin_num << 1)); - value |= (pindrv << (pin_num << 1)); - writel(value, reg + PIN_DRV); + exynos_pinctrl_set_pincfg(reg, pin_num, pindrv, + PINCFG_TYPE_DRV, bank->type); } } diff --git a/drivers/pinctrl/exynos/pinctrl-exynos.h b/drivers/pinctrl/exynos/pinctrl-exynos.h index 6b19f196bc..743bb55730 100644 --- a/drivers/pinctrl/exynos/pinctrl-exynos.h +++ b/drivers/pinctrl/exynos/pinctrl-exynos.h @@ -8,25 +8,51 @@ #ifndef __PINCTRL_EXYNOS_H_ #define __PINCTRL_EXYNOS_H_ -#define PIN_CON 0x00 /* Offset of pin function register */ -#define PIN_DAT 0x04 /* Offset of pin data register */ -#define PIN_PUD 0x08 /* Offset of pin pull up/down config register */ -#define PIN_DRV 0x0C /* Offset of pin drive strength register */ +/** + * enum pincfg_type - possible pin configuration types supported. + * @PINCFG_TYPE_FUNC: Function configuration. + * @PINCFG_TYPE_DAT: Pin value configuration. + * @PINCFG_TYPE_PUD: Pull up/down configuration. + * @PINCFG_TYPE_DRV: Drive strength configuration. + */ +enum pincfg_type { + PINCFG_TYPE_FUNC, + PINCFG_TYPE_DAT, + PINCFG_TYPE_PUD, + PINCFG_TYPE_DRV, + + PINCFG_TYPE_NUM +}; + +/** + * struct samsung_pin_bank_type: pin bank type description + * @fld_width: widths of configuration bitfields (0 if unavailable) + * @reg_offset: offsets of configuration registers (don't care of width is 0) + */ +struct samsung_pin_bank_type { + u8 fld_width[PINCFG_TYPE_NUM]; + u8 reg_offset[PINCFG_TYPE_NUM]; +}; /** * struct samsung_pin_bank_data: represent a controller pin-bank data. + * @type: type of the bank (register offsets and bitfield widths) * @offset: starting offset of the pin-bank registers. * @nr_pins: number of pins included in this bank. * @name: name to be prefixed for each pin in this pin bank. */ struct samsung_pin_bank_data { + const struct samsung_pin_bank_type *type; u32 offset; u8 nr_pins; const char *name; }; +extern const struct samsung_pin_bank_type bank_type_alive; + #define EXYNOS_PIN_BANK(pins, reg, id) \ { \ + .type = &bank_type_alive, \ .offset = reg, \ .nr_pins = pins, \ .name = id \ diff --git a/drivers/pinctrl/exynos/pinctrl-exynos7420.c b/drivers/pinctrl/exynos/pinctrl-exynos7420.c index 07870b7f51..77d510d8f6 100644 --- a/drivers/pinctrl/exynos/pinctrl-exynos7420.c +++ b/drivers/pinctrl/exynos/pinctrl-exynos7420.c @@ -16,6 +16,8 @@ #include "pinctrl-exynos.h" #define GPD1_OFFSET 0xc0 +#define PIN_CON 0x00 /* Offset of pin function register */ +#define PIN_PUD 0x08 /* Offset of pin pull up/down config register */ static struct exynos_pinctrl_config_data serial2_conf[] = { { -- 2.39.5