Watch
1
Fork
You've already forked kernel_a52xq
0
mirror of https://github.com/a52xq-dev/kernel.git synced 2026-10-18 21:58:11 +07:00

This is the bulk of GPIO changes for the v4.18 development

cycle.
 
 Core changes:
 
 - We have killed off VLA from the core library and all drivers.
   The background should be clear for everyone at this point:
   https://lwn.net/Articles/749064/
   Also I just don't like VLA's, kernel developers hate it when
   compilers do things behind their back. It's as simple as that.
   I'm sorry that they even slipped in to begin with.
   Kudos to Laura Abbott for exorcising them.
 
 - Support GPIO hogs in machines/board files.
 
 New drivers and chip support:
 
 - R-Car r8a77470 (RZ/G1C)
 - R-Car r8a77965 (M3-N)
 - R-Car r8a77990 (E3)
 - PCA953x driver improvements to accomodate more variants.
 
 Improvements and new features:
 
 - Support one interrupt per line on port A in the DesignWare
   dwapb driver.
 
 Misc:
 
 - Random cleanups, right header files in the drivers, some
   size optimizations etc.
 -----BEGIN PGP SIGNATURE-----
 
 iQIcBAABAgAGBQJbGOMeAAoJEEEQszewGV1zGR0P/Rq/Mh6BRum7kZee8v22aKJE
 imtSamaVk7eOSdLC00VLvJ5QYJBMWz2GV5ZJkaxAwHBh1GhfddTDj35uXoOkRRWs
 vRXSYthujluGJ5YYfRNrXZhD4ahVYPnJV5XxLy4OF+aQBAd4jjRAqXLhQT1PVK9Q
 AQD/BOjToxrjgPREaLX9sQTW8DbICmjRhEWieJoQab2mZC+qD/aCen0rkj+UD0Qu
 wQRk5mSEsrC0qmWNS/rhzFa7/nRa4qWOMkHxim7/GqwGzgOTpv+TctmQOqMUjHqq
 k0ikVgBfZbaz3MqcuqLbKJ00mRK6G/yQIlECP4xcMbxKRxXucJj1ytOedIdG4nJE
 5porXbW1d1bIhv3Zv8tt7vh00x+mEF+hv6p8DUa9ppe7qwsdbhUdzeczeyR8eM7U
 ZBi80jMJfp9wEugZ0F8syIUs3PPgp7y461hJDbZRuHp4P4jmpdUBMAF4XvWl6XPy
 DAlPHnSc2ZNaqWJtfc1ja4e6DlwltEV81Sd9Y0clLhkD95k95gZ7EzoyGPAIO4FG
 ir0getZE1mfh9K/EfkTOkcKHJh3b5rA5TiSbTVVaPO9SzqPtIK+xhDJI0r9IJkW1
 XKgScOaJqpYEe2Y/Y/ezfnjxDLVxwOz6R77GsZCle1uPevOcxqN9fmjEn7gGYzmX
 PDf5pOuRrWApqix4a3Jr
 =Ly/0
 -----END PGP SIGNATURE-----

Merge tag 'gpio-v4.18-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio

Pull GPIO updates from Linus Walleij:
 "This is the bulk of GPIO changes for the v4.18 development cycle.

  Core changes:

   - We have killed off VLA from the core library and all drivers.

     The background should be clear for everyone at this point:

        https://lwn.net/Articles/749064/

     Also I just don't like VLA's, kernel developers hate it when
     compilers do things behind their back. It's as simple as that.

     I'm sorry that they even slipped in to begin with. Kudos to Laura
     Abbott for exorcising them.

   - Support GPIO hogs in machines/board files.

  New drivers and chip support:

   - R-Car r8a77470 (RZ/G1C)

   - R-Car r8a77965 (M3-N)

   - R-Car r8a77990 (E3)

   - PCA953x driver improvements to accomodate more variants.

  Improvements and new features:

   - Support one interrupt per line on port A in the DesignWare dwapb
     driver.

  Misc:

   - Random cleanups, right header files in the drivers, some size
     optimizations etc"

