Commit d20f7a09 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'gpio-updates-for-v5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux

Pull gpio updates from Bartosz Golaszewski:
 "We have a single new driver, new features in others and some cleanups
  all over the place.

  Nothing really stands out and it is all relatively small.

   - new driver: gpio-modepin (plus relevant change in zynqmp firmware)

   - add interrupt support to gpio-virtio

   - enable the 'gpio-line-names' property in the DT bindings for
     gpio-rockchip

   - use the subsystem helpers where applicable in gpio-uniphier instead
     of accessing IRQ structures directly

   - code shrink in gpio-xilinx

   - add interrupt to gpio-mlxbf2 (and include the removal of custom
     interrupt code from the mellanox ethernet driver)

   - support multiple interrupts per bank in gpio-tegra186 (and force
     one interrupt per bank in older models)

   - fix GPIO line IRQ offset calculation in gpio-realtek-otto

   - drop unneeded MODULE_ALIAS expansions in multiple drivers

   - code cleanup in gpio-aggregator

   - minor improvements in gpio-max730x and gpio-mc33880

   - Kconfig cleanups"

* tag 'gpio-updates-for-v5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux:
  virtio_gpio: drop packed attribute
  gpio: virtio: Add IRQ support
  gpio: realtek-otto: fix GPIO line IRQ offset
  gpio: clean up Kconfig file
  net: mellanox: mlxbf_gige: Replace non-standard interrupt handling
  gpio: mlxbf2: Introduce IRQ support
  gpio: mc33880: Drop if with an always false condition
  gpio: max730x: Make __max730x_remove() return void
  gpio: aggregator: Wrap access to gpiochip_fwd.tmp[]
  gpio: modepin: Add driver support for modepin GPIO controller
  dt-bindings: gpio: zynqmp: Add binding documentation for modepin
  firmware: zynqmp: Add MMIO read and write support for PS_MODE pin
  gpio: tps65218: drop unneeded MODULE_ALIAS
  gpio: max77620: drop unneeded MODULE_ALIAS
  gpio: xilinx: simplify getting .driver_data
  gpio: tegra186: Support multiple interrupts per bank
  gpio: tegra186: Force one interrupt per bank
  gpio: uniphier: Use helper functions to get private data from IRQ data
  gpio: uniphier: Use helper function to get IRQ hardware number
  dt-bindings: gpio: add gpio-line-names to rockchip,gpio-bank.yaml
