| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Driver for the ps-mode pin configuration.
- *
- * Copyright (c) 2021 Xilinx, Inc.
- */
- #include <linux/delay.h>
- #include <linux/err.h>
- #include <linux/gpio/driver.h>
- #include <linux/io.h>
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/platform_device.h>
- #include <linux/slab.h>
- #include <linux/firmware/xlnx-zynqmp.h>
- /* 4-bit boot mode pins */
- #define MODE_PINS 4
- /**
- * modepin_gpio_get_value - Get the state of the specified pin of GPIO device
- * @chip: gpio_chip instance to be worked on
- * @pin: gpio pin number within the device
- *
- * This function reads the state of the specified pin of the GPIO device.
- *
- * Return: 0 if the pin is low, 1 if pin is high, -EINVAL wrong pin configured
- * or error value.
- */
- static int modepin_gpio_get_value(struct gpio_chip *chip, unsigned int pin)
- {
- u32 regval = 0;
- int ret;
- ret = zynqmp_pm_bootmode_read(®val);
- if (ret)
- return ret;
- /* When [0:3] corresponding bit is set, then read output bit [8:11],
- * if the bit is clear then read input bit [4:7] for status or value.
- */
- if (regval & BIT(pin))
- return !!(regval & BIT(pin + 8));
- else
- return !!(regval & BIT(pin + 4));
- }
- /**
- * modepin_gpio_set_value - Modify the state of the pin with specified value
- * @chip: gpio_chip instance to be worked on
- * @pin: gpio pin number within the device
- * @state: value used to modify the state of the specified pin
- *
- * This function reads the state of the specified pin of the GPIO device, mask
- * with the capture state of GPIO pin, and update pin of GPIO device.
- *
- * Return: None.
- */
- static void modepin_gpio_set_value(struct gpio_chip *chip, unsigned int pin,
- int state)
- {
- u32 bootpin_val = 0;
- int ret;
- zynqmp_pm_bootmode_read(&bootpin_val);
- /* Configure pin as an output by set bit [0:3] */
- bootpin_val |= BIT(pin);
- if (state)
- bootpin_val |= BIT(pin + 8);
- else
- bootpin_val &= ~BIT(pin + 8);
- /* Configure bootpin value */
- ret = zynqmp_pm_bootmode_write(bootpin_val);
- if (ret)
- pr_err("modepin: set value error %d for pin %d\n", ret, pin);
- }
- /**
- * modepin_gpio_dir_in - Set the direction of the specified GPIO pin as input
- * @chip: gpio_chip instance to be worked on
- * @pin: gpio pin number within the device
- *
- * Return: 0 always
- */
- static int modepin_gpio_dir_in(struct gpio_chip *chip, unsigned int pin)
- {
- return 0;
- }
- /**
- * modepin_gpio_dir_out - Set the direction of the specified GPIO pin as output
- * @chip: gpio_chip instance to be worked on
- * @pin: gpio pin number within the device
- * @state: value to be written to specified pin
- *
- * Return: 0 always
- */
- static int modepin_gpio_dir_out(struct gpio_chip *chip, unsigned int pin,
- int state)
- {
- return 0;
- }
- /**
- * modepin_gpio_probe - Initialization method for modepin_gpio
- * @pdev: platform device instance
- *
- * Return: 0 on success, negative error otherwise.
- */
- static int modepin_gpio_probe(struct platform_device *pdev)
- {
- struct gpio_chip *chip;
- int status;
- chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
- if (!chip)
- return -ENOMEM;
- platform_set_drvdata(pdev, chip);
- /* configure the gpio chip */
- chip->base = -1;
- chip->ngpio = MODE_PINS;
- chip->owner = THIS_MODULE;
- chip->parent = &pdev->dev;
- chip->get = modepin_gpio_get_value;
- chip->set = modepin_gpio_set_value;
- chip->direction_input = modepin_gpio_dir_in;
- chip->direction_output = modepin_gpio_dir_out;
- chip->label = dev_name(&pdev->dev);
- /* modepin gpio registration */
- status = devm_gpiochip_add_data(&pdev->dev, chip, chip);
- if (status)
- return dev_err_probe(&pdev->dev, status,
- "Failed to add GPIO chip\n");
- return status;
- }
- static const struct of_device_id modepin_platform_id[] = {
- { .compatible = "xlnx,zynqmp-gpio-modepin", },
- { }
- };
- MODULE_DEVICE_TABLE(of, modepin_platform_id);
- static struct platform_driver modepin_platform_driver = {
- .driver = {
- .name = "modepin-gpio",
- .of_match_table = modepin_platform_id,
- },
- .probe = modepin_gpio_probe,
- };
- module_platform_driver(modepin_platform_driver);
- MODULE_AUTHOR("Piyush Mehta <piyush.mehta@xilinx.com>");
- MODULE_DESCRIPTION("ZynqMP Boot PS_MODE Configuration");
- MODULE_LICENSE("GPL v2");
|