1 // SPDX-License-Identifier: GPL-2.0-only
3 * Pinconf driver for TI DA850/OMAP-L138/AM18XX pullup/pulldown groups
5 * Copyright (C) 2016 David Lechner
8 #include <linux/bitops.h>
9 #include <linux/device.h>
11 #include <linux/ioport.h>
12 #include <linux/mod_devicetable.h>
13 #include <linux/module.h>
14 #include <linux/pinctrl/pinconf.h>
15 #include <linux/pinctrl/pinconf-generic.h>
16 #include <linux/pinctrl/pinctrl.h>
17 #include <linux/platform_device.h>
19 #define DA850_PUPD_ENA 0x00
20 #define DA850_PUPD_SEL 0x04
22 struct da850_pupd_data
{
24 struct pinctrl_desc desc
;
25 struct pinctrl_dev
*pinctrl
;
28 static const char * const da850_pupd_group_names
[] = {
29 "cp0", "cp1", "cp2", "cp3", "cp4", "cp5", "cp6", "cp7",
30 "cp8", "cp9", "cp10", "cp11", "cp12", "cp13", "cp14", "cp15",
31 "cp16", "cp17", "cp18", "cp19", "cp20", "cp21", "cp22", "cp23",
32 "cp24", "cp25", "cp26", "cp27", "cp28", "cp29", "cp30", "cp31",
35 static int da850_pupd_get_groups_count(struct pinctrl_dev
*pctldev
)
37 return ARRAY_SIZE(da850_pupd_group_names
);
40 static const char *da850_pupd_get_group_name(struct pinctrl_dev
*pctldev
,
41 unsigned int selector
)
43 return da850_pupd_group_names
[selector
];
46 static int da850_pupd_get_group_pins(struct pinctrl_dev
*pctldev
,
47 unsigned int selector
,
48 const unsigned int **pins
,
49 unsigned int *num_pins
)
56 static const struct pinctrl_ops da850_pupd_pctlops
= {
57 .get_groups_count
= da850_pupd_get_groups_count
,
58 .get_group_name
= da850_pupd_get_group_name
,
59 .get_group_pins
= da850_pupd_get_group_pins
,
60 .dt_node_to_map
= pinconf_generic_dt_node_to_map_group
,
61 .dt_free_map
= pinconf_generic_dt_free_map
,
64 static int da850_pupd_pin_config_group_get(struct pinctrl_dev
*pctldev
,
65 unsigned int selector
,
66 unsigned long *config
)
68 struct da850_pupd_data
*data
= pinctrl_dev_get_drvdata(pctldev
);
69 enum pin_config_param param
= pinconf_to_config_param(*config
);
73 val
= readl(data
->base
+ DA850_PUPD_ENA
);
74 arg
= !!(~val
& BIT(selector
));
77 case PIN_CONFIG_BIAS_DISABLE
:
79 case PIN_CONFIG_BIAS_PULL_UP
:
80 case PIN_CONFIG_BIAS_PULL_DOWN
:
82 /* bias is disabled */
86 val
= readl(data
->base
+ DA850_PUPD_SEL
);
87 if (param
== PIN_CONFIG_BIAS_PULL_DOWN
)
89 arg
= !!(val
& BIT(selector
));
95 *config
= pinconf_to_config_packed(param
, arg
);
100 static int da850_pupd_pin_config_group_set(struct pinctrl_dev
*pctldev
,
101 unsigned int selector
,
102 unsigned long *configs
,
103 unsigned int num_configs
)
105 struct da850_pupd_data
*data
= pinctrl_dev_get_drvdata(pctldev
);
107 enum pin_config_param param
;
110 ena
= readl(data
->base
+ DA850_PUPD_ENA
);
111 sel
= readl(data
->base
+ DA850_PUPD_SEL
);
113 for (i
= 0; i
< num_configs
; i
++) {
114 param
= pinconf_to_config_param(configs
[i
]);
117 case PIN_CONFIG_BIAS_DISABLE
:
118 ena
&= ~BIT(selector
);
120 case PIN_CONFIG_BIAS_PULL_UP
:
121 ena
|= BIT(selector
);
122 sel
|= BIT(selector
);
124 case PIN_CONFIG_BIAS_PULL_DOWN
:
125 ena
|= BIT(selector
);
126 sel
&= ~BIT(selector
);
133 writel(sel
, data
->base
+ DA850_PUPD_SEL
);
134 writel(ena
, data
->base
+ DA850_PUPD_ENA
);
139 static const struct pinconf_ops da850_pupd_confops
= {
141 .pin_config_group_get
= da850_pupd_pin_config_group_get
,
142 .pin_config_group_set
= da850_pupd_pin_config_group_set
,
145 static int da850_pupd_probe(struct platform_device
*pdev
)
147 struct device
*dev
= &pdev
->dev
;
148 struct da850_pupd_data
*data
;
149 struct resource
*res
;
151 data
= devm_kzalloc(dev
, sizeof(*data
), GFP_KERNEL
);
155 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
156 data
->base
= devm_ioremap_resource(dev
, res
);
157 if (IS_ERR(data
->base
)) {
158 dev_err(dev
, "Could not map resource\n");
159 return PTR_ERR(data
->base
);
162 data
->desc
.name
= dev_name(dev
);
163 data
->desc
.pctlops
= &da850_pupd_pctlops
;
164 data
->desc
.confops
= &da850_pupd_confops
;
165 data
->desc
.owner
= THIS_MODULE
;
167 data
->pinctrl
= devm_pinctrl_register(dev
, &data
->desc
, data
);
168 if (IS_ERR(data
->pinctrl
)) {
169 dev_err(dev
, "Failed to register pinctrl\n");
170 return PTR_ERR(data
->pinctrl
);
173 platform_set_drvdata(pdev
, data
);
178 static int da850_pupd_remove(struct platform_device
*pdev
)
183 static const struct of_device_id da850_pupd_of_match
[] = {
184 { .compatible
= "ti,da850-pupd" },
187 MODULE_DEVICE_TABLE(of
, da850_pupd_of_match
);
189 static struct platform_driver da850_pupd_driver
= {
191 .name
= "ti-da850-pupd",
192 .of_match_table
= da850_pupd_of_match
,
194 .probe
= da850_pupd_probe
,
195 .remove
= da850_pupd_remove
,
197 module_platform_driver(da850_pupd_driver
);
199 MODULE_AUTHOR("David Lechner <david@lechnology.com>");
200 MODULE_DESCRIPTION("TI DA850/OMAP-L138/AM18XX pullup/pulldown configuration");
201 MODULE_LICENSE("GPL");