gpio updates for v5.15

- new driver: gpio-virtio allowing a guest VM running linux to access
   GPIO lines provided by the host
 - split the GPIO driver out of the rockchip pin control driver
 - add support for a new model to gpio-aspeed-sgpio, refactor the driver
   and use generic device property interfaces, improve property sanitization
 - add ACPI support to gpio-tegra186
 - improve the code setting the line names to support multiple GPIO banks
   per device
 - constify a bunch of OF functions in the core GPIO code and make the
   declaration for one of the core OF functions we use consistent within its
   header
 - use software nodes in intel_quark_i2c_gpio
 - add support for the gpio-line-names property in gpio-mt7621
 - use the standard GPIO function for setting the GPIO names in gpio-brcmstb
 - fix a bunch of leaks and other bugs in gpio-mpc8xxx
 - use generic pm callbacks in gpio-ml-ioh
 - improve resource management and PM handling in gpio-mlxbf2
 - modernize and improve the gpio-dwapb driver
 - coding style improvements in gpio-rcar
 - documentation fixes and improvements
 - update the MAINTAINERS entry for gpio-zynq
 - minor tweaks in several drivers
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEFp3rbAvDxGAT0sefEacuoBRx13IFAmE3ItgACgkQEacuoBRx
 13LKqA//Q2E9QYJx0lLO0C15JKzJjqYGyVqSm73Huo8pKWRSKr9YuB4/tBPKz5Ya
 pg/h7wbsk+mtQ0pqot/SEGVLo1rK6ZcPiCDkYkuaVsY9pS0zX7A/Sb2N7xKML+Nj
 wTFuhSZH2byxH6QgUrX3RLMagW4p/owlDvFjZ6Z6Vh8Ulsnb0pdL3nYg5L017GMT
 A1ySzbP79NK3LfOLTqdqgALv4EF2x+paolyEpI/Jv0naBYkIP4AcbOBQEVMpoCY/
 XEcIdPvqMyPm4PdYSy3iCqtkf7jclDbV030SHlir2bKHjI79l8ARy0Tu6hvISRSG
 8XMwt6ke40GYnPkESZTkWlqeVHYzli84FxYXYLnqFa/21c4qswHk/aZZq5h83fn8
 7aonkEQQuHfQM00MvLu0mhtKXYdLbqv7jjd0CYChwxQSpu0iu7IQSWW8c2YmGvvt
 vqfM8TdKyGNPAmSl2/enPKOr+LugG4rcgMehU9/p6QvHbB6y2SxC1MykldPOdC6d
 53PeDeNP6XOp2s10zVPWh6P0rbrMaEtv/GZ143kUw9bhb1g3woX5SaS7W76cOXhE
 kty6g1e8xNaKDZbJ++UAh7G9IGQdtz0xRCXDUHFUc89uCThc9RcHowNPtzMMnmgM
 ucWJ81XnGDSDyzzG/f7uhcOtszWYCOtFmteooaMGB36/pH2CG9Y=
 =y/RY
 -----END PGP SIGNATURE-----

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

Pull gpio updates from Bartosz Golaszewski:
 "We mostly have various improvements and refactoring all over the place
  but also some interesting new features - like the virtio GPIO driver
  that allows guest VMs to use host's GPIOs. We also have a new/old GPIO
  driver for rockchip - this one has been split out of the pinctrl
  driver.

  Summary:

   - new driver: gpio-virtio allowing a guest VM running linux to access
     GPIO lines provided by the host

   - split the GPIO driver out of the rockchip pin control driver

   - add support for a new model to gpio-aspeed-sgpio, refactor the
     driver and use generic device property interfaces, improve property
     sanitization

   - add ACPI support to gpio-tegra186

   - improve the code setting the line names to support multiple GPIO
     banks per device

   - constify a bunch of OF functions in the core GPIO code and make the
     declaration for one of the core OF functions we use consistent
     within its header

   - use software nodes in intel_quark_i2c_gpio

   - add support for the gpio-line-names property in gpio-mt7621

   - use the standard GPIO function for setting the GPIO names in
     gpio-brcmstb

   - fix a bunch of leaks and other bugs in gpio-mpc8xxx

   - use generic pm callbacks in gpio-ml-ioh

   - improve resource management and PM handling in gpio-mlxbf2

   - modernize and improve the gpio-dwapb driver

   - coding style improvements in gpio-rcar

   - documentation fixes and improvements

   - update the MAINTAINERS entry for gpio-zynq

   - minor tweaks in several drivers"

* tag 'gpio-updates-for-v5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux: (35 commits)
  gpio: mpc8xxx: Use 'devm_gpiochip_add_data()' to simplify the code and avoid a leak
  gpio: mpc8xxx: Fix a potential double iounmap call in 'mpc8xxx_probe()'
  gpio: mpc8xxx: Fix a resources leak in the error handling path of 'mpc8xxx_probe()'
  gpio: viperboard: remove platform_set_drvdata() call in probe
  gpio: virtio: Add missing mailings lists in MAINTAINERS entry
  gpio: virtio: Fix sparse warnings
  gpio: remove the obsolete MX35 3DS BOARD MC9S08DZ60 GPIO functions
  gpio: max730x: Use the right include
  gpio: Add virtio-gpio driver
  gpio: mlxbf2: Use DEFINE_RES_MEM_NAMED() helper macro
  gpio: mlxbf2: Use devm_platform_ioremap_resource()
  gpio: mlxbf2: Drop wrong use of ACPI_PTR()
  gpio: mlxbf2: Convert to device PM ops
  gpio: dwapb: Get rid of legacy platform data
  mfd: intel_quark_i2c_gpio: Convert GPIO to use software nodes
  gpio: dwapb: Read GPIO base from gpio-base property
  gpio: dwapb: Unify ACPI enumeration checks in get_irq() and configure_irqs()
  gpiolib: Deduplicate forward declaration in the consumer.h header
  MAINTAINERS: update gpio-zynq.yaml reference
  gpio: tegra186: Add ACPI support
  ...
This commit is contained in:
Linus Torvalds 2021-09-07 12:27:27 -07:00
commit 5e6a5845dd
29 changed files with 752 additions and 447 deletions

View File

@ -72,6 +72,10 @@ for the GPIO. Values can be:
* GPIOD_OUT_HIGH_OPEN_DRAIN same as GPIOD_OUT_HIGH but also enforce the line
to be electrically used with open drain.
Note that the initial value is *logical* and the physical line level depends on
whether the line is configured active high or active low (see
:ref:`active_low_semantics`).
The two last flags are used for use cases where open drain is mandatory, such
as I2C: if the line is not already configured as open drain in the mappings
(see board.txt), then open drain will be enforced anyway and a warning will be
@ -252,6 +256,8 @@ that can't be accessed from hardIRQ handlers, these calls act the same as the
spinlock-safe calls.
.. _active_low_semantics:
The active low and open drain semantics
---------------------------------------
As a consumer should not have to care about the physical line level, all of the
@ -309,9 +315,11 @@ work on the raw line value::
void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value)
int gpiod_direction_output_raw(struct gpio_desc *desc, int value)
The active low state of a GPIO can also be queried using the following call::
The active low state of a GPIO can also be queried and toggled using the
following calls::
int gpiod_is_active_low(const struct gpio_desc *desc)
void gpiod_toggle_active_low(struct gpio_desc *desc)
Note that these functions should only be used with great moderation; a driver
should not have to care about the physical line level or open drain semantics.

View File

@ -547,13 +547,10 @@ To use the helpers please keep the following in mind:
the irqchip can initialize. E.g. .dev and .can_sleep shall be set up
properly.
- Nominally set all handlers to handle_bad_irq() in the setup call and pass
handle_bad_irq() as flow handler parameter in gpiochip_irqchip_add() if it is
expected for GPIO driver that irqchip .set_type() callback will be called
before using/enabling each GPIO IRQ. Then set the handler to
handle_level_irq() and/or handle_edge_irq() in the irqchip .set_type()
callback depending on what your controller supports and what is requested
by the consumer.
- Nominally set gpio_irq_chip.handler to handle_bad_irq. Then, if your irqchip
is cascaded, set the handler to handle_level_irq() and/or handle_edge_irq()
in the irqchip .set_type() callback depending on what your controller
supports and what is requested by the consumer.
Locking IRQ usage

View File

@ -19852,6 +19852,15 @@ F: Documentation/filesystems/virtiofs.rst
F: fs/fuse/virtio_fs.c
F: include/uapi/linux/virtio_fs.h
VIRTIO GPIO DRIVER
M: Enrico Weigelt, metux IT consult <info@metux.net>
M: Viresh Kumar <vireshk@kernel.org>
L: linux-gpio@vger.kernel.org
L: virtualization@lists.linux-foundation.org
S: Maintained
F: drivers/gpio/gpio-virtio.c
F: include/uapi/linux/virtio_gpio.h
VIRTIO GPU DRIVER
M: David Airlie <airlied@linux.ie>
M: Gerd Hoffmann <kraxel@redhat.com>
@ -20546,7 +20555,7 @@ R: Srinivas Neeli <srinivas.neeli@xilinx.com>
R: Michal Simek <michal.simek@xilinx.com>
S: Maintained
F: Documentation/devicetree/bindings/gpio/gpio-xilinx.txt
F: Documentation/devicetree/bindings/gpio/gpio-zynq.txt
F: Documentation/devicetree/bindings/gpio/gpio-zynq.yaml
F: drivers/gpio/gpio-xilinx.c
F: drivers/gpio/gpio-zynq.c

View File

@ -1018,12 +1018,6 @@ config GPIO_MAX732X_IRQ
Say yes here to enable the max732x to be used as an interrupt
controller. It requires the driver to be built in the kernel.
config GPIO_MC9S08DZ60
bool "MX35 3DS BOARD MC9S08DZ60 GPIO functions"
depends on I2C=y && MACH_MX35_3DS
help
Select this to enable the MC9S08DZ60 GPIO driver
config GPIO_PCA953X
tristate "PCA95[357]x, PCA9698, TCA64xx, and MAX7310 I/O ports"
select REGMAP_I2C
@ -1677,6 +1671,15 @@ config GPIO_MOCKUP
tools/testing/selftests/gpio/gpio-mockup.sh. Reference the usage in
it.
config GPIO_VIRTIO
tristate "VirtIO GPIO support"
depends on VIRTIO
help
Say Y here to enable guest support for virtio-based GPIO controllers.
These virtual GPIOs can be routed to real GPIOs or attached to
simulators on the host (like QEMU).
endmenu
endif

View File

@ -92,7 +92,6 @@ obj-$(CONFIG_GPIO_MAX77620) += gpio-max77620.o
obj-$(CONFIG_GPIO_MAX77650) += gpio-max77650.o
obj-$(CONFIG_GPIO_MB86S7X) += gpio-mb86s7x.o
obj-$(CONFIG_GPIO_MC33880) += gpio-mc33880.o
obj-$(CONFIG_GPIO_MC9S08DZ60) += gpio-mc9s08dz60.o
obj-$(CONFIG_GPIO_MENZ127) += gpio-menz127.o
obj-$(CONFIG_GPIO_MERRIFIELD) += gpio-merrifield.o
obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o
@ -166,6 +165,7 @@ obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o
obj-$(CONFIG_GPIO_UNIPHIER) += gpio-uniphier.o
obj-$(CONFIG_GPIO_VF610) += gpio-vf610.o
obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o
obj-$(CONFIG_GPIO_VIRTIO) += gpio-virtio.o
obj-$(CONFIG_GPIO_VISCONTI) += gpio-visconti.o
obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o
obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o

View File

@ -17,37 +17,30 @@
#include <linux/spinlock.h>
#include <linux/string.h>
/*
* MAX_NR_HW_GPIO represents the number of actual hardware-supported GPIOs (ie,
* slots within the clocked serial GPIO data). Since each HW GPIO is both an
* input and an output, we provide MAX_NR_HW_GPIO * 2 lines on our gpiochip
* device.
*
* We use SGPIO_OUTPUT_OFFSET to define the split between the inputs and
* outputs; the inputs start at line 0, the outputs start at OUTPUT_OFFSET.
*/
#define MAX_NR_HW_SGPIO 80
#define SGPIO_OUTPUT_OFFSET MAX_NR_HW_SGPIO
#define ASPEED_SGPIO_CTRL 0x54
#define ASPEED_SGPIO_PINS_MASK GENMASK(9, 6)
#define ASPEED_SGPIO_CLK_DIV_MASK GENMASK(31, 16)
#define ASPEED_SGPIO_ENABLE BIT(0)
#define ASPEED_SGPIO_PINS_SHIFT 6
struct aspeed_sgpio_pdata {
const u32 pin_mask;
};
struct aspeed_sgpio {
struct gpio_chip chip;
struct irq_chip intc;
struct clk *pclk;
spinlock_t lock;
void __iomem *base;
int irq;
int n_sgpio;
};
struct aspeed_sgpio_bank {
uint16_t val_regs;
uint16_t rdata_reg;
uint16_t irq_regs;
u16 val_regs;
u16 rdata_reg;
u16 irq_regs;
u16 tolerance_regs;
const char names[4][3];
};
@ -63,19 +56,29 @@ static const struct aspeed_sgpio_bank aspeed_sgpio_banks[] = {
.val_regs = 0x0000,
.rdata_reg = 0x0070,
.irq_regs = 0x0004,
.tolerance_regs = 0x0018,
.names = { "A", "B", "C", "D" },
},
{
.val_regs = 0x001C,
.rdata_reg = 0x0074,
.irq_regs = 0x0020,
.tolerance_regs = 0x0034,
.names = { "E", "F", "G", "H" },
},
{
.val_regs = 0x0038,
.rdata_reg = 0x0078,
.irq_regs = 0x003C,
.names = { "I", "J" },
.tolerance_regs = 0x0050,
.names = { "I", "J", "K", "L" },
},
{
.val_regs = 0x0090,
.rdata_reg = 0x007C,
.irq_regs = 0x0094,
.tolerance_regs = 0x00A8,
.names = { "M", "N", "O", "P" },
},
};
@ -87,6 +90,7 @@ enum aspeed_sgpio_reg {
reg_irq_type1,
reg_irq_type2,
reg_irq_status,
reg_tolerance,
};
#define GPIO_VAL_VALUE 0x00
@ -115,15 +119,17 @@ static void __iomem *bank_reg(struct aspeed_sgpio *gpio,
return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE2;
case reg_irq_status:
return gpio->base + bank->irq_regs + GPIO_IRQ_STATUS;
case reg_tolerance:
return gpio->base + bank->tolerance_regs;
default:
/* acturally if code runs to here, it's an error case */
BUG();
}
}
#define GPIO_BANK(x) ((x % SGPIO_OUTPUT_OFFSET) >> 5)
#define GPIO_OFFSET(x) ((x % SGPIO_OUTPUT_OFFSET) & 0x1f)
#define GPIO_BIT(x) BIT(GPIO_OFFSET(x))
#define GPIO_BANK(x) ((x) >> 6)
#define GPIO_OFFSET(x) ((x) & GENMASK(5, 0))
#define GPIO_BIT(x) BIT(GPIO_OFFSET(x) >> 1)
static const struct aspeed_sgpio_bank *to_bank(unsigned int offset)
{
@ -138,39 +144,25 @@ static const struct aspeed_sgpio_bank *to_bank(unsigned int offset)
static int aspeed_sgpio_init_valid_mask(struct gpio_chip *gc,
unsigned long *valid_mask, unsigned int ngpios)
{
struct aspeed_sgpio *sgpio = gpiochip_get_data(gc);
int n = sgpio->n_sgpio;
int c = SGPIO_OUTPUT_OFFSET - n;
WARN_ON(ngpios < MAX_NR_HW_SGPIO * 2);
/* input GPIOs in the lower range */
bitmap_set(valid_mask, 0, n);
bitmap_clear(valid_mask, n, c);
/* output GPIOS above SGPIO_OUTPUT_OFFSET */
bitmap_set(valid_mask, SGPIO_OUTPUT_OFFSET, n);
bitmap_clear(valid_mask, SGPIO_OUTPUT_OFFSET + n, c);
bitmap_set(valid_mask, 0, ngpios);
return 0;
}
static void aspeed_sgpio_irq_init_valid_mask(struct gpio_chip *gc,
unsigned long *valid_mask, unsigned int ngpios)
{
struct aspeed_sgpio *sgpio = gpiochip_get_data(gc);
int n = sgpio->n_sgpio;
unsigned int i;
WARN_ON(ngpios < MAX_NR_HW_SGPIO * 2);
/* input GPIOs in the lower range */
bitmap_set(valid_mask, 0, n);
bitmap_clear(valid_mask, n, ngpios - n);
/* input GPIOs are even bits */
for (i = 0; i < ngpios; i++) {
if (i % 2)
clear_bit(i, valid_mask);
}
}
static bool aspeed_sgpio_is_input(unsigned int offset)
{
return offset < SGPIO_OUTPUT_OFFSET;
return !(offset % 2);
}
static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset)
@ -409,14 +401,6 @@ static void aspeed_sgpio_irq_handler(struct irq_desc *desc)
chained_irq_exit(ic, desc);
}
static struct irq_chip aspeed_sgpio_irqchip = {
.name = "aspeed-sgpio",
.irq_ack = aspeed_sgpio_irq_ack,
.irq_mask = aspeed_sgpio_irq_mask,
.irq_unmask = aspeed_sgpio_irq_unmask,
.irq_set_type = aspeed_sgpio_set_type,
};
static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio,
struct platform_device *pdev)
{
@ -439,8 +423,14 @@ static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio,
iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_status));
}
gpio->intc.name = dev_name(&pdev->dev);
gpio->intc.irq_ack = aspeed_sgpio_irq_ack;
gpio->intc.irq_mask = aspeed_sgpio_irq_mask;
gpio->intc.irq_unmask = aspeed_sgpio_irq_unmask;
gpio->intc.irq_set_type = aspeed_sgpio_set_type;
irq = &gpio->chip.irq;
irq->chip = &aspeed_sgpio_irqchip;
irq->chip = &gpio->intc;
irq->init_valid_mask = aspeed_sgpio_irq_init_valid_mask;
irq->handler = handle_bad_irq;
irq->default_type = IRQ_TYPE_NONE;
@ -463,9 +453,56 @@ static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio,
return 0;
}
static const struct aspeed_sgpio_pdata ast2400_sgpio_pdata = {
.pin_mask = GENMASK(9, 6),
};
static int aspeed_sgpio_reset_tolerance(struct gpio_chip *chip,
unsigned int offset, bool enable)
{
struct aspeed_sgpio *gpio = gpiochip_get_data(chip);
unsigned long flags;
void __iomem *reg;
u32 val;
reg = bank_reg(gpio, to_bank(offset), reg_tolerance);
spin_lock_irqsave(&gpio->lock, flags);
val = readl(reg);
if (enable)
val |= GPIO_BIT(offset);
else
val &= ~GPIO_BIT(offset);
writel(val, reg);
spin_unlock_irqrestore(&gpio->lock, flags);
return 0;
}
static int aspeed_sgpio_set_config(struct gpio_chip *chip, unsigned int offset,
unsigned long config)
{
unsigned long param = pinconf_to_config_param(config);
u32 arg = pinconf_to_config_argument(config);
if (param == PIN_CONFIG_PERSIST_STATE)
return aspeed_sgpio_reset_tolerance(chip, offset, arg);
return -ENOTSUPP;
}
static const struct aspeed_sgpio_pdata ast2600_sgpiom_pdata = {
.pin_mask = GENMASK(10, 6),
};
static const struct of_device_id aspeed_sgpio_of_table[] = {
{ .compatible = "aspeed,ast2400-sgpio" },
{ .compatible = "aspeed,ast2500-sgpio" },
{ .compatible = "aspeed,ast2400-sgpio", .data = &ast2400_sgpio_pdata, },
{ .compatible = "aspeed,ast2500-sgpio", .data = &ast2400_sgpio_pdata, },
{ .compatible = "aspeed,ast2600-sgpiom", .data = &ast2600_sgpiom_pdata, },
{}
};
@ -473,10 +510,11 @@ MODULE_DEVICE_TABLE(of, aspeed_sgpio_of_table);
static int __init aspeed_sgpio_probe(struct platform_device *pdev)
{
u32 nr_gpios, sgpio_freq, sgpio_clk_div, gpio_cnt_regval, pin_mask;
const struct aspeed_sgpio_pdata *pdata;
struct aspeed_sgpio *gpio;
u32 nr_gpios, sgpio_freq, sgpio_clk_div;
int rc;
unsigned long apb_freq;
int rc;
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
if (!gpio)
@ -486,18 +524,23 @@ static int __init aspeed_sgpio_probe(struct platform_device *pdev)
if (IS_ERR(gpio->base))
return PTR_ERR(gpio->base);
rc = of_property_read_u32(pdev->dev.of_node, "ngpios", &nr_gpios);
pdata = device_get_match_data(&pdev->dev);
if (!pdata)
return -EINVAL;
pin_mask = pdata->pin_mask;
rc = device_property_read_u32(&pdev->dev, "ngpios", &nr_gpios);
if (rc < 0) {
dev_err(&pdev->dev, "Could not read ngpios property\n");
return -EINVAL;
} else if (nr_gpios > MAX_NR_HW_SGPIO) {
dev_err(&pdev->dev, "Number of GPIOs exceeds the maximum of %d: %d\n",
MAX_NR_HW_SGPIO, nr_gpios);
} else if (nr_gpios % 8) {
dev_err(&pdev->dev, "Number of GPIOs not multiple of 8: %d\n",
nr_gpios);
return -EINVAL;
}
gpio->n_sgpio = nr_gpios;
rc = of_property_read_u32(pdev->dev.of_node, "bus-frequency", &sgpio_freq);
rc = device_property_read_u32(&pdev->dev, "bus-frequency", &sgpio_freq);
if (rc < 0) {
dev_err(&pdev->dev, "Could not read bus-frequency property\n");
return -EINVAL;
@ -528,15 +571,14 @@ static int __init aspeed_sgpio_probe(struct platform_device *pdev)
if (sgpio_clk_div > (1 << 16) - 1)
return -EINVAL;
iowrite32(FIELD_PREP(ASPEED_SGPIO_CLK_DIV_MASK, sgpio_clk_div) |
FIELD_PREP(ASPEED_SGPIO_PINS_MASK, (nr_gpios / 8)) |
ASPEED_SGPIO_ENABLE,
gpio->base + ASPEED_SGPIO_CTRL);
gpio_cnt_regval = ((nr_gpios / 8) << ASPEED_SGPIO_PINS_SHIFT) & pin_mask;
iowrite32(FIELD_PREP(ASPEED_SGPIO_CLK_DIV_MASK, sgpio_clk_div) | gpio_cnt_regval |
ASPEED_SGPIO_ENABLE, gpio->base + ASPEED_SGPIO_CTRL);
spin_lock_init(&gpio->lock);
gpio->chip.parent = &pdev->dev;
gpio->chip.ngpio = MAX_NR_HW_SGPIO * 2;
gpio->chip.ngpio = nr_gpios * 2;
gpio->chip.init_valid_mask = aspeed_sgpio_init_valid_mask;
gpio->chip.direction_input = aspeed_sgpio_dir_in;
gpio->chip.direction_output = aspeed_sgpio_dir_out;
@ -545,7 +587,7 @@ static int __init aspeed_sgpio_probe(struct platform_device *pdev)
gpio->chip.free = NULL;
gpio->chip.get = aspeed_sgpio_get;
gpio->chip.set = aspeed_sgpio_set;
gpio->chip.set_config = NULL;
gpio->chip.set_config = aspeed_sgpio_set_config;
gpio->chip.label = dev_name(&pdev->dev);
gpio->chip.base = -1;

View File

@ -602,49 +602,6 @@ static const struct dev_pm_ops brcmstb_gpio_pm_ops = {
.resume_noirq = brcmstb_gpio_resume,
};
static void brcmstb_gpio_set_names(struct device *dev,
struct brcmstb_gpio_bank *bank)
{
struct device_node *np = dev->of_node;
const char **names;
int nstrings, base;
unsigned int i;
base = bank->id * MAX_GPIO_PER_BANK;
nstrings = of_property_count_strings(np, "gpio-line-names");
if (nstrings <= base)
/* Line names not present */
return;
names = devm_kcalloc(dev, MAX_GPIO_PER_BANK, sizeof(*names),
GFP_KERNEL);
if (!names)
return;
/*
* Make sure to not index beyond the end of the number of descriptors
* of the GPIO device.
*/
for (i = 0; i < bank->width; i++) {
const char *name;
int ret;
ret = of_property_read_string_index(np, "gpio-line-names",
base + i, &name);
if (ret) {
if (ret != -ENODATA)
dev_err(dev, "unable to name line %d: %d\n",
base + i, ret);
break;
}
if (*name)
names[i] = name;
}
bank->gc.names = names;
}
static int brcmstb_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@ -758,6 +715,7 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
gc->of_xlate = brcmstb_gpio_of_xlate;
/* not all ngpio lines are valid, will use bank width later */
gc->ngpio = MAX_GPIO_PER_BANK;
gc->offset = bank->id * MAX_GPIO_PER_BANK;
if (priv->parent_irq > 0)
gc->to_irq = brcmstb_gpio_to_irq;
@ -768,7 +726,6 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
need_wakeup_event |= !!__brcmstb_gpio_get_active_irqs(bank);
gc->write_reg(reg_base + GIO_MASK(bank->id), 0);
brcmstb_gpio_set_names(dev, bank);
err = gpiochip_add_data(gc, bank);
if (err) {
dev_err(dev, "Could not add gpiochip for bank %d\n",

View File

@ -16,7 +16,6 @@
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_data/gpio-dwapb.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/reset.h>
@ -48,6 +47,7 @@
#define DWAPB_DRIVER_NAME "gpio-dwapb"
#define DWAPB_MAX_PORTS 4
#define DWAPB_MAX_GPIOS 32
#define GPIO_EXT_PORT_STRIDE 0x04 /* register stride 32 bits */
#define GPIO_SWPORT_DR_STRIDE 0x0c /* register stride 3*32 bits */
@ -65,6 +65,19 @@
struct dwapb_gpio;
struct dwapb_port_property {
struct fwnode_handle *fwnode;
unsigned int idx;
unsigned int ngpio;
unsigned int gpio_base;
int irq[DWAPB_MAX_GPIOS];
};
struct dwapb_platform_data {
struct dwapb_port_property *properties;
unsigned int nports;
};
#ifdef CONFIG_PM_SLEEP
/* Store GPIO context across system-wide suspend/resume transitions */
struct dwapb_context {
@ -436,21 +449,17 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio,
pirq->irqchip.irq_set_wake = dwapb_irq_set_wake;
#endif
if (!pp->irq_shared) {
girq->num_parents = pirq->nr_irqs;
girq->parents = pirq->irq;
girq->parent_handler_data = gpio;
girq->parent_handler = dwapb_irq_handler;
} else {
/* This will let us handle the parent IRQ in the driver */
/*
* Intel ACPI-based platforms mostly have the DesignWare APB GPIO
* IRQ lane shared between several devices. In that case the parental
* IRQ has to be handled in the shared way so to be properly delivered
* to all the connected devices.
*/
if (has_acpi_companion(gpio->dev)) {
girq->num_parents = 0;
girq->parents = NULL;
girq->parent_handler = NULL;
/*
* Request a shared IRQ since where MFD would have devices
* using the same irq pin
*/
err = devm_request_irq(gpio->dev, pp->irq[0],
dwapb_irq_handler_mfd,
IRQF_SHARED, DWAPB_DRIVER_NAME, gpio);
@ -458,6 +467,11 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio,
dev_err(gpio->dev, "error requesting IRQ\n");
goto err_kfree_pirq;
}
} else {
girq->num_parents = pirq->nr_irqs;
girq->parents = pirq->irq;
girq->parent_handler_data = gpio;
girq->parent_handler = dwapb_irq_handler;
}
girq->chip = &pirq->irqchip;
@ -581,9 +595,12 @@ static struct dwapb_platform_data *dwapb_gpio_get_pdata(struct device *dev)
pp->ngpio = DWAPB_MAX_GPIOS;
}
pp->irq_shared = false;
pp->gpio_base = -1;
/* For internal use only, new platforms mustn't exercise this */
if (is_software_node(fwnode))
fwnode_property_read_u32(fwnode, "gpio-base", &pp->gpio_base);
/*
* Only port A can provide interrupts in all configurations of
* the IP.
@ -670,17 +687,12 @@ static int dwapb_gpio_probe(struct platform_device *pdev)
unsigned int i;
struct dwapb_gpio *gpio;
int err;
struct dwapb_platform_data *pdata;
struct device *dev = &pdev->dev;
struct dwapb_platform_data *pdata = dev_get_platdata(dev);
if (!pdata) {
pdata = dwapb_gpio_get_pdata(dev);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
}
if (!pdata->nports)
return -ENODEV;
pdata = dwapb_gpio_get_pdata(dev);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
if (!gpio)

View File

@ -1,112 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright 2009-2012 Freescale Semiconductor, Inc. All Rights Reserved.
*
* Author: Wu Guoxing <b39297@freescale.com>
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/gpio/driver.h>
#define GPIO_GROUP_NUM 2
#define GPIO_NUM_PER_GROUP 8
#define GPIO_NUM (GPIO_GROUP_NUM*GPIO_NUM_PER_GROUP)
struct mc9s08dz60 {
struct i2c_client *client;
struct gpio_chip chip;
};
static void mc9s_gpio_to_reg_and_bit(int offset, u8 *reg, u8 *bit)
{
*reg = 0x20 + offset / GPIO_NUM_PER_GROUP;
*bit = offset % GPIO_NUM_PER_GROUP;
}
static int mc9s08dz60_get_value(struct gpio_chip *gc, unsigned offset)
{
u8 reg, bit;
s32 value;
struct mc9s08dz60 *mc9s = gpiochip_get_data(gc);
mc9s_gpio_to_reg_and_bit(offset, &reg, &bit);
value = i2c_smbus_read_byte_data(mc9s->client, reg);
return (value >= 0) ? (value >> bit) & 0x1 : 0;
}
static int mc9s08dz60_set(struct mc9s08dz60 *mc9s, unsigned offset, int val)
{
u8 reg, bit;
s32 value;
mc9s_gpio_to_reg_and_bit(offset, &reg, &bit);
value = i2c_smbus_read_byte_data(mc9s->client, reg);
if (value >= 0) {
if (val)
value |= 1 << bit;
else
value &= ~(1 << bit);
return i2c_smbus_write_byte_data(mc9s->client, reg, value);
} else
return value;
}
static void mc9s08dz60_set_value(struct gpio_chip *gc, unsigned offset, int val)
{
struct mc9s08dz60 *mc9s = gpiochip_get_data(gc);
mc9s08dz60_set(mc9s, offset, val);
}
static int mc9s08dz60_direction_output(struct gpio_chip *gc,
unsigned offset, int val)
{
struct mc9s08dz60 *mc9s = gpiochip_get_data(gc);
return mc9s08dz60_set(mc9s, offset, val);
}
static int mc9s08dz60_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct mc9s08dz60 *mc9s;
mc9s = devm_kzalloc(&client->dev, sizeof(*mc9s), GFP_KERNEL);
if (!mc9s)
return -ENOMEM;
mc9s->chip.label = client->name;
mc9s->chip.base = -1;
mc9s->chip.parent = &client->dev;
mc9s->chip.owner = THIS_MODULE;
mc9s->chip.ngpio = GPIO_NUM;
mc9s->chip.can_sleep = true;
mc9s->chip.get = mc9s08dz60_get_value;
mc9s->chip.set = mc9s08dz60_set_value;
mc9s->chip.direction_output = mc9s08dz60_direction_output;
mc9s->client = client;
i2c_set_clientdata(client, mc9s);
return devm_gpiochip_add_data(&client->dev, &mc9s->chip, mc9s);
}
static const struct i2c_device_id mc9s08dz60_id[] = {
{"mc9s08dz60", 0},
{},
};
static struct i2c_driver mc9s08dz60_i2c_driver = {
.driver = {
.name = "mc9s08dz60",
},
.probe = mc9s08dz60_probe,
.id_table = mc9s08dz60_id,
};
builtin_i2c_driver(mc9s08dz60_i2c_driver);

View File

@ -155,11 +155,10 @@ static int ioh_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
return 0;
}
#ifdef CONFIG_PM
/*
* Save register configuration and disable interrupts.
*/
static void ioh_gpio_save_reg_conf(struct ioh_gpio *chip)
static void __maybe_unused ioh_gpio_save_reg_conf(struct ioh_gpio *chip)
{
int i;
@ -185,7 +184,7 @@ static void ioh_gpio_save_reg_conf(struct ioh_gpio *chip)
/*
* This function restores the register configuration of the GPIO device.
*/
static void ioh_gpio_restore_reg_conf(struct ioh_gpio *chip)
static void __maybe_unused ioh_gpio_restore_reg_conf(struct ioh_gpio *chip)
{
int i;
@ -207,7 +206,6 @@ static void ioh_gpio_restore_reg_conf(struct ioh_gpio *chip)
&chip->reg->ioh_sel_reg[i]);
}
}
#endif
static int ioh_gpio_to_irq(struct gpio_chip *gpio, unsigned offset)
{
@ -522,47 +520,23 @@ static void ioh_gpio_remove(struct pci_dev *pdev)
kfree(chip);
}
#ifdef CONFIG_PM
static int ioh_gpio_suspend(struct pci_dev *pdev, pm_message_t state)
static int __maybe_unused ioh_gpio_suspend(struct device *dev)
{
s32 ret;
struct ioh_gpio *chip = pci_get_drvdata(pdev);
struct ioh_gpio *chip = dev_get_drvdata(dev);
unsigned long flags;
spin_lock_irqsave(&chip->spinlock, flags);
ioh_gpio_save_reg_conf(chip);
spin_unlock_irqrestore(&chip->spinlock, flags);
ret = pci_save_state(pdev);
if (ret) {
dev_err(&pdev->dev, "pci_save_state Failed-%d\n", ret);
return ret;
}
pci_disable_device(pdev);
pci_set_power_state(pdev, PCI_D0);
ret = pci_enable_wake(pdev, PCI_D0, 1);
if (ret)
dev_err(&pdev->dev, "pci_enable_wake Failed -%d\n", ret);
return 0;
}
static int ioh_gpio_resume(struct pci_dev *pdev)
static int __maybe_unused ioh_gpio_resume(struct device *dev)
{
s32 ret;
struct ioh_gpio *chip = pci_get_drvdata(pdev);
struct ioh_gpio *chip = dev_get_drvdata(dev);
unsigned long flags;
ret = pci_enable_wake(pdev, PCI_D0, 0);
pci_set_power_state(pdev, PCI_D0);
ret = pci_enable_device(pdev);
if (ret) {
dev_err(&pdev->dev, "pci_enable_device Failed-%d ", ret);
return ret;
}
pci_restore_state(pdev);
spin_lock_irqsave(&chip->spinlock, flags);
iowrite32(0x01, &chip->reg->srst);
iowrite32(0x00, &chip->reg->srst);
@ -571,10 +545,8 @@ static int ioh_gpio_resume(struct pci_dev *pdev)
return 0;
}
#else
#define ioh_gpio_suspend NULL
#define ioh_gpio_resume NULL
#endif
static SIMPLE_DEV_PM_OPS(ioh_gpio_pm_ops, ioh_gpio_suspend, ioh_gpio_resume);
static const struct pci_device_id ioh_gpio_pcidev_id[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x802E) },
@ -587,8 +559,9 @@ static struct pci_driver ioh_gpio_driver = {
.id_table = ioh_gpio_pcidev_id,
.probe = ioh_gpio_probe,
.remove = ioh_gpio_remove,
.suspend = ioh_gpio_suspend,
.resume = ioh_gpio_resume
.driver = {
.pm = &ioh_gpio_pm_ops,
},
};
module_pci_driver(ioh_gpio_driver);

View File

@ -1,6 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/acpi.h>
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/device.h>
@ -8,6 +7,7 @@
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
@ -47,12 +47,10 @@
#define YU_GPIO_MODE0_SET 0x54
#define YU_GPIO_MODE0_CLEAR 0x58
#ifdef CONFIG_PM
struct mlxbf2_gpio_context_save_regs {
u32 gpio_mode0;
u32 gpio_mode1;
};
#endif
/* BlueField-2 gpio block context structure. */
struct mlxbf2_gpio_context {
@ -61,9 +59,7 @@ struct mlxbf2_gpio_context {
/* YU GPIO blocks address */
void __iomem *gpio_io;
#ifdef CONFIG_PM
struct mlxbf2_gpio_context_save_regs *csave_regs;
#endif
};
/* BlueField-2 gpio shared structure. */
@ -73,11 +69,8 @@ struct mlxbf2_gpio_param {
struct mutex *lock;
};
static struct resource yu_arm_gpio_lock_res = {
.start = YU_ARM_GPIO_LOCK_ADDR,
.end = YU_ARM_GPIO_LOCK_ADDR + YU_ARM_GPIO_LOCK_SIZE - 1,
.name = "YU_ARM_GPIO_LOCK",
};
static struct resource yu_arm_gpio_lock_res =
DEFINE_RES_MEM_NAMED(YU_ARM_GPIO_LOCK_ADDR, YU_ARM_GPIO_LOCK_SIZE, "YU_ARM_GPIO_LOCK");
static DEFINE_MUTEX(yu_arm_gpio_lock_mutex);
@ -232,7 +225,6 @@ mlxbf2_gpio_probe(struct platform_device *pdev)
struct mlxbf2_gpio_context *gs;
struct device *dev = &pdev->dev;
struct gpio_chip *gc;
struct resource *res;
unsigned int npins;
int ret;
@ -241,13 +233,9 @@ mlxbf2_gpio_probe(struct platform_device *pdev)
return -ENOMEM;
/* YU GPIO block address */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
gs->gpio_io = devm_ioremap(dev, res->start, resource_size(res));
if (!gs->gpio_io)
return -ENOMEM;
gs->gpio_io = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(gs->gpio_io))
return PTR_ERR(gs->gpio_io);
ret = mlxbf2_gpio_get_lock_res(pdev);
if (ret) {
@ -284,11 +272,9 @@ mlxbf2_gpio_probe(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM
static int mlxbf2_gpio_suspend(struct platform_device *pdev,
pm_message_t state)
static int __maybe_unused mlxbf2_gpio_suspend(struct device *dev)
{
struct mlxbf2_gpio_context *gs = platform_get_drvdata(pdev);
struct mlxbf2_gpio_context *gs = dev_get_drvdata(dev);
gs->csave_regs->gpio_mode0 = readl(gs->gpio_io +
YU_GPIO_MODE0);
@ -298,9 +284,9 @@ static int mlxbf2_gpio_suspend(struct platform_device *pdev,
return 0;
}
static int mlxbf2_gpio_resume(struct platform_device *pdev)
static int __maybe_unused mlxbf2_gpio_resume(struct device *dev)
{
struct mlxbf2_gpio_context *gs = platform_get_drvdata(pdev);
struct mlxbf2_gpio_context *gs = dev_get_drvdata(dev);
writel(gs->csave_regs->gpio_mode0, gs->gpio_io +
YU_GPIO_MODE0);
@ -309,7 +295,7 @@ static int mlxbf2_gpio_resume(struct platform_device *pdev)
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(mlxbf2_pm_ops, mlxbf2_gpio_suspend, mlxbf2_gpio_resume);
static const struct acpi_device_id __maybe_unused mlxbf2_gpio_acpi_match[] = {
{ "MLNXBF22", 0 },
@ -320,13 +306,10 @@ MODULE_DEVICE_TABLE(acpi, mlxbf2_gpio_acpi_match);
static struct platform_driver mlxbf2_gpio_driver = {
.driver = {
.name = "mlxbf2_gpio",
.acpi_match_table = ACPI_PTR(mlxbf2_gpio_acpi_match),
.acpi_match_table = mlxbf2_gpio_acpi_match,
.pm = &mlxbf2_pm_ops,
},
.probe = mlxbf2_gpio_probe,
#ifdef CONFIG_PM
.suspend = mlxbf2_gpio_suspend,
.resume = mlxbf2_gpio_resume,
#endif
};
module_platform_driver(mlxbf2_gpio_driver);

View File

@ -332,7 +332,7 @@ static int mpc8xxx_probe(struct platform_device *pdev)
mpc8xxx_gc->regs + GPIO_DIR, NULL,
BGPIOF_BIG_ENDIAN);
if (ret)
goto err;
return ret;
dev_dbg(&pdev->dev, "GPIO registers are LITTLE endian\n");
} else {
ret = bgpio_init(gc, &pdev->dev, 4,
@ -342,7 +342,7 @@ static int mpc8xxx_probe(struct platform_device *pdev)
BGPIOF_BIG_ENDIAN
| BGPIOF_BIG_ENDIAN_BYTE_ORDER);
if (ret)
goto err;
return ret;
dev_dbg(&pdev->dev, "GPIO registers are BIG endian\n");
}
@ -380,11 +380,11 @@ static int mpc8xxx_probe(struct platform_device *pdev)
is_acpi_node(fwnode))
gc->write_reg(mpc8xxx_gc->regs + GPIO_IBE, 0xffffffff);
ret = gpiochip_add_data(gc, mpc8xxx_gc);
ret = devm_gpiochip_add_data(&pdev->dev, gc, mpc8xxx_gc);
if (ret) {
dev_err(&pdev->dev,
"GPIO chip registration failed with status %d\n", ret);
goto err;
return ret;
}
mpc8xxx_gc->irqn = platform_get_irq(pdev, 0);
@ -416,7 +416,7 @@ static int mpc8xxx_probe(struct platform_device *pdev)
return 0;
err:
iounmap(mpc8xxx_gc->regs);
irq_domain_remove(mpc8xxx_gc->irq);
return ret;
}
@ -429,9 +429,6 @@ static int mpc8xxx_remove(struct platform_device *pdev)
irq_domain_remove(mpc8xxx_gc->irq);
}
gpiochip_remove(&mpc8xxx_gc->gc);
iounmap(mpc8xxx_gc->regs);
return 0;
}

View File

@ -239,6 +239,7 @@ mediatek_gpio_bank_probe(struct device *dev,
if (!rg->chip.label)
return -ENOMEM;
rg->chip.offset = bank * MTK_BANK_WIDTH;
rg->irq_chip.name = dev_name(dev);
rg->irq_chip.parent_device = dev;
rg->irq_chip.irq_unmask = mediatek_gpio_irq_unmask;

View File

@ -564,9 +564,9 @@ static int gpio_rcar_probe(struct platform_device *pdev)
}
if (p->info.has_inen) {
pm_runtime_get_sync(p->dev);
pm_runtime_get_sync(dev);
gpio_rcar_enable_inputs(p);
pm_runtime_put(p->dev);
pm_runtime_put(dev);
}
dev_info(dev, "driving %d GPIOs\n", npins);

View File

@ -607,15 +607,21 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
if (!gpio)
return -ENOMEM;
gpio->soc = of_device_get_match_data(&pdev->dev);
gpio->soc = device_get_match_data(&pdev->dev);
gpio->secure = devm_platform_ioremap_resource_byname(pdev, "security");
if (IS_ERR(gpio->secure))
return PTR_ERR(gpio->secure);
if (IS_ERR(gpio->secure)) {
gpio->secure = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(gpio->secure))
return PTR_ERR(gpio->secure);
}
gpio->base = devm_platform_ioremap_resource_byname(pdev, "gpio");
if (IS_ERR(gpio->base))
return PTR_ERR(gpio->base);
if (IS_ERR(gpio->base)) {
gpio->base = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(gpio->base))
return PTR_ERR(gpio->base);
}
err = platform_irq_count(pdev);
if (err < 0)
@ -677,11 +683,13 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
gpio->gpio.names = (const char * const *)names;
#if defined(CONFIG_OF_GPIO)
gpio->gpio.of_node = pdev->dev.of_node;
gpio->gpio.of_gpio_n_cells = 2;
gpio->gpio.of_xlate = tegra186_gpio_of_xlate;
#endif /* CONFIG_OF_GPIO */
gpio->intc.name = pdev->dev.of_node->name;
gpio->intc.name = dev_name(&pdev->dev);
gpio->intc.irq_ack = tegra186_irq_ack;
gpio->intc.irq_mask = tegra186_irq_mask;
gpio->intc.irq_unmask = tegra186_irq_unmask;
@ -893,10 +901,20 @@ static const struct of_device_id tegra186_gpio_of_match[] = {
};
MODULE_DEVICE_TABLE(of, tegra186_gpio_of_match);
static const struct acpi_device_id tegra186_gpio_acpi_match[] = {
{ .id = "NVDA0108", .driver_data = (kernel_ulong_t)&tegra186_main_soc },
{ .id = "NVDA0208", .driver_data = (kernel_ulong_t)&tegra186_aon_soc },
{ .id = "NVDA0308", .driver_data = (kernel_ulong_t)&tegra194_main_soc },
{ .id = "NVDA0408", .driver_data = (kernel_ulong_t)&tegra194_aon_soc },
{}
};
MODULE_DEVICE_TABLE(acpi, tegra186_gpio_acpi_match);
static struct platform_driver tegra186_gpio_driver = {
.driver = {
.name = "tegra186-gpio",
.of_match_table = tegra186_gpio_of_match,
.acpi_match_table = tegra186_gpio_acpi_match,
},
.probe = tegra186_gpio_probe,
};

View File

@ -404,11 +404,10 @@ static int vprbrd_gpio_probe(struct platform_device *pdev)
vb_gpio->gpioa.get = vprbrd_gpioa_get;
vb_gpio->gpioa.direction_input = vprbrd_gpioa_direction_input;
vb_gpio->gpioa.direction_output = vprbrd_gpioa_direction_output;
ret = devm_gpiochip_add_data(&pdev->dev, &vb_gpio->gpioa, vb_gpio);
if (ret < 0) {
dev_err(vb_gpio->gpioa.parent, "could not add gpio a");
if (ret < 0)
return ret;
}
/* registering gpio b */
vb_gpio->gpiob.label = "viperboard gpio b";
@ -421,15 +420,8 @@ static int vprbrd_gpio_probe(struct platform_device *pdev)
vb_gpio->gpiob.get = vprbrd_gpiob_get;
vb_gpio->gpiob.direction_input = vprbrd_gpiob_direction_input;
vb_gpio->gpiob.direction_output = vprbrd_gpiob_direction_output;
ret = devm_gpiochip_add_data(&pdev->dev, &vb_gpio->gpiob, vb_gpio);
if (ret < 0) {
dev_err(vb_gpio->gpiob.parent, "could not add gpio b");
return ret;
}
platform_set_drvdata(pdev, vb_gpio);
return ret;
return devm_gpiochip_add_data(&pdev->dev, &vb_gpio->gpiob, vb_gpio);
}
static struct platform_driver vprbrd_gpio_driver = {

374
drivers/gpio/gpio-virtio.c Normal file
View File

@ -0,0 +1,374 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* GPIO driver for virtio-based virtual GPIO controllers
*
* Copyright (C) 2021 metux IT consult
* Enrico Weigelt, metux IT consult <info@metux.net>
*
* Copyright (C) 2021 Linaro.
* Viresh Kumar <viresh.kumar@linaro.org>
*/
#include <linux/completion.h>
#include <linux/err.h>
#include <linux/gpio/driver.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/virtio_config.h>
#include <uapi/linux/virtio_gpio.h>
#include <uapi/linux/virtio_ids.h>
struct virtio_gpio_line {
struct mutex lock; /* Protects line operation */
struct completion completion;
struct virtio_gpio_request req ____cacheline_aligned;
struct virtio_gpio_response res ____cacheline_aligned;
unsigned int rxlen;
};
struct virtio_gpio {
struct virtio_device *vdev;
struct mutex lock; /* Protects virtqueue operation */
struct gpio_chip gc;
struct virtio_gpio_line *lines;
struct virtqueue *request_vq;
};
static int _virtio_gpio_req(struct virtio_gpio *vgpio, u16 type, u16 gpio,
u8 txvalue, u8 *rxvalue, void *response, u32 rxlen)
{
struct virtio_gpio_line *line = &vgpio->lines[gpio];
struct virtio_gpio_request *req = &line->req;
struct virtio_gpio_response *res = response;
struct scatterlist *sgs[2], req_sg, res_sg;
struct device *dev = &vgpio->vdev->dev;
int ret;
/*
* Prevent concurrent requests for the same line since we have
* pre-allocated request/response buffers for each GPIO line. Moreover
* Linux always accesses a GPIO line sequentially, so this locking shall
* always go through without any delays.
*/
mutex_lock(&line->lock);
req->type = cpu_to_le16(type);
req->gpio = cpu_to_le16(gpio);
req->value = cpu_to_le32(txvalue);
sg_init_one(&req_sg, req, sizeof(*req));
sg_init_one(&res_sg, res, rxlen);
sgs[0] = &req_sg;
sgs[1] = &res_sg;
line->rxlen = 0;
reinit_completion(&line->completion);
/*
* Virtqueue callers need to ensure they don't call its APIs with other
* virtqueue operations at the same time.
*/
mutex_lock(&vgpio->lock);
ret = virtqueue_add_sgs(vgpio->request_vq, sgs, 1, 1, line, GFP_KERNEL);
if (ret) {
dev_err(dev, "failed to add request to vq\n");
mutex_unlock(&vgpio->lock);
goto out;
}
virtqueue_kick(vgpio->request_vq);
mutex_unlock(&vgpio->lock);
if (!wait_for_completion_timeout(&line->completion, HZ)) {
dev_err(dev, "GPIO operation timed out\n");
ret = -ETIMEDOUT;
goto out;
}
if (unlikely(res->status != VIRTIO_GPIO_STATUS_OK)) {
dev_err(dev, "GPIO request failed: %d\n", gpio);
ret = -EINVAL;
goto out;
}
if (unlikely(line->rxlen != rxlen)) {
dev_err(dev, "GPIO operation returned incorrect len (%u : %u)\n",
rxlen, line->rxlen);
ret = -EINVAL;
goto out;
}
if (rxvalue)
*rxvalue = res->value;
out:
mutex_unlock(&line->lock);
return ret;
}
static int virtio_gpio_req(struct virtio_gpio *vgpio, u16 type, u16 gpio,
u8 txvalue, u8 *rxvalue)
{
struct virtio_gpio_line *line = &vgpio->lines[gpio];
struct virtio_gpio_response *res = &line->res;
return _virtio_gpio_req(vgpio, type, gpio, txvalue, rxvalue, res,
sizeof(*res));
}
static void virtio_gpio_free(struct gpio_chip *gc, unsigned int gpio)
{
struct virtio_gpio *vgpio = gpiochip_get_data(gc);
virtio_gpio_req(vgpio, VIRTIO_GPIO_MSG_SET_DIRECTION, gpio,
VIRTIO_GPIO_DIRECTION_NONE, NULL);
}
static int virtio_gpio_get_direction(struct gpio_chip *gc, unsigned int gpio)
{
struct virtio_gpio *vgpio = gpiochip_get_data(gc);
u8 direction;
int ret;
ret = virtio_gpio_req(vgpio, VIRTIO_GPIO_MSG_GET_DIRECTION, gpio, 0,
&direction);
if (ret)
return ret;
switch (direction) {
case VIRTIO_GPIO_DIRECTION_IN:
return GPIO_LINE_DIRECTION_IN;
case VIRTIO_GPIO_DIRECTION_OUT:
return GPIO_LINE_DIRECTION_OUT;
default:
return -EINVAL;
}
}
static int virtio_gpio_direction_input(struct gpio_chip *gc, unsigned int gpio)
{
struct virtio_gpio *vgpio = gpiochip_get_data(gc);
return virtio_gpio_req(vgpio, VIRTIO_GPIO_MSG_SET_DIRECTION, gpio,
VIRTIO_GPIO_DIRECTION_IN, NULL);
}
static int virtio_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio,
int value)
{
struct virtio_gpio *vgpio = gpiochip_get_data(gc);
int ret;
ret = virtio_gpio_req(vgpio, VIRTIO_GPIO_MSG_SET_VALUE, gpio, value, NULL);
if (ret)
return ret;
return virtio_gpio_req(vgpio, VIRTIO_GPIO_MSG_SET_DIRECTION, gpio,
VIRTIO_GPIO_DIRECTION_OUT, NULL);
}
static int virtio_gpio_get(struct gpio_chip *gc, unsigned int gpio)
{
struct virtio_gpio *vgpio = gpiochip_get_data(gc);
u8 value;
int ret;
ret = virtio_gpio_req(vgpio, VIRTIO_GPIO_MSG_GET_VALUE, gpio, 0, &value);
return ret ? ret : value;
}
static void virtio_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value)
{
struct virtio_gpio *vgpio = gpiochip_get_data(gc);
virtio_gpio_req(vgpio, VIRTIO_GPIO_MSG_SET_VALUE, gpio, value, NULL);
}
static void virtio_gpio_request_vq(struct virtqueue *vq)
{
struct virtio_gpio_line *line;
unsigned int len;
do {
line = virtqueue_get_buf(vq, &len);
if (!line)
return;
line->rxlen = len;
complete(&line->completion);
} while (1);
}
static void virtio_gpio_free_vqs(struct virtio_device *vdev)
{
vdev->config->reset(vdev);
vdev->config->del_vqs(vdev);
}
static int virtio_gpio_alloc_vqs(struct virtio_gpio *vgpio,
struct virtio_device *vdev)
{
const char * const names[] = { "requestq" };
vq_callback_t *cbs[] = {
virtio_gpio_request_vq,
};
struct virtqueue *vqs[1] = { NULL };
int ret;
ret = virtio_find_vqs(vdev, 1, vqs, cbs, names, NULL);
if (ret) {
dev_err(&vdev->dev, "failed to find vqs: %d\n", ret);
return ret;
}
if (!vqs[0]) {
dev_err(&vdev->dev, "failed to find requestq vq\n");
return -ENODEV;
}
vgpio->request_vq = vqs[0];
return 0;
}
static const char **virtio_gpio_get_names(struct virtio_gpio *vgpio,
u32 gpio_names_size, u16 ngpio)
{
struct virtio_gpio_response_get_names *res;
struct device *dev = &vgpio->vdev->dev;
u8 *gpio_names, *str;
const char **names;
int i, ret, len;
if (!gpio_names_size)
return NULL;
len = sizeof(*res) + gpio_names_size;
res = devm_kzalloc(dev, len, GFP_KERNEL);
if (!res)
return NULL;
gpio_names = res->value;
ret = _virtio_gpio_req(vgpio, VIRTIO_GPIO_MSG_GET_NAMES, 0, 0, NULL,
res, len);
if (ret) {
dev_err(dev, "Failed to get GPIO names: %d\n", ret);
return NULL;
}
names = devm_kcalloc(dev, ngpio, sizeof(*names), GFP_KERNEL);
if (!names)
return NULL;
/* NULL terminate the string instead of checking it */
gpio_names[gpio_names_size - 1] = '\0';
for (i = 0, str = gpio_names; i < ngpio; i++) {
names[i] = str;
str += strlen(str) + 1; /* zero-length strings are allowed */
if (str > gpio_names + gpio_names_size) {
dev_err(dev, "gpio_names block is too short (%d)\n", i);
return NULL;
}
}
return names;
}
static int virtio_gpio_probe(struct virtio_device *vdev)
{
struct virtio_gpio_config config;
struct device *dev = &vdev->dev;
struct virtio_gpio *vgpio;
u32 gpio_names_size;
u16 ngpio;
int ret, i;
vgpio = devm_kzalloc(dev, sizeof(*vgpio), GFP_KERNEL);
if (!vgpio)
return -ENOMEM;
/* Read configuration */
virtio_cread_bytes(vdev, 0, &config, sizeof(config));
gpio_names_size = le32_to_cpu(config.gpio_names_size);
ngpio = le16_to_cpu(config.ngpio);
if (!ngpio) {
dev_err(dev, "Number of GPIOs can't be zero\n");
return -EINVAL;
}
vgpio->lines = devm_kcalloc(dev, ngpio, sizeof(*vgpio->lines), GFP_KERNEL);
if (!vgpio->lines)
return -ENOMEM;
for (i = 0; i < ngpio; i++) {
mutex_init(&vgpio->lines[i].lock);
init_completion(&vgpio->lines[i].completion);
}
mutex_init(&vgpio->lock);
vdev->priv = vgpio;
vgpio->vdev = vdev;
vgpio->gc.free = virtio_gpio_free;
vgpio->gc.get_direction = virtio_gpio_get_direction;
vgpio->gc.direction_input = virtio_gpio_direction_input;
vgpio->gc.direction_output = virtio_gpio_direction_output;
vgpio->gc.get = virtio_gpio_get;
vgpio->gc.set = virtio_gpio_set;
vgpio->gc.ngpio = ngpio;
vgpio->gc.base = -1; /* Allocate base dynamically */
vgpio->gc.label = dev_name(dev);
vgpio->gc.parent = dev;
vgpio->gc.owner = THIS_MODULE;
vgpio->gc.can_sleep = true;
ret = virtio_gpio_alloc_vqs(vgpio, vdev);
if (ret)
return ret;
/* Mark the device ready to perform operations from within probe() */
virtio_device_ready(vdev);
vgpio->gc.names = virtio_gpio_get_names(vgpio, gpio_names_size, ngpio);
ret = gpiochip_add_data(&vgpio->gc, vgpio);
if (ret) {
virtio_gpio_free_vqs(vdev);
dev_err(dev, "Failed to add virtio-gpio controller\n");
}
return ret;
}
static void virtio_gpio_remove(struct virtio_device *vdev)
{
struct virtio_gpio *vgpio = vdev->priv;
gpiochip_remove(&vgpio->gc);
virtio_gpio_free_vqs(vdev);
}
static const struct virtio_device_id id_table[] = {
{ VIRTIO_ID_GPIO, VIRTIO_DEV_ANY_ID },
{},
};
MODULE_DEVICE_TABLE(virtio, id_table);
static struct virtio_driver virtio_gpio_driver = {
.id_table = id_table,
.probe = virtio_gpio_probe,
.remove = virtio_gpio_remove,
.driver = {
.name = KBUILD_MODNAME,
.owner = THIS_MODULE,
},
};
module_virtio_driver(virtio_gpio_driver);
MODULE_AUTHOR("Enrico Weigelt, metux IT consult <info@metux.net>");
MODULE_AUTHOR("Viresh Kumar <viresh.kumar@linaro.org>");
MODULE_DESCRIPTION("VirtIO GPIO driver");
MODULE_LICENSE("GPL");

