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(®val); 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 int 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 return ret; 82 } 83 84 /** 85 * modepin_gpio_dir_in - Set the direction of the specified GPIO pin as input 86 * @chip: gpio_chip instance to be worked on 87 * @pin: gpio pin number within the device 88 * 89 * Return: 0 always 90 */ 91 static int modepin_gpio_dir_in(struct gpio_chip *chip, unsigned int pin) 92 { 93 return 0; 94 } 95 96 /** 97 * modepin_gpio_dir_out - Set the direction of the specified GPIO pin as output 98 * @chip: gpio_chip instance to be worked on 99 * @pin: gpio pin number within the device 100 * @state: value to be written to specified pin 101 * 102 * Return: 0 always 103 */ 104 static int modepin_gpio_dir_out(struct gpio_chip *chip, unsigned int pin, 105 int state) 106 { 107 return modepin_gpio_set_value(chip, pin, state); 108 } 109 110 /** 111 * modepin_gpio_probe - Initialization method for modepin_gpio 112 * @pdev: platform device instance 113 * 114 * Return: 0 on success, negative error otherwise. 115 */ 116 static int modepin_gpio_probe(struct platform_device *pdev) 117 { 118 struct gpio_chip *chip; 119 int status; 120 121 chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); 122 if (!chip) 123 return -ENOMEM; 124 125 platform_set_drvdata(pdev, chip); 126 127 /* configure the gpio chip */ 128 chip->base = -1; 129 chip->ngpio = MODE_PINS; 130 chip->owner = THIS_MODULE; 131 chip->parent = &pdev->dev; 132 chip->get = modepin_gpio_get_value; 133 chip->set = modepin_gpio_set_value; 134 chip->direction_input = modepin_gpio_dir_in; 135 chip->direction_output = modepin_gpio_dir_out; 136 chip->label = dev_name(&pdev->dev); 137 138 /* modepin gpio registration */ 139 status = devm_gpiochip_add_data(&pdev->dev, chip, chip); 140 if (status) 141 return dev_err_probe(&pdev->dev, status, 142 "Failed to add GPIO chip\n"); 143 144 return status; 145 } 146 147 static const struct of_device_id modepin_platform_id[] = { 148 { .compatible = "xlnx,zynqmp-gpio-modepin", }, 149 { } 150 }; 151 MODULE_DEVICE_TABLE(of, modepin_platform_id); 152 153 static struct platform_driver modepin_platform_driver = { 154 .driver = { 155 .name = "modepin-gpio", 156 .of_match_table = modepin_platform_id, 157 }, 158 .probe = modepin_gpio_probe, 159 }; 160 161 module_platform_driver(modepin_platform_driver); 162 163 MODULE_AUTHOR("Piyush Mehta <piyush.mehta@xilinx.com>"); 164 MODULE_DESCRIPTION("ZynqMP Boot PS_MODE Configuration"); 165 MODULE_LICENSE("GPL v2"); 166