[COMMON] pinctrl: samsung: support debug show
authoreunki_kim <eunki_kim@samsung.com>
Fri, 26 Jun 2015 08:46:27 +0000 (17:46 +0900)
committerJaehyoung Choi <jkkkkk.choi@samsung.com>
Thu, 3 May 2018 11:11:53 +0000 (20:11 +0900)
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 <eunki_kim@samsung.com>
drivers/pinctrl/samsung/pinctrl-samsung.c

index 3e44b261197102d12a45f20f06bc37c518bd4dcc..60a4422261639ac4350886833a68aed3a61d135e 100644 (file)
@@ -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, &reg_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, &reg_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,
 };
 
 /*