View File

@ -145,7 +145,7 @@ EXPORT_SYMBOL_GPL(devm_gpiod_get_index);
* In case of error an ERR_PTR() is returned.
*/
struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev,
struct device_node *node,
const struct device_node *node,
const char *propname, int index,
enum gpiod_flags dflags,
const char *label)

View File

@ -122,7 +122,7 @@ static struct gpio_desc *of_xlate_and_get_gpiod_flags(struct gpio_chip *chip,
bool of_gpio_need_valid_mask(const struct gpio_chip *gc)
{
int size;
struct device_node *np = gc->of_node;
const struct device_node *np = gc->of_node;
size = of_property_count_u32_elems(np, "gpio-reserved-ranges");
if (size > 0 && size % 2 == 0)
@ -130,7 +130,7 @@ bool of_gpio_need_valid_mask(const struct gpio_chip *gc)
return false;
}
static void of_gpio_flags_quirks(struct device_node *np,
static void of_gpio_flags_quirks(const struct device_node *np,
const char *propname,
enum of_gpio_flags *flags,
int index)
@ -236,7 +236,7 @@ static void of_gpio_flags_quirks(struct device_node *np,
* value on the error condition. If @flags is not NULL the function also fills
* in flags for the GPIO.
*/
static struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
static struct gpio_desc *of_get_named_gpiod_flags(const struct device_node *np,
const char *propname, int index, enum of_gpio_flags *flags)
{
struct of_phandle_args gpiospec;
@ -275,7 +275,7 @@ out:
return desc;
}
int of_get_named_gpio_flags(struct device_node *np, const char *list_name,
int of_get_named_gpio_flags(const struct device_node *np, const char *list_name,
int index, enum of_gpio_flags *flags)
{
struct gpio_desc *desc;
@ -303,7 +303,7 @@ EXPORT_SYMBOL_GPL(of_get_named_gpio_flags);
*
* In case of error an ERR_PTR() is returned.
*/
struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
struct gpio_desc *gpiod_get_from_of_node(const struct device_node *node,
const char *propname, int index,
enum gpiod_flags dflags,
const char *label)
@ -373,7 +373,7 @@ static struct gpio_desc *of_find_spi_gpio(struct device *dev, const char *con_id
enum of_gpio_flags *of_flags)
{
char prop_name[32]; /* 32 is max size of property name */
struct device_node *np = dev->of_node;
const struct device_node *np = dev->of_node;
struct gpio_desc *desc;
/*
@ -404,7 +404,7 @@ static struct gpio_desc *of_find_spi_cs_gpio(struct device *dev,
unsigned int idx,
unsigned long *flags)
{
struct device_node *np = dev->of_node;
const struct device_node *np = dev->of_node;
if (!IS_ENABLED(CONFIG_SPI_MASTER))
return ERR_PTR(-ENOENT);
@ -440,7 +440,7 @@ static struct gpio_desc *of_find_regulator_gpio(struct device *dev, const char *
"wlf,ldo1ena", /* WM8994 */
"wlf,ldo2ena", /* WM8994 */
};
struct device_node *np = dev->of_node;
const struct device_node *np = dev->of_node;
struct gpio_desc *desc;
int i;

View File

@ -382,10 +382,18 @@ static int devprop_gpiochip_set_names(struct gpio_chip *chip)
if (count < 0)
return 0;
if (count > gdev->ngpio) {
dev_warn(&gdev->dev, "gpio-line-names is length %d but should be at most length %d",
count, gdev->ngpio);
count = gdev->ngpio;
/*
* When offset is set in the driver side we assume the driver internally
* is using more than one gpiochip per the same device. We have to stop
* setting friendly names if the specified ones with 'gpio-line-names'
* are less than the offset in the device itself. This means all the
* lines are not present for every single pin within all the internal
* gpiochips.
*/
if (count <= chip->offset) {
dev_warn(&gdev->dev, "gpio-line-names too short (length %d), cannot map names for the gpiochip at offset %u\n",
count, chip->offset);
return 0;
}
names = kcalloc(count, sizeof(*names), GFP_KERNEL);
@ -400,8 +408,22 @@ static int devprop_gpiochip_set_names(struct gpio_chip *chip)
return ret;
}
/*
* When more that one gpiochip per device is used, 'count' can
* contain at most number gpiochips x chip->ngpio. We have to
* correctly distribute all defined lines taking into account
* chip->offset as starting point from where we will assign
* the names to pins from the 'names' array. Since property
* 'gpio-line-names' cannot contains gaps, we have to be sure
* we only assign those pins that really exists since chip->ngpio
* can be different of the chip->offset.
*/
count = (count > chip->offset) ? count - chip->offset : count;
if (count > chip->ngpio)
count = chip->ngpio;
for (i = 0; i < count; i++)
gdev->descs[i].name = names[i];
gdev->descs[i].name = names[chip->offset + i];
kfree(names);

View File

@ -17,7 +17,6 @@
#include <linux/clk-provider.h>
#include <linux/dmi.h>
#include <linux/i2c.h>
#include <linux/platform_data/gpio-dwapb.h>
#include <linux/property.h>
/* PCI BAR for register base address */
@ -28,15 +27,6 @@
#define MFD_ACPI_MATCH_GPIO 0ULL
#define MFD_ACPI_MATCH_I2C 1ULL
/* The base GPIO number under GPIOLIB framework */
#define INTEL_QUARK_MFD_GPIO_BASE 8
/* The default number of South-Cluster GPIO on Quark. */
#define INTEL_QUARK_MFD_NGPIO 8
/* The DesignWare GPIO ports on Quark. */
#define INTEL_QUARK_GPIO_NPORTS 1
#define INTEL_QUARK_IORES_MEM 0
#define INTEL_QUARK_IORES_IRQ 1
@ -111,12 +101,38 @@ static struct resource intel_quark_gpio_res[] = {
[INTEL_QUARK_IORES_MEM] = {
.flags = IORESOURCE_MEM,
},
[INTEL_QUARK_IORES_IRQ] = {
.flags = IORESOURCE_IRQ,
},
};
static struct mfd_cell_acpi_match intel_quark_acpi_match_gpio = {
.adr = MFD_ACPI_MATCH_GPIO,
};
static const struct software_node intel_quark_gpio_controller_node = {
.name = "intel-quark-gpio-controller",
};
static const struct property_entry intel_quark_gpio_portA_properties[] = {
PROPERTY_ENTRY_U32("reg", 0),
PROPERTY_ENTRY_U32("snps,nr-gpios", 8),
PROPERTY_ENTRY_U32("gpio-base", 8),
{ }
};
static const struct software_node intel_quark_gpio_portA_node = {
.name = "portA",
.parent = &intel_quark_gpio_controller_node,
.properties = intel_quark_gpio_portA_properties,
};
static const struct software_node *intel_quark_gpio_node_group[] = {
&intel_quark_gpio_controller_node,
&intel_quark_gpio_portA_node,
NULL
};
static struct mfd_cell intel_quark_mfd_cells[] = {
[MFD_I2C_BAR] = {
.id = MFD_I2C_BAR,
@ -203,35 +219,19 @@ static int intel_quark_gpio_setup(struct pci_dev *pdev)
{
struct mfd_cell *cell = &intel_quark_mfd_cells[MFD_GPIO_BAR];
struct resource *res = intel_quark_gpio_res;
struct dwapb_platform_data *pdata;
struct device *dev = &pdev->dev;
int ret;
res[INTEL_QUARK_IORES_MEM].start = pci_resource_start(pdev, MFD_GPIO_BAR);
res[INTEL_QUARK_IORES_MEM].end = pci_resource_end(pdev, MFD_GPIO_BAR);
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
res[INTEL_QUARK_IORES_IRQ].start = pci_irq_vector(pdev, 0);
res[INTEL_QUARK_IORES_IRQ].end = pci_irq_vector(pdev, 0);
/* For intel quark x1000, it has only one port: portA */
pdata->nports = INTEL_QUARK_GPIO_NPORTS;
pdata->properties = devm_kcalloc(dev, pdata->nports,
sizeof(*pdata->properties),
GFP_KERNEL);
if (!pdata->properties)
return -ENOMEM;
/* Set the properties for portA */
pdata->properties->fwnode = NULL;
pdata->properties->idx = 0;
pdata->properties->ngpio = INTEL_QUARK_MFD_NGPIO;
pdata->properties->gpio_base = INTEL_QUARK_MFD_GPIO_BASE;
pdata->properties->irq[0] = pci_irq_vector(pdev, 0);
pdata->properties->irq_shared = true;
cell->platform_data = pdata;
cell->pdata_size = sizeof(*pdata);
ret = software_node_register_node_group(intel_quark_gpio_node_group);
if (ret)
return ret;
cell->swnode = &intel_quark_gpio_controller_node;
return 0;
}
@ -274,10 +274,12 @@ static int intel_quark_mfd_probe(struct pci_dev *pdev,
ARRAY_SIZE(intel_quark_mfd_cells), NULL, 0,
NULL);
if (ret)
goto err_free_irq_vectors;
goto err_unregister_gpio_node_group;
return 0;
err_unregister_gpio_node_group:
software_node_unregister_node_group(intel_quark_gpio_node_group);
err_free_irq_vectors:
pci_free_irq_vectors(pdev);
err_unregister_i2c_clk:
@ -288,6 +290,7 @@ err_unregister_i2c_clk:
static void intel_quark_mfd_remove(struct pci_dev *pdev)
{
mfd_remove_devices(&pdev->dev);
software_node_unregister_node_group(intel_quark_gpio_node_group);
pci_free_irq_vectors(pdev);
intel_quark_unregister_i2c_clk(&pdev->dev);
}

View File

@ -609,7 +609,7 @@ struct gpio_desc *devm_fwnode_get_gpiod_from_child(struct device *dev,
#if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_OF_GPIO)
struct device_node;
struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
struct gpio_desc *gpiod_get_from_of_node(const struct device_node *node,
const char *propname, int index,
enum gpiod_flags dflags,
const char *label);
@ -619,7 +619,7 @@ struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
struct device_node;
static inline
struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
struct gpio_desc *gpiod_get_from_of_node(const struct device_node *node,
const char *propname, int index,
enum gpiod_flags dflags,
const char *label)
@ -633,7 +633,7 @@ struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
struct device_node;
struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev,
struct device_node *node,
const struct device_node *node,
const char *propname, int index,
enum gpiod_flags dflags,
const char *label);
@ -644,7 +644,7 @@ struct device_node;
static inline
struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev,
struct device_node *node,
const struct device_node *node,
const char *propname, int index,
enum gpiod_flags dflags,
const char *label)
@ -680,10 +680,10 @@ struct acpi_gpio_mapping {
unsigned int quirks;
};
#if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_ACPI)
struct acpi_device;
#if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_ACPI)
int acpi_dev_add_driver_gpios(struct acpi_device *adev,
const struct acpi_gpio_mapping *gpios);
void acpi_dev_remove_driver_gpios(struct acpi_device *adev);
@ -696,8 +696,6 @@ struct gpio_desc *acpi_get_and_request_gpiod(char *path, int pin, char *label);
#else /* CONFIG_GPIOLIB && CONFIG_ACPI */
struct acpi_device;
static inline int acpi_dev_add_driver_gpios(struct acpi_device *adev,
const struct acpi_gpio_mapping *gpios)
{

View File

@ -312,6 +312,9 @@ struct gpio_irq_chip {
* get rid of the static GPIO number space in the long run.
* @ngpio: the number of GPIOs handled by this controller; the last GPIO
* handled is (base + ngpio - 1).
* @offset: when multiple gpio chips belong to the same device this
* can be used as offset within the device so friendly names can
* be properly assigned.
* @names: if set, must be an array of strings to use as alternative
* names for the GPIOs in this chip. Any entry in the array
* may be NULL if there is no alias for the GPIO, however the
@ -398,6 +401,7 @@ struct gpio_chip {
int base;
u16 ngpio;
u16 offset;
const char *const *names;
bool can_sleep;

View File

@ -896,7 +896,7 @@ static inline int of_parse_phandle_with_fixed_args(const struct device_node *np,
return -ENOSYS;
}
static inline int of_count_phandle_with_args(struct device_node *np,
static inline int of_count_phandle_with_args(const struct device_node *np,
const char *list_name,
const char *cells_name)
{

View File

@ -49,7 +49,7 @@ static inline struct of_mm_gpio_chip *to_of_mm_gpio_chip(struct gpio_chip *gc)
return container_of(gc, struct of_mm_gpio_chip, gc);
}
extern int of_get_named_gpio_flags(struct device_node *np,
extern int of_get_named_gpio_flags(const struct device_node *np,
const char *list_name, int index, enum of_gpio_flags *flags);
extern int of_mm_gpiochip_add_data(struct device_node *np,
@ -67,7 +67,7 @@ extern void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc);
#include <linux/errno.h>
/* Drivers may not strictly depend on the GPIO support, so let them link. */
static inline int of_get_named_gpio_flags(struct device_node *np,
static inline int of_get_named_gpio_flags(const struct device_node *np,
const char *list_name, int index, enum of_gpio_flags *flags)
{
if (flags)
@ -98,7 +98,8 @@ static inline int of_get_named_gpio_flags(struct device_node *np,
* The above example defines four GPIOs, two of which are not specified.
* This function will return '4'
*/
static inline int of_gpio_named_count(struct device_node *np, const char* propname)
static inline int of_gpio_named_count(const struct device_node *np,
const char *propname)
{
return of_count_phandle_with_args(np, propname, "#gpio-cells");
}
@ -109,12 +110,12 @@ static inline int of_gpio_named_count(struct device_node *np, const char* propna
*
* Same as of_gpio_named_count, but hard coded to use the 'gpios' property
*/
static inline int of_gpio_count(struct device_node *np)
static inline int of_gpio_count(const struct device_node *np)
{
return of_gpio_named_count(np, "gpios");
}
static inline int of_get_gpio_flags(struct device_node *np, int index,
static inline int of_get_gpio_flags(const struct device_node *np, int index,
enum of_gpio_flags *flags)
{
return of_get_named_gpio_flags(np, "gpios", index, flags);
@ -129,7 +130,7 @@ static inline int of_get_gpio_flags(struct device_node *np, int index,
* Returns GPIO number to use with Linux generic GPIO API, or one of the errno
* value on the error condition.
*/
static inline int of_get_named_gpio(struct device_node *np,
static inline int of_get_named_gpio(const struct device_node *np,
const char *propname, int index)
{
return of_get_named_gpio_flags(np, propname, index, NULL);
@ -143,7 +144,7 @@ static inline int of_get_named_gpio(struct device_node *np,
* Returns GPIO number to use with Linux generic GPIO API, or one of the errno
* value on the error condition.
*/
static inline int of_get_gpio(struct device_node *np, int index)
static inline int of_get_gpio(const struct device_node *np, int index)
{
return of_get_gpio_flags(np, index, NULL);
}

View File

@ -1,25 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright(c) 2014 Intel Corporation.
*/
#ifndef GPIO_DW_APB_H
#define GPIO_DW_APB_H
#define DWAPB_MAX_GPIOS 32
struct dwapb_port_property {
struct fwnode_handle *fwnode;
unsigned int idx;
unsigned int ngpio;
unsigned int gpio_base;
int irq[DWAPB_MAX_GPIOS];
bool irq_shared;
};
struct dwapb_platform_data {
struct dwapb_port_property *properties;
unsigned int nports;
};
#endif

View File

@ -2,7 +2,7 @@
#ifndef LINUX_SPI_MAX7301_H
#define LINUX_SPI_MAX7301_H
#include <linux/gpio.h>
#include <linux/gpio/driver.h>
/*
* Some registers must be read back to modify.

View File

@ -0,0 +1,47 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _LINUX_VIRTIO_GPIO_H
#define _LINUX_VIRTIO_GPIO_H
#include <linux/types.h>
/* 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
/* Possible values of the status field */
#define VIRTIO_GPIO_STATUS_OK 0x0
#define VIRTIO_GPIO_STATUS_ERR 0x1
/* Direction types */
#define VIRTIO_GPIO_DIRECTION_NONE 0x00
#define VIRTIO_GPIO_DIRECTION_OUT 0x01
#define VIRTIO_GPIO_DIRECTION_IN 0x02
struct virtio_gpio_config {
__le16 ngpio;
__u8 padding[2];
__le32 gpio_names_size;
} __packed;
/* Virtio GPIO Request / Response */
struct virtio_gpio_request {
__le16 type;
__le16 gpio;
__le32 value;
};
struct virtio_gpio_response {
__u8 status;
__u8 value;
};
struct virtio_gpio_response_get_names {
__u8 status;
__u8 value[];
};
#endif /* _LINUX_VIRTIO_GPIO_H */

View File

@ -58,6 +58,7 @@
#define VIRTIO_ID_SCMI 32 /* virtio SCMI */
#define VIRTIO_ID_I2C_ADAPTER 34 /* virtio i2c adapter */
#define VIRTIO_ID_BT 40 /* virtio bluetooth */
#define VIRTIO_ID_GPIO 41 /* virtio gpio */
/*
* Virtio Transitional IDs