parents dd72945c 7d0003da
......@@ -29,6 +29,8 @@ properties:
gpio-controller: true
gpio-line-names: true
"#gpio-cells":
const: 2
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/gpio/xlnx,zynqmp-gpio-modepin.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: ZynqMP Mode Pin GPIO controller
description:
PS_MODE is 4-bits boot mode pins sampled on POR deassertion. Mode Pin
GPIO controller with configurable from numbers of pins (from 0 to 3 per
PS_MODE). Every pin can be configured as input/output.
maintainers:
- Piyush Mehta <piyush.mehta@xilinx.com>
properties:
compatible:
const: xlnx,zynqmp-gpio-modepin
gpio-controller: true
"#gpio-cells":
const: 2
required:
- compatible
- gpio-controller
- "#gpio-cells"
additionalProperties: false
examples:
- |
zynqmp-firmware {
gpio {
compatible = "xlnx,zynqmp-gpio-modepin";
gpio-controller;
#gpio-cells = <2>;
};
};
...
......@@ -28,6 +28,13 @@
/* Max HashMap Order for PM API feature check (1<<7 = 128) */
#define PM_API_FEATURE_CHECK_MAX_ORDER 7
/* CRL registers and bitfields */
#define CRL_APB_BASE 0xFF5E0000U
/* BOOT_PIN_CTRL- Used to control the mode pins after boot */
#define CRL_APB_BOOT_PIN_CTRL (CRL_APB_BASE + (0x250U))
/* BOOT_PIN_CTRL_MASK- out_val[11:8], out_en[3:0] */
#define CRL_APB_BOOTPIN_CTRL_MASK 0xF0FU
static bool feature_check_enabled;
static DEFINE_HASHTABLE(pm_api_features_map, PM_API_FEATURE_CHECK_MAX_ORDER);
......@@ -942,6 +949,45 @@ int zynqmp_pm_pinctrl_set_config(const u32 pin, const u32 param,
}
EXPORT_SYMBOL_GPL(zynqmp_pm_pinctrl_set_config);
/**
* zynqmp_pm_bootmode_read() - PM Config API for read bootpin status
* @ps_mode: Returned output value of ps_mode
*
* This API function is to be used for notify the power management controller
* to read bootpin status.
*
* Return: status, either success or error+reason
*/
unsigned int zynqmp_pm_bootmode_read(u32 *ps_mode)
{
unsigned int ret;
u32 ret_payload[PAYLOAD_ARG_CNT];
ret = zynqmp_pm_invoke_fn(PM_MMIO_READ, CRL_APB_BOOT_PIN_CTRL, 0,
0, 0, ret_payload);
*ps_mode = ret_payload[1];
return ret;
}
EXPORT_SYMBOL_GPL(zynqmp_pm_bootmode_read);
/**
* zynqmp_pm_bootmode_write() - PM Config API for Configure bootpin
* @ps_mode: Value to be written to the bootpin ctrl register
*
* This API function is to be used for notify the power management controller
* to configure bootpin.
*
* Return: Returns status, either success or error+reason
*/
int zynqmp_pm_bootmode_write(u32 ps_mode)
{
return zynqmp_pm_invoke_fn(PM_MMIO_WRITE, CRL_APB_BOOT_PIN_CTRL,
CRL_APB_BOOTPIN_CTRL_MASK, ps_mode, 0, NULL);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_bootmode_write);
/**
* zynqmp_pm_init_finalize() - PM call to inform firmware that the caller
* master has initialized its own power management
......
This diff is collapsed.
......@@ -184,3 +184,4 @@ obj-$(CONFIG_GPIO_XRA1403) += gpio-xra1403.o
obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o
obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o
obj-$(CONFIG_GPIO_ZYNQ) += gpio-zynq.o
obj-$(CONFIG_GPIO_ZYNQMP_MODEPIN) += gpio-zynqmp-modepin.o
......@@ -247,6 +247,11 @@ struct gpiochip_fwd {
unsigned long tmp[]; /* values and descs for multiple ops */
};
#define fwd_tmp_values(fwd) &(fwd)->tmp[0]
#define fwd_tmp_descs(fwd) (void *)&(fwd)->tmp[BITS_TO_LONGS((fwd)->chip.ngpio)]
#define fwd_tmp_size(ngpios) (BITS_TO_LONGS((ngpios)) + (ngpios))
static int gpio_fwd_get_direction(struct gpio_chip *chip, unsigned int offset)
{
struct gpiochip_fwd *fwd = gpiochip_get_data(chip);
......@@ -279,15 +284,11 @@ static int gpio_fwd_get(struct gpio_chip *chip, unsigned int offset)
static int gpio_fwd_get_multiple(struct gpiochip_fwd *fwd, unsigned long *mask,
unsigned long *bits)
{
struct gpio_desc **descs;
unsigned long *values;
struct gpio_desc **descs = fwd_tmp_descs(fwd);
unsigned long *values = fwd_tmp_values(fwd);
unsigned int i, j = 0;
int error;
/* Both values bitmap and desc pointers are stored in tmp[] */
values = &fwd->tmp[0];
descs = (void *)&fwd->tmp[BITS_TO_LONGS(fwd->chip.ngpio)];
bitmap_clear(values, 0, fwd->chip.ngpio);
for_each_set_bit(i, mask, fwd->chip.ngpio)
descs[j++] = fwd->descs[i];
......@@ -333,14 +334,10 @@ static void gpio_fwd_set(struct gpio_chip *chip, unsigned int offset, int value)
static void gpio_fwd_set_multiple(struct gpiochip_fwd *fwd, unsigned long *mask,
unsigned long *bits)
{
struct gpio_desc **descs;
unsigned long *values;
struct gpio_desc **descs = fwd_tmp_descs(fwd);
unsigned long *values = fwd_tmp_values(fwd);
unsigned int i, j = 0;
/* Both values bitmap and desc pointers are stored in tmp[] */
values = &fwd->tmp[0];
descs = (void *)&fwd->tmp[BITS_TO_LONGS(fwd->chip.ngpio)];
for_each_set_bit(i, mask, fwd->chip.ngpio) {
__assign_bit(j, values, test_bit(i, bits));
descs[j++] = fwd->descs[i];
......@@ -398,8 +395,8 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev,
unsigned int i;
int error;
fwd = devm_kzalloc(dev, struct_size(fwd, tmp,
BITS_TO_LONGS(ngpios) + ngpios), GFP_KERNEL);
fwd = devm_kzalloc(dev, struct_size(fwd, tmp, fwd_tmp_size(ngpios)),
GFP_KERNEL);
if (!fwd)
return ERR_PTR(-ENOMEM);
......
......@@ -50,7 +50,9 @@ static int max7300_probe(struct i2c_client *client,
static int max7300_remove(struct i2c_client *client)
{
return __max730x_remove(&client->dev);
__max730x_remove(&client->dev);
return 0;
}
static const struct i2c_device_id max7300_id[] = {
......
......@@ -66,7 +66,9 @@ static int max7301_probe(struct spi_device *spi)
static int max7301_remove(struct spi_device *spi)
{
return __max730x_remove(&spi->dev);
__max730x_remove(&spi->dev);
return 0;
}
static const struct spi_device_id max7301_id[] = {
......
......@@ -220,18 +220,14 @@ int __max730x_probe(struct max7301 *ts)
}
EXPORT_SYMBOL_GPL(__max730x_probe);
int __max730x_remove(struct device *dev)
void __max730x_remove(struct device *dev)
{
struct max7301 *ts = dev_get_drvdata(dev);
if (ts == NULL)
return -ENODEV;
/* Power down the chip and disable IRQ output */
ts->write(dev, 0x04, 0x00);
gpiochip_remove(&ts->chip);
mutex_destroy(&ts->lock);
return 0;
}
EXPORT_SYMBOL_GPL(__max730x_remove);
......
......@@ -365,5 +365,4 @@ module_platform_driver(max77620_gpio_driver);
MODULE_DESCRIPTION("GPIO interface for MAX77620 and MAX20024 PMIC");
MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
MODULE_AUTHOR("Chaitanya Bandi <bandik@nvidia.com>");
MODULE_ALIAS("platform:max77620-gpio");
MODULE_LICENSE("GPL v2");
......@@ -139,8 +139,6 @@ static int mc33880_remove(struct spi_device *spi)
struct mc33880 *mc;
mc = spi_get_drvdata(spi);
if (!mc)
return -ENODEV;
gpiochip_remove(&mc->chip);
mutex_destroy(&mc->lock);
......
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2020-2021 NVIDIA CORPORATION & AFFILIATES
*/
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/gpio/driver.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
......@@ -43,9 +48,14 @@
#define YU_GPIO_MODE0 0x0c
#define YU_GPIO_DATASET 0x14
#define YU_GPIO_DATACLEAR 0x18
#define YU_GPIO_CAUSE_RISE_EN 0x44
#define YU_GPIO_CAUSE_FALL_EN 0x48
#define YU_GPIO_MODE1_CLEAR 0x50
#define YU_GPIO_MODE0_SET 0x54
#define YU_GPIO_MODE0_CLEAR 0x58
#define YU_GPIO_CAUSE_OR_CAUSE_EVTEN0 0x80
#define YU_GPIO_CAUSE_OR_EVTEN0 0x94
#define YU_GPIO_CAUSE_OR_CLRCAUSE 0x98
struct mlxbf2_gpio_context_save_regs {
u32 gpio_mode0;
......@@ -55,6 +65,7 @@ struct mlxbf2_gpio_context_save_regs {
/* BlueField-2 gpio block context structure. */
struct mlxbf2_gpio_context {
struct gpio_chip gc;
struct irq_chip irq_chip;
/* YU GPIO blocks address */
void __iomem *gpio_io;
......@@ -218,15 +229,114 @@ static int mlxbf2_gpio_direction_output(struct gpio_chip *chip,
return ret;
}
static void mlxbf2_gpio_irq_enable(struct irq_data *irqd)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
struct mlxbf2_gpio_context *gs = gpiochip_get_data(gc);
int offset = irqd_to_hwirq(irqd);
unsigned long flags;
u32 val;
spin_lock_irqsave(&gs->gc.bgpio_lock, flags);
val = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_CLRCAUSE);
val |= BIT(offset);
writel(val, gs->gpio_io + YU_GPIO_CAUSE_OR_CLRCAUSE);
val = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0);
val |= BIT(offset);
writel(val, gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0);
spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags);
}
static void mlxbf2_gpio_irq_disable(struct irq_data *irqd)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
struct mlxbf2_gpio_context *gs = gpiochip_get_data(gc);
int offset = irqd_to_hwirq(irqd);
unsigned long flags;
u32 val;
spin_lock_irqsave(&gs->gc.bgpio_lock, flags);
val = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0);
val &= ~BIT(offset);
writel(val, gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0);
spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags);
}
static irqreturn_t mlxbf2_gpio_irq_handler(int irq, void *ptr)
{
struct mlxbf2_gpio_context *gs = ptr;
struct gpio_chip *gc = &gs->gc;
unsigned long pending;
u32 level;
pending = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_CAUSE_EVTEN0);
writel(pending, gs->gpio_io + YU_GPIO_CAUSE_OR_CLRCAUSE);
for_each_set_bit(level, &pending, gc->ngpio) {
int gpio_irq = irq_find_mapping(gc->irq.domain, level);
generic_handle_irq(gpio_irq);
}
return IRQ_RETVAL(pending);
}
static int
mlxbf2_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
struct mlxbf2_gpio_context *gs = gpiochip_get_data(gc);
int offset = irqd_to_hwirq(irqd);
unsigned long flags;
bool fall = false;
bool rise = false;
u32 val;
switch (type & IRQ_TYPE_SENSE_MASK) {
case IRQ_TYPE_EDGE_BOTH:
fall = true;
rise = true;
break;
case IRQ_TYPE_EDGE_RISING:
rise = true;
break;
case IRQ_TYPE_EDGE_FALLING:
fall = true;
break;
default:
return -EINVAL;
}
spin_lock_irqsave(&gs->gc.bgpio_lock, flags);
if (fall) {
val = readl(gs->gpio_io + YU_GPIO_CAUSE_FALL_EN);
val |= BIT(offset);
writel(val, gs->gpio_io + YU_GPIO_CAUSE_FALL_EN);
}
if (rise) {
val = readl(gs->gpio_io + YU_GPIO_CAUSE_RISE_EN);
val |= BIT(offset);
writel(val, gs->gpio_io + YU_GPIO_CAUSE_RISE_EN);
}
spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags);
return 0;
}
/* BlueField-2 GPIO driver initialization routine. */
static int
mlxbf2_gpio_probe(struct platform_device *pdev)
{
struct mlxbf2_gpio_context *gs;
struct device *dev = &pdev->dev;
struct gpio_irq_chip *girq;
struct gpio_chip *gc;
unsigned int npins;
int ret;
const char *name;
int ret, irq;
name = dev_name(dev);
gs = devm_kzalloc(dev, sizeof(*gs), GFP_KERNEL);
if (!gs)
......@@ -266,6 +376,34 @@ mlxbf2_gpio_probe(struct platform_device *pdev)
gc->ngpio = npins;
gc->owner = THIS_MODULE;
irq = platform_get_irq(pdev, 0);
if (irq >= 0) {
gs->irq_chip.name = name;
gs->irq_chip.irq_set_type = mlxbf2_gpio_irq_set_type;
gs->irq_chip.irq_enable = mlxbf2_gpio_irq_enable;
gs->irq_chip.irq_disable = mlxbf2_gpio_irq_disable;
girq = &gs->gc.irq;
girq->chip = &gs->irq_chip;
girq->handler = handle_simple_irq;
girq->default_type = IRQ_TYPE_NONE;
/* This will let us handle the parent IRQ in the driver */
girq->num_parents = 0;
girq->parents = NULL;
girq->parent_handler = NULL;
/*
* Directly request the irq here instead of passing
* a flow-handler because the irq is shared.
*/
ret = devm_request_irq(dev, irq, mlxbf2_gpio_irq_handler,
IRQF_SHARED, name, gs);
if (ret) {
dev_err(dev, "failed to request IRQ");
return ret;
}
}
platform_set_drvdata(pdev, gs);
ret = devm_gpiochip_add_data(dev, &gs->gc, gs);
......@@ -320,5 +458,5 @@ static struct platform_driver mlxbf2_gpio_driver = {
module_platform_driver(mlxbf2_gpio_driver);
MODULE_DESCRIPTION("Mellanox BlueField-2 GPIO Driver");
MODULE_AUTHOR("Mellanox Technologies");
MODULE_AUTHOR("Asmaa Mnebhi <asmaa@nvidia.com>");
MODULE_LICENSE("GPL v2");
......@@ -205,7 +205,7 @@ static void realtek_gpio_irq_handler(struct irq_desc *desc)
status = realtek_gpio_read_isr(ctrl, lines_done / 8);
port_pin_count = min(gc->ngpio - lines_done, 8U);
for_each_set_bit(offset, &status, port_pin_count)
generic_handle_domain_irq(gc->irq.domain, offset);
generic_handle_domain_irq(gc->irq.domain, offset + lines_done);
}
chained_irq_exit(irq_chip, desc);
......
......@@ -69,6 +69,8 @@ struct tegra_gpio_soc {
const char *name;
unsigned int instance;
unsigned int num_irqs_per_bank;
const struct tegra186_pin_range *pin_ranges;
unsigned int num_pin_ranges;
const char *pinmux;
......@@ -81,6 +83,8 @@ struct tegra_gpio {
unsigned int *irq;
const struct tegra_gpio_soc *soc;
unsigned int num_irqs_per_bank;
unsigned int num_banks;
void __iomem *secure;
void __iomem *base;
......@@ -450,7 +454,7 @@ static void tegra186_gpio_irq(struct irq_desc *desc)
struct irq_domain *domain = gpio->gpio.irq.domain;
struct irq_chip *chip = irq_desc_get_chip(desc);
unsigned int parent = irq_desc_get_irq(desc);
unsigned int i, offset = 0;
unsigned int i, j, offset = 0;
chained_irq_enter(chip, desc);
......@@ -463,7 +467,12 @@ static void tegra186_gpio_irq(struct irq_desc *desc)
base = gpio->base + port->bank * 0x1000 + port->port * 0x200;
/* skip ports that are not associated with this bank */
if (parent != gpio->irq[port->bank])
for (j = 0; j < gpio->num_irqs_per_bank; j++) {
if (parent == gpio->irq[port->bank * gpio->num_irqs_per_bank + j])
break;
}
if (j == gpio->num_irqs_per_bank)
goto skip;
value = readl(base + TEGRA186_GPIO_INTERRUPT_STATUS(1));
......@@ -565,6 +574,7 @@ static const struct of_device_id tegra186_pmc_of_match[] = {
static void tegra186_gpio_init_route_mapping(struct tegra_gpio *gpio)
{
struct device *dev = gpio->gpio.parent;
unsigned int i, j;
u32 value;
......@@ -583,17 +593,60 @@ static void tegra186_gpio_init_route_mapping(struct tegra_gpio *gpio)
*/
if ((value & TEGRA186_GPIO_CTL_SCR_SEC_REN) == 0 &&
(value & TEGRA186_GPIO_CTL_SCR_SEC_WEN) == 0) {
for (j = 0; j < 8; j++) {
/*
* On Tegra194 and later, each pin can be routed to one or more
* interrupts.
*/
for (j = 0; j < gpio->num_irqs_per_bank; j++) {
dev_dbg(dev, "programming default interrupt routing for port %s\n",
port->name);
offset = TEGRA186_GPIO_INT_ROUTE_MAPPING(p, j);
value = readl(base + offset);
value = BIT(port->pins) - 1;
writel(value, base + offset);
/*
* By default we only want to route GPIO pins to IRQ 0. This works
* only under the assumption that we're running as the host kernel
* and hence all GPIO pins are owned by Linux.
*
* For cases where Linux is the guest OS, the hypervisor will have
* to configure the interrupt routing and pass only the valid
* interrupts via device tree.
*/
if (j == 0) {
value = readl(base + offset);
value = BIT(port->pins) - 1;
writel(value, base + offset);
}
}
}
}
}
static unsigned int tegra186_gpio_irqs_per_bank(struct tegra_gpio *gpio)
{
struct device *dev = gpio->gpio.parent;
if (gpio->num_irq > gpio->num_banks) {
if (gpio->num_irq % gpio->num_banks != 0)
goto error;
}
if (gpio->num_irq < gpio->num_banks)
goto error;
gpio->num_irqs_per_bank = gpio->num_irq / gpio->num_banks;
if (gpio->num_irqs_per_bank > gpio->soc->num_irqs_per_bank)
goto error;
return 0;
error:
dev_err(dev, "invalid number of interrupts (%u) for %u banks\n",
gpio->num_irq, gpio->num_banks);
return -EINVAL;
}
static int tegra186_gpio_probe(struct platform_device *pdev)
{
unsigned int i, j, offset;
......@@ -608,7 +661,17 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
return -ENOMEM;
gpio->soc = device_get_match_data(&pdev->dev);
gpio->gpio.label = gpio->soc->name;
gpio->gpio.parent = &pdev->dev;
/* count the number of banks in the controller */
for (i = 0; i < gpio->soc->num_ports; i++)
if (gpio->soc->ports[i].bank > gpio->num_banks)
gpio->num_banks = gpio->soc->ports[i].bank;
gpio->num_banks++;
/* get register apertures */
gpio->secure = devm_platform_ioremap_resource_byname(pdev, "security");
if (IS_ERR(gpio->secure)) {
gpio->secure = devm_platform_ioremap_resource(pdev, 0);
......@@ -629,6 +692,10 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
gpio->num_irq = err;
err = tegra186_gpio_irqs_per_bank(gpio);
if (err < 0)
return err;
gpio->irq = devm_kcalloc(&pdev->dev, gpio->num_irq, sizeof(*gpio->irq),
GFP_KERNEL);
if (!gpio->irq)
......@@ -642,9 +709,6 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
gpio->irq[i] = err;
}
gpio->gpio.label = gpio->soc->name;
gpio->gpio.parent = &pdev->dev;
gpio->gpio.request = gpiochip_generic_request;
gpio->gpio.free = gpiochip_generic_free;
gpio->gpio.get_direction = tegra186_gpio_get_direction;
......@@ -708,7 +772,31 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
irq->parent_handler = tegra186_gpio_irq;
irq->parent_handler_data = gpio;
irq->num_parents = gpio->num_irq;
irq->parents = gpio->irq;
/*
* To simplify things, use a single interrupt per bank for now. Some
* chips support up to 8 interrupts per bank, which can be useful to
* distribute the load and decrease the processing latency for GPIOs
* but it also requires a more complicated interrupt routing than we
* currently program.
*/
if (gpio->num_irqs_per_bank > 1) {
irq->parents = devm_kcalloc(&pdev->dev, gpio->num_banks,
sizeof(*irq->parents), GFP_KERNEL);
if (!irq->parents)
return -ENOMEM;
for (i = 0; i < gpio->num_banks; i++)
irq->parents[i] = gpio->irq[i * gpio->num_irqs_per_bank];
irq->num_parents = gpio->num_banks;
} else {
irq->num_parents = gpio->num_irq;
irq->parents = gpio->irq;
}
if (gpio->soc->num_irqs_per_bank > 1)
tegra186_gpio_init_route_mapping(gpio);
np = of_find_matching_node(NULL, tegra186_pmc_of_match);
if (np) {
......@@ -719,8 +807,6 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
return -EPROBE_DEFER;
}
tegra186_gpio_init_route_mapping(gpio);
irq->map = devm_kcalloc(&pdev->dev, gpio->gpio.ngpio,
sizeof(*irq->map), GFP_KERNEL);
if (!irq->map)
......@@ -777,6 +863,7 @@ static const struct tegra_gpio_soc tegra186_main_soc = {
.ports = tegra186_main_ports,
.name = "tegra186-gpio",
.instance = 0,
.num_irqs_per_bank = 1,
};
#define TEGRA186_AON_GPIO_PORT(_name, _bank, _port, _pins) \
......@@ -803,6 +890,7 @@ static const struct tegra_gpio_soc tegra186_aon_soc = {
.ports = tegra186_aon_ports,
.name = "tegra186-gpio-aon",
.instance = 1,
.num_irqs_per_bank = 1,
};
#define TEGRA194_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \
......@@ -854,6 +942,7 @@ static const struct tegra_gpio_soc tegra194_main_soc = {
.ports = tegra194_main_ports,
.name = "tegra194-gpio",
.instance = 0,
.num_irqs_per_bank = 8,
.num_pin_ranges = ARRAY_SIZE(tegra194_main_pin_ranges),
.pin_ranges = tegra194_main_pin_ranges,
.pinmux = "nvidia,tegra194-pinmux",
......@@ -880,6 +969,7 @@ static const struct tegra_gpio_soc tegra194_aon_soc = {
.ports = tegra194_aon_ports,
.name = "tegra194-gpio-aon",
.instance = 1,
.num_irqs_per_bank = 8,
};
static const struct of_device_id tegra186_gpio_of_match[] = {
......
......@@ -230,4 +230,3 @@ module_platform_driver(tps65218_gpio_driver);
MODULE_AUTHOR("Nicolas Saenz Julienne <nicolassaenzj@gmail.com>");
MODULE_DESCRIPTION("GPO interface for TPS65218 PMICs");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:tps65218-gpio");
......@@ -179,8 +179,8 @@ static int uniphier_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
static void uniphier_gpio_irq_mask(struct irq_data *data)
{
struct uniphier_gpio_priv *priv = data->chip_data;
u32 mask = BIT(data->hwirq);
struct uniphier_gpio_priv *priv = irq_data_get_irq_chip_data(data);
u32 mask = BIT(irqd_to_hwirq(data));
uniphier_gpio_reg_update(priv, UNIPHIER_GPIO_IRQ_EN, mask, 0);
......@@ -189,8 +189,8 @@ static void uniphier_gpio_irq_mask(struct irq_data *data)
static void uniphier_gpio_irq_unmask(struct irq_data *data)
{
struct uniphier_gpio_priv *priv = data->chip_data;
u32 mask = BIT(data->hwirq);
struct uniphier_gpio_priv *priv = irq_data_get_irq_chip_data(data);
u32 mask = BIT(irqd_to_hwirq(data));
uniphier_gpio_reg_update(priv, UNIPHIER_GPIO_IRQ_EN, mask, mask);
......@@ -199,8 +199,8 @@ static void uniphier_gpio_irq_unmask(struct irq_data *data)
static int uniphier_gpio_irq_set_type(struct irq_data *data, unsigned int type)
{
struct uniphier_gpio_priv *priv = data->chip_data;
u32 mask = BIT(data->hwirq);
struct uniphier_gpio_priv *priv = irq_data_get_irq_chip_data(data);
u32 mask = BIT(irqd_to_hwirq(data));
u32 val = 0;
if (type == IRQ_TYPE_EDGE_BOTH) {
......@@ -297,7 +297,8 @@ static int uniphier_gpio_irq_domain_activate(struct irq_domain *domain,
struct uniphier_gpio_priv *priv = domain->host_data;
struct gpio_chip *chip = &priv->chip;
return gpiochip_lock_as_irq(chip, data->hwirq + UNIPHIER_GPIO_IRQ_OFFSET);
return gpiochip_lock_as_irq(chip,
irqd_to_hwirq(data) + UNIPHIER_GPIO_IRQ_OFFSET);
}
static void uniphier_gpio_irq_domain_deactivate(struct irq_domain *domain,
......@@ -306,7 +307,8 @@ static void uniphier_gpio_irq_domain_deactivate(struct irq_domain *domain,
struct uniphier_gpio_priv *priv = domain->host_data;
struct gpio_chip *chip = &priv->chip;
gpiochip_unlock_as_irq(chip, data->hwirq + UNIPHIER_GPIO_IRQ_OFFSET);
gpiochip_unlock_as_irq(chip,
irqd_to_hwirq(data) + UNIPHIER_GPIO_IRQ_OFFSET);
}
static const struct irq_domain_ops uniphier_gpio_irq_domain_ops = {
......
This diff is collapsed.
......@@ -371,8 +371,7 @@ static int __maybe_unused xgpio_resume(struct device *dev)
static int __maybe_unused xgpio_runtime_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct xgpio_instance *gpio = platform_get_drvdata(pdev);
struct xgpio_instance *gpio = dev_get_drvdata(dev);
clk_disable(gpio->clk);
......@@ -381,8 +380,7 @@ static int __maybe_unused xgpio_runtime_suspend(struct device *dev)
static int __maybe_unused xgpio_runtime_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct xgpio_instance *gpio = platform_get_drvdata(pdev);
struct xgpio_instance *gpio = dev_get_drvdata(dev);
return clk_enable(gpio->clk);
}
......
// 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(&regval);
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", },
{ }
};
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");
......@@ -3,7 +3,6 @@
obj-$(CONFIG_MLXBF_GIGE) += mlxbf_gige.o
mlxbf_gige-y := mlxbf_gige_ethtool.o \
mlxbf_gige_gpio.o \
mlxbf_gige_intr.o \
mlxbf_gige_main.o \
mlxbf_gige_mdio.o \
......
......@@ -51,11 +51,6 @@
#define MLXBF_GIGE_ERROR_INTR_IDX 0
#define MLXBF_GIGE_RECEIVE_PKT_INTR_IDX 1
#define MLXBF_GIGE_LLU_PLU_INTR_IDX 2
#define MLXBF_GIGE_PHY_INT_N 3
#define MLXBF_GIGE_MDIO_DEFAULT_PHY_ADDR 0x3
#define MLXBF_GIGE_DEFAULT_PHY_INT_GPIO 12
struct mlxbf_gige_stats {
u64 hw_access_errors;
......@@ -81,11 +76,7 @@ struct mlxbf_gige {
struct platform_device *pdev;
void __iomem *mdio_io;
struct mii_bus *mdiobus;
void __iomem *gpio_io;
struct irq_domain *irqdomain;
u32 phy_int_gpio_mask;
spinlock_t lock; /* for packet processing indices */
spinlock_t gpio_lock; /* for GPIO bus access */
u16 rx_q_entries;
u16 tx_q_entries;
u64 *tx_wqe_base;
......@@ -184,7 +175,4 @@ int mlxbf_gige_poll(struct napi_struct *napi, int budget);
extern const struct ethtool_ops mlxbf_gige_ethtool_ops;
void mlxbf_gige_update_tx_wqe_next(struct mlxbf_gige *priv);
int mlxbf_gige_gpio_init(struct platform_device *pdev, struct mlxbf_gige *priv);
void mlxbf_gige_gpio_free(struct mlxbf_gige *priv);
#endif /* !defined(__MLXBF_GIGE_H__) */
// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
/* Initialize and handle GPIO interrupt triggered by INT_N PHY signal.
* This GPIO interrupt triggers the PHY state machine to bring the link
* up/down.
*
* Copyright (C) 2021 NVIDIA CORPORATION & AFFILIATES
*/
#include <linux/acpi.h>
#include <linux/bitfield.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/gpio/driver.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/irqreturn.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include "mlxbf_gige.h"
#include "mlxbf_gige_regs.h"
#define MLXBF_GIGE_GPIO_CAUSE_FALL_EN 0x48
#define MLXBF_GIGE_GPIO_CAUSE_OR_CAUSE_EVTEN0 0x80
#define MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0 0x94
#define MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE 0x98
static void mlxbf_gige_gpio_enable(struct mlxbf_gige *priv)
{
unsigned long flags;
u32 val;
spin_lock_irqsave(&priv->gpio_lock, flags);
val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE);
val |= priv->phy_int_gpio_mask;
writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE);
/* The INT_N interrupt level is active low.
* So enable cause fall bit to detect when GPIO
* state goes low.
*/
val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_FALL_EN);
val |= priv->phy_int_gpio_mask;
writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_FALL_EN);
/* Enable PHY interrupt by setting the priority level */
val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0);
val |= priv->phy_int_gpio_mask;
writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0);
spin_unlock_irqrestore(&priv->gpio_lock, flags);
}
static void mlxbf_gige_gpio_disable(struct mlxbf_gige *priv)
{
unsigned long flags;
u32 val;
spin_lock_irqsave(&priv->gpio_lock, flags);
val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0);
val &= ~priv->phy_int_gpio_mask;
writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0);
spin_unlock_irqrestore(&priv->gpio_lock, flags);
}
static irqreturn_t mlxbf_gige_gpio_handler(int irq, void *ptr)
{
struct mlxbf_gige *priv;
u32 val;
priv = ptr;
/* Check if this interrupt is from PHY device.
* Return if it is not.
*/
val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_CAUSE_EVTEN0);
if (!(val & priv->phy_int_gpio_mask))
return IRQ_NONE;
/* Clear interrupt when done, otherwise, no further interrupt
* will be triggered.
*/
val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE);
val |= priv->phy_int_gpio_mask;
writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE);
generic_handle_irq(priv->phy_irq);
return IRQ_HANDLED;
}
static void mlxbf_gige_gpio_mask(struct irq_data *irqd)
{
struct mlxbf_gige *priv = irq_data_get_irq_chip_data(irqd);
mlxbf_gige_gpio_disable(priv);
}
static void mlxbf_gige_gpio_unmask(struct irq_data *irqd)
{
struct mlxbf_gige *priv = irq_data_get_irq_chip_data(irqd);
mlxbf_gige_gpio_enable(priv);
}
static struct irq_chip mlxbf_gige_gpio_chip = {
.name = "mlxbf_gige_phy",
.irq_mask = mlxbf_gige_gpio_mask,
.irq_unmask = mlxbf_gige_gpio_unmask,
};
static int mlxbf_gige_gpio_domain_map(struct irq_domain *d,
unsigned int irq,
irq_hw_number_t hwirq)
{
irq_set_chip_data(irq, d->host_data);
irq_set_chip_and_handler(irq, &mlxbf_gige_gpio_chip, handle_simple_irq);
irq_set_noprobe(irq);
return 0;
}
static const struct irq_domain_ops mlxbf_gige_gpio_domain_ops = {
.map = mlxbf_gige_gpio_domain_map,
.xlate = irq_domain_xlate_twocell,
};
#ifdef CONFIG_ACPI
static int mlxbf_gige_gpio_resources(struct acpi_resource *ares,
void *data)
{
struct acpi_resource_gpio *gpio;
u32 *phy_int_gpio = data;
if (ares->type == ACPI_RESOURCE_TYPE_GPIO) {
gpio = &ares->data.gpio;
*phy_int_gpio = gpio->pin_table[0];
}
return 1;
}
#endif
void mlxbf_gige_gpio_free(struct mlxbf_gige *priv)
{
irq_dispose_mapping(priv->phy_irq);
irq_domain_remove(priv->irqdomain);
}
int mlxbf_gige_gpio_init(struct platform_device *pdev,
struct mlxbf_gige *priv)
{
struct device *dev = &pdev->dev;
struct resource *res;
u32 phy_int_gpio = 0;
int ret;
LIST_HEAD(resources);
res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_GPIO0);
if (!res)
return -ENODEV;
priv->gpio_io = devm_ioremap(dev, res->start, resource_size(res));
if (!priv->gpio_io)
return -ENOMEM;
#ifdef CONFIG_ACPI
ret = acpi_dev_get_resources(ACPI_COMPANION(dev),
&resources, mlxbf_gige_gpio_resources,
&phy_int_gpio);
acpi_dev_free_resource_list(&resources);
if (ret < 0 || !phy_int_gpio) {
dev_err(dev, "Error retrieving the gpio phy pin");
return -EINVAL;
}
#endif
priv->phy_int_gpio_mask = BIT(phy_int_gpio);
mlxbf_gige_gpio_disable(priv);
priv->hw_phy_irq = platform_get_irq(pdev, MLXBF_GIGE_PHY_INT_N);
priv->irqdomain = irq_domain_add_simple(NULL, 1, 0,
&mlxbf_gige_gpio_domain_ops,
priv);
if (!priv->irqdomain) {
dev_err(dev, "Failed to add IRQ domain\n");
return -ENOMEM;
}
priv->phy_irq = irq_create_mapping(priv->irqdomain, 0);
if (!priv->phy_irq) {
irq_domain_remove(priv->irqdomain);
priv->irqdomain = NULL;
dev_err(dev, "Error mapping PHY IRQ\n");
return -EINVAL;
}
ret = devm_request_irq(dev, priv->hw_phy_irq, mlxbf_gige_gpio_handler,
IRQF_ONESHOT | IRQF_SHARED, "mlxbf_gige_phy", priv);
if (ret) {
dev_err(dev, "Failed to request PHY IRQ");
mlxbf_gige_gpio_free(priv);
return ret;
}
return ret;
}
......@@ -280,8 +280,8 @@ static int mlxbf_gige_probe(struct platform_device *pdev)
void __iomem *llu_base;
void __iomem *plu_base;
void __iomem *base;
int addr, phy_irq;
u64 control;
int addr;
int err;
base = devm_platform_ioremap_resource(pdev, MLXBF_GIGE_RES_MAC);
......@@ -316,20 +316,12 @@ static int mlxbf_gige_probe(struct platform_device *pdev)
priv->pdev = pdev;
spin_lock_init(&priv->lock);
spin_lock_init(&priv->gpio_lock);
/* Attach MDIO device */
err = mlxbf_gige_mdio_probe(pdev, priv);
if (err)
return err;
err = mlxbf_gige_gpio_init(pdev, priv);
if (err) {
dev_err(&pdev->dev, "PHY IRQ initialization failed\n");
mlxbf_gige_mdio_remove(priv);
return -ENODEV;
}
priv->base = base;
priv->llu_base = llu_base;
priv->plu_base = plu_base;
......@@ -350,6 +342,12 @@ static int mlxbf_gige_probe(struct platform_device *pdev)
priv->rx_irq = platform_get_irq(pdev, MLXBF_GIGE_RECEIVE_PKT_INTR_IDX);
priv->llu_plu_irq = platform_get_irq(pdev, MLXBF_GIGE_LLU_PLU_INTR_IDX);
phy_irq = acpi_dev_gpio_irq_get_by(ACPI_COMPANION(&pdev->dev), "phy-gpios", 0);
if (phy_irq < 0) {
dev_err(&pdev->dev, "Error getting PHY irq. Use polling instead");
phy_irq = PHY_POLL;
}
phydev = phy_find_first(priv->mdiobus);
if (!phydev) {
err = -ENODEV;
......@@ -357,8 +355,8 @@ static int mlxbf_gige_probe(struct platform_device *pdev)
}
addr = phydev->mdio.addr;
priv->mdiobus->irq[addr] = priv->phy_irq;
phydev->irq = priv->phy_irq;
priv->mdiobus->irq[addr] = phy_irq;
phydev->irq = phy_irq;
err = phy_connect_direct(netdev, phydev,
mlxbf_gige_adjust_link,
......@@ -394,7 +392,6 @@ static int mlxbf_gige_probe(struct platform_device *pdev)
return 0;
out:
mlxbf_gige_gpio_free(priv);
mlxbf_gige_mdio_remove(priv);
return err;
}
......@@ -405,7 +402,6 @@ static int mlxbf_gige_remove(struct platform_device *pdev)
unregister_netdev(priv->netdev);
phy_disconnect(priv->netdev->phydev);
mlxbf_gige_gpio_free(priv);
mlxbf_gige_mdio_remove(priv);
platform_set_drvdata(pdev, NULL);
......
......@@ -72,6 +72,8 @@ enum pm_api_id {
PM_SET_REQUIREMENT = 15,
PM_RESET_ASSERT = 17,
PM_RESET_GET_STATUS = 18,
PM_MMIO_WRITE = 19,
PM_MMIO_READ = 20,
PM_PM_INIT_FINALIZE = 21,
PM_FPGA_LOAD = 22,
PM_FPGA_GET_STATUS = 23,
......@@ -397,6 +399,8 @@ int zynqmp_pm_ospi_mux_select(u32 dev_id, u32 select);
int zynqmp_pm_reset_assert(const enum zynqmp_pm_reset reset,
const enum zynqmp_pm_reset_action assert_flag);
int zynqmp_pm_reset_get_status(const enum zynqmp_pm_reset reset, u32 *status);
unsigned int zynqmp_pm_bootmode_read(u32 *ps_mode);
int zynqmp_pm_bootmode_write(u32 ps_mode);
int zynqmp_pm_init_finalize(void);
int zynqmp_pm_set_suspend_mode(u32 mode);
int zynqmp_pm_request_node(const u32 node, const u32 capabilities,
......@@ -532,6 +536,16 @@ static inline int zynqmp_pm_reset_get_status(const enum zynqmp_pm_reset reset,
return -ENODEV;
}
static inline unsigned int zynqmp_pm_bootmode_read(u32 *ps_mode)
{
return -ENODEV;
}
static inline int zynqmp_pm_bootmode_write(u32 ps_mode)
{
return -ENODEV;
}
static inline int zynqmp_pm_init_finalize(void)
{
return -ENODEV;
......
......@@ -31,6 +31,6 @@ struct max7301_platform_data {
u32 input_pullup_active;
};
extern int __max730x_remove(struct device *dev);
extern void __max730x_remove(struct device *dev);
extern int __max730x_probe(struct max7301 *ts);
#endif
......@@ -5,12 +5,16 @@
#include <linux/types.h>
/* Virtio GPIO Feature bits */
#define VIRTIO_GPIO_F_IRQ 0
/* Virtio GPIO request types */
#define VIRTIO_GPIO_MSG_GET_NAMES 0x0001
#define VIRTIO_GPIO_MSG_GET_DIRECTION 0x0002
#define VIRTIO_GPIO_MSG_SET_DIRECTION 0x0003
#define VIRTIO_GPIO_MSG_GET_VALUE 0x0004
#define VIRTIO_GPIO_MSG_SET_VALUE 0x0005
#define VIRTIO_GPIO_MSG_IRQ_TYPE 0x0006
/* Possible values of the status field */
#define VIRTIO_GPIO_STATUS_OK 0x0
......@@ -21,11 +25,19 @@
#define VIRTIO_GPIO_DIRECTION_OUT 0x01
#define VIRTIO_GPIO_DIRECTION_IN 0x02
/* Virtio GPIO IRQ types */
#define VIRTIO_GPIO_IRQ_TYPE_NONE 0x00
#define VIRTIO_GPIO_IRQ_TYPE_EDGE_RISING 0x01
#define VIRTIO_GPIO_IRQ_TYPE_EDGE_FALLING 0x02
#define VIRTIO_GPIO_IRQ_TYPE_EDGE_BOTH 0x03
#define VIRTIO_GPIO_IRQ_TYPE_LEVEL_HIGH 0x04
#define VIRTIO_GPIO_IRQ_TYPE_LEVEL_LOW 0x08
struct virtio_gpio_config {
__le16 ngpio;
__u8 padding[2];
__le32 gpio_names_size;
} __packed;
};
/* Virtio GPIO Request / Response */
struct virtio_gpio_request {
......@@ -44,4 +56,17 @@ struct virtio_gpio_response_get_names {
__u8 value[];
};
/* Virtio GPIO IRQ Request / Response */
struct virtio_gpio_irq_request {
__le16 gpio;
};
struct virtio_gpio_irq_response {
__u8 status;
};
/* Possible values of the interrupt status field */
#define VIRTIO_GPIO_IRQ_STATUS_INVALID 0x0
#define VIRTIO_GPIO_IRQ_STATUS_VALID 0x1
#endif /* _LINUX_VIRTIO_GPIO_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment