164 lines · c
1// SPDX-License-Identifier: GPL-2.02/*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 420 21/**22 * modepin_gpio_get_value - Get the state of the specified pin of GPIO device23 * @chip: gpio_chip instance to be worked on24 * @pin: gpio pin number within the device25 *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 configured29 * or error value.30 */31static 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 else46 return !!(regval & BIT(pin + 4));47}48 49/**50 * modepin_gpio_set_value - Modify the state of the pin with specified value51 * @chip: gpio_chip instance to be worked on52 * @pin: gpio pin number within the device53 * @state: value used to modify the state of the specified pin54 *55 * This function reads the state of the specified pin of the GPIO device, mask56 * with the capture state of GPIO pin, and update pin of GPIO device.57 *58 * Return: None.59 */60static 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 else74 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 input84 * @chip: gpio_chip instance to be worked on85 * @pin: gpio pin number within the device86 *87 * Return: 0 always88 */89static 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 output96 * @chip: gpio_chip instance to be worked on97 * @pin: gpio pin number within the device98 * @state: value to be written to specified pin99 *100 * Return: 0 always101 */102static 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_gpio110 * @pdev: platform device instance111 *112 * Return: 0 on success, negative error otherwise.113 */114static 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 145static const struct of_device_id modepin_platform_id[] = {146 { .compatible = "xlnx,zynqmp-gpio-modepin", },147 { }148};149MODULE_DEVICE_TABLE(of, modepin_platform_id);150 151static struct platform_driver modepin_platform_driver = {152 .driver = {153 .name = "modepin-gpio",154 .of_match_table = modepin_platform_id,155 },156 .probe = modepin_gpio_probe,157};158 159module_platform_driver(modepin_platform_driver);160 161MODULE_AUTHOR("Piyush Mehta <piyush.mehta@xilinx.com>");162MODULE_DESCRIPTION("ZynqMP Boot PS_MODE Configuration");163MODULE_LICENSE("GPL v2");164