GNU Linux-libre 5.19-rc6-gnu
[releases.git] / drivers / gpio / gpio-zynqmp-modepin.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Driver for the ps-mode pin configuration.
4  *
5  * Copyright (c) 2021 Xilinx, Inc.
6  */
7
8 #include <linux/delay.h>
9 #include <linux/err.h>
10 #include <linux/gpio/driver.h>
11 #include <linux/io.h>
12 #include <linux/kernel.h>
13 #include <linux/module.h>
14 #include <linux/platform_device.h>
15 #include <linux/slab.h>
16 #include <linux/firmware/xlnx-zynqmp.h>
17
18 /* 4-bit boot mode pins */
19 #define MODE_PINS                       4
20
21 /**
22  * modepin_gpio_get_value - Get the state of the specified pin of GPIO device
23  * @chip:       gpio_chip instance to be worked on
24  * @pin:        gpio pin number within the device
25  *
26  * This function reads the state of the specified pin of the GPIO device.
27  *
28  * Return: 0 if the pin is low, 1 if pin is high, -EINVAL wrong pin configured
29  *         or error value.
30  */
31 static int modepin_gpio_get_value(struct gpio_chip *chip, unsigned int pin)
32 {
33         u32 regval = 0;
34         int ret;
35
36         ret = zynqmp_pm_bootmode_read(&regval);
37         if (ret)
38                 return ret;
39
40         /* When [0:3] corresponding bit is set, then read output bit [8:11],
41          * if the bit is clear then read input bit [4:7] for status or value.
42          */
43         if (regval & BIT(pin))
44                 return !!(regval & BIT(pin + 8));
45         else
46                 return !!(regval & BIT(pin + 4));
47 }
48
49 /**
50  * modepin_gpio_set_value - Modify the state of the pin with specified value
51  * @chip:       gpio_chip instance to be worked on
52  * @pin:        gpio pin number within the device
53  * @state:      value used to modify the state of the specified pin
54  *
55  * This function reads the state of the specified pin of the GPIO device, mask
56  * with the capture state of GPIO pin, and update pin of GPIO device.
57  *
58  * Return:      None.
59  */
60 static void modepin_gpio_set_value(struct gpio_chip *chip, unsigned int pin,
61                                    int state)
62 {
63         u32 bootpin_val = 0;
64         int ret;
65
66         zynqmp_pm_bootmode_read(&bootpin_val);
67
68         /* Configure pin as an output by set bit [0:3] */
69         bootpin_val |= BIT(pin);
70
71         if (state)
72                 bootpin_val |= BIT(pin + 8);
73         else
74                 bootpin_val &= ~BIT(pin + 8);
75
76         /* Configure bootpin value */
77         ret = zynqmp_pm_bootmode_write(bootpin_val);
78         if (ret)
79                 pr_err("modepin: set value error %d for pin %d\n", ret, pin);
80 }
81
82 /**
83  * modepin_gpio_dir_in - Set the direction of the specified GPIO pin as input
84  * @chip:       gpio_chip instance to be worked on
85  * @pin:        gpio pin number within the device
86  *
87  * Return: 0 always
88  */
89 static int modepin_gpio_dir_in(struct gpio_chip *chip, unsigned int pin)
90 {
91         return 0;
92 }
93
94 /**
95  * modepin_gpio_dir_out - Set the direction of the specified GPIO pin as output
96  * @chip:       gpio_chip instance to be worked on
97  * @pin:        gpio pin number within the device
98  * @state:      value to be written to specified pin
99  *
100  * Return: 0 always
101  */
102 static int modepin_gpio_dir_out(struct gpio_chip *chip, unsigned int pin,
103                                 int state)
104 {
105         return 0;
106 }
107
108 /**
109  * modepin_gpio_probe - Initialization method for modepin_gpio
110  * @pdev:               platform device instance
111  *
112  * Return: 0 on success, negative error otherwise.
113  */
114 static int modepin_gpio_probe(struct platform_device *pdev)
115 {
116         struct gpio_chip *chip;
117         int status;
118
119         chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
120         if (!chip)
121                 return -ENOMEM;
122
123         platform_set_drvdata(pdev, chip);
124
125         /* configure the gpio chip */
126         chip->base = -1;
127         chip->ngpio = MODE_PINS;
128         chip->owner = THIS_MODULE;
129         chip->parent = &pdev->dev;
130         chip->get = modepin_gpio_get_value;
131         chip->set = modepin_gpio_set_value;
132         chip->direction_input = modepin_gpio_dir_in;
133         chip->direction_output = modepin_gpio_dir_out;
134         chip->label = dev_name(&pdev->dev);
135
136         /* modepin gpio registration */
137         status = devm_gpiochip_add_data(&pdev->dev, chip, chip);
138         if (status)
139                 return dev_err_probe(&pdev->dev, status,
140                               "Failed to add GPIO chip\n");
141
142         return status;
143 }
144
145 static const struct of_device_id modepin_platform_id[] = {
146         { .compatible = "xlnx,zynqmp-gpio-modepin", },
147         { }
148 };
149
150 static struct platform_driver modepin_platform_driver = {
151         .driver = {
152                 .name = "modepin-gpio",
153                 .of_match_table = modepin_platform_id,
154         },
155         .probe = modepin_gpio_probe,
156 };
157
158 module_platform_driver(modepin_platform_driver);
159
160 MODULE_AUTHOR("Piyush Mehta <piyush.mehta@xilinx.com>");
161 MODULE_DESCRIPTION("ZynqMP Boot PS_MODE Configuration");
162 MODULE_LICENSE("GPL v2");