Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2015, The Linux Foundation. All rights reserved.
0004  *
0005  * GPIO and pin control functions on this SOC are handled by the "TLMM"
0006  * device.  The driver which controls this device is pinctrl-msm.c.  Each
0007  * SOC with a TLMM is expected to create a client driver that registers
0008  * with pinctrl-msm.c.  This means that all TLMM drivers are pin control
0009  * drivers.
0010  *
0011  * This pin control driver is intended to be used only an ACPI-enabled
0012  * system.  As such, UEFI will handle all pin control configuration, so
0013  * this driver does not provide pin control functions.  It is effectively
0014  * a GPIO-only driver.  The alternative is to duplicate the GPIO code of
0015  * pinctrl-msm.c into another driver.
0016  */
0017 
0018 #include <linux/module.h>
0019 #include <linux/platform_device.h>
0020 #include <linux/pinctrl/pinctrl.h>
0021 #include <linux/acpi.h>
0022 
0023 #include "pinctrl-msm.h"
0024 
0025 /* A maximum of 256 allows us to use a u8 array to hold the GPIO numbers */
0026 #define MAX_GPIOS   256
0027 
0028 /* maximum size of each gpio name (enough room for "gpioXXX" + null) */
0029 #define NAME_SIZE   8
0030 
0031 static int qdf2xxx_pinctrl_probe(struct platform_device *pdev)
0032 {
0033     struct msm_pinctrl_soc_data *pinctrl;
0034     struct pinctrl_pin_desc *pins;
0035     struct msm_pingroup *groups;
0036     char (*names)[NAME_SIZE];
0037     unsigned int i;
0038     u32 num_gpios;
0039     unsigned int avail_gpios; /* The number of GPIOs we support */
0040     u8 gpios[MAX_GPIOS];      /* An array of supported GPIOs */
0041     int ret;
0042 
0043     /* Query the number of GPIOs from ACPI */
0044     ret = device_property_read_u32(&pdev->dev, "num-gpios", &num_gpios);
0045     if (ret < 0) {
0046         dev_err(&pdev->dev, "missing 'num-gpios' property\n");
0047         return ret;
0048     }
0049     if (!num_gpios || num_gpios > MAX_GPIOS) {
0050         dev_err(&pdev->dev, "invalid 'num-gpios' property\n");
0051         return -ENODEV;
0052     }
0053 
0054     /* The number of GPIOs in the approved list */
0055     ret = device_property_count_u8(&pdev->dev, "gpios");
0056     if (ret < 0) {
0057         dev_err(&pdev->dev, "missing 'gpios' property\n");
0058         return ret;
0059     }
0060     /*
0061      * The number of available GPIOs should be non-zero, and no
0062      * more than the total number of GPIOS.
0063      */
0064     if (!ret || ret > num_gpios) {
0065         dev_err(&pdev->dev, "invalid 'gpios' property\n");
0066         return -ENODEV;
0067     }
0068     avail_gpios = ret;
0069 
0070     ret = device_property_read_u8_array(&pdev->dev, "gpios", gpios,
0071                         avail_gpios);
0072     if (ret < 0) {
0073         dev_err(&pdev->dev, "could not read list of GPIOs\n");
0074         return ret;
0075     }
0076 
0077     pinctrl = devm_kzalloc(&pdev->dev, sizeof(*pinctrl), GFP_KERNEL);
0078     pins = devm_kcalloc(&pdev->dev, num_gpios,
0079         sizeof(struct pinctrl_pin_desc), GFP_KERNEL);
0080     groups = devm_kcalloc(&pdev->dev, num_gpios,
0081         sizeof(struct msm_pingroup), GFP_KERNEL);
0082     names = devm_kcalloc(&pdev->dev, avail_gpios, NAME_SIZE, GFP_KERNEL);
0083 
0084     if (!pinctrl || !pins || !groups || !names)
0085         return -ENOMEM;
0086 
0087     /*
0088      * Initialize the array.  GPIOs not listed in the 'gpios' array
0089      * still need a number, but nothing else.
0090      */
0091     for (i = 0; i < num_gpios; i++) {
0092         pins[i].number = i;
0093         groups[i].pins = &pins[i].number;
0094     }
0095 
0096     /* Populate the entries that are meant to be exposed as GPIOs. */
0097     for (i = 0; i < avail_gpios; i++) {
0098         unsigned int gpio = gpios[i];
0099 
0100         groups[gpio].npins = 1;
0101         snprintf(names[i], NAME_SIZE, "gpio%u", gpio);
0102         pins[gpio].name = names[i];
0103         groups[gpio].name = names[i];
0104 
0105         groups[gpio].ctl_reg = 0x10000 * gpio;
0106         groups[gpio].io_reg = 0x04 + 0x10000 * gpio;
0107         groups[gpio].intr_cfg_reg = 0x08 + 0x10000 * gpio;
0108         groups[gpio].intr_status_reg = 0x0c + 0x10000 * gpio;
0109         groups[gpio].intr_target_reg = 0x08 + 0x10000 * gpio;
0110 
0111         groups[gpio].mux_bit = 2;
0112         groups[gpio].pull_bit = 0;
0113         groups[gpio].drv_bit = 6;
0114         groups[gpio].oe_bit = 9;
0115         groups[gpio].in_bit = 0;
0116         groups[gpio].out_bit = 1;
0117         groups[gpio].intr_enable_bit = 0;
0118         groups[gpio].intr_status_bit = 0;
0119         groups[gpio].intr_target_bit = 5;
0120         groups[gpio].intr_target_kpss_val = 1;
0121         groups[gpio].intr_raw_status_bit = 4;
0122         groups[gpio].intr_polarity_bit = 1;
0123         groups[gpio].intr_detection_bit = 2;
0124         groups[gpio].intr_detection_width = 2;
0125     }
0126 
0127     pinctrl->pins = pins;
0128     pinctrl->groups = groups;
0129     pinctrl->npins = num_gpios;
0130     pinctrl->ngroups = num_gpios;
0131     pinctrl->ngpios = num_gpios;
0132 
0133     return msm_pinctrl_probe(pdev, pinctrl);
0134 }
0135 
0136 static const struct acpi_device_id qdf2xxx_acpi_ids[] = {
0137     {"QCOM8002"},
0138     {},
0139 };
0140 MODULE_DEVICE_TABLE(acpi, qdf2xxx_acpi_ids);
0141 
0142 static struct platform_driver qdf2xxx_pinctrl_driver = {
0143     .driver = {
0144         .name = "qdf2xxx-pinctrl",
0145         .acpi_match_table = ACPI_PTR(qdf2xxx_acpi_ids),
0146     },
0147     .probe = qdf2xxx_pinctrl_probe,
0148     .remove = msm_pinctrl_remove,
0149 };
0150 
0151 static int __init qdf2xxx_pinctrl_init(void)
0152 {
0153     return platform_driver_register(&qdf2xxx_pinctrl_driver);
0154 }
0155 arch_initcall(qdf2xxx_pinctrl_init);
0156 
0157 static void __exit qdf2xxx_pinctrl_exit(void)
0158 {
0159     platform_driver_unregister(&qdf2xxx_pinctrl_driver);
0160 }
0161 module_exit(qdf2xxx_pinctrl_exit);
0162 
0163 MODULE_DESCRIPTION("Qualcomm Technologies QDF2xxx pin control driver");
0164 MODULE_LICENSE("GPL v2");