^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Pinconf driver for TI DA850/OMAP-L138/AM18XX pullup/pulldown groups
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2016 David Lechner
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/bitops.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/ioport.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/mod_devicetable.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/pinctrl/pinconf.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/pinctrl/pinconf-generic.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/pinctrl/pinctrl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define DA850_PUPD_ENA 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define DA850_PUPD_SEL 0x04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) struct da850_pupd_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) void __iomem *base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) struct pinctrl_desc desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) struct pinctrl_dev *pinctrl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) static const char * const da850_pupd_group_names[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) "cp0", "cp1", "cp2", "cp3", "cp4", "cp5", "cp6", "cp7",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) "cp8", "cp9", "cp10", "cp11", "cp12", "cp13", "cp14", "cp15",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) "cp16", "cp17", "cp18", "cp19", "cp20", "cp21", "cp22", "cp23",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) "cp24", "cp25", "cp26", "cp27", "cp28", "cp29", "cp30", "cp31",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) static int da850_pupd_get_groups_count(struct pinctrl_dev *pctldev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) return ARRAY_SIZE(da850_pupd_group_names);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) static const char *da850_pupd_get_group_name(struct pinctrl_dev *pctldev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) unsigned int selector)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) return da850_pupd_group_names[selector];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) static int da850_pupd_get_group_pins(struct pinctrl_dev *pctldev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) unsigned int selector,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) const unsigned int **pins,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) unsigned int *num_pins)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) *num_pins = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) static const struct pinctrl_ops da850_pupd_pctlops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) .get_groups_count = da850_pupd_get_groups_count,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) .get_group_name = da850_pupd_get_group_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) .get_group_pins = da850_pupd_get_group_pins,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) .dt_node_to_map = pinconf_generic_dt_node_to_map_group,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) .dt_free_map = pinconf_generic_dt_free_map,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) static int da850_pupd_pin_config_group_get(struct pinctrl_dev *pctldev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) unsigned int selector,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) unsigned long *config)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) struct da850_pupd_data *data = pinctrl_dev_get_drvdata(pctldev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) enum pin_config_param param = pinconf_to_config_param(*config);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) u16 arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) val = readl(data->base + DA850_PUPD_ENA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) arg = !!(~val & BIT(selector));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) switch (param) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) case PIN_CONFIG_BIAS_DISABLE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) case PIN_CONFIG_BIAS_PULL_UP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) case PIN_CONFIG_BIAS_PULL_DOWN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if (arg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) /* bias is disabled */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) arg = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) val = readl(data->base + DA850_PUPD_SEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) if (param == PIN_CONFIG_BIAS_PULL_DOWN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) val = ~val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) arg = !!(val & BIT(selector));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) *config = pinconf_to_config_packed(param, arg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) static int da850_pupd_pin_config_group_set(struct pinctrl_dev *pctldev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) unsigned int selector,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) unsigned long *configs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) unsigned int num_configs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) struct da850_pupd_data *data = pinctrl_dev_get_drvdata(pctldev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) u32 ena, sel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) enum pin_config_param param;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) ena = readl(data->base + DA850_PUPD_ENA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) sel = readl(data->base + DA850_PUPD_SEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) for (i = 0; i < num_configs; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) param = pinconf_to_config_param(configs[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) switch (param) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) case PIN_CONFIG_BIAS_DISABLE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) ena &= ~BIT(selector);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) case PIN_CONFIG_BIAS_PULL_UP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) ena |= BIT(selector);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) sel |= BIT(selector);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) case PIN_CONFIG_BIAS_PULL_DOWN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) ena |= BIT(selector);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) sel &= ~BIT(selector);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) writel(sel, data->base + DA850_PUPD_SEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) writel(ena, data->base + DA850_PUPD_ENA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) static const struct pinconf_ops da850_pupd_confops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) .is_generic = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) .pin_config_group_get = da850_pupd_pin_config_group_get,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) .pin_config_group_set = da850_pupd_pin_config_group_set,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) static int da850_pupd_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) struct da850_pupd_data *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) if (!data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) data->base = devm_platform_ioremap_resource(pdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) if (IS_ERR(data->base)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) dev_err(dev, "Could not map resource\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) return PTR_ERR(data->base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) data->desc.name = dev_name(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) data->desc.pctlops = &da850_pupd_pctlops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) data->desc.confops = &da850_pupd_confops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) data->desc.owner = THIS_MODULE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) data->pinctrl = devm_pinctrl_register(dev, &data->desc, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) if (IS_ERR(data->pinctrl)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) dev_err(dev, "Failed to register pinctrl\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) return PTR_ERR(data->pinctrl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) platform_set_drvdata(pdev, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) static int da850_pupd_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) static const struct of_device_id da850_pupd_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) { .compatible = "ti,da850-pupd" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) MODULE_DEVICE_TABLE(of, da850_pupd_of_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) static struct platform_driver da850_pupd_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) .name = "ti-da850-pupd",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) .of_match_table = da850_pupd_of_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) .probe = da850_pupd_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) .remove = da850_pupd_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) module_platform_driver(da850_pupd_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) MODULE_AUTHOR("David Lechner <david@lechnology.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) MODULE_DESCRIPTION("TI DA850/OMAP-L138/AM18XX pullup/pulldown configuration");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) MODULE_LICENSE("GPL");