forked from Minki/linux
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:
commit
5e6a5845dd
@ -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.
|
||||
|
@ -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
|
||||
|
11
MAINTAINERS
11
MAINTAINERS
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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)
|
||||
|
@ -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, ®, &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, ®, &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);
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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
374
drivers/gpio/gpio-virtio.c
Normal 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");
|
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
@ -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.
|
||||
|
47
include/uapi/linux/virtio_gpio.h
Normal file
47
include/uapi/linux/virtio_gpio.h
Normal 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 */
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user