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