* tag 'gpio-v4.18-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (73 commits)
  gpio: davinci: fix build warning when !CONFIG_OF
  gpio: dwapb: Fix rework support for 1 interrupt per port A GPIO
  gpio: pxa: Include the right header
  gpio: pl061: Include the right header
  gpio: pch: Include the right header
  gpio: pcf857x: Include the right header
  gpio: pca953x: Include the right header
  gpio: palmas: Include the right header
  gpio: omap: Include the right header
  gpio: octeon: Include the right header
  gpio: mxs: Switch to SPDX identifier
  gpio: Remove VLA from stmpe driver
  gpio: mxc: Switch to SPDX identifier
  gpio: mxc: add clock operation
  gpio: Remove VLA from gpiolib
  gpio: aspeed: Use a cache of output data registers
  gpio: aspeed: Set output latch before changing direction
  gpio: pca953x: fix address calculation for pcal6524
  gpio: pca953x: define masks for addressing common and extended registers
  gpio: pca953x: set the PCA_PCAL flag also when matching by DT
  ...
This commit is contained in:
Linus Torvalds 2018-06-08 10:31:52 -07:00
commit ea125dedbc
54 changed files with 647 additions and 293 deletions

View file

@ -31,10 +31,15 @@ Required properties:
ti,tca9554
onnn,pca9654
exar,xra1202
- gpio-controller: if used as gpio expander.
- #gpio-cells: if used as gpio expander.
- interrupt-controller: if to be used as interrupt expander.
- #interrupt-cells: if to be used as interrupt expander.
Optional properties:
- reset-gpios: GPIO specification for the RESET input. This is an
active low signal to the PCA953x.
- vcc-supply: power supply regulator.
Example:
@ -47,3 +52,32 @@ Example:
interrupt-parent = <&gpio3>;
interrupts = <23 IRQ_TYPE_LEVEL_LOW>;
};
Example with Interrupts:
gpio99: gpio@22 {
compatible = "nxp,pcal6524";
reg = <0x22>;
interrupt-parent = <&gpio6>;
interrupts = <1 IRQ_TYPE_EDGE_FALLING>; /* gpio6_161 */
interrupt-controller;
#interrupt-cells = <2>;
vcc-supply = <&vdds_1v8_main>;
gpio-controller;
#gpio-cells = <2>;
gpio-line-names =
"hdmi-ct-hpd", "hdmi.ls-oe", "p02", "p03", "vibra", "fault2", "p06", "p07",
"en-usb", "en-host1", "en-host2", "chg-int", "p14", "p15", "mic-int", "en-modem",
"shdn-hs-amp", "chg-status+red", "green", "blue", "en-esata", "fault1", "p26", "p27";
};
ts3a227@3b {
compatible = "ti,ts3a227e";
reg = <0x3b>;
interrupt-parent = <&gpio99>;
interrupts = <14 IRQ_TYPE_EDGE_RISING>;
ti,micbias = <0>; /* 2.1V */
};

View file

@ -5,6 +5,7 @@ Required Properties:
- compatible: should contain one or more of the following:
- "renesas,gpio-r8a7743": for R8A7743 (RZ/G1M) compatible GPIO controller.
- "renesas,gpio-r8a7745": for R8A7745 (RZ/G1E) compatible GPIO controller.
- "renesas,gpio-r8a77470": for R8A77470 (RZ/G1C) compatible GPIO controller.
- "renesas,gpio-r8a7778": for R8A7778 (R-Car M1) compatible GPIO controller.
- "renesas,gpio-r8a7779": for R8A7779 (R-Car H1) compatible GPIO controller.
- "renesas,gpio-r8a7790": for R8A7790 (R-Car H2) compatible GPIO controller.
@ -14,7 +15,9 @@ Required Properties:
- "renesas,gpio-r8a7794": for R8A7794 (R-Car E2) compatible GPIO controller.
- "renesas,gpio-r8a7795": for R8A7795 (R-Car H3) compatible GPIO controller.
- "renesas,gpio-r8a7796": for R8A7796 (R-Car M3-W) compatible GPIO controller.
- "renesas,gpio-r8a77965": for R8A77965 (R-Car M3-N) compatible GPIO controller.
- "renesas,gpio-r8a77970": for R8A77970 (R-Car V3M) compatible GPIO controller.
- "renesas,gpio-r8a77990": for R8A77990 (R-Car E3) compatible GPIO controller.
- "renesas,gpio-r8a77995": for R8A77995 (R-Car D3) compatible GPIO controller.
- "renesas,rcar-gen1-gpio": for a generic R-Car Gen1 GPIO controller.
- "renesas,rcar-gen2-gpio": for a generic R-Car Gen2 or RZ/G1 GPIO controller.

