Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Pinconf driver for TI DA850/OMAP-L138/AM18XX pullup/pulldown groups
0004  *
0005  * Copyright (C) 2016  David Lechner
0006  */
0007 
0008 #include <linux/bitops.h>
0009 #include <linux/device.h>
0010 #include <linux/io.h>
0011 #include <linux/ioport.h>
0012 #include <linux/mod_devicetable.h>
0013 #include <linux/module.h>
0014 #include <linux/pinctrl/pinconf.h>
0015 #include <linux/pinctrl/pinconf-generic.h>
0016 #include <linux/pinctrl/pinctrl.h>
0017 #include <linux/platform_device.h>
0018 
0019 #define DA850_PUPD_ENA      0x00
0020 #define DA850_PUPD_SEL      0x04
0021 
0022 struct da850_pupd_data {
0023     void __iomem *base;
0024     struct pinctrl_desc desc;
0025     struct pinctrl_dev *pinctrl;
0026 };
0027 
0028 static const char * const da850_pupd_group_names[] = {
0029     "cp0", "cp1", "cp2", "cp3", "cp4", "cp5", "cp6", "cp7",
0030     "cp8", "cp9", "cp10", "cp11", "cp12", "cp13", "cp14", "cp15",
0031     "cp16", "cp17", "cp18", "cp19", "cp20", "cp21", "cp22", "cp23",
0032     "cp24", "cp25", "cp26", "cp27", "cp28", "cp29", "cp30", "cp31",
0033 };
0034 
0035 static int da850_pupd_get_groups_count(struct pinctrl_dev *pctldev)
0036 {
0037     return ARRAY_SIZE(da850_pupd_group_names);
0038 }
0039 
0040 static const char *da850_pupd_get_group_name(struct pinctrl_dev *pctldev,
0041                          unsigned int selector)
0042 {
0043     return da850_pupd_group_names[selector];
0044 }
0045 
0046 static int da850_pupd_get_group_pins(struct pinctrl_dev *pctldev,
0047                      unsigned int selector,
0048                      const unsigned int **pins,
0049                      unsigned int *num_pins)
0050 {
0051     *num_pins = 0;
0052 
0053     return 0;
0054 }
0055 
0056 static const struct pinctrl_ops da850_pupd_pctlops = {
0057     .get_groups_count   = da850_pupd_get_groups_count,
0058     .get_group_name     = da850_pupd_get_group_name,
0059     .get_group_pins     = da850_pupd_get_group_pins,
0060     .dt_node_to_map     = pinconf_generic_dt_node_to_map_group,
0061     .dt_free_map        = pinconf_generic_dt_free_map,
0062 };
0063 
0064 static int da850_pupd_pin_config_group_get(struct pinctrl_dev *pctldev,
0065                        unsigned int selector,
0066                        unsigned long *config)
0067 {
0068     struct da850_pupd_data *data = pinctrl_dev_get_drvdata(pctldev);
0069     enum pin_config_param param = pinconf_to_config_param(*config);
0070     u32 val;
0071     u16 arg;
0072 
0073     val = readl(data->base + DA850_PUPD_ENA);
0074     arg = !!(~val & BIT(selector));
0075 
0076     switch (param) {
0077     case PIN_CONFIG_BIAS_DISABLE:
0078         break;
0079     case PIN_CONFIG_BIAS_PULL_UP:
0080     case PIN_CONFIG_BIAS_PULL_DOWN:
0081         if (arg) {
0082             /* bias is disabled */
0083             arg = 0;
0084             break;
0085         }
0086         val = readl(data->base + DA850_PUPD_SEL);
0087         if (param == PIN_CONFIG_BIAS_PULL_DOWN)
0088             val = ~val;
0089         arg = !!(val & BIT(selector));
0090         break;
0091     default:
0092         return -EINVAL;
0093     }
0094 
0095     *config = pinconf_to_config_packed(param, arg);
0096 
0097     return 0;
0098 }
0099 
0100 static int da850_pupd_pin_config_group_set(struct pinctrl_dev *pctldev,
0101                        unsigned int selector,
0102                        unsigned long *configs,
0103                        unsigned int num_configs)
0104 {
0105     struct da850_pupd_data *data = pinctrl_dev_get_drvdata(pctldev);
0106     u32 ena, sel;
0107     enum pin_config_param param;
0108     int i;
0109 
0110     ena = readl(data->base + DA850_PUPD_ENA);
0111     sel = readl(data->base + DA850_PUPD_SEL);
0112 
0113     for (i = 0; i < num_configs; i++) {
0114         param = pinconf_to_config_param(configs[i]);
0115 
0116         switch (param) {
0117         case PIN_CONFIG_BIAS_DISABLE:
0118             ena &= ~BIT(selector);
0119             break;
0120         case PIN_CONFIG_BIAS_PULL_UP:
0121             ena |= BIT(selector);
0122             sel |= BIT(selector);
0123             break;
0124         case PIN_CONFIG_BIAS_PULL_DOWN:
0125             ena |= BIT(selector);
0126             sel &= ~BIT(selector);
0127             break;
0128         default:
0129             return -EINVAL;
0130         }
0131     }
0132 
0133     writel(sel, data->base + DA850_PUPD_SEL);
0134     writel(ena, data->base + DA850_PUPD_ENA);
0135 
0136     return 0;
0137 }
0138 
0139 static const struct pinconf_ops da850_pupd_confops = {
0140     .is_generic     = true,
0141     .pin_config_group_get   = da850_pupd_pin_config_group_get,
0142     .pin_config_group_set   = da850_pupd_pin_config_group_set,
0143 };
0144 
0145 static int da850_pupd_probe(struct platform_device *pdev)
0146 {
0147     struct device *dev = &pdev->dev;
0148     struct da850_pupd_data *data;
0149 
0150     data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
0151     if (!data)
0152         return -ENOMEM;
0153 
0154     data->base = devm_platform_ioremap_resource(pdev, 0);
0155     if (IS_ERR(data->base)) {
0156         dev_err(dev, "Could not map resource\n");
0157         return PTR_ERR(data->base);
0158     }
0159 
0160     data->desc.name = dev_name(dev);
0161     data->desc.pctlops = &da850_pupd_pctlops;
0162     data->desc.confops = &da850_pupd_confops;
0163     data->desc.owner = THIS_MODULE;
0164 
0165     data->pinctrl = devm_pinctrl_register(dev, &data->desc, data);
0166     if (IS_ERR(data->pinctrl)) {
0167         dev_err(dev, "Failed to register pinctrl\n");
0168         return PTR_ERR(data->pinctrl);
0169     }
0170 
0171     platform_set_drvdata(pdev, data);
0172 
0173     return 0;
0174 }
0175 
0176 static int da850_pupd_remove(struct platform_device *pdev)
0177 {
0178     return 0;
0179 }
0180 
0181 static const struct of_device_id da850_pupd_of_match[] = {
0182     { .compatible = "ti,da850-pupd" },
0183     { }
0184 };
0185 MODULE_DEVICE_TABLE(of, da850_pupd_of_match);
0186 
0187 static struct platform_driver da850_pupd_driver = {
0188     .driver = {
0189         .name       = "ti-da850-pupd",
0190         .of_match_table = da850_pupd_of_match,
0191     },
0192     .probe  = da850_pupd_probe,
0193     .remove = da850_pupd_remove,
0194 };
0195 module_platform_driver(da850_pupd_driver);
0196 
0197 MODULE_AUTHOR("David Lechner <david@lechnology.com>");
0198 MODULE_DESCRIPTION("TI DA850/OMAP-L138/AM18XX pullup/pulldown configuration");
0199 MODULE_LICENSE("GPL");