[RFC PATCH 13/16] pinctrl: samsung: Parse offsets of particular registers from DT
Tomasz Figa
t.figa at samsung.com
Fri Sep 28 10:28:44 EDT 2012
The order and availability of pin control registers vary with SoC.
This patch modifies the driver to parse register offsets from device
tree as a part of bank type definition.
Signed-off-by: Tomasz Figa <t.figa at samsung.com>
---
drivers/pinctrl/pinctrl-exynos.c | 12 ++---
drivers/pinctrl/pinctrl-samsung.c | 93 +++++++++++++++++++++------------------
drivers/pinctrl/pinctrl-samsung.h | 38 +++++++++-------
3 files changed, 78 insertions(+), 65 deletions(-)
diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c
index 001d2ec..7ad2884 100644
--- a/drivers/pinctrl/pinctrl-exynos.c
+++ b/drivers/pinctrl/pinctrl-exynos.c
@@ -113,9 +113,9 @@ static int exynos_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
con |= trig_type << shift;
writel(con, d->virt_base + reg_con);
- reg_con = bank->pctl_offset;
- shift = pin * bank->func_width;
- mask = (1 << bank->func_width) - 1;
+ reg_con = bank->pctl_offset + bank->regs[REG_FUNC].offset;
+ shift = pin * bank->regs[REG_FUNC].width;
+ mask = (1 << bank->regs[REG_FUNC].width) - 1;
con = readl(d->virt_base + reg_con);
con &= ~(mask << shift);
@@ -290,9 +290,9 @@ static int exynos_wkup_irq_set_type(struct irq_data *irqd, unsigned int type)
con |= trig_type << shift;
writel(con, d->virt_base + reg_con);
- reg_con = bank->pctl_offset;
- shift = pin * bank->func_width;
- mask = (1 << bank->func_width) - 1;
+ reg_con = bank->pctl_offset + bank->regs[REG_FUNC].offset;
+ shift = pin * bank->regs[REG_FUNC].width;
+ mask = (1 << bank->regs[REG_FUNC].width) - 1;
con = readl(d->virt_base + reg_con);
con &= ~(mask << shift);
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c
index 9b38609..b02cd46 100644
--- a/drivers/pinctrl/pinctrl-samsung.c
+++ b/drivers/pinctrl/pinctrl-samsung.c
@@ -273,10 +273,6 @@ static void pin_to_reg_bank(struct samsung_pinctrl_drv_data *drvdata,
*offset = pin - b->pin_base;
if (bank)
*bank = b;
-
- /* some banks have two config registers in a single bank */
- if (*offset * b->func_width > BITS_PER_LONG)
- *reg += 4;
}
/* enable or disable a pinmux function */
@@ -299,8 +295,9 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector,
for (cnt = 0; cnt < drvdata->pin_groups[group].num_pins; cnt++) {
pin_to_reg_bank(drvdata, pins[cnt] - drvdata->ctrl->base,
®, &pin_offset, &bank);
- mask = (1 << bank->func_width) - 1;
- shift = pin_offset * bank->func_width;
+ mask = (1 << bank->regs[REG_FUNC].width) - 1;
+ shift = pin_offset * bank->regs[REG_FUNC].width;
+ reg += bank->regs[REG_FUNC].offset;
data = readl(reg);
data &= ~(mask << shift);
@@ -342,10 +339,11 @@ static int samsung_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
drvdata = pinctrl_dev_get_drvdata(pctldev);
pin_offset = offset - bank->pin_base;
- reg = drvdata->virt_base + bank->pctl_offset;
+ reg = drvdata->virt_base + bank->pctl_offset
+ + bank->regs[REG_FUNC].offset;
- mask = (1 << bank->func_width) - 1;
- shift = pin_offset * bank->func_width;
+ mask = (1 << bank->regs[REG_FUNC].width) - 1;
+ shift = pin_offset * bank->regs[REG_FUNC].width;
data = readl(reg);
data &= ~(mask << shift);
@@ -382,20 +380,20 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin,
switch (cfg_type) {
case PINCFG_TYPE_PUD:
- width = bank->pud_width;
- cfg_reg = PUD_REG;
+ width = bank->regs[REG_PUD].width;
+ cfg_reg = bank->regs[REG_PUD].offset;
break;
case PINCFG_TYPE_DRV:
- width = bank->drv_width;
- cfg_reg = DRV_REG;
+ width = bank->regs[REG_DRV].width;
+ cfg_reg = bank->regs[REG_DRV].offset;
break;
case PINCFG_TYPE_CON_PDN:
- width = bank->conpdn_width;
- cfg_reg = CONPDN_REG;
+ width = bank->regs[REG_CONPDN].width;
+ cfg_reg = bank->regs[REG_CONPDN].offset;
break;
case PINCFG_TYPE_PUD_PDN:
- width = bank->pudpdn_width;
- cfg_reg = PUDPDN_REG;
+ width = bank->regs[REG_PUDPDN].width;
+ cfg_reg = bank->regs[REG_PUDPDN].offset;
break;
default:
WARN_ON(1);
@@ -481,13 +479,14 @@ static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
void __iomem *reg;
u32 data;
- reg = bank->drvdata->virt_base + bank->pctl_offset;
+ reg = bank->drvdata->virt_base + bank->pctl_offset
+ + bank->regs[REG_DAT].offset;
- data = readl(reg + DAT_REG);
+ data = readl(reg);
data &= ~(1 << offset);
if (value)
data |= 1 << offset;
- writel(data, reg + DAT_REG);
+ writel(data, reg);
}
/* gpiolib gpio_get callback function */
@@ -497,9 +496,10 @@ static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset)
u32 data;
struct samsung_pin_bank *bank = gc_to_pin_bank(gc);
- reg = bank->drvdata->virt_base + bank->pctl_offset;
+ reg = bank->drvdata->virt_base + bank->pctl_offset
+ + bank->regs[REG_DAT].offset;
- data = readl(reg + DAT_REG);
+ data = readl(reg);
data >>= offset;
data &= 1;
return data;
@@ -817,12 +817,24 @@ static int __init samsung_gpiolib_unregister(struct platform_device *pdev,
static const struct of_device_id samsung_pinctrl_dt_match[];
+
+
static int samsung_pinctrl_parse_dt_bank_type(struct samsung_pin_bank *bank,
struct device_node *np)
{
+ static const char *reg_names[REG_NUM] = {
+ [REG_FUNC] = "func",
+ [REG_DAT] = "dat",
+ [REG_PUD] = "pud",
+ [REG_DRV] = "drv",
+ [REG_CONPDN] = "conpdn",
+ [REG_PUDPDN] = "pudpdn",
+ };
struct samsung_pin_bank *type = np->data;
- int ret;
- u32 val;
+ const __be32 *data;
+ int len = 0;
+ int index;
+ int i;
if (type) {
*bank = *type;
@@ -833,26 +845,21 @@ static int samsung_pinctrl_parse_dt_bank_type(struct samsung_pin_bank *bank,
if (!type)
return -ENOMEM;
- ret = of_property_read_u32(np, "samsung,func-width", &val);
- if (ret)
- return ret;
- type->func_width = val;
-
- ret = of_property_read_u32(np, "samsung,pud-width", &val);
- if (!ret)
- type->pud_width = val;
-
- ret = of_property_read_u32(np, "samsung,drv-width", &val);
- if (!ret)
- type->drv_width = val;
-
- ret = of_property_read_u32(np, "samsung,conpdn-width", &val);
- if (!ret)
- type->conpdn_width = val;
+ data = of_get_property(np, "samsung,reg-params", &len);
+ if (!data)
+ return -EINVAL;
+ len /= sizeof(*data);
- ret = of_property_read_u32(np, "samsung,pudpdn-width", &val);
- if (!ret)
- type->pudpdn_width = val;
+ for (i = 0; i < ARRAY_SIZE(reg_names); ++i) {
+ index = of_property_match_string(np, "samsung,reg-names",
+ reg_names[i]);
+ if (index < 0)
+ continue;
+ if (index >= len / 2)
+ return -EINVAL;
+ type->regs[i].offset = be32_to_cpu(data[2 * index]);
+ type->regs[i].width = be32_to_cpu(data[2 * index + 1]);
+ }
*bank = *type;
np->data = type;
diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h
index 355f4e2..684f042 100644
--- a/drivers/pinctrl/pinctrl-samsung.h
+++ b/drivers/pinctrl/pinctrl-samsung.h
@@ -25,12 +25,16 @@
#include <linux/gpio.h>
-/* register offsets within a pin bank */
-#define DAT_REG 0x4
-#define PUD_REG 0x8
-#define DRV_REG 0xC
-#define CONPDN_REG 0x10
-#define PUDPDN_REG 0x14
+enum pincfg_reg {
+ REG_FUNC = 0,
+ REG_DAT,
+ REG_PUD,
+ REG_DRV,
+ REG_CONPDN,
+ REG_PUDPDN,
+
+ REG_NUM
+};
/* pinmux function number for pin as gpio output line */
#define FUNC_OUTPUT 0x1
@@ -103,15 +107,21 @@ enum eint_type {
struct samsung_pinctrl_drv_data;
/**
+ * struct samsung_pin_reg: defines a configuration register.
+ * @offset: offset from bank base.
+ * @width: with of a bit field used for single pin.
+ */
+struct samsung_pin_reg {
+ u8 offset;
+ u8 width;
+};
+
+/**
* struct samsung_pin_bank: represent a controller pin-bank.
* @reg_offset: starting offset of the pin-bank registers.
* @pin_base: starting pin number of the bank.
* @nr_pins: number of pins included in this bank.
- * @func_width: width of the function selector bit field.
- * @pud_width: width of the pin pull up/down selector bit field.
- * @drv_width: width of the pin driver strength selector bit field.
- * @conpdn_width: width of the sleep mode function selector bin field.
- * @pudpdn_width: width of the sleep mode pull up/down selector bit field.
+ * @regs: low level parameters of available configuration registers.
* @eint_type: type of the external interrupt supported by the bank.
* @name: name to be prefixed for each pin in this pin bank.
* @of_node: node of pin bank in device tree
@@ -124,11 +134,7 @@ struct samsung_pin_bank {
u32 pctl_offset;
u32 pin_base;
u8 nr_pins;
- u8 func_width;
- u8 pud_width;
- u8 drv_width;
- u8 conpdn_width;
- u8 pudpdn_width;
+ struct samsung_pin_reg regs[REG_NUM];
enum eint_type eint_type;
u32 eint_offset;
const char *name;
--
1.7.12
More information about the linux-arm-kernel
mailing list