View file

@ -26,8 +26,13 @@ controller.
the second encodes the triger flags encoded as described in
Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
- interrupt-parent : The parent interrupt controller.
- interrupts : The interrupt to the parent controller raised when GPIOs
generate the interrupts.
- interrupts : The interrupts to the parent controller raised when GPIOs
generate the interrupts. If the controller provides one combined interrupt
for all GPIOs, specify a single interrupt. If the controller provides one
interrupt for each GPIO, provide a list of interrupts that correspond to each
of the GPIO pins. When specifying multiple interrupts, if any are unconnected,
use the interrupts-extended property to specify the interrupts and set the
interrupt controller handle for unused interrupts to 0.
- snps,nr-gpios : The number of pins in the port, a single cell.
- resets : Reset line for the controller.

View file

@ -177,3 +177,19 @@ mapping and is thus transparent to GPIO consumers.
A set of functions such as gpiod_set_value() is available to work with
the new descriptor-oriented interface.
Boards using platform data can also hog GPIO lines by defining GPIO hog tables.
.. code-block:: c
struct gpiod_hog gpio_hog_table[] = {
GPIO_HOG("gpio.0", 10, "foo", GPIO_ACTIVE_LOW, GPIOD_OUT_HIGH),
{ }
};
And the table can be added to the board code as follows::
gpiod_add_hogs(gpio_hog_table);
The line will be hogged as soon as the gpiochip is created or - in case the
chip was created earlier - when the hog table is registered.

View file

@ -85,6 +85,10 @@ hardware descriptions such as device tree or ACPI:
any other serio bus to the system and makes it possible to connect drivers
for e.g. keyboards and other PS/2 protocol based devices.
- cec-gpio: drivers/media/platform/cec-gpio/ is used to interact with a CEC
Consumer Electronics Control bus using only GPIO. It is used to communicate
with devices on the HDMI bus.
Apart from this there are special GPIO drivers in subsystems like MMC/SD to
read card detect and write protect GPIO lines, and in the TTY serial subsystem
to emulate MCTRL (modem control) signals CTS/RTS by using two GPIO lines. The

View file

@ -22,6 +22,18 @@ menuconfig GPIOLIB
if GPIOLIB
config GPIOLIB_FASTPATH_LIMIT
int "Maximum number of GPIOs for fast path"
range 32 512
default 512
help
This adjusts the point at which certain APIs will switch from
using a stack allocated buffer to a dynamically allocated buffer.
You shouldn't need to change this unless you really need to
optimize either stack space or performance. Change this carefully
since setting an incorrect value could cause stack corruption.
config OF_GPIO
def_bool y
depends on OF

View file

@ -188,7 +188,7 @@ static int dio48e_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
{
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
size_t i;
const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
static const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
const unsigned int gpio_reg_size = 8;
unsigned int bits_offset;
size_t word_index;

View file

@ -94,7 +94,7 @@ static int idi_48_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
{
struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
size_t i;
const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
static const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
const unsigned int gpio_reg_size = 8;
unsigned int bits_offset;
size_t word_index;

View file

@ -105,27 +105,22 @@ static int mmio_74xx_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
static int mmio_74xx_gpio_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id;
struct mmio_74xx_gpio_priv *priv;
struct resource *res;
void __iomem *dat;
int err;
of_id = of_match_device(mmio_74xx_gpio_ids, &pdev->dev);
if (!of_id)
return -ENODEV;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->flags = (uintptr_t)of_device_get_match_data(&pdev->dev);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dat = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(dat))
return PTR_ERR(dat);
priv->flags = (uintptr_t) of_id->data;
err = bgpio_init(&priv->gc, &pdev->dev,
DIV_ROUND_UP(MMIO_74XX_BIT_CNT(priv->flags), 8),
dat, NULL, NULL, NULL, NULL, 0);

View file

@ -54,6 +54,8 @@ struct aspeed_gpio {
u8 *offset_timer;
unsigned int timer_users[4];
struct clk *clk;
u32 *dcache;
};
struct aspeed_gpio_bank {
@ -231,12 +233,13 @@ static void __aspeed_gpio_set(struct gpio_chip *gc, unsigned int offset,
u32 reg;
addr = bank_val_reg(gpio, bank, GPIO_DATA);
reg = ioread32(addr);
reg = gpio->dcache[GPIO_BANK(offset)];
if (val)
reg |= GPIO_BIT(offset);
else
reg &= ~GPIO_BIT(offset);
gpio->dcache[GPIO_BANK(offset)] = reg;
iowrite32(reg, addr);
}
@ -287,11 +290,10 @@ static int aspeed_gpio_dir_out(struct gpio_chip *gc,
spin_lock_irqsave(&gpio->lock, flags);
__aspeed_gpio_set(gc, offset, val);
reg = ioread32(bank_val_reg(gpio, bank, GPIO_DIR));
iowrite32(reg | GPIO_BIT(offset), bank_val_reg(gpio, bank, GPIO_DIR));
__aspeed_gpio_set(gc, offset, val);
spin_unlock_irqrestore(&gpio->lock, flags);
return 0;
@ -852,7 +854,7 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
const struct of_device_id *gpio_id;
struct aspeed_gpio *gpio;
struct resource *res;
int rc;
int rc, i, banks;
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
if (!gpio)
@ -893,6 +895,20 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
gpio->chip.base = -1;
gpio->chip.irq.need_valid_mask = true;
/* Allocate a cache of the output registers */
banks = gpio->config->nr_gpios >> 5;
gpio->dcache = devm_kzalloc(&pdev->dev,
sizeof(u32) * banks, GFP_KERNEL);
if (!gpio->dcache)
return -ENOMEM;
/* Populate it with initial values read from the HW */
for (i = 0; i < banks; i++) {
const struct aspeed_gpio_bank *bank = &aspeed_gpio_banks[i];
gpio->dcache[i] = ioread32(gpio->base + bank->val_regs +
GPIO_DATA);
}
rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
if (rc < 0)
return rc;

View file

@ -610,14 +610,12 @@ done:
return 0;
}
#if IS_ENABLED(CONFIG_OF)
static const struct of_device_id davinci_gpio_ids[] = {
{ .compatible = "ti,keystone-gpio", keystone_gpio_get_irq_chip},
{ .compatible = "ti,dm6441-gpio", davinci_gpio_get_irq_chip},
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, davinci_gpio_ids);
#endif
static struct platform_driver davinci_gpio_driver = {
.probe = davinci_gpio_probe,

View file

@ -441,14 +441,19 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio,
irq_gc->chip_types[1].handler = handle_edge_irq;
if (!pp->irq_shared) {
irq_set_chained_handler_and_data(pp->irq, dwapb_irq_handler,
gpio);
int i;
for (i = 0; i < pp->ngpio; i++) {
if (pp->irq[i] >= 0)
irq_set_chained_handler_and_data(pp->irq[i],
dwapb_irq_handler, gpio);
}
} else {
/*
* Request a shared IRQ since where MFD would have devices
* using the same irq pin
*/
err = devm_request_irq(gpio->dev, pp->irq,
err = devm_request_irq(gpio->dev, pp->irq[0],
dwapb_irq_handler_mfd,
IRQF_SHARED, "gpio-dwapb-mfd", gpio);
if (err) {
@ -524,7 +529,7 @@ static int dwapb_gpio_add_port(struct dwapb_gpio *gpio,
if (pp->idx == 0)
port->gc.set_config = dwapb_gpio_set_config;
if (pp->irq)
if (pp->has_irq)
dwapb_configure_irqs(gpio, port, pp);
err = gpiochip_add_data(&port->gc, port);
@ -535,7 +540,7 @@ static int dwapb_gpio_add_port(struct dwapb_gpio *gpio,
port->is_registered = true;
/* Add GPIO-signaled ACPI event support */
if (pp->irq)
if (pp->has_irq)
acpi_gpiochip_request_interrupts(&port->gc);
return err;
@ -557,7 +562,7 @@ dwapb_gpio_get_pdata(struct device *dev)
struct dwapb_platform_data *pdata;
struct dwapb_port_property *pp;
int nports;
int i;
int i, j;
nports = device_get_child_node_count(dev);
if (nports == 0)
@ -575,6 +580,8 @@ dwapb_gpio_get_pdata(struct device *dev)
i = 0;
device_for_each_child_node(dev, fwnode) {
struct device_node *np = NULL;
pp = &pdata->properties[i++];
pp->fwnode = fwnode;
@ -594,23 +601,35 @@ dwapb_gpio_get_pdata(struct device *dev)
pp->ngpio = 32;
}
pp->irq_shared = false;
pp->gpio_base = -1;
/*
* Only port A can provide interrupts in all configurations of
* the IP.
*/
if (dev->of_node && pp->idx == 0 &&
fwnode_property_read_bool(fwnode,
if (pp->idx != 0)
continue;
if (dev->of_node && fwnode_property_read_bool(fwnode,
"interrupt-controller")) {
pp->irq = irq_of_parse_and_map(to_of_node(fwnode), 0);
if (!pp->irq)
dev_warn(dev, "no irq for port%d\n", pp->idx);
np = to_of_node(fwnode);
}
if (has_acpi_companion(dev) && pp->idx == 0)
pp->irq = platform_get_irq(to_platform_device(dev), 0);
for (j = 0; j < pp->ngpio; j++) {
pp->irq[j] = -ENXIO;
pp->irq_shared = false;
pp->gpio_base = -1;
if (np)
pp->irq[j] = of_irq_get(np, j);
else if (has_acpi_companion(dev))
pp->irq[j] = platform_get_irq(to_platform_device(dev), j);
if (pp->irq[j] >= 0)
pp->has_irq = true;
}
if (!pp->has_irq)
dev_warn(dev, "no irq for port%d\n", pp->idx);
}
return pdata;
@ -684,13 +703,7 @@ static int dwapb_gpio_probe(struct platform_device *pdev)
gpio->flags = 0;
if (dev->of_node) {
const struct of_device_id *of_devid;
of_devid = of_match_device(dwapb_of_match, dev);
if (of_devid) {
if (of_devid->data)
gpio->flags = (uintptr_t)of_devid->data;
}
gpio->flags = (uintptr_t)of_device_get_match_data(dev);
} else if (has_acpi_companion(dev)) {
const struct acpi_device_id *acpi_id;

View file

@ -300,6 +300,7 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type)
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
struct sprd_eic *sprd_eic = gpiochip_get_data(chip);
u32 offset = irqd_to_hwirq(data);
int state;
switch (sprd_eic->type) {
case SPRD_EIC_DEBOUNCE:
@ -310,6 +311,17 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type)
case IRQ_TYPE_LEVEL_LOW:
sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IEV, 0);
break;
case IRQ_TYPE_EDGE_RISING:
case IRQ_TYPE_EDGE_FALLING:
case IRQ_TYPE_EDGE_BOTH:
state = sprd_eic_get(chip, offset);
if (state)
sprd_eic_update(chip, offset,
SPRD_EIC_DBNC_IEV, 0);
else
sprd_eic_update(chip, offset,
SPRD_EIC_DBNC_IEV, 1);
break;
default:
return -ENOTSUPP;
}
@ -324,6 +336,17 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type)
case IRQ_TYPE_LEVEL_LOW:
sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 1);
break;
case IRQ_TYPE_EDGE_RISING:
case IRQ_TYPE_EDGE_FALLING:
case IRQ_TYPE_EDGE_BOTH:
state = sprd_eic_get(chip, offset);
if (state)
sprd_eic_update(chip, offset,
SPRD_EIC_LATCH_INTPOL, 0);
else
sprd_eic_update(chip, offset,
SPRD_EIC_LATCH_INTPOL, 1);
break;
default:
return -ENOTSUPP;
}
@ -405,6 +428,55 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type)
return 0;
}
static void sprd_eic_toggle_trigger(struct gpio_chip *chip, unsigned int irq,
unsigned int offset)
{
struct sprd_eic *sprd_eic = gpiochip_get_data(chip);
struct irq_data *data = irq_get_irq_data(irq);
u32 trigger = irqd_get_trigger_type(data);
int state, post_state;
/*
* The debounce EIC and latch EIC can only support level trigger, so we
* can toggle the level trigger to emulate the edge trigger.
*/
if ((sprd_eic->type != SPRD_EIC_DEBOUNCE &&
sprd_eic->type != SPRD_EIC_LATCH) ||
!(trigger & IRQ_TYPE_EDGE_BOTH))
return;
sprd_eic_irq_mask(data);
state = sprd_eic_get(chip, offset);
retry:
switch (sprd_eic->type) {
case SPRD_EIC_DEBOUNCE:
if (state)
sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IEV, 0);
else
sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IEV, 1);
break;
case SPRD_EIC_LATCH:
if (state)
sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 0);
else
sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 1);
break;
default:
sprd_eic_irq_unmask(data);
return;
}
post_state = sprd_eic_get(chip, offset);
if (state != post_state) {
dev_warn(chip->parent, "EIC level was changed.\n");
state = post_state;
goto retry;
}
sprd_eic_irq_unmask(data);
}
static int sprd_eic_match_chip_by_type(struct gpio_chip *chip, void *data)
{
enum sprd_eic_type type = *(enum sprd_eic_type *)data;
@ -448,6 +520,7 @@ static void sprd_eic_handle_one_type(struct gpio_chip *chip)
bank * SPRD_EIC_PER_BANK_NR + n);
generic_handle_irq(girq);
sprd_eic_toggle_trigger(chip, girq, n);
}
}
}

View file

@ -52,8 +52,6 @@ MODULE_DEVICE_TABLE(of, gef_gpio_ids);
static int __init gef_gpio_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id =
of_match_device(gef_gpio_ids, &pdev->dev);
struct gpio_chip *gc;
void __iomem *regs;
int ret;
@ -82,7 +80,7 @@ static int __init gef_gpio_probe(struct platform_device *pdev)
}
gc->base = -1;
gc->ngpio = (u16)(uintptr_t)of_id->data;
gc->ngpio = (u16)(uintptr_t)of_device_get_match_data(&pdev->dev);
gc->of_gpio_n_cells = 2;
gc->of_node = pdev->dev.of_node;

View file

@ -177,7 +177,7 @@ static int gpiomm_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
{
struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
size_t i;
const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
static const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
const unsigned int gpio_reg_size = 8;
unsigned int bits_offset;
size_t word_index;

View file

@ -285,8 +285,6 @@ MODULE_DEVICE_TABLE(of, ingenic_gpio_of_match);
static int ingenic_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const struct of_device_id *of_id = of_match_device(
ingenic_gpio_of_match, dev);
struct ingenic_gpio_chip *jzgc;
u32 bank;
int err;
@ -323,7 +321,7 @@ static int ingenic_gpio_probe(struct platform_device *pdev)
jzgc->gc.parent = dev;
jzgc->gc.of_node = dev->of_node;
jzgc->gc.owner = THIS_MODULE;
jzgc->version = (enum jz_version)of_id->data;
jzgc->version = (enum jz_version)of_device_get_match_data(dev);
jzgc->gc.set = ingenic_gpio_set;
jzgc->gc.get = ingenic_gpio_get;

View file

@ -17,9 +17,11 @@
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/err.h>
#include <linux/gpio/driver.h>
#include <linux/platform_device.h>
#include <linux/bitops.h>
#include <asm/types.h>
#include <loongson.h>
#include <linux/gpio.h>
#define STLS2F_N_GPIO 4
#define STLS3A_N_GPIO 16
@ -30,19 +32,48 @@
#define LOONGSON_N_GPIO STLS2F_N_GPIO
#endif
/*
* Offset into the register where we read lines, we write them from offset 0.
* This offset is the only thing that stand between us and using
* GPIO_GENERIC.
*/
#define LOONGSON_GPIO_IN_OFFSET 16
static DEFINE_SPINLOCK(gpio_lock);
static int loongson_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
{
u32 val;
spin_lock(&gpio_lock);
val = LOONGSON_GPIODATA;
spin_unlock(&gpio_lock);
return !!(val & BIT(gpio + LOONGSON_GPIO_IN_OFFSET));
}
static void loongson_gpio_set_value(struct gpio_chip *chip,
unsigned gpio, int value)
{
u32 val;
spin_lock(&gpio_lock);
val = LOONGSON_GPIODATA;
if (value)
val |= BIT(gpio);
else
val &= ~BIT(gpio);
LOONGSON_GPIODATA = val;
spin_unlock(&gpio_lock);
}
static int loongson_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
{
u32 temp;
u32 mask;
spin_lock(&gpio_lock);
mask = 1 << gpio;
temp = LOONGSON_GPIOIE;
temp |= mask;
temp |= BIT(gpio);
LOONGSON_GPIOIE = temp;
spin_unlock(&gpio_lock);
@ -53,63 +84,56 @@ static int loongson_gpio_direction_output(struct gpio_chip *chip,
unsigned gpio, int level)
{
u32 temp;
u32 mask;
gpio_set_value(gpio, level);
loongson_gpio_set_value(chip, gpio, level);
spin_lock(&gpio_lock);
mask = 1 << gpio;
temp = LOONGSON_GPIOIE;
temp &= (~mask);
temp &= ~BIT(gpio);
LOONGSON_GPIOIE = temp;
spin_unlock(&gpio_lock);
return 0;
}
static int loongson_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
static int loongson_gpio_probe(struct platform_device *pdev)
{
u32 val;
u32 mask;
struct gpio_chip *gc;
struct device *dev = &pdev->dev;
mask = 1 << (gpio + LOONGSON_GPIO_IN_OFFSET);
spin_lock(&gpio_lock);
val = LOONGSON_GPIODATA;
spin_unlock(&gpio_lock);
gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL);
if (!gc)
return -ENOMEM;
return (val & mask) != 0;
gc->label = "loongson-gpio-chip";
gc->base = 0;
gc->ngpio = LOONGSON_N_GPIO;
gc->get = loongson_gpio_get_value;
gc->set = loongson_gpio_set_value;
gc->direction_input = loongson_gpio_direction_input;
gc->direction_output = loongson_gpio_direction_output;
return gpiochip_add_data(gc, NULL);
}
static void loongson_gpio_set_value(struct gpio_chip *chip,
unsigned gpio, int value)
{
u32 val;
u32 mask;
mask = 1 << gpio;
spin_lock(&gpio_lock);
val = LOONGSON_GPIODATA;
if (value)
val |= mask;
else
val &= (~mask);
LOONGSON_GPIODATA = val;
spin_unlock(&gpio_lock);
}
static struct gpio_chip loongson_chip = {
.label = "Loongson-gpio-chip",
.direction_input = loongson_gpio_direction_input,
.get = loongson_gpio_get_value,
.direction_output = loongson_gpio_direction_output,
.set = loongson_gpio_set_value,
.base = 0,
.ngpio = LOONGSON_N_GPIO,
.can_sleep = false,
static struct platform_driver loongson_gpio_driver = {
.driver = {
.name = "loongson-gpio",
},
.probe = loongson_gpio_probe,
};
static int __init loongson_gpio_setup(void)
{
return gpiochip_add_data(&loongson_chip, NULL);
struct platform_device *pdev;
int ret;
ret = platform_driver_register(&loongson_gpio_driver);
if (ret) {
pr_err("error registering loongson GPIO driver\n");
return ret;
}
pdev = platform_device_register_simple("loongson-gpio", -1, NULL, 0);
return PTR_ERR_OR_ZERO(pdev);
}
postcore_initcall(loongson_gpio_setup);

View file

@ -12,7 +12,7 @@
#include <linux/bitops.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/gpio/driver.h>
#include <linux/i2c.h>
#include <linux/mfd/lp3943.h>
#include <linux/module.h>

View file

@ -14,7 +14,7 @@
* Based on the TPS65218 driver
*/
#include <linux/gpio.h>
#include <linux/gpio/driver.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>

View file

@ -20,9 +20,8 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/gpio/driver.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/module.h>

Some files were not shown because too many files have changed in this diff Show more