Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Driver for the ps-mode pin configuration.
0004  *
0005  * Copyright (c) 2021 Xilinx, Inc.
0006  */
0007 
0008 #include <linux/delay.h>
0009 #include <linux/err.h>
0010 #include <linux/gpio/driver.h>
0011 #include <linux/io.h>
0012 #include <linux/kernel.h>
0013 #include <linux/module.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/slab.h>
0016 #include <linux/firmware/xlnx-zynqmp.h>
0017 
0018 /* 4-bit boot mode pins */
0019 #define MODE_PINS           4
0020 
0021 /**
0022  * modepin_gpio_get_value - Get the state of the specified pin of GPIO device
0023  * @chip:   gpio_chip instance to be worked on
0024  * @pin:    gpio pin number within the device
0025  *
0026  * This function reads the state of the specified pin of the GPIO device.
0027  *
0028  * Return: 0 if the pin is low, 1 if pin is high, -EINVAL wrong pin configured
0029  *         or error value.
0030  */
0031 static int modepin_gpio_get_value(struct gpio_chip *chip, unsigned int pin)
0032 {
0033     u32 regval = 0;
0034     int ret;
0035 
0036     ret = zynqmp_pm_bootmode_read(&regval);
0037     if (ret)
0038         return ret;
0039 
0040     /* When [0:3] corresponding bit is set, then read output bit [8:11],
0041      * if the bit is clear then read input bit [4:7] for status or value.
0042      */
0043     if (regval & BIT(pin))
0044         return !!(regval & BIT(pin + 8));
0045     else
0046         return !!(regval & BIT(pin + 4));
0047 }
0048 
0049 /**
0050  * modepin_gpio_set_value - Modify the state of the pin with specified value
0051  * @chip:   gpio_chip instance to be worked on
0052  * @pin:    gpio pin number within the device
0053  * @state:  value used to modify the state of the specified pin
0054  *
0055  * This function reads the state of the specified pin of the GPIO device, mask
0056  * with the capture state of GPIO pin, and update pin of GPIO device.
0057  *
0058  * Return:  None.
0059  */
0060 static void modepin_gpio_set_value(struct gpio_chip *chip, unsigned int pin,
0061                    int state)
0062 {
0063     u32 bootpin_val = 0;
0064     int ret;
0065 
0066     zynqmp_pm_bootmode_read(&bootpin_val);
0067 
0068     /* Configure pin as an output by set bit [0:3] */
0069     bootpin_val |= BIT(pin);
0070 
0071     if (state)
0072         bootpin_val |= BIT(pin + 8);
0073     else
0074         bootpin_val &= ~BIT(pin + 8);
0075 
0076     /* Configure bootpin value */
0077     ret = zynqmp_pm_bootmode_write(bootpin_val);
0078     if (ret)
0079         pr_err("modepin: set value error %d for pin %d\n", ret, pin);
0080 }
0081 
0082 /**
0083  * modepin_gpio_dir_in - Set the direction of the specified GPIO pin as input
0084  * @chip:   gpio_chip instance to be worked on
0085  * @pin:    gpio pin number within the device
0086  *
0087  * Return: 0 always
0088  */
0089 static int modepin_gpio_dir_in(struct gpio_chip *chip, unsigned int pin)
0090 {
0091     return 0;
0092 }
0093 
0094 /**
0095  * modepin_gpio_dir_out - Set the direction of the specified GPIO pin as output
0096  * @chip:   gpio_chip instance to be worked on
0097  * @pin:    gpio pin number within the device
0098  * @state:  value to be written to specified pin
0099  *
0100  * Return: 0 always
0101  */
0102 static int modepin_gpio_dir_out(struct gpio_chip *chip, unsigned int pin,
0103                 int state)
0104 {
0105     return 0;
0106 }
0107 
0108 /**
0109  * modepin_gpio_probe - Initialization method for modepin_gpio
0110  * @pdev:       platform device instance
0111  *
0112  * Return: 0 on success, negative error otherwise.
0113  */
0114 static int modepin_gpio_probe(struct platform_device *pdev)
0115 {
0116     struct gpio_chip *chip;
0117     int status;
0118 
0119     chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
0120     if (!chip)
0121         return -ENOMEM;
0122 
0123     platform_set_drvdata(pdev, chip);
0124 
0125     /* configure the gpio chip */
0126     chip->base = -1;
0127     chip->ngpio = MODE_PINS;
0128     chip->owner = THIS_MODULE;
0129     chip->parent = &pdev->dev;
0130     chip->get = modepin_gpio_get_value;
0131     chip->set = modepin_gpio_set_value;
0132     chip->direction_input = modepin_gpio_dir_in;
0133     chip->direction_output = modepin_gpio_dir_out;
0134     chip->label = dev_name(&pdev->dev);
0135 
0136     /* modepin gpio registration */
0137     status = devm_gpiochip_add_data(&pdev->dev, chip, chip);
0138     if (status)
0139         return dev_err_probe(&pdev->dev, status,
0140                   "Failed to add GPIO chip\n");
0141 
0142     return status;
0143 }
0144 
0145 static const struct of_device_id modepin_platform_id[] = {
0146     { .compatible = "xlnx,zynqmp-gpio-modepin", },
0147     { }
0148 };
0149 
0150 static struct platform_driver modepin_platform_driver = {
0151     .driver = {
0152         .name = "modepin-gpio",
0153         .of_match_table = modepin_platform_id,
0154     },
0155     .probe = modepin_gpio_probe,
0156 };
0157 
0158 module_platform_driver(modepin_platform_driver);
0159 
0160 MODULE_AUTHOR("Piyush Mehta <piyush.mehta@xilinx.com>");
0161 MODULE_DESCRIPTION("ZynqMP Boot PS_MODE Configuration");
0162 MODULE_LICENSE("GPL v2");