From ae06aea27c5cf43f7153cec241e49797559c9107 Mon Sep 17 00:00:00 2001 From: eunki_kim Date: Fri, 26 Jun 2015 17:46:27 +0900 Subject: [PATCH] [COMMON] pinctrl: samsung: support debug show Each pin is possible to show its register value through DEBUG_FS. This patch supports it like below: cat /sys/kernel/debug/pinctrl/10580000.pinctrl/pinconf-pins cat /sys/kernel/debug/pinctrl/10580000.pinctrl/pinconf-groups cat /sys/kernel/debug/pinctrl/10580000.pinctrl/pins Change-Id: I99a05520946d7299ff692a1043b5b5390f33dd0f Signed-off-by: eunki_kim --- drivers/pinctrl/samsung/pinctrl-samsung.c | 105 ++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c index 3e44b2611971..60a442226163 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.c +++ b/drivers/pinctrl/samsung/pinctrl-samsung.c @@ -284,6 +284,65 @@ static int samsung_dt_node_to_map(struct pinctrl_dev *pctldev, return 0; } +/* GPIO register names */ +static char *gpio_regs[] = {"CON", "DAT", "PUD", "DRV", "CON_PDN", "PUD_PDN"}; + +static void pin_to_reg_bank(struct samsung_pinctrl_drv_data *drvdata, + unsigned pin, void __iomem **reg, u32 *offset, + struct samsung_pin_bank **bank); + +/* common debug show function */ +static void samsung_pin_dbg_show_by_type(struct samsung_pin_bank *bank, + void __iomem *reg_base, u32 pin_offset, + struct seq_file *s, unsigned pin, + enum pincfg_type cfg_type) +{ + const struct samsung_pin_bank_type *type; + u32 data, width, mask, shift, cfg_reg; + + type = bank->type; + + if (!type->fld_width[cfg_type]) + return; + + width = type->fld_width[cfg_type]; + cfg_reg = type->reg_offset[cfg_type]; + mask = (1 << width) - 1; + shift = pin_offset * width; + + data = readl(reg_base + cfg_reg); + + data >>= shift; + data &= mask; + + seq_printf(s, " %s(0x%x)", gpio_regs[cfg_type], data); +} + +/* show GPIO register status */ +static void samsung_pin_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned pin) +{ + struct samsung_pinctrl_drv_data *drvdata; + struct samsung_pin_bank *bank; + void __iomem *reg_base; + u32 pin_offset; + unsigned long flags; + enum pincfg_type cfg_type; + + drvdata = pinctrl_dev_get_drvdata(pctldev); + pin_to_reg_bank(drvdata, pin - drvdata->pin_base, ®_base, + &pin_offset, &bank); + + spin_lock_irqsave(&bank->slock, flags); + + for (cfg_type = 0; cfg_type < PINCFG_TYPE_NUM; cfg_type++) { + samsung_pin_dbg_show_by_type(bank, reg_base, + pin_offset, s, pin, cfg_type); + } + + spin_unlock_irqrestore(&bank->slock, flags); +} + /* list of pinctrl callbacks for the pinctrl core */ static const struct pinctrl_ops samsung_pctrl_ops = { .get_groups_count = samsung_get_group_count, @@ -291,6 +350,7 @@ static const struct pinctrl_ops samsung_pctrl_ops = { .get_group_pins = samsung_get_group_pins, .dt_node_to_map = samsung_dt_node_to_map, .dt_free_map = samsung_dt_free_map, + .pin_dbg_show = samsung_pin_dbg_show, }; /* check if the selector is a valid pin function selector */ @@ -501,12 +561,57 @@ static int samsung_pinconf_group_get(struct pinctrl_dev *pctldev, return 0; } +/* show whole PUD, DRV, CON_PDN and PUD_PDN register status */ +static void samsung_pinconf_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned pin) +{ + struct samsung_pinctrl_drv_data *drvdata; + struct samsung_pin_bank *bank; + void __iomem *reg_base; + u32 pin_offset; + unsigned long flags; + enum pincfg_type cfg_type; + + drvdata = pinctrl_dev_get_drvdata(pctldev); + pin_to_reg_bank(drvdata, pin - drvdata->pin_base, ®_base, + &pin_offset, &bank); + + spin_lock_irqsave(&bank->slock, flags); + + for (cfg_type = PINCFG_TYPE_PUD; cfg_type <= PINCFG_TYPE_PUD_PDN + ; cfg_type++) { + samsung_pin_dbg_show_by_type(bank, reg_base, + pin_offset, s, pin, cfg_type); + } + + spin_unlock_irqrestore(&bank->slock, flags); +} + +/* show group's PUD, DRV, CON_PDN and PUD_PDN register status */ +static void samsung_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned group) +{ + struct samsung_pinctrl_drv_data *drvdata; + const unsigned int *pins; + int i; + + drvdata = pinctrl_dev_get_drvdata(pctldev); + pins = drvdata->pin_groups[group].pins; + + for (i = 0; i < drvdata->pin_groups[group].num_pins; i++) { + seq_printf(s, "\n\t%s:", pin_get_name(pctldev, pins[i])); + samsung_pinconf_dbg_show(pctldev, s, pins[i]); + } +} + /* list of pinconfig callbacks for pinconfig vertical in the pinctrl code */ static const struct pinconf_ops samsung_pinconf_ops = { .pin_config_get = samsung_pinconf_get, .pin_config_set = samsung_pinconf_set, .pin_config_group_get = samsung_pinconf_group_get, .pin_config_group_set = samsung_pinconf_group_set, + .pin_config_dbg_show = samsung_pinconf_dbg_show, + .pin_config_group_dbg_show = samsung_pinconf_group_dbg_show, }; /* -- 2.20.1