mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 02:17:36 -04:00
Merge tag 'gpio-updates-for-v7.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux
Pull gpio updates from Bartosz Golaszewski:
"There's one new driver, one legacy driver removed, a kunit test-suite
for the GPIO core, support for new models in existing drivers and a
slew of various changes in many places though I can't think of
anything controversial that would stand out - it's been a relatively
calm cycle.
GPIO core:
- Add an initial set of kunit test cases for the GPIO subsystem
- Use the devres owner as the GPIO chip's parent in absence of any
other parent
- Fix const-correctness of GPIO chip SRCU guards
- Provide new GPIO consumer interfaces: gpiod_is_single_ended() and
fwnode_gpiod_get()
- Quarantine all legacy GPIO APIs in linux/gpio/legacy.h
- Use __ro_after_init where applicable
New drivers:
- Add driver for the GPIO controller on Waveshare DSI TOUCH panels
Removed drivers:
- Remove the obsolete ts5500 GPIO driver
Driver updates:
- Modernize gpio-timberdale: remove platform data support and use
generic device property accessors
- Extend test build coverage by enabling COMPILE_TEST for more GPIO
drivers
- Add some missing dependencies in Kconfig
- Add support for sparse fixed direction to gpio-regmap
- Remove dead code from gpio-nomadik
- use BIT() in gpio-mxc
- use bitmap_complement() in gpio-xilinx and gpio-pca953x
- Use more appropriate printing functions where applicable
- Use named initializers for platform_device_id and i2c_device_id
arrays
- Convert gpio-altera to using the generic GPIO chip helper library
- Add support for new models to gpio-dwapb, gpio-zynq, gpio-usbio and
gpio-tegra186
- Unify the naming convention for Qualcomm in GPIO drivers
- Fix interrupt bank mapping to GPIO chips in gpio-mt7621
- Add support for the lines-initial-states property to gpio-74x164
- Switch to using dynamic GPIO base in gpio-ixp4xx
- Move the handling of an OF quirk from ASoC to gpiolib-of.c where
other such quirks live
- Use handle_bad_irq() in gpio-ep93xx
- Some other minor tweaks and refactorings
Devicetree bindings:
- Document the Waveshare GPIO controller for DSI TOUCH panels
- Document new models: Tegra238 in gpio-tegra186 and EIO GPIO in
gpio-zynq
- Add new properties for gpio-dwapb and fairchild,74hc595
- Fix whitespace issues
- Sort compatibles alphabetically in gpio-zynq
Documentation:
- Fix kerneldoc warnings in gpio-realtek-otto
Misc:
- Attach software nodes representing GPIO chips to the actual struct
device objects associated with them in some legacy platforms
enabling real firmware node lookup instead of string matching
- Drop unneeded dependencies on OF_GPIO from bus and staging drivers"
* tag 'gpio-updates-for-v7.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux: (62 commits)
gpio: nomadik: remove dead DB8540 code from <gpio/gpio-nomadik.h>
gpio: mt7621: fix interrupt banks mapping on gpio chips
bus: ts-nbus: drop unneeded dependency on OF_GPIO
staging: media: max96712: drop unneeded dependency on OF_GPIO
gpiolib: Replace strcpy() with memcpy()
gpio: remove obsolete UAF FIXMEs from lookup paths
gpio: core: fix const-correctness of gpio_chip_guard
gpio: mxc: use BIT() macro
gpio: realtek-otto: fix kernel-doc warnings
gpio: max77620: Unify usage of space and comma in platform_device_id array
gpio: Use named initializers for platform_device_id arrays
gpio: cros-ec: Drop unused assignment of platform_device_id driver data
ARM: omap1: enable real software node lookup of GPIOs on Nokia 770
ARM: omap1: use platform_device_register_full() for GPIO devices on OMAP 16xx
ARM: omap1: drop unused variable from omap16xx_gpio_init()
gpio: gpiolib: use seq_puts() for plain strings
gpio: ts5500: remove obsolete driver
gpio: add kunit test cases for the GPIO subsystem
kunit: provide kunit_platform_device_unregister()
kunit: provide kunit_platform_device_register_full()
...
This commit is contained in:
@@ -45,6 +45,18 @@ properties:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: Number of daisy-chained shift registers
|
||||
|
||||
lines-initial-states:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
Bitmask that specifies the initial state of each output line, written
|
||||
by the driver before the gpiochip is registered. Bit N corresponds to
|
||||
GPIO line N, following the convention already documented for
|
||||
nxp,pcf8575. Because the 74HC595/74LVC594 family is push-pull output
|
||||
only, a bit set to zero drives the line low and a bit set to one
|
||||
drives it high. The bitmask covers up to 32 lines (four cascaded
|
||||
registers); outputs beyond that come up zeroed. When the property is
|
||||
absent all outputs come up low, preserving the previous behaviour.
|
||||
|
||||
enable-gpios:
|
||||
description: GPIO connected to the OE (Output Enable) pin.
|
||||
maxItems: 1
|
||||
@@ -79,6 +91,7 @@ examples:
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
registers-number = <4>;
|
||||
lines-initial-states = <0xffff0000>;
|
||||
spi-max-frequency = <100000>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -12,10 +12,11 @@ maintainers:
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- xlnx,eio-gpio-1.0
|
||||
- xlnx,pmc-gpio-1.0
|
||||
- xlnx,versal-gpio-1.0
|
||||
- xlnx,zynq-gpio-1.0
|
||||
- xlnx,zynqmp-gpio-1.0
|
||||
- xlnx,versal-gpio-1.0
|
||||
- xlnx,pmc-gpio-1.0
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
@@ -30,7 +31,7 @@ properties:
|
||||
|
||||
gpio-line-names:
|
||||
description: strings describing the names of each gpio line
|
||||
minItems: 58
|
||||
minItems: 52
|
||||
maxItems: 174
|
||||
|
||||
interrupt-controller: true
|
||||
@@ -89,6 +90,16 @@ allOf:
|
||||
minItems: 116
|
||||
maxItems: 116
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- xlnx,eio-gpio-1.0
|
||||
then:
|
||||
properties:
|
||||
gpio-line-names:
|
||||
maxItems: 52
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
@@ -85,6 +85,8 @@ properties:
|
||||
- nvidia,tegra194-gpio-aon
|
||||
- nvidia,tegra234-gpio
|
||||
- nvidia,tegra234-gpio-aon
|
||||
- nvidia,tegra238-gpio
|
||||
- nvidia,tegra238-gpio-aon
|
||||
- nvidia,tegra256-gpio
|
||||
- nvidia,tegra264-gpio
|
||||
- nvidia,tegra264-gpio-uphy
|
||||
@@ -163,6 +165,7 @@ allOf:
|
||||
- nvidia,tegra186-gpio
|
||||
- nvidia,tegra194-gpio
|
||||
- nvidia,tegra234-gpio
|
||||
- nvidia,tegra238-gpio
|
||||
- nvidia,tegra256-gpio
|
||||
- nvidia,tegra264-gpio
|
||||
- nvidia,tegra264-gpio-uphy
|
||||
@@ -180,6 +183,7 @@ allOf:
|
||||
- nvidia,tegra186-gpio-aon
|
||||
- nvidia,tegra194-gpio-aon
|
||||
- nvidia,tegra234-gpio-aon
|
||||
- nvidia,tegra238-gpio-aon
|
||||
- nvidia,tegra264-gpio-aon
|
||||
then:
|
||||
properties:
|
||||
@@ -192,6 +196,8 @@ allOf:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- nvidia,tegra238-gpio
|
||||
- nvidia,tegra238-gpio-aon
|
||||
- nvidia,tegra264-gpio
|
||||
- nvidia,tegra264-gpio-uphy
|
||||
- nvidia,tegra264-gpio-aon
|
||||
|
||||
@@ -95,6 +95,12 @@ patternProperties:
|
||||
'#interrupt-cells':
|
||||
const: 2
|
||||
|
||||
patternProperties:
|
||||
"^.+-hog(-[0-9]+)?$":
|
||||
type: object
|
||||
required:
|
||||
- gpio-hog
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/gpio/waveshare,dsi-touch-gpio.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Waveshare GPIO controller on DSI TOUCH panels
|
||||
|
||||
maintainers:
|
||||
- Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
|
||||
|
||||
description:
|
||||
Waveshare DSI TOUCH panel kits contain separate GPIO controller for toggling
|
||||
power supplies and panel / touchscreen resets.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: waveshare,dsi-touch-gpio
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
gpio-controller: true
|
||||
|
||||
'#gpio-cells':
|
||||
const: 2
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- gpio-controller
|
||||
- "#gpio-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
wsgpio: gpio@45 {
|
||||
compatible = "waveshare,dsi-touch-gpio";
|
||||
reg = <0x45>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
};
|
||||
};
|
||||
|
||||
panel_avdd: regulator-panel-avdd {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "panel-avdd";
|
||||
gpios = <&wsgpio 0 GPIO_ACTIVE_HIGH>;
|
||||
enable-active-high;
|
||||
};
|
||||
|
||||
panel_iovcc: regulator-panel-iovcc {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "panel-iovcc";
|
||||
gpios = <&wsgpio 4 GPIO_ACTIVE_HIGH>;
|
||||
enable-active-high;
|
||||
};
|
||||
|
||||
panel_vcc: regulator-panel-vcc {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "panel-vcc";
|
||||
gpios = <&wsgpio 8 GPIO_ACTIVE_HIGH>;
|
||||
enable-active-high;
|
||||
regulator-always-on;
|
||||
};
|
||||
...
|
||||
@@ -36,27 +36,6 @@
|
||||
#include "clock.h"
|
||||
#include "mmc.h"
|
||||
|
||||
static const struct software_node nokia770_mpuio_gpiochip_node = {
|
||||
.name = "mpuio",
|
||||
};
|
||||
|
||||
static const struct software_node nokia770_gpiochip1_node = {
|
||||
.name = "gpio-0-15",
|
||||
};
|
||||
|
||||
static const struct software_node nokia770_gpiochip2_node = {
|
||||
.name = "gpio-16-31",
|
||||
};
|
||||
|
||||
static const struct software_node *nokia770_gpiochip_nodes[] = {
|
||||
&nokia770_mpuio_gpiochip_node,
|
||||
&nokia770_gpiochip1_node,
|
||||
&nokia770_gpiochip2_node,
|
||||
NULL
|
||||
};
|
||||
|
||||
#define ADS7846_PENDOWN_GPIO 15
|
||||
|
||||
static const unsigned int nokia770_keymap[] = {
|
||||
KEY(1, 0, GROUP_0 | KEY_UP),
|
||||
KEY(2, 0, GROUP_1 | KEY_F5),
|
||||
@@ -112,7 +91,7 @@ static const struct omap_lcd_config nokia770_lcd_config __initconst = {
|
||||
};
|
||||
|
||||
static const struct property_entry nokia770_mipid_props[] = {
|
||||
PROPERTY_ENTRY_GPIO("reset-gpios", &nokia770_gpiochip1_node,
|
||||
PROPERTY_ENTRY_GPIO("reset-gpios", &omap16xx_gpio1_swnode,
|
||||
13, GPIO_ACTIVE_LOW),
|
||||
{ }
|
||||
};
|
||||
@@ -138,8 +117,7 @@ static const struct property_entry nokia770_ads7846_props[] = {
|
||||
PROPERTY_ENTRY_U16("ti,x-plate-ohms", 180),
|
||||
PROPERTY_ENTRY_U16("ti,debounce-tol", 3),
|
||||
PROPERTY_ENTRY_U16("ti,debounce-rep", 1),
|
||||
PROPERTY_ENTRY_GPIO("pendown-gpios", &nokia770_gpiochip1_node,
|
||||
ADS7846_PENDOWN_GPIO, GPIO_ACTIVE_LOW),
|
||||
PROPERTY_ENTRY_GPIO("pendown-gpios", &omap16xx_gpio1_swnode, 15, GPIO_ACTIVE_LOW),
|
||||
{ }
|
||||
};
|
||||
|
||||
@@ -225,9 +203,9 @@ static inline void nokia770_mmc_init(void)
|
||||
#if IS_ENABLED(CONFIG_I2C_CBUS_GPIO)
|
||||
|
||||
static const struct software_node_ref_args nokia770_cbus_gpio_refs[] = {
|
||||
SOFTWARE_NODE_REFERENCE(&nokia770_mpuio_gpiochip_node, 9, 0),
|
||||
SOFTWARE_NODE_REFERENCE(&nokia770_mpuio_gpiochip_node, 10, 0),
|
||||
SOFTWARE_NODE_REFERENCE(&nokia770_mpuio_gpiochip_node, 11, 0),
|
||||
SOFTWARE_NODE_REFERENCE(&omap16xx_mpu_gpio_swnode, 9, 0),
|
||||
SOFTWARE_NODE_REFERENCE(&omap16xx_mpu_gpio_swnode, 10, 0),
|
||||
SOFTWARE_NODE_REFERENCE(&omap16xx_mpu_gpio_swnode, 11, 0),
|
||||
};
|
||||
|
||||
static const struct property_entry nokia770_cbus_props[] = {
|
||||
@@ -318,7 +296,6 @@ static void __init omap_nokia770_init(void)
|
||||
/* Unmask SleepX signal */
|
||||
omap_writew((omap_readw(0xfffb5004) & ~2), 0xfffb5004);
|
||||
|
||||
software_node_register_node_group(nokia770_gpiochip_nodes);
|
||||
platform_add_devices(nokia770_devices, ARRAY_SIZE(nokia770_devices));
|
||||
|
||||
gpiod_add_lookup_table(&nokia770_irq_gpio_table);
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
#include "soc.h"
|
||||
#include "i2c.h"
|
||||
|
||||
extern const struct software_node omap16xx_mpu_gpio_swnode;
|
||||
extern const struct software_node omap16xx_gpio1_swnode;
|
||||
|
||||
#ifdef CONFIG_OMAP_SERIAL_WAKE
|
||||
int omap_serial_wakeup_init(void);
|
||||
#else
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/platform_data/gpio-omap.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/soc/ti/omap1-io.h>
|
||||
|
||||
#include "hardware.h"
|
||||
@@ -55,14 +56,16 @@ static struct omap_gpio_platform_data omap16xx_mpu_gpio_config = {
|
||||
.regs = &omap16xx_mpuio_regs,
|
||||
};
|
||||
|
||||
static struct platform_device omap16xx_mpu_gpio = {
|
||||
const struct software_node omap16xx_mpu_gpio_swnode = { };
|
||||
|
||||
static const struct platform_device_info omap16xx_mpu_gpio = {
|
||||
.name = "omap_gpio",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
.platform_data = &omap16xx_mpu_gpio_config,
|
||||
},
|
||||
.num_resources = ARRAY_SIZE(omap16xx_mpu_gpio_resources),
|
||||
.resource = omap16xx_mpu_gpio_resources,
|
||||
.data = &omap16xx_mpu_gpio_config,
|
||||
.size_data = sizeof(omap16xx_mpu_gpio_config),
|
||||
.num_res = ARRAY_SIZE(omap16xx_mpu_gpio_resources),
|
||||
.res = omap16xx_mpu_gpio_resources,
|
||||
.swnode = &omap16xx_mpu_gpio_swnode,
|
||||
};
|
||||
|
||||
/* gpio1 */
|
||||
@@ -99,14 +102,16 @@ static struct omap_gpio_platform_data omap16xx_gpio1_config = {
|
||||
.regs = &omap16xx_gpio_regs,
|
||||
};
|
||||
|
||||
static struct platform_device omap16xx_gpio1 = {
|
||||
const struct software_node omap16xx_gpio1_swnode = { };
|
||||
|
||||
static const struct platform_device_info omap16xx_gpio1 = {
|
||||
.name = "omap_gpio",
|
||||
.id = 1,
|
||||
.dev = {
|
||||
.platform_data = &omap16xx_gpio1_config,
|
||||
},
|
||||
.num_resources = ARRAY_SIZE(omap16xx_gpio1_resources),
|
||||
.resource = omap16xx_gpio1_resources,
|
||||
.data = &omap16xx_gpio1_config,
|
||||
.size_data = sizeof(omap16xx_gpio1_config),
|
||||
.num_res = ARRAY_SIZE(omap16xx_gpio1_resources),
|
||||
.res = omap16xx_gpio1_resources,
|
||||
.swnode = &omap16xx_gpio1_swnode,
|
||||
};
|
||||
|
||||
/* gpio2 */
|
||||
@@ -127,14 +132,13 @@ static struct omap_gpio_platform_data omap16xx_gpio2_config = {
|
||||
.regs = &omap16xx_gpio_regs,
|
||||
};
|
||||
|
||||
static struct platform_device omap16xx_gpio2 = {
|
||||
static const struct platform_device_info omap16xx_gpio2 = {
|
||||
.name = "omap_gpio",
|
||||
.id = 2,
|
||||
.dev = {
|
||||
.platform_data = &omap16xx_gpio2_config,
|
||||
},
|
||||
.num_resources = ARRAY_SIZE(omap16xx_gpio2_resources),
|
||||
.resource = omap16xx_gpio2_resources,
|
||||
.data = &omap16xx_gpio2_config,
|
||||
.size_data = sizeof(omap16xx_gpio2_config),
|
||||
.num_res = ARRAY_SIZE(omap16xx_gpio2_resources),
|
||||
.res = omap16xx_gpio2_resources,
|
||||
};
|
||||
|
||||
/* gpio3 */
|
||||
@@ -155,14 +159,13 @@ static struct omap_gpio_platform_data omap16xx_gpio3_config = {
|
||||
.regs = &omap16xx_gpio_regs,
|
||||
};
|
||||
|
||||
static struct platform_device omap16xx_gpio3 = {
|
||||
static const struct platform_device_info omap16xx_gpio3 = {
|
||||
.name = "omap_gpio",
|
||||
.id = 3,
|
||||
.dev = {
|
||||
.platform_data = &omap16xx_gpio3_config,
|
||||
},
|
||||
.num_resources = ARRAY_SIZE(omap16xx_gpio3_resources),
|
||||
.resource = omap16xx_gpio3_resources,
|
||||
.data = &omap16xx_gpio3_config,
|
||||
.size_data = sizeof(omap16xx_gpio3_config),
|
||||
.num_res = ARRAY_SIZE(omap16xx_gpio3_resources),
|
||||
.res = omap16xx_gpio3_resources,
|
||||
};
|
||||
|
||||
/* gpio4 */
|
||||
@@ -183,17 +186,16 @@ static struct omap_gpio_platform_data omap16xx_gpio4_config = {
|
||||
.regs = &omap16xx_gpio_regs,
|
||||
};
|
||||
|
||||
static struct platform_device omap16xx_gpio4 = {
|
||||
static const struct platform_device_info omap16xx_gpio4 = {
|
||||
.name = "omap_gpio",
|
||||
.id = 4,
|
||||
.dev = {
|
||||
.platform_data = &omap16xx_gpio4_config,
|
||||
},
|
||||
.num_resources = ARRAY_SIZE(omap16xx_gpio4_resources),
|
||||
.resource = omap16xx_gpio4_resources,
|
||||
.data = &omap16xx_gpio4_config,
|
||||
.size_data = sizeof(omap16xx_gpio4_config),
|
||||
.num_res = ARRAY_SIZE(omap16xx_gpio4_resources),
|
||||
.res = omap16xx_gpio4_resources,
|
||||
};
|
||||
|
||||
static struct platform_device *omap16xx_gpio_dev[] __initdata = {
|
||||
static const struct platform_device_info *omap16xx_gpio_dev[] __initconst = {
|
||||
&omap16xx_mpu_gpio,
|
||||
&omap16xx_gpio1,
|
||||
&omap16xx_gpio2,
|
||||
@@ -210,9 +212,8 @@ static int __init omap16xx_gpio_init(void)
|
||||
{
|
||||
int i;
|
||||
void __iomem *base;
|
||||
struct resource *res;
|
||||
struct platform_device *pdev;
|
||||
struct omap_gpio_platform_data *pdata;
|
||||
const struct resource *res;
|
||||
const struct platform_device_info *pdevinfo;
|
||||
|
||||
if (!cpu_is_omap16xx())
|
||||
return -EINVAL;
|
||||
@@ -225,25 +226,24 @@ static int __init omap16xx_gpio_init(void)
|
||||
ULPD_CAM_CLK_CTRL);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(omap16xx_gpio_dev); i++) {
|
||||
pdev = omap16xx_gpio_dev[i];
|
||||
pdata = pdev->dev.platform_data;
|
||||
pdevinfo = omap16xx_gpio_dev[i];
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
res = &pdevinfo->res[0];
|
||||
if (unlikely(!res)) {
|
||||
dev_err(&pdev->dev, "Invalid mem resource.\n");
|
||||
pr_err("%s.%d: Invalid mem resource.\n", pdevinfo->name, pdevinfo->id);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
base = ioremap(res->start, resource_size(res));
|
||||
if (unlikely(!base)) {
|
||||
dev_err(&pdev->dev, "ioremap failed.\n");
|
||||
pr_err("%s.%d: ioremap failed.\n", pdevinfo->name, pdevinfo->id);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
__raw_writel(SYSCONFIG_WORD, base + OMAP1610_GPIO_SYSCONFIG);
|
||||
iounmap(base);
|
||||
|
||||
platform_device_register(omap16xx_gpio_dev[i]);
|
||||
platform_device_register_full(omap16xx_gpio_dev[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -216,7 +216,7 @@ config TI_SYSC
|
||||
config TS_NBUS
|
||||
tristate "Technologic Systems NBUS Driver"
|
||||
depends on SOC_IMX28
|
||||
depends on OF_GPIO && PWM
|
||||
depends on PWM
|
||||
help
|
||||
Driver for the Technologic Systems NBUS which is used to interface
|
||||
with the peripherals in the FPGA of the TS-4600 SoM.
|
||||
|
||||
@@ -102,6 +102,14 @@ config GPIO_CDEV_V1
|
||||
This ABI version is deprecated.
|
||||
Please use the latest ABI for new developments.
|
||||
|
||||
config GPIO_KUNIT
|
||||
tristate "Build GPIO Kunit test cases"
|
||||
depends on KUNIT
|
||||
default KUNIT_ALL_TESTS
|
||||
help
|
||||
Say Y here to build the module containing Kunit test cases verifying
|
||||
the functionality of the GPIO subsystem.
|
||||
|
||||
config GPIO_GENERIC
|
||||
depends on HAS_IOMEM # Only for IOMEM drivers
|
||||
tristate
|
||||
@@ -156,6 +164,7 @@ config GPIO_74XX_MMIO
|
||||
|
||||
config GPIO_ALTERA
|
||||
tristate "Altera GPIO"
|
||||
select GPIO_GENERIC
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
Say Y or M here to build support for the Altera PIO device.
|
||||
@@ -301,7 +310,7 @@ config GPIO_EM
|
||||
|
||||
config GPIO_EN7523
|
||||
tristate "Airoha GPIO support"
|
||||
depends on ARCH_AIROHA
|
||||
depends on ARCH_AIROHA || COMPILE_TEST
|
||||
default ARCH_AIROHA
|
||||
select GPIO_GENERIC
|
||||
select GPIOLIB_IRQCHIP
|
||||
@@ -698,7 +707,7 @@ config GPIO_SPACEMIT_K1
|
||||
|
||||
config GPIO_SPEAR_SPICS
|
||||
bool "ST SPEAr13xx SPI Chip Select as GPIO support"
|
||||
depends on PLAT_SPEAR
|
||||
depends on PLAT_SPEAR || COMPILE_TEST
|
||||
select GENERIC_IRQ_CHIP
|
||||
help
|
||||
Say yes here to support ST SPEAr SPI Chip Select as GPIO device.
|
||||
@@ -805,8 +814,18 @@ config GPIO_VISCONTI
|
||||
help
|
||||
Say yes here to support GPIO on Tohisba Visconti.
|
||||
|
||||
config GPIO_WAVESHARE_DSI_TOUCH
|
||||
tristate "Waveshare GPIO controller for DSI panels"
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
help
|
||||
Enable support for the GPIO and PWM controller found on Waveshare DSI
|
||||
TOUCH panel kits. It provides GPIOs (used for regulator control and
|
||||
resets) and backlight support.
|
||||
|
||||
config GPIO_WCD934X
|
||||
tristate "Qualcomm Technologies Inc WCD9340/WCD9341 GPIO controller driver"
|
||||
tristate "Qualcomm WCD9340/WCD9341 GPIO controller driver"
|
||||
depends on MFD_WCD934X
|
||||
help
|
||||
This driver is to support GPIO block found on the Qualcomm Technologies
|
||||
@@ -814,7 +833,7 @@ config GPIO_WCD934X
|
||||
|
||||
config GPIO_XGENE
|
||||
bool "APM X-Gene GPIO controller support"
|
||||
depends on ARM64
|
||||
depends on ARM64 || COMPILE_TEST
|
||||
help
|
||||
This driver is to support the GPIO block within the APM X-Gene SoC
|
||||
platform's generic flash controller. The GPIO pins are muxed with
|
||||
@@ -858,7 +877,7 @@ config GPIO_XTENSA
|
||||
|
||||
config GPIO_ZEVIO
|
||||
bool "LSI ZEVIO SoC memory mapped GPIOs"
|
||||
depends on ARM
|
||||
depends on ARM || COMPILE_TEST
|
||||
help
|
||||
Say yes here to support the GPIO controller in LSI ZEVIO SoCs.
|
||||
|
||||
@@ -1093,15 +1112,6 @@ config GPIO_SCH311X
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called gpio-sch311x.
|
||||
|
||||
config GPIO_TS5500
|
||||
tristate "TS-5500 DIO blocks and compatibles"
|
||||
depends on TS5500 || COMPILE_TEST
|
||||
help
|
||||
This driver supports Digital I/O exposed by pin blocks found on some
|
||||
Technologic Systems platforms. It includes, but is not limited to, 3
|
||||
blocks of the TS-5500: DIO1, DIO2 and the LCD port, and the TS-5600
|
||||
LCD port.
|
||||
|
||||
config GPIO_WINBOND
|
||||
tristate "Winbond Super I/O GPIO support"
|
||||
select ISA_BUS_API
|
||||
@@ -2060,6 +2070,7 @@ config GPIO_VIRTIO
|
||||
|
||||
config GPIO_SIM
|
||||
tristate "GPIO Simulator Module"
|
||||
depends on SYSFS
|
||||
select IRQ_SIM
|
||||
select CONFIGFS_FS
|
||||
help
|
||||
|
||||
@@ -13,6 +13,7 @@ obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o
|
||||
gpiolib-acpi-y := gpiolib-acpi-core.o gpiolib-acpi-quirks.o
|
||||
obj-$(CONFIG_GPIOLIB) += gpiolib-swnode.o
|
||||
obj-$(CONFIG_GPIO_SHARED) += gpiolib-shared.o
|
||||
obj-$(CONFIG_GPIO_KUNIT) += gpiolib-kunit.o
|
||||
|
||||
# Device drivers. Generally keep list sorted alphabetically
|
||||
obj-$(CONFIG_GPIO_REGMAP) += gpio-regmap.o
|
||||
@@ -194,7 +195,6 @@ obj-$(CONFIG_GPIO_TPS68470) += gpio-tps68470.o
|
||||
obj-$(CONFIG_GPIO_TQMX86) += gpio-tqmx86.o
|
||||
obj-$(CONFIG_GPIO_TS4800) += gpio-ts4800.o
|
||||
obj-$(CONFIG_GPIO_TS4900) += gpio-ts4900.o
|
||||
obj-$(CONFIG_GPIO_TS5500) += gpio-ts5500.o
|
||||
obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o
|
||||
obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o
|
||||
obj-$(CONFIG_GPIO_UNIPHIER) += gpio-uniphier.o
|
||||
@@ -205,6 +205,7 @@ obj-$(CONFIG_GPIO_VIRTUSER) += gpio-virtuser.o
|
||||
obj-$(CONFIG_GPIO_VIRTIO) += gpio-virtio.o
|
||||
obj-$(CONFIG_GPIO_VISCONTI) += gpio-visconti.o
|
||||
obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o
|
||||
obj-$(CONFIG_GPIO_WAVESHARE_DSI_TOUCH) += gpio-waveshare-dsi.o
|
||||
obj-$(CONFIG_GPIO_WCD934X) += gpio-wcd934x.o
|
||||
obj-$(CONFIG_GPIO_WHISKEY_COVE) += gpio-wcove.o
|
||||
obj-$(CONFIG_GPIO_WINBOND) += gpio-winbond.o
|
||||
|
||||
@@ -112,7 +112,7 @@ static int gen_74x164_probe(struct spi_device *spi)
|
||||
{
|
||||
struct device *dev = &spi->dev;
|
||||
struct gen_74x164_chip *chip;
|
||||
u32 nregs;
|
||||
u32 nregs, init_state;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
@@ -134,6 +134,21 @@ static int gen_74x164_probe(struct spi_device *spi)
|
||||
|
||||
chip->registers = nregs;
|
||||
|
||||
/*
|
||||
* Optionally seed the chain with a board-specified pattern so the
|
||||
* outputs come up in a known state on the first SPI write. The
|
||||
* property follows the nxp,pcf8575 convention where bit N maps to
|
||||
* GPIO line N. On this output-only device, bit=0 drives the line
|
||||
* low and bit=1 drives it high. The bitmask covers up to 32 lines;
|
||||
* any further outputs come up zeroed by devm_kzalloc().
|
||||
*/
|
||||
if (!device_property_read_u32(dev, "lines-initial-states", &init_state)) {
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < min(nregs, 4U); i++)
|
||||
chip->buffer[nregs - 1 - i] = (init_state >> (i * 8)) & 0xff;
|
||||
}
|
||||
|
||||
chip->gpiod_oe = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(chip->gpiod_oe))
|
||||
return PTR_ERR(chip->gpiod_oe);
|
||||
|
||||
@@ -501,8 +501,8 @@ static int adnp_i2c_probe(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id adnp_i2c_id[] = {
|
||||
{ "gpio-adnp" },
|
||||
{ },
|
||||
{ .name = "gpio-adnp" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adnp_i2c_id);
|
||||
|
||||
|
||||
@@ -507,8 +507,8 @@ static const struct adp5585_gpio_chip adp5589_gpio_chip_info = {
|
||||
};
|
||||
|
||||
static const struct platform_device_id adp5585_gpio_id_table[] = {
|
||||
{ "adp5585-gpio", (kernel_ulong_t)&adp5585_gpio_chip_info },
|
||||
{ "adp5589-gpio", (kernel_ulong_t)&adp5589_gpio_chip_info },
|
||||
{ .name = "adp5585-gpio", .driver_data = (kernel_ulong_t)&adp5585_gpio_chip_info },
|
||||
{ .name = "adp5589-gpio", .driver_data = (kernel_ulong_t)&adp5589_gpio_chip_info },
|
||||
{ /* Sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, adp5585_gpio_id_table);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/gpio/generic.h>
|
||||
|
||||
#define ALTERA_GPIO_MAX_NGPIO 32
|
||||
#define ALTERA_GPIO_DATA 0x0
|
||||
@@ -26,7 +27,7 @@
|
||||
|
||||
/**
|
||||
* struct altera_gpio_chip
|
||||
* @gc : GPIO chip structure.
|
||||
* @chip : Generic GPIO chip structure.
|
||||
* @regs : memory mapped IO address for the controller registers.
|
||||
* @gpio_lock : synchronization lock so that new irq/set/get requests
|
||||
* will be blocked until the current one completes.
|
||||
@@ -34,7 +35,7 @@
|
||||
* (rising, falling, both, high)
|
||||
*/
|
||||
struct altera_gpio_chip {
|
||||
struct gpio_chip gc;
|
||||
struct gpio_generic_chip chip;
|
||||
void __iomem *regs;
|
||||
raw_spinlock_t gpio_lock;
|
||||
int interrupt_trigger;
|
||||
@@ -106,72 +107,6 @@ static unsigned int altera_gpio_irq_startup(struct irq_data *d)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int altera_gpio_get(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
struct altera_gpio_chip *altera_gc = gpiochip_get_data(gc);
|
||||
|
||||
return !!(readl(altera_gc->regs + ALTERA_GPIO_DATA) & BIT(offset));
|
||||
}
|
||||
|
||||
static int altera_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
|
||||
{
|
||||
struct altera_gpio_chip *altera_gc = gpiochip_get_data(gc);
|
||||
unsigned long flags;
|
||||
unsigned int data_reg;
|
||||
|
||||
raw_spin_lock_irqsave(&altera_gc->gpio_lock, flags);
|
||||
data_reg = readl(altera_gc->regs + ALTERA_GPIO_DATA);
|
||||
if (value)
|
||||
data_reg |= BIT(offset);
|
||||
else
|
||||
data_reg &= ~BIT(offset);
|
||||
writel(data_reg, altera_gc->regs + ALTERA_GPIO_DATA);
|
||||
raw_spin_unlock_irqrestore(&altera_gc->gpio_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int altera_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
struct altera_gpio_chip *altera_gc = gpiochip_get_data(gc);
|
||||
unsigned long flags;
|
||||
unsigned int gpio_ddr;
|
||||
|
||||
raw_spin_lock_irqsave(&altera_gc->gpio_lock, flags);
|
||||
/* Set pin as input, assumes software controlled IP */
|
||||
gpio_ddr = readl(altera_gc->regs + ALTERA_GPIO_DIR);
|
||||
gpio_ddr &= ~BIT(offset);
|
||||
writel(gpio_ddr, altera_gc->regs + ALTERA_GPIO_DIR);
|
||||
raw_spin_unlock_irqrestore(&altera_gc->gpio_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int altera_gpio_direction_output(struct gpio_chip *gc,
|
||||
unsigned offset, int value)
|
||||
{
|
||||
struct altera_gpio_chip *altera_gc = gpiochip_get_data(gc);
|
||||
unsigned long flags;
|
||||
unsigned int data_reg, gpio_ddr;
|
||||
|
||||
raw_spin_lock_irqsave(&altera_gc->gpio_lock, flags);
|
||||
/* Sets the GPIO value */
|
||||
data_reg = readl(altera_gc->regs + ALTERA_GPIO_DATA);
|
||||
if (value)
|
||||
data_reg |= BIT(offset);
|
||||
else
|
||||
data_reg &= ~BIT(offset);
|
||||
writel(data_reg, altera_gc->regs + ALTERA_GPIO_DATA);
|
||||
|
||||
/* Set pin as output, assumes software controlled IP */
|
||||
gpio_ddr = readl(altera_gc->regs + ALTERA_GPIO_DIR);
|
||||
gpio_ddr |= BIT(offset);
|
||||
writel(gpio_ddr, altera_gc->regs + ALTERA_GPIO_DIR);
|
||||
raw_spin_unlock_irqrestore(&altera_gc->gpio_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void altera_gpio_irq_edge_handler(struct irq_desc *desc)
|
||||
{
|
||||
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
|
||||
@@ -231,9 +166,12 @@ static const struct irq_chip altera_gpio_irq_chip = {
|
||||
|
||||
static int altera_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct gpio_generic_chip_config config;
|
||||
struct device *dev = &pdev->dev;
|
||||
int reg, ret;
|
||||
struct altera_gpio_chip *altera_gc;
|
||||
struct gpio_generic_chip *chip;
|
||||
struct gpio_chip *gc;
|
||||
struct gpio_irq_chip *girq;
|
||||
int mapped_irq;
|
||||
|
||||
@@ -243,35 +181,45 @@ static int altera_gpio_probe(struct platform_device *pdev)
|
||||
|
||||
raw_spin_lock_init(&altera_gc->gpio_lock);
|
||||
|
||||
altera_gc->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(altera_gc->regs))
|
||||
return dev_err_probe(dev, PTR_ERR(altera_gc->regs),
|
||||
"failed to ioremap memory resource\n");
|
||||
|
||||
chip = &altera_gc->chip;
|
||||
|
||||
config = (struct gpio_generic_chip_config) {
|
||||
.dev = dev,
|
||||
.sz = 4,
|
||||
.dat = altera_gc->regs + ALTERA_GPIO_DATA,
|
||||
.set = altera_gc->regs + ALTERA_GPIO_DATA,
|
||||
.dirout = altera_gc->regs + ALTERA_GPIO_DIR,
|
||||
};
|
||||
|
||||
ret = gpio_generic_chip_init(chip, &config);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "unable to init generic GPIO\n");
|
||||
|
||||
gc = &chip->gc;
|
||||
|
||||
if (device_property_read_u32(dev, "altr,ngpio", ®))
|
||||
/* By default assume maximum ngpio */
|
||||
altera_gc->gc.ngpio = ALTERA_GPIO_MAX_NGPIO;
|
||||
gc->ngpio = ALTERA_GPIO_MAX_NGPIO;
|
||||
else
|
||||
altera_gc->gc.ngpio = reg;
|
||||
gc->ngpio = reg;
|
||||
|
||||
if (altera_gc->gc.ngpio > ALTERA_GPIO_MAX_NGPIO) {
|
||||
if (gc->ngpio > ALTERA_GPIO_MAX_NGPIO) {
|
||||
dev_warn(&pdev->dev,
|
||||
"ngpio is greater than %d, defaulting to %d\n",
|
||||
ALTERA_GPIO_MAX_NGPIO, ALTERA_GPIO_MAX_NGPIO);
|
||||
altera_gc->gc.ngpio = ALTERA_GPIO_MAX_NGPIO;
|
||||
gc->ngpio = ALTERA_GPIO_MAX_NGPIO;
|
||||
}
|
||||
|
||||
altera_gc->gc.direction_input = altera_gpio_direction_input;
|
||||
altera_gc->gc.direction_output = altera_gpio_direction_output;
|
||||
altera_gc->gc.get = altera_gpio_get;
|
||||
altera_gc->gc.set = altera_gpio_set;
|
||||
altera_gc->gc.owner = THIS_MODULE;
|
||||
altera_gc->gc.parent = &pdev->dev;
|
||||
altera_gc->gc.base = -1;
|
||||
|
||||
altera_gc->gc.label = devm_kasprintf(dev, GFP_KERNEL, "%pfw", dev_fwnode(dev));
|
||||
if (!altera_gc->gc.label)
|
||||
gc->base = -1;
|
||||
gc->label = devm_kasprintf(dev, GFP_KERNEL, "%pfw", dev_fwnode(dev));
|
||||
if (!gc->label)
|
||||
return -ENOMEM;
|
||||
|
||||
altera_gc->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(altera_gc->regs))
|
||||
return dev_err_probe(dev, PTR_ERR(altera_gc->regs), "failed to ioremap memory resource\n");
|
||||
|
||||
mapped_irq = platform_get_irq_optional(pdev, 0);
|
||||
if (mapped_irq < 0)
|
||||
goto skip_irq;
|
||||
@@ -283,7 +231,7 @@ static int altera_gpio_probe(struct platform_device *pdev)
|
||||
}
|
||||
altera_gc->interrupt_trigger = reg;
|
||||
|
||||
girq = &altera_gc->gc.irq;
|
||||
girq = &gc->irq;
|
||||
gpio_irq_chip_set_chip(girq, &altera_gpio_irq_chip);
|
||||
|
||||
if (altera_gc->interrupt_trigger == IRQ_TYPE_LEVEL_HIGH)
|
||||
@@ -300,7 +248,7 @@ static int altera_gpio_probe(struct platform_device *pdev)
|
||||
girq->parents[0] = mapped_irq;
|
||||
|
||||
skip_irq:
|
||||
ret = devm_gpiochip_add_data(dev, &altera_gc->gc, altera_gc);
|
||||
ret = devm_gpiochip_add_data(dev, gc, altera_gc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed adding memory mapped gpiochip\n");
|
||||
return ret;
|
||||
|
||||
@@ -59,8 +59,8 @@
|
||||
* want to register another driver on the same PCI id.
|
||||
*/
|
||||
static const struct pci_device_id pci_tbl[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS), 0 },
|
||||
{ 0, }, /* terminate list */
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS) },
|
||||
{ }, /* terminate list */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, pci_tbl);
|
||||
|
||||
|
||||
@@ -263,8 +263,8 @@ static int gpo_bd72720_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
static const struct platform_device_id bd72720_gpio_id[] = {
|
||||
{ "bd72720-gpio" },
|
||||
{ },
|
||||
{ .name = "bd72720-gpio" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, bd72720_gpio_id);
|
||||
|
||||
|
||||
@@ -110,8 +110,8 @@ static int bd9571mwv_gpio_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
static const struct platform_device_id bd9571mwv_gpio_id_table[] = {
|
||||
{ "bd9571mwv-gpio", ROHM_CHIP_TYPE_BD9571 },
|
||||
{ "bd9574mwf-gpio", ROHM_CHIP_TYPE_BD9574 },
|
||||
{ .name = "bd9571mwv-gpio", .driver_data = ROHM_CHIP_TYPE_BD9571 },
|
||||
{ .name = "bd9574mwf-gpio", .driver_data = ROHM_CHIP_TYPE_BD9574 },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, bd9571mwv_gpio_id_table);
|
||||
|
||||
@@ -196,8 +196,8 @@ static int cros_ec_gpio_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
static const struct platform_device_id cros_ec_gpio_id[] = {
|
||||
{ "cros-ec-gpio", 0 },
|
||||
{}
|
||||
{ .name = "cros-ec-gpio" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, cros_ec_gpio_id);
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ static const struct of_device_id ds4520_gpio_of_match_table[] = {
|
||||
MODULE_DEVICE_TABLE(of, ds4520_gpio_of_match_table);
|
||||
|
||||
static const struct i2c_device_id ds4520_gpio_id_table[] = {
|
||||
{ "ds4520-gpio" },
|
||||
{ .name = "ds4520-gpio" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ds4520_gpio_id_table);
|
||||
|
||||
@@ -694,6 +694,7 @@ static const struct acpi_device_id dwapb_acpi_match[] = {
|
||||
{"APMC0D07", GPIO_REG_OFFSET_V1},
|
||||
{"APMC0D81", GPIO_REG_OFFSET_V2},
|
||||
{"FUJI200A", GPIO_REG_OFFSET_V1},
|
||||
{"LECA0001", GPIO_REG_OFFSET_V1},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, dwapb_acpi_match);
|
||||
|
||||
@@ -323,8 +323,7 @@ static int ep93xx_setup_irqs(struct platform_device *pdev,
|
||||
}
|
||||
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
/* TODO: replace with handle_bad_irq() once we are fully hierarchical */
|
||||
girq->handler = handle_simple_irq;
|
||||
girq->handler = handle_bad_irq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ static const __maybe_unused struct of_device_id fxl6408_dt_ids[] = {
|
||||
MODULE_DEVICE_TABLE(of, fxl6408_dt_ids);
|
||||
|
||||
static const struct i2c_device_id fxl6408_id[] = {
|
||||
{ "fxl6408" },
|
||||
{ .name = "fxl6408" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, fxl6408_id);
|
||||
|
||||
@@ -109,7 +109,7 @@ static int gw_pld_probe(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id gw_pld_id[] = {
|
||||
{ "gw-pld", },
|
||||
{ .name = "gw-pld" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, gw_pld_id);
|
||||
|
||||
@@ -311,12 +311,7 @@ static int ixp4xx_gpio_probe(struct platform_device *pdev)
|
||||
}
|
||||
g->chip.gc.ngpio = 16;
|
||||
g->chip.gc.label = "IXP4XX_GPIO_CHIP";
|
||||
/*
|
||||
* TODO: when we have migrated to device tree and all GPIOs
|
||||
* are fetched using phandles, set this to -1 to get rid of
|
||||
* the fixed gpiochip base.
|
||||
*/
|
||||
g->chip.gc.base = 0;
|
||||
g->chip.gc.base = -1;
|
||||
g->chip.gc.parent = &pdev->dev;
|
||||
g->chip.gc.owner = THIS_MODULE;
|
||||
|
||||
|
||||
@@ -156,7 +156,7 @@ static int lp873x_gpio_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
static const struct platform_device_id lp873x_gpio_id_table[] = {
|
||||
{ "lp873x-gpio", },
|
||||
{ .name = "lp873x-gpio" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, lp873x_gpio_id_table);
|
||||
|
||||
@@ -171,7 +171,7 @@ static int lp87565_gpio_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
static const struct platform_device_id lp87565_gpio_id_table[] = {
|
||||
{ "lp87565-q1-gpio", },
|
||||
{ .name = "lp87565-q1-gpio" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, lp87565_gpio_id_table);
|
||||
|
||||
@@ -53,7 +53,7 @@ static void max7300_remove(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id max7300_id[] = {
|
||||
{ "max7300" },
|
||||
{ .name = "max7300" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, max7300_id);
|
||||
|
||||
@@ -103,16 +103,16 @@ static uint64_t max732x_features[] = {
|
||||
};
|
||||
|
||||
static const struct i2c_device_id max732x_id[] = {
|
||||
{ "max7319", MAX7319 },
|
||||
{ "max7320", MAX7320 },
|
||||
{ "max7321", MAX7321 },
|
||||
{ "max7322", MAX7322 },
|
||||
{ "max7323", MAX7323 },
|
||||
{ "max7324", MAX7324 },
|
||||
{ "max7325", MAX7325 },
|
||||
{ "max7326", MAX7326 },
|
||||
{ "max7327", MAX7327 },
|
||||
{ },
|
||||
{ .name = "max7319", .driver_data = MAX7319 },
|
||||
{ .name = "max7320", .driver_data = MAX7320 },
|
||||
{ .name = "max7321", .driver_data = MAX7321 },
|
||||
{ .name = "max7322", .driver_data = MAX7322 },
|
||||
{ .name = "max7323", .driver_data = MAX7323 },
|
||||
{ .name = "max7324", .driver_data = MAX7324 },
|
||||
{ .name = "max7325", .driver_data = MAX7325 },
|
||||
{ .name = "max7326", .driver_data = MAX7326 },
|
||||
{ .name = "max7327", .driver_data = MAX7327 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, max732x_id);
|
||||
|
||||
|
||||
@@ -367,7 +367,7 @@ static int max77620_gpio_probe(struct platform_device *pdev)
|
||||
static const struct platform_device_id max77620_gpio_devtype[] = {
|
||||
{ .name = "max77620-gpio", },
|
||||
{ .name = "max20024-gpio", },
|
||||
{},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, max77620_gpio_devtype);
|
||||
|
||||
|
||||
@@ -502,7 +502,7 @@ static const struct of_device_id max77759_gpio_of_id[] = {
|
||||
MODULE_DEVICE_TABLE(of, max77759_gpio_of_id);
|
||||
|
||||
static const struct platform_device_id max77759_gpio_platform_id[] = {
|
||||
{ "max77759-gpio", },
|
||||
{ .name = "max77759-gpio" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, max77759_gpio_platform_id);
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
#define GPIO_REG_EDGE 0xA0
|
||||
|
||||
struct mtk_gc {
|
||||
struct irq_chip irq_chip;
|
||||
struct gpio_generic_chip chip;
|
||||
struct mtk *parent_priv;
|
||||
int bank;
|
||||
u32 rising;
|
||||
u32 falling;
|
||||
@@ -41,20 +41,32 @@ struct mtk_gc {
|
||||
/**
|
||||
* struct mtk - state container for
|
||||
* data of the platform driver. It is 3
|
||||
* separate gpio-chip each one with its
|
||||
* own irq_chip.
|
||||
* @dev: device instance
|
||||
* separate gpio-chip having an IRQ
|
||||
* linear domain shared for all of them
|
||||
* @pdev: platform device instance
|
||||
* @base: memory base address
|
||||
* @irq_domain: IRQ linear domain shared across the three gpio chips
|
||||
* @gpio_irq: irq number from the device tree
|
||||
* @num_gpios: total number of gpio pins on the three gpio chips
|
||||
* @gc_map: array of the gpio chips
|
||||
*/
|
||||
struct mtk {
|
||||
struct device *dev;
|
||||
struct platform_device *pdev;
|
||||
void __iomem *base;
|
||||
struct irq_domain *irq_domain;
|
||||
int gpio_irq;
|
||||
int num_gpios;
|
||||
struct mtk_gc gc_map[MTK_BANK_CNT];
|
||||
};
|
||||
|
||||
static inline struct mtk *
|
||||
mt7621_gpio_gc_to_priv(struct gpio_chip *gc)
|
||||
{
|
||||
struct mtk_gc *bank = gpiochip_get_data(gc);
|
||||
|
||||
return bank->parent_priv;
|
||||
}
|
||||
|
||||
static inline struct mtk_gc *
|
||||
to_mediatek_gpio(struct gpio_chip *chip)
|
||||
{
|
||||
@@ -67,7 +79,7 @@ static inline void
|
||||
mtk_gpio_w32(struct mtk_gc *rg, u32 offset, u32 val)
|
||||
{
|
||||
struct gpio_chip *gc = &rg->chip.gc;
|
||||
struct mtk *mtk = gpiochip_get_data(gc);
|
||||
struct mtk *mtk = mt7621_gpio_gc_to_priv(gc);
|
||||
|
||||
offset = (rg->bank * GPIO_BANK_STRIDE) + offset;
|
||||
gpio_generic_write_reg(&rg->chip, mtk->base + offset, val);
|
||||
@@ -77,41 +89,62 @@ static inline u32
|
||||
mtk_gpio_r32(struct mtk_gc *rg, u32 offset)
|
||||
{
|
||||
struct gpio_chip *gc = &rg->chip.gc;
|
||||
struct mtk *mtk = gpiochip_get_data(gc);
|
||||
struct mtk *mtk = mt7621_gpio_gc_to_priv(gc);
|
||||
|
||||
offset = (rg->bank * GPIO_BANK_STRIDE) + offset;
|
||||
return gpio_generic_read_reg(&rg->chip, mtk->base + offset);
|
||||
}
|
||||
|
||||
static irqreturn_t
|
||||
mediatek_gpio_irq_handler(int irq, void *data)
|
||||
static void
|
||||
mt7621_gpio_irq_bank_handler(struct mtk_gc *bank)
|
||||
{
|
||||
struct gpio_chip *gc = data;
|
||||
struct mtk_gc *rg = to_mediatek_gpio(gc);
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
struct mtk *priv = bank->parent_priv;
|
||||
struct irq_domain *domain = priv->irq_domain;
|
||||
int hwbase = bank->chip.gc.offset;
|
||||
unsigned long pending;
|
||||
int bit;
|
||||
unsigned int offset;
|
||||
|
||||
pending = mtk_gpio_r32(rg, GPIO_REG_STAT);
|
||||
pending = mtk_gpio_r32(bank, GPIO_REG_STAT);
|
||||
if (!pending)
|
||||
return;
|
||||
|
||||
for_each_set_bit(bit, &pending, MTK_BANK_WIDTH) {
|
||||
generic_handle_domain_irq(gc->irq.domain, bit);
|
||||
mtk_gpio_w32(rg, GPIO_REG_STAT, BIT(bit));
|
||||
ret |= IRQ_HANDLED;
|
||||
mtk_gpio_w32(bank, GPIO_REG_STAT, pending);
|
||||
|
||||
for_each_set_bit(offset, &pending, MTK_BANK_WIDTH)
|
||||
generic_handle_domain_irq(domain, hwbase + offset);
|
||||
}
|
||||
|
||||
static void
|
||||
mt7621_gpio_irq_handler(struct irq_desc *desc)
|
||||
{
|
||||
struct mtk *priv = irq_desc_get_handler_data(desc);
|
||||
struct irq_chip *chip = irq_desc_get_chip(desc);
|
||||
int i;
|
||||
|
||||
chained_irq_enter(chip, desc);
|
||||
for (i = 0; i < MTK_BANK_CNT; i++) {
|
||||
struct mtk_gc *bank = &priv->gc_map[i];
|
||||
|
||||
mt7621_gpio_irq_bank_handler(bank);
|
||||
}
|
||||
chained_irq_exit(chip, desc);
|
||||
}
|
||||
|
||||
return ret;
|
||||
static int
|
||||
mt7621_gpio_hwirq_to_offset(irq_hw_number_t hwirq, struct mtk_gc *bank)
|
||||
{
|
||||
return hwirq - bank->chip.gc.offset;
|
||||
}
|
||||
|
||||
static void
|
||||
mediatek_gpio_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct mtk_gc *rg = to_mediatek_gpio(gc);
|
||||
int pin = d->hwirq;
|
||||
struct mtk_gc *rg = gpiochip_get_data(gc);
|
||||
u32 mask = mt7621_gpio_hwirq_to_offset(d->hwirq, rg);
|
||||
u32 rise, fall, high, low;
|
||||
|
||||
gpiochip_enable_irq(gc, d->hwirq);
|
||||
gpiochip_enable_irq(gc, mask);
|
||||
|
||||
guard(gpio_generic_lock_irqsave)(&rg->chip);
|
||||
|
||||
@@ -119,18 +152,18 @@ mediatek_gpio_irq_unmask(struct irq_data *d)
|
||||
fall = mtk_gpio_r32(rg, GPIO_REG_FEDGE);
|
||||
high = mtk_gpio_r32(rg, GPIO_REG_HLVL);
|
||||
low = mtk_gpio_r32(rg, GPIO_REG_LLVL);
|
||||
mtk_gpio_w32(rg, GPIO_REG_REDGE, rise | (BIT(pin) & rg->rising));
|
||||
mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall | (BIT(pin) & rg->falling));
|
||||
mtk_gpio_w32(rg, GPIO_REG_HLVL, high | (BIT(pin) & rg->hlevel));
|
||||
mtk_gpio_w32(rg, GPIO_REG_LLVL, low | (BIT(pin) & rg->llevel));
|
||||
mtk_gpio_w32(rg, GPIO_REG_REDGE, rise | (BIT(mask) & rg->rising));
|
||||
mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall | (BIT(mask) & rg->falling));
|
||||
mtk_gpio_w32(rg, GPIO_REG_HLVL, high | (BIT(mask) & rg->hlevel));
|
||||
mtk_gpio_w32(rg, GPIO_REG_LLVL, low | (BIT(mask) & rg->llevel));
|
||||
}
|
||||
|
||||
static void
|
||||
mediatek_gpio_irq_mask(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct mtk_gc *rg = to_mediatek_gpio(gc);
|
||||
int pin = d->hwirq;
|
||||
struct mtk_gc *rg = gpiochip_get_data(gc);
|
||||
u32 mask = mt7621_gpio_hwirq_to_offset(d->hwirq, rg);
|
||||
u32 rise, fall, high, low;
|
||||
|
||||
scoped_guard(gpio_generic_lock_irqsave, &rg->chip) {
|
||||
@@ -138,22 +171,21 @@ mediatek_gpio_irq_mask(struct irq_data *d)
|
||||
fall = mtk_gpio_r32(rg, GPIO_REG_FEDGE);
|
||||
high = mtk_gpio_r32(rg, GPIO_REG_HLVL);
|
||||
low = mtk_gpio_r32(rg, GPIO_REG_LLVL);
|
||||
mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall & ~BIT(pin));
|
||||
mtk_gpio_w32(rg, GPIO_REG_REDGE, rise & ~BIT(pin));
|
||||
mtk_gpio_w32(rg, GPIO_REG_HLVL, high & ~BIT(pin));
|
||||
mtk_gpio_w32(rg, GPIO_REG_LLVL, low & ~BIT(pin));
|
||||
mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall & ~BIT(mask));
|
||||
mtk_gpio_w32(rg, GPIO_REG_REDGE, rise & ~BIT(mask));
|
||||
mtk_gpio_w32(rg, GPIO_REG_HLVL, high & ~BIT(mask));
|
||||
mtk_gpio_w32(rg, GPIO_REG_LLVL, low & ~BIT(mask));
|
||||
}
|
||||
|
||||
gpiochip_disable_irq(gc, d->hwirq);
|
||||
gpiochip_disable_irq(gc, mask);
|
||||
}
|
||||
|
||||
static int
|
||||
mediatek_gpio_irq_type(struct irq_data *d, unsigned int type)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct mtk_gc *rg = to_mediatek_gpio(gc);
|
||||
int pin = d->hwirq;
|
||||
u32 mask = BIT(pin);
|
||||
struct mtk_gc *rg = gpiochip_get_data(gc);
|
||||
u32 mask = BIT(mt7621_gpio_hwirq_to_offset(d->hwirq, rg));
|
||||
|
||||
if (type == IRQ_TYPE_PROBE) {
|
||||
if ((rg->rising | rg->falling |
|
||||
@@ -190,6 +222,26 @@ mediatek_gpio_irq_type(struct irq_data *d, unsigned int type)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mt7621_gpio_irq_reqres(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct mtk_gc *rg = gpiochip_get_data(gc);
|
||||
unsigned int irq = mt7621_gpio_hwirq_to_offset(d->hwirq, rg);
|
||||
|
||||
return gpiochip_reqres_irq(gc, irq);
|
||||
}
|
||||
|
||||
static void
|
||||
mt7621_gpio_irq_relres(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct mtk_gc *rg = gpiochip_get_data(gc);
|
||||
unsigned int irq = mt7621_gpio_hwirq_to_offset(d->hwirq, rg);
|
||||
|
||||
gpiochip_relres_irq(gc, irq);
|
||||
}
|
||||
|
||||
static int
|
||||
mediatek_gpio_xlate(struct gpio_chip *chip,
|
||||
const struct of_phandle_args *spec, u32 *flags)
|
||||
@@ -208,14 +260,123 @@ mediatek_gpio_xlate(struct gpio_chip *chip,
|
||||
|
||||
static const struct irq_chip mt7621_irq_chip = {
|
||||
.name = "mt7621-gpio",
|
||||
.irq_request_resources = mt7621_gpio_irq_reqres,
|
||||
.irq_release_resources = mt7621_gpio_irq_relres,
|
||||
.irq_mask_ack = mediatek_gpio_irq_mask,
|
||||
.irq_mask = mediatek_gpio_irq_mask,
|
||||
.irq_unmask = mediatek_gpio_irq_unmask,
|
||||
.irq_set_type = mediatek_gpio_irq_type,
|
||||
.flags = IRQCHIP_IMMUTABLE,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
static void
|
||||
mt7621_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mtk *priv = platform_get_drvdata(pdev);
|
||||
int offset, virq;
|
||||
|
||||
if (priv->gpio_irq > 0)
|
||||
irq_set_chained_handler_and_data(priv->gpio_irq, NULL, NULL);
|
||||
|
||||
/* Remove all IRQ mappings and delete the domain */
|
||||
if (priv->irq_domain) {
|
||||
for (offset = 0; offset < priv->num_gpios; offset++) {
|
||||
virq = irq_find_mapping(priv->irq_domain, offset);
|
||||
irq_dispose_mapping(virq);
|
||||
}
|
||||
irq_domain_remove(priv->irq_domain);
|
||||
}
|
||||
}
|
||||
|
||||
static struct mtk_gc *
|
||||
mt7621_gpio_hwirq_to_bank(struct mtk *priv, irq_hw_number_t hwirq)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MTK_BANK_CNT; i++) {
|
||||
struct mtk_gc *bank = &priv->gc_map[i];
|
||||
|
||||
if (hwirq >= bank->chip.gc.offset &&
|
||||
hwirq < (bank->chip.gc.offset + bank->chip.gc.ngpio))
|
||||
return bank;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
mt7621_gpio_irq_map(struct irq_domain *d, unsigned int irq,
|
||||
irq_hw_number_t hwirq)
|
||||
{
|
||||
struct mtk *priv = d->host_data;
|
||||
struct mtk_gc *bank = mt7621_gpio_hwirq_to_bank(priv, hwirq);
|
||||
struct platform_device *pdev = priv->pdev;
|
||||
int ret;
|
||||
|
||||
if (!bank)
|
||||
return -EINVAL;
|
||||
|
||||
dev_dbg(&pdev->dev, "Mapping irq %d for gpio line %d (bank %d)\n",
|
||||
irq, (int)hwirq, bank->bank);
|
||||
|
||||
ret = irq_set_chip_data(irq, &bank->chip.gc);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
irq_set_chip_and_handler(irq, &mt7621_irq_chip, handle_simple_irq);
|
||||
irq_set_noprobe(irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
mt7621_gpio_irq_unmap(struct irq_domain *d, unsigned int irq)
|
||||
{
|
||||
irq_set_chip_and_handler(irq, NULL, NULL);
|
||||
irq_set_chip_data(irq, NULL);
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops mt7621_gpio_irq_domain_ops = {
|
||||
.map = mt7621_gpio_irq_map,
|
||||
.unmap = mt7621_gpio_irq_unmap,
|
||||
.xlate = irq_domain_xlate_twocell,
|
||||
};
|
||||
|
||||
static int
|
||||
mt7621_gpio_irq_setup(struct platform_device *pdev,
|
||||
struct mtk *priv)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
priv->irq_domain = irq_domain_create_linear(dev_fwnode(dev),
|
||||
priv->num_gpios,
|
||||
&mt7621_gpio_irq_domain_ops,
|
||||
priv);
|
||||
if (!priv->irq_domain) {
|
||||
dev_err(dev, "Couldn't allocate IRQ domain\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
irq_set_chained_handler_and_data(priv->gpio_irq,
|
||||
mt7621_gpio_irq_handler, priv);
|
||||
irq_set_status_flags(priv->gpio_irq, IRQ_DISABLE_UNLAZY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mt7621_gpio_to_irq(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
struct mtk *priv = mt7621_gpio_gc_to_priv(gc);
|
||||
/* gc_offset is relative to this gpio_chip; want real offset */
|
||||
int hwirq = offset + gc->offset;
|
||||
|
||||
if (hwirq >= priv->num_gpios)
|
||||
return -ENXIO;
|
||||
|
||||
return irq_create_mapping(priv->irq_domain, hwirq);
|
||||
}
|
||||
|
||||
static int
|
||||
mediatek_gpio_bank_probe(struct device *dev, int bank)
|
||||
{
|
||||
@@ -228,6 +389,7 @@ mediatek_gpio_bank_probe(struct device *dev, int bank)
|
||||
rg = &mtk->gc_map[bank];
|
||||
memset(rg, 0, sizeof(*rg));
|
||||
|
||||
rg->parent_priv = mtk;
|
||||
rg->bank = bank;
|
||||
|
||||
dat = mtk->base + GPIO_REG_DATA + (rg->bank * GPIO_BANK_STRIDE);
|
||||
@@ -253,41 +415,17 @@ mediatek_gpio_bank_probe(struct device *dev, int bank)
|
||||
|
||||
rg->chip.gc.of_gpio_n_cells = 2;
|
||||
rg->chip.gc.of_xlate = mediatek_gpio_xlate;
|
||||
rg->chip.gc.ngpio = MTK_BANK_WIDTH;
|
||||
rg->chip.gc.label = devm_kasprintf(dev, GFP_KERNEL, "%s-bank%d",
|
||||
dev_name(dev), bank);
|
||||
if (!rg->chip.gc.label)
|
||||
return -ENOMEM;
|
||||
|
||||
rg->chip.gc.offset = bank * MTK_BANK_WIDTH;
|
||||
if (mtk->gpio_irq > 0)
|
||||
rg->chip.gc.to_irq = mt7621_gpio_to_irq;
|
||||
|
||||
if (mtk->gpio_irq) {
|
||||
struct gpio_irq_chip *girq;
|
||||
|
||||
/*
|
||||
* Directly request the irq here instead of passing
|
||||
* a flow-handler because the irq is shared.
|
||||
*/
|
||||
ret = devm_request_irq(dev, mtk->gpio_irq,
|
||||
mediatek_gpio_irq_handler, IRQF_SHARED,
|
||||
rg->chip.gc.label, &rg->chip.gc);
|
||||
|
||||
if (ret) {
|
||||
dev_err(dev, "Error requesting IRQ %d: %d\n",
|
||||
mtk->gpio_irq, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
girq = &rg->chip.gc.irq;
|
||||
gpio_irq_chip_set_chip(girq, &mt7621_irq_chip);
|
||||
/* This will let us handle the parent IRQ in the driver */
|
||||
girq->parent_handler = NULL;
|
||||
girq->num_parents = 0;
|
||||
girq->parents = NULL;
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_simple_irq;
|
||||
}
|
||||
|
||||
ret = devm_gpiochip_add_data(dev, &rg->chip.gc, mtk);
|
||||
ret = devm_gpiochip_add_data(dev, &rg->chip.gc, rg);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Could not register gpio %d, ret=%d\n",
|
||||
rg->chip.gc.ngpio, ret);
|
||||
@@ -322,7 +460,8 @@ mediatek_gpio_probe(struct platform_device *pdev)
|
||||
if (mtk->gpio_irq < 0)
|
||||
return mtk->gpio_irq;
|
||||
|
||||
mtk->dev = dev;
|
||||
mtk->pdev = pdev;
|
||||
mtk->num_gpios = MTK_BANK_WIDTH * MTK_BANK_CNT;
|
||||
platform_set_drvdata(pdev, mtk);
|
||||
|
||||
for (i = 0; i < MTK_BANK_CNT; i++) {
|
||||
@@ -331,7 +470,17 @@ mediatek_gpio_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (mtk->gpio_irq > 0) {
|
||||
ret = mt7621_gpio_irq_setup(pdev, mtk);
|
||||
if (ret)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
mt7621_gpio_remove(pdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id mediatek_gpio_match[] = {
|
||||
@@ -342,6 +491,7 @@ MODULE_DEVICE_TABLE(of, mediatek_gpio_match);
|
||||
|
||||
static struct platform_driver mediatek_gpio_driver = {
|
||||
.probe = mediatek_gpio_probe,
|
||||
.remove = mt7621_gpio_remove,
|
||||
.driver = {
|
||||
.name = "mt7621_gpio",
|
||||
.of_match_table = mediatek_gpio_match,
|
||||
|
||||
@@ -330,13 +330,13 @@ static int gpio_set_wake_irq(struct irq_data *d, u32 enable)
|
||||
ret = enable_irq_wake(port->irq_high);
|
||||
else
|
||||
ret = enable_irq_wake(port->irq);
|
||||
port->wakeup_pads |= (1 << gpio_idx);
|
||||
port->wakeup_pads |= BIT(gpio_idx);
|
||||
} else {
|
||||
if (port->irq_high && (gpio_idx >= 16))
|
||||
ret = disable_irq_wake(port->irq_high);
|
||||
else
|
||||
ret = disable_irq_wake(port->irq);
|
||||
port->wakeup_pads &= ~(1 << gpio_idx);
|
||||
port->wakeup_pads &= ~BIT(gpio_idx);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -86,49 +86,49 @@
|
||||
#define PCA_CHIP_TYPE(x) ((x) & PCA_TYPE_MASK)
|
||||
|
||||
static const struct i2c_device_id pca953x_id[] = {
|
||||
{ "pca6408", 8 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "pca6416", 16 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "pca9505", 40 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "pca9506", 40 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "pca9534", 8 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "pca9535", 16 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "pca9536", 4 | PCA953X_TYPE, },
|
||||
{ "pca9537", 4 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "pca9538", 8 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "pca9539", 16 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "pca9554", 8 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "pca9555", 16 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "pca9556", 8 | PCA953X_TYPE, },
|
||||
{ "pca9557", 8 | PCA953X_TYPE, },
|
||||
{ "pca9574", 8 | PCA957X_TYPE | PCA_INT, },
|
||||
{ "pca9575", 16 | PCA957X_TYPE | PCA_INT, },
|
||||
{ "pca9698", 40 | PCA953X_TYPE, },
|
||||
{ .name = "pca6408", .driver_data = 8 | PCA953X_TYPE | PCA_INT },
|
||||
{ .name = "pca6416", .driver_data = 16 | PCA953X_TYPE | PCA_INT },
|
||||
{ .name = "pca9505", .driver_data = 40 | PCA953X_TYPE | PCA_INT },
|
||||
{ .name = "pca9506", .driver_data = 40 | PCA953X_TYPE | PCA_INT },
|
||||
{ .name = "pca9534", .driver_data = 8 | PCA953X_TYPE | PCA_INT },
|
||||
{ .name = "pca9535", .driver_data = 16 | PCA953X_TYPE | PCA_INT },
|
||||
{ .name = "pca9536", .driver_data = 4 | PCA953X_TYPE },
|
||||
{ .name = "pca9537", .driver_data = 4 | PCA953X_TYPE | PCA_INT },
|
||||
{ .name = "pca9538", .driver_data = 8 | PCA953X_TYPE | PCA_INT },
|
||||
{ .name = "pca9539", .driver_data = 16 | PCA953X_TYPE | PCA_INT },
|
||||
{ .name = "pca9554", .driver_data = 8 | PCA953X_TYPE | PCA_INT },
|
||||
{ .name = "pca9555", .driver_data = 16 | PCA953X_TYPE | PCA_INT },
|
||||
{ .name = "pca9556", .driver_data = 8 | PCA953X_TYPE },
|
||||
{ .name = "pca9557", .driver_data = 8 | PCA953X_TYPE },
|
||||
{ .name = "pca9574", .driver_data = 8 | PCA957X_TYPE | PCA_INT },
|
||||
{ .name = "pca9575", .driver_data = 16 | PCA957X_TYPE | PCA_INT },
|
||||
{ .name = "pca9698", .driver_data = 40 | PCA953X_TYPE },
|
||||
|
||||
{ "pcal6408", 8 | PCA953X_TYPE | PCA_LATCH_INT, },
|
||||
{ "pcal6416", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
|
||||
{ "pcal6524", 24 | PCA953X_TYPE | PCA_LATCH_INT, },
|
||||
{ "pcal6534", 34 | PCAL653X_TYPE | PCA_LATCH_INT, },
|
||||
{ "pcal9535", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
|
||||
{ "pcal9554b", 8 | PCA953X_TYPE | PCA_LATCH_INT, },
|
||||
{ "pcal9555a", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
|
||||
{ .name = "pcal6408", .driver_data = 8 | PCA953X_TYPE | PCA_LATCH_INT },
|
||||
{ .name = "pcal6416", .driver_data = 16 | PCA953X_TYPE | PCA_LATCH_INT },
|
||||
{ .name = "pcal6524", .driver_data = 24 | PCA953X_TYPE | PCA_LATCH_INT },
|
||||
{ .name = "pcal6534", .driver_data = 34 | PCAL653X_TYPE | PCA_LATCH_INT },
|
||||
{ .name = "pcal9535", .driver_data = 16 | PCA953X_TYPE | PCA_LATCH_INT },
|
||||
{ .name = "pcal9554b", .driver_data = 8 | PCA953X_TYPE | PCA_LATCH_INT },
|
||||
{ .name = "pcal9555a", .driver_data = 16 | PCA953X_TYPE | PCA_LATCH_INT },
|
||||
|
||||
{ "max7310", 8 | PCA953X_TYPE, },
|
||||
{ "max7312", 16 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "max7313", 16 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "max7315", 8 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "max7318", 16 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "pca6107", 8 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "tca6408", 8 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "tca6416", 16 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "tca6418", 18 | TCA6418_TYPE | PCA_INT, },
|
||||
{ "tca6424", 24 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "tca9538", 8 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "tca9539", 16 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "tca9554", 8 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "xra1202", 8 | PCA953X_TYPE },
|
||||
{ .name = "max7310", .driver_data = 8 | PCA953X_TYPE },
|
||||
{ .name = "max7312", .driver_data = 16 | PCA953X_TYPE | PCA_INT },
|
||||
{ .name = "max7313", .driver_data = 16 | PCA953X_TYPE | PCA_INT },
|
||||
{ .name = "max7315", .driver_data = 8 | PCA953X_TYPE | PCA_INT },
|
||||
{ .name = "max7318", .driver_data = 16 | PCA953X_TYPE | PCA_INT },
|
||||
{ .name = "pca6107", .driver_data = 8 | PCA953X_TYPE | PCA_INT },
|
||||
{ .name = "tca6408", .driver_data = 8 | PCA953X_TYPE | PCA_INT },
|
||||
{ .name = "tca6416", .driver_data = 16 | PCA953X_TYPE | PCA_INT },
|
||||
{ .name = "tca6418", .driver_data = 18 | TCA6418_TYPE | PCA_INT },
|
||||
{ .name = "tca6424", .driver_data = 24 | PCA953X_TYPE | PCA_INT },
|
||||
{ .name = "tca9538", .driver_data = 8 | PCA953X_TYPE | PCA_INT },
|
||||
{ .name = "tca9539", .driver_data = 16 | PCA953X_TYPE | PCA_INT },
|
||||
{ .name = "tca9554", .driver_data = 8 | PCA953X_TYPE | PCA_INT },
|
||||
{ .name = "xra1202", .driver_data = 8 | PCA953X_TYPE },
|
||||
|
||||
{ "tcal6408", 8 | PCA953X_TYPE | PCA_LATCH_INT, },
|
||||
{ "tcal6416", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
|
||||
{ .name = "tcal6408", .driver_data = 8 | PCA953X_TYPE | PCA_LATCH_INT },
|
||||
{ .name = "tcal6416", .driver_data = 16 | PCA953X_TYPE | PCA_LATCH_INT },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, pca953x_id);
|
||||
@@ -877,11 +877,9 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
|
||||
bitmap_or(irq_mask, chip->irq_trig_fall, chip->irq_trig_raise, gc->ngpio);
|
||||
bitmap_or(irq_mask, irq_mask, chip->irq_trig_level_high, gc->ngpio);
|
||||
bitmap_or(irq_mask, irq_mask, chip->irq_trig_level_low, gc->ngpio);
|
||||
bitmap_complement(reg_direction, reg_direction, gc->ngpio);
|
||||
bitmap_and(irq_mask, irq_mask, reg_direction, gc->ngpio);
|
||||
|
||||
/* Look for any newly setup interrupt */
|
||||
for_each_set_bit(level, irq_mask, gc->ngpio)
|
||||
for_each_andnot_bit(level, irq_mask, reg_direction, gc->ngpio)
|
||||
pca953x_gpio_direction_input(&chip->gpio_chip, level);
|
||||
|
||||
mutex_unlock(&chip->irq_lock);
|
||||
@@ -1005,8 +1003,7 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, unsigned long *pendin
|
||||
bitmap_and(cur_stat, cur_stat, chip->irq_mask, gc->ngpio);
|
||||
bitmap_or(pending, pending, cur_stat, gc->ngpio);
|
||||
|
||||
bitmap_complement(cur_stat, new_stat, gc->ngpio);
|
||||
bitmap_and(cur_stat, cur_stat, reg_direction, gc->ngpio);
|
||||
bitmap_andnot(cur_stat, reg_direction, new_stat, gc->ngpio);
|
||||
bitmap_and(old_stat, cur_stat, chip->irq_trig_level_low, gc->ngpio);
|
||||
bitmap_and(old_stat, old_stat, chip->irq_mask, gc->ngpio);
|
||||
bitmap_or(pending, pending, old_stat, gc->ngpio);
|
||||
|
||||
@@ -163,9 +163,9 @@ static const struct pca9570_chip_data slg7xl45106_gpio = {
|
||||
};
|
||||
|
||||
static const struct i2c_device_id pca9570_id_table[] = {
|
||||
{ "pca9570", (kernel_ulong_t)&pca9570_gpio},
|
||||
{ "pca9571", (kernel_ulong_t)&pca9571_gpio },
|
||||
{ "slg7xl45106", (kernel_ulong_t)&slg7xl45106_gpio },
|
||||
{ .name = "pca9570", .driver_data = (kernel_ulong_t)&pca9570_gpio },
|
||||
{ .name = "pca9571", .driver_data = (kernel_ulong_t)&pca9571_gpio },
|
||||
{ .name = "slg7xl45106", .driver_data = (kernel_ulong_t)&slg7xl45106_gpio },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, pca9570_id_table);
|
||||
|
||||
@@ -20,19 +20,19 @@
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
static const struct i2c_device_id pcf857x_id[] = {
|
||||
{ "pcf8574", 8 },
|
||||
{ "pcf8574a", 8 },
|
||||
{ "pca8574", 8 },
|
||||
{ "pca9670", 8 },
|
||||
{ "pca9672", 8 },
|
||||
{ "pca9674", 8 },
|
||||
{ "pcf8575", 16 },
|
||||
{ "pca8575", 16 },
|
||||
{ "pca9671", 16 },
|
||||
{ "pca9673", 16 },
|
||||
{ "pca9675", 16 },
|
||||
{ "max7328", 8 },
|
||||
{ "max7329", 8 },
|
||||
{ .name = "pcf8574", .driver_data = 8 },
|
||||
{ .name = "pcf8574a", .driver_data = 8 },
|
||||
{ .name = "pca8574", .driver_data = 8 },
|
||||
{ .name = "pca9670", .driver_data = 8 },
|
||||
{ .name = "pca9672", .driver_data = 8 },
|
||||
{ .name = "pca9674", .driver_data = 8 },
|
||||
{ .name = "pcf8575", .driver_data = 16 },
|
||||
{ .name = "pca8575", .driver_data = 16 },
|
||||
{ .name = "pca9671", .driver_data = 16 },
|
||||
{ .name = "pca9673", .driver_data = 16 },
|
||||
{ .name = "pca9675", .driver_data = 16 },
|
||||
{ .name = "max7328", .driver_data = 8 },
|
||||
{ .name = "max7329", .driver_data = 8 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, pcf857x_id);
|
||||
|
||||
@@ -708,15 +708,15 @@ static int pxa_gpio_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
static const struct platform_device_id gpio_id_table[] = {
|
||||
{ "pxa25x-gpio", (unsigned long)&pxa25x_id },
|
||||
{ "pxa26x-gpio", (unsigned long)&pxa26x_id },
|
||||
{ "pxa27x-gpio", (unsigned long)&pxa27x_id },
|
||||
{ "pxa3xx-gpio", (unsigned long)&pxa3xx_id },
|
||||
{ "pxa93x-gpio", (unsigned long)&pxa93x_id },
|
||||
{ "mmp-gpio", (unsigned long)&mmp_id },
|
||||
{ "mmp2-gpio", (unsigned long)&mmp2_id },
|
||||
{ "pxa1928-gpio", (unsigned long)&pxa1928_id },
|
||||
{ },
|
||||
{ .name = "pxa25x-gpio", .driver_data = (unsigned long)&pxa25x_id },
|
||||
{ .name = "pxa26x-gpio", .driver_data = (unsigned long)&pxa26x_id },
|
||||
{ .name = "pxa27x-gpio", .driver_data = (unsigned long)&pxa27x_id },
|
||||
{ .name = "pxa3xx-gpio", .driver_data = (unsigned long)&pxa3xx_id },
|
||||
{ .name = "pxa93x-gpio", .driver_data = (unsigned long)&pxa93x_id },
|
||||
{ .name = "mmp-gpio", .driver_data = (unsigned long)&mmp_id },
|
||||
{ .name = "mmp2-gpio", .driver_data = (unsigned long)&mmp2_id },
|
||||
{ .name = "pxa1928-gpio", .driver_data = (unsigned long)&pxa1928_id },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct platform_driver pxa_gpio_driver = {
|
||||
|
||||
@@ -40,16 +40,18 @@
|
||||
#define REALTEK_GPIO_PORTS_PER_BANK 4
|
||||
|
||||
/**
|
||||
* realtek_gpio_ctrl - Realtek Otto GPIO driver data
|
||||
* struct realtek_gpio_ctrl - Realtek Otto GPIO driver data
|
||||
*
|
||||
* @chip: Associated gpio_generic_chip instance
|
||||
* @base: Base address of the register block for a GPIO bank
|
||||
* @cpumask_base: Base address of the per-CPU interrupt mask registers
|
||||
* @cpu_irq_maskable: CPUs that can receive GPIO interrupts
|
||||
* @lock: Lock for accessing the IRQ registers and values
|
||||
* @intr_mask: Mask for interrupts lines
|
||||
* @intr_type: Interrupt type selection
|
||||
* @bank_read: Read a bank setting as a single 32-bit value
|
||||
* @bank_write: Write a bank setting as a single 32-bit value
|
||||
* @imr_line_pos: Bit shift of an IRQ line's IMR value.
|
||||
* @line_imr_pos: Bit shift of an IRQ line's IMR value.
|
||||
*
|
||||
* The DIR, DATA, and ISR registers consist of four 8-bit port values, packed
|
||||
* into a single 32-bit register. Use @bank_read (@bank_write) to get (assign)
|
||||
|
||||
@@ -31,6 +31,7 @@ struct gpio_regmap {
|
||||
unsigned int reg_clr_base;
|
||||
unsigned int reg_dir_in_base;
|
||||
unsigned int reg_dir_out_base;
|
||||
unsigned long *fixed_direction_mask;
|
||||
unsigned long *fixed_direction_output;
|
||||
|
||||
#ifdef CONFIG_REGMAP_IRQ
|
||||
@@ -138,6 +139,20 @@ static int gpio_regmap_set_with_clear(struct gpio_chip *chip,
|
||||
return regmap_write(gpio->regmap, reg, mask);
|
||||
}
|
||||
|
||||
static bool gpio_regmap_fixed_direction(struct gpio_regmap *gpio,
|
||||
unsigned int offset)
|
||||
{
|
||||
if (!gpio->fixed_direction_output)
|
||||
return false;
|
||||
|
||||
/* In this case only some GPIOs are fixed as input/output */
|
||||
if (gpio->fixed_direction_mask &&
|
||||
!test_bit(offset, gpio->fixed_direction_mask))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int gpio_regmap_get_direction(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
@@ -145,7 +160,7 @@ static int gpio_regmap_get_direction(struct gpio_chip *chip,
|
||||
unsigned int base, val, reg, mask;
|
||||
int invert, ret;
|
||||
|
||||
if (gpio->fixed_direction_output) {
|
||||
if (gpio_regmap_fixed_direction(gpio, offset)) {
|
||||
if (test_bit(offset, gpio->fixed_direction_output))
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
else
|
||||
@@ -181,6 +196,22 @@ static int gpio_regmap_get_direction(struct gpio_chip *chip,
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
static int gpio_regmap_try_direction_fixed(struct gpio_regmap *gpio,
|
||||
unsigned int offset, bool output)
|
||||
{
|
||||
if (test_bit(offset, gpio->fixed_direction_output)) {
|
||||
if (output)
|
||||
return 0;
|
||||
else
|
||||
return -EINVAL;
|
||||
} else {
|
||||
if (output)
|
||||
return -EINVAL;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int gpio_regmap_set_direction(struct gpio_chip *chip,
|
||||
unsigned int offset, bool output)
|
||||
{
|
||||
@@ -188,6 +219,13 @@ static int gpio_regmap_set_direction(struct gpio_chip *chip,
|
||||
unsigned int base, val, reg, mask;
|
||||
int invert, ret;
|
||||
|
||||
/*
|
||||
* If the direction is fixed, only accept the fixed
|
||||
* direction in this call.
|
||||
*/
|
||||
if (gpio_regmap_fixed_direction(gpio, offset))
|
||||
return gpio_regmap_try_direction_fixed(gpio, offset, output);
|
||||
|
||||
if (gpio->reg_dir_out_base) {
|
||||
base = gpio_regmap_addr(gpio->reg_dir_out_base);
|
||||
invert = 0;
|
||||
@@ -219,6 +257,20 @@ static int gpio_regmap_direction_input(struct gpio_chip *chip,
|
||||
static int gpio_regmap_direction_output(struct gpio_chip *chip,
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
struct gpio_regmap *gpio = gpiochip_get_data(chip);
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* First check if this is gonna work on a fixed direction line,
|
||||
* if it doesn't (i.e. this is a fixed input line), then do not
|
||||
* attempt to set the output value either and just bail out.
|
||||
*/
|
||||
if (gpio_regmap_fixed_direction(gpio, offset)) {
|
||||
ret = gpio_regmap_try_direction_fixed(gpio, offset, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
gpio_regmap_set(chip, offset, value);
|
||||
|
||||
return gpio_regmap_set_direction(chip, offset, true);
|
||||
@@ -302,12 +354,23 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
|
||||
goto err_free_gpio;
|
||||
}
|
||||
|
||||
if (config->fixed_direction_mask) {
|
||||
gpio->fixed_direction_mask = bitmap_alloc(chip->ngpio,
|
||||
GFP_KERNEL);
|
||||
if (!gpio->fixed_direction_mask) {
|
||||
ret = -ENOMEM;
|
||||
goto err_free_gpio;
|
||||
}
|
||||
bitmap_copy(gpio->fixed_direction_mask,
|
||||
config->fixed_direction_mask, chip->ngpio);
|
||||
}
|
||||
|
||||
if (config->fixed_direction_output) {
|
||||
gpio->fixed_direction_output = bitmap_alloc(chip->ngpio,
|
||||
GFP_KERNEL);
|
||||
if (!gpio->fixed_direction_output) {
|
||||
ret = -ENOMEM;
|
||||
goto err_free_gpio;
|
||||
goto err_free_bitmap_dirmask;
|
||||
}
|
||||
bitmap_copy(gpio->fixed_direction_output,
|
||||
config->fixed_direction_output, chip->ngpio);
|
||||
@@ -329,7 +392,7 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
|
||||
|
||||
ret = gpiochip_add_data(chip, gpio);
|
||||
if (ret < 0)
|
||||
goto err_free_bitmap;
|
||||
goto err_free_bitmap_output;
|
||||
|
||||
#ifdef CONFIG_REGMAP_IRQ
|
||||
if (config->regmap_irq_chip) {
|
||||
@@ -355,8 +418,10 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
|
||||
|
||||
err_remove_gpiochip:
|
||||
gpiochip_remove(chip);
|
||||
err_free_bitmap:
|
||||
err_free_bitmap_output:
|
||||
bitmap_free(gpio->fixed_direction_output);
|
||||
err_free_bitmap_dirmask:
|
||||
bitmap_free(gpio->fixed_direction_mask);
|
||||
err_free_gpio:
|
||||
kfree(gpio);
|
||||
return ERR_PTR(ret);
|
||||
@@ -376,6 +441,7 @@ void gpio_regmap_unregister(struct gpio_regmap *gpio)
|
||||
|
||||
gpiochip_remove(&gpio->gpio_chip);
|
||||
bitmap_free(gpio->fixed_direction_output);
|
||||
bitmap_free(gpio->fixed_direction_mask);
|
||||
kfree(gpio);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpio_regmap_unregister);
|
||||
|
||||
@@ -695,9 +695,9 @@ static ssize_t gpio_sim_device_config_dev_name_show(struct config_item *item,
|
||||
|
||||
pdev = dev->pdev;
|
||||
if (pdev)
|
||||
return sprintf(page, "%s\n", dev_name(&pdev->dev));
|
||||
return sysfs_emit(page, "%s\n", dev_name(&pdev->dev));
|
||||
|
||||
return sprintf(page, "gpio-sim.%d\n", dev->id);
|
||||
return sysfs_emit(page, "gpio-sim.%d\n", dev->id);
|
||||
}
|
||||
|
||||
CONFIGFS_ATTR_RO(gpio_sim_device_config_, dev_name);
|
||||
@@ -711,7 +711,7 @@ gpio_sim_device_config_live_show(struct config_item *item, char *page)
|
||||
scoped_guard(mutex, &dev->lock)
|
||||
live = gpio_sim_device_is_live(dev);
|
||||
|
||||
return sprintf(page, "%c\n", live ? '1' : '0');
|
||||
return sysfs_emit(page, "%c\n", live ? '1' : '0');
|
||||
}
|
||||
|
||||
static unsigned int gpio_sim_get_line_names_size(struct gpio_sim_bank *bank)
|
||||
@@ -1059,7 +1059,7 @@ static int gpio_sim_emit_chip_name(struct device *dev, void *data)
|
||||
return 0;
|
||||
|
||||
if (device_match_fwnode(dev, ctx->swnode))
|
||||
return sprintf(ctx->page, "%s\n", dev_name(dev));
|
||||
return sysfs_emit(ctx->page, "%s\n", dev_name(dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1077,7 +1077,7 @@ static ssize_t gpio_sim_bank_config_chip_name_show(struct config_item *item,
|
||||
return device_for_each_child(&dev->pdev->dev, &ctx,
|
||||
gpio_sim_emit_chip_name);
|
||||
|
||||
return sprintf(page, "none\n");
|
||||
return sysfs_emit(page, "none\n");
|
||||
}
|
||||
|
||||
CONFIGFS_ATTR_RO(gpio_sim_bank_config_, chip_name);
|
||||
@@ -1090,7 +1090,7 @@ gpio_sim_bank_config_label_show(struct config_item *item, char *page)
|
||||
|
||||
guard(mutex)(&dev->lock);
|
||||
|
||||
return sprintf(page, "%s\n", bank->label ?: "");
|
||||
return sysfs_emit(page, "%s\n", bank->label ?: "");
|
||||
}
|
||||
|
||||
static ssize_t gpio_sim_bank_config_label_store(struct config_item *item,
|
||||
@@ -1125,7 +1125,7 @@ gpio_sim_bank_config_num_lines_show(struct config_item *item, char *page)
|
||||
|
||||
guard(mutex)(&dev->lock);
|
||||
|
||||
return sprintf(page, "%u\n", bank->num_lines);
|
||||
return sysfs_emit(page, "%u\n", bank->num_lines);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
@@ -1171,7 +1171,7 @@ gpio_sim_line_config_name_show(struct config_item *item, char *page)
|
||||
|
||||
guard(mutex)(&dev->lock);
|
||||
|
||||
return sprintf(page, "%s\n", line->name ?: "");
|
||||
return sysfs_emit(page, "%s\n", line->name ?: "");
|
||||
}
|
||||
|
||||
static ssize_t gpio_sim_line_config_name_store(struct config_item *item,
|
||||
@@ -1206,7 +1206,7 @@ gpio_sim_line_config_valid_show(struct config_item *item, char *page)
|
||||
|
||||
guard(mutex)(&dev->lock);
|
||||
|
||||
return sprintf(page, "%c\n", line->valid ? '1' : '0');
|
||||
return sysfs_emit(page, "%c\n", line->valid ? '1' : '0');
|
||||
}
|
||||
|
||||
static ssize_t gpio_sim_line_config_valid_store(struct config_item *item,
|
||||
@@ -1244,7 +1244,7 @@ static ssize_t gpio_sim_hog_config_name_show(struct config_item *item,
|
||||
|
||||
guard(mutex)(&dev->lock);
|
||||
|
||||
return sprintf(page, "%s\n", hog->name ?: "");
|
||||
return sysfs_emit(page, "%s\n", hog->name ?: "");
|
||||
}
|
||||
|
||||
static ssize_t gpio_sim_hog_config_name_store(struct config_item *item,
|
||||
@@ -1298,7 +1298,7 @@ static ssize_t gpio_sim_hog_config_direction_show(struct config_item *item,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return sprintf(page, "%s\n", repr);
|
||||
return sysfs_emit(page, "%s\n", repr);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
@@ -1338,7 +1338,7 @@ static ssize_t gpio_sim_hog_config_active_low_show(struct config_item *item,
|
||||
|
||||
guard(mutex)(&dev->lock);
|
||||
|
||||
return sprintf(page, "%c\n", hog->active_low ? '1' : '0');
|
||||
return sysfs_emit(page, "%c\n", hog->active_low ? '1' : '0');
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <dt-bindings/gpio/tegra186-gpio.h>
|
||||
#include <dt-bindings/gpio/tegra194-gpio.h>
|
||||
#include <dt-bindings/gpio/tegra234-gpio.h>
|
||||
#include <dt-bindings/gpio/nvidia,tegra238-gpio.h>
|
||||
#include <dt-bindings/gpio/tegra241-gpio.h>
|
||||
#include <dt-bindings/gpio/tegra256-gpio.h>
|
||||
#include <dt-bindings/gpio/nvidia,tegra264-gpio.h>
|
||||
@@ -1239,6 +1240,67 @@ static const struct tegra_gpio_soc tegra234_aon_soc = {
|
||||
.has_vm_support = false,
|
||||
};
|
||||
|
||||
#define TEGRA238_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \
|
||||
TEGRA_GPIO_PORT(TEGRA238_MAIN, _name, _bank, _port, _pins)
|
||||
|
||||
static const struct tegra_gpio_port tegra238_main_ports[] = {
|
||||
TEGRA238_MAIN_GPIO_PORT(A, 0, 0, 8),
|
||||
TEGRA238_MAIN_GPIO_PORT(B, 0, 1, 5),
|
||||
TEGRA238_MAIN_GPIO_PORT(C, 0, 2, 8),
|
||||
TEGRA238_MAIN_GPIO_PORT(D, 0, 3, 8),
|
||||
TEGRA238_MAIN_GPIO_PORT(E, 0, 4, 4),
|
||||
TEGRA238_MAIN_GPIO_PORT(F, 0, 5, 8),
|
||||
TEGRA238_MAIN_GPIO_PORT(G, 0, 6, 8),
|
||||
TEGRA238_MAIN_GPIO_PORT(H, 0, 7, 6),
|
||||
TEGRA238_MAIN_GPIO_PORT(J, 1, 0, 8),
|
||||
TEGRA238_MAIN_GPIO_PORT(K, 1, 1, 4),
|
||||
TEGRA238_MAIN_GPIO_PORT(L, 1, 2, 8),
|
||||
TEGRA238_MAIN_GPIO_PORT(M, 1, 3, 8),
|
||||
TEGRA238_MAIN_GPIO_PORT(N, 1, 4, 3),
|
||||
TEGRA238_MAIN_GPIO_PORT(P, 1, 5, 8),
|
||||
TEGRA238_MAIN_GPIO_PORT(Q, 1, 6, 3),
|
||||
TEGRA238_MAIN_GPIO_PORT(R, 2, 0, 8),
|
||||
TEGRA238_MAIN_GPIO_PORT(S, 2, 1, 8),
|
||||
TEGRA238_MAIN_GPIO_PORT(T, 2, 2, 8),
|
||||
TEGRA238_MAIN_GPIO_PORT(U, 2, 3, 6),
|
||||
TEGRA238_MAIN_GPIO_PORT(V, 2, 4, 2),
|
||||
TEGRA238_MAIN_GPIO_PORT(W, 3, 0, 8),
|
||||
TEGRA238_MAIN_GPIO_PORT(X, 3, 1, 2)
|
||||
};
|
||||
|
||||
static const struct tegra_gpio_soc tegra238_main_soc = {
|
||||
.num_ports = ARRAY_SIZE(tegra238_main_ports),
|
||||
.ports = tegra238_main_ports,
|
||||
.name = "tegra238-gpio",
|
||||
.instance = 0,
|
||||
.num_irqs_per_bank = 8,
|
||||
.has_vm_support = true,
|
||||
};
|
||||
|
||||
#define TEGRA238_AON_GPIO_PORT(_name, _bank, _port, _pins) \
|
||||
TEGRA_GPIO_PORT(TEGRA238_AON, _name, _bank, _port, _pins)
|
||||
|
||||
static const struct tegra_gpio_port tegra238_aon_ports[] = {
|
||||
TEGRA238_AON_GPIO_PORT(AA, 0, 0, 8),
|
||||
TEGRA238_AON_GPIO_PORT(BB, 0, 1, 1),
|
||||
TEGRA238_AON_GPIO_PORT(CC, 0, 2, 8),
|
||||
TEGRA238_AON_GPIO_PORT(DD, 0, 3, 8),
|
||||
TEGRA238_AON_GPIO_PORT(EE, 0, 4, 6),
|
||||
TEGRA238_AON_GPIO_PORT(FF, 0, 5, 8),
|
||||
TEGRA238_AON_GPIO_PORT(GG, 0, 6, 8),
|
||||
TEGRA238_AON_GPIO_PORT(HH, 0, 7, 4)
|
||||
};
|
||||
|
||||
static const struct tegra_gpio_soc tegra238_aon_soc = {
|
||||
.num_ports = ARRAY_SIZE(tegra238_aon_ports),
|
||||
.ports = tegra238_aon_ports,
|
||||
.name = "tegra238-gpio-aon",
|
||||
.instance = 1,
|
||||
.num_irqs_per_bank = 8,
|
||||
.has_gte = true,
|
||||
.has_vm_support = false,
|
||||
};
|
||||
|
||||
#define TEGRA241_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \
|
||||
TEGRA_GPIO_PORT(TEGRA241_MAIN, _name, _bank, _port, _pins)
|
||||
|
||||
@@ -1333,6 +1395,7 @@ static const struct tegra_gpio_soc tegra264_aon_soc = {
|
||||
.name = "tegra264-gpio-aon",
|
||||
.instance = 1,
|
||||
.num_irqs_per_bank = 8,
|
||||
.has_gte = true,
|
||||
.has_vm_support = true,
|
||||
};
|
||||
|
||||
@@ -1447,6 +1510,12 @@ static const struct of_device_id tegra186_gpio_of_match[] = {
|
||||
}, {
|
||||
.compatible = "nvidia,tegra234-gpio-aon",
|
||||
.data = &tegra234_aon_soc
|
||||
}, {
|
||||
.compatible = "nvidia,tegra238-gpio",
|
||||
.data = &tegra238_main_soc
|
||||
}, {
|
||||
.compatible = "nvidia,tegra238-gpio-aon",
|
||||
.data = &tegra238_aon_soc
|
||||
}, {
|
||||
.compatible = "nvidia,tegra256-gpio",
|
||||
.data = &tegra256_main_soc
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/timb_gpio.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
@@ -225,19 +224,21 @@ static int timbgpio_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
struct gpio_chip *gc;
|
||||
struct timbgpio *tgpio;
|
||||
struct timbgpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
int irq = platform_get_irq(pdev, 0);
|
||||
|
||||
if (!pdata || pdata->nr_pins > 32) {
|
||||
dev_err(dev, "Invalid platform data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tgpio = devm_kzalloc(dev, sizeof(*tgpio), GFP_KERNEL);
|
||||
if (!tgpio)
|
||||
return -EINVAL;
|
||||
|
||||
tgpio->irq_base = pdata->irq_base;
|
||||
gc = &tgpio->gpio;
|
||||
|
||||
err = device_property_read_u32(dev, "irq-base", &tgpio->irq_base);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = device_property_read_u32(dev, "gpio-base", &gc->base);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
spin_lock_init(&tgpio->lock);
|
||||
|
||||
@@ -245,8 +246,6 @@ static int timbgpio_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(tgpio->membase))
|
||||
return PTR_ERR(tgpio->membase);
|
||||
|
||||
gc = &tgpio->gpio;
|
||||
|
||||
gc->label = dev_name(&pdev->dev);
|
||||
gc->owner = THIS_MODULE;
|
||||
gc->parent = &pdev->dev;
|
||||
@@ -256,21 +255,22 @@ static int timbgpio_probe(struct platform_device *pdev)
|
||||
gc->set = timbgpio_gpio_set;
|
||||
gc->to_irq = (irq >= 0 && tgpio->irq_base > 0) ? timbgpio_to_irq : NULL;
|
||||
gc->dbg_show = NULL;
|
||||
gc->base = pdata->gpio_base;
|
||||
gc->ngpio = pdata->nr_pins;
|
||||
gc->can_sleep = false;
|
||||
|
||||
err = devm_gpiochip_add_data(&pdev->dev, gc, tgpio);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (gc->ngpio > 32)
|
||||
return dev_err_probe(dev, -EINVAL, "Invalid number of pins\n");
|
||||
|
||||
/* make sure to disable interrupts */
|
||||
iowrite32(0x0, tgpio->membase + TGPIO_IER);
|
||||
|
||||
if (irq < 0 || tgpio->irq_base <= 0)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < pdata->nr_pins; i++) {
|
||||
for (i = 0; i < gc->ngpio; i++) {
|
||||
irq_set_chip_and_handler(tgpio->irq_base + i,
|
||||
&timbgpio_irqchip, handle_simple_irq);
|
||||
irq_set_chip_data(tgpio->irq_base + i, tgpio);
|
||||
|
||||
@@ -112,7 +112,7 @@ static int tpic2810_probe(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id tpic2810_id_table[] = {
|
||||
{ "tpic2810", },
|
||||
{ .name = "tpic2810" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, tpic2810_id_table);
|
||||
|
||||
@@ -91,7 +91,7 @@ static int tps65086_gpio_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
static const struct platform_device_id tps65086_gpio_id_table[] = {
|
||||
{ "tps65086-gpio", },
|
||||
{ .name = "tps65086-gpio" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, tps65086_gpio_id_table);
|
||||
|
||||
@@ -201,7 +201,7 @@ static const struct of_device_id tps65218_dt_match[] = {
|
||||
MODULE_DEVICE_TABLE(of, tps65218_dt_match);
|
||||
|
||||
static const struct platform_device_id tps65218_gpio_id_table[] = {
|
||||
{ "tps65218-gpio", },
|
||||
{ .name = "tps65218-gpio" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, tps65218_gpio_id_table);
|
||||
|
||||
@@ -249,8 +249,8 @@ static int tps65219_gpio_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
static const struct platform_device_id tps6521x_gpio_id_table[] = {
|
||||
{ "tps65214-gpio", TPS65214 },
|
||||
{ "tps65219-gpio", TPS65219 },
|
||||
{ .name = "tps65214-gpio", .driver_data = TPS65214 },
|
||||
{ .name = "tps65219-gpio", .driver_data = TPS65219 },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, tps6521x_gpio_id_table);
|
||||
|
||||
@@ -115,7 +115,7 @@ static int tps65912_gpio_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
static const struct platform_device_id tps65912_gpio_id_table[] = {
|
||||
{ "tps65912-gpio", },
|
||||
{ .name = "tps65912-gpio" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, tps65912_gpio_id_table);
|
||||
|
||||
@@ -175,7 +175,7 @@ static int ts4900_gpio_probe(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ts4900_gpio_id_table[] = {
|
||||
{ "ts4900-gpio", },
|
||||
{ .name = "ts4900-gpio" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ts4900_gpio_id_table);
|
||||
|
||||
@@ -1,446 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Digital I/O driver for Technologic Systems TS-5500
|
||||
*
|
||||
* Copyright (c) 2012 Savoir-faire Linux Inc.
|
||||
* Vivien Didelot <vivien.didelot@savoirfairelinux.com>
|
||||
*
|
||||
* Technologic Systems platforms have pin blocks, exposing several Digital
|
||||
* Input/Output lines (DIO). This driver aims to support single pin blocks.
|
||||
* In that sense, the support is not limited to the TS-5500 blocks.
|
||||
* Actually, the following platforms have DIO support:
|
||||
*
|
||||
* TS-5500:
|
||||
* Documentation: https://docs.embeddedts.com/TS-5500
|
||||
* Blocks: DIO1, DIO2 and LCD port.
|
||||
*
|
||||
* TS-5600:
|
||||
* Documentation: https://docs.embeddedts.com/TS-5600
|
||||
* Blocks: LCD port (identical to TS-5500 LCD).
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/* List of supported Technologic Systems platforms DIO blocks */
|
||||
enum ts5500_blocks { TS5500_DIO1, TS5500_DIO2, TS5500_LCD, TS5600_LCD };
|
||||
|
||||
struct ts5500_priv {
|
||||
const struct ts5500_dio *pinout;
|
||||
struct gpio_chip gpio_chip;
|
||||
spinlock_t lock;
|
||||
bool strap;
|
||||
u8 hwirq;
|
||||
};
|
||||
|
||||
/*
|
||||
* Hex 7D is used to control several blocks (e.g. DIO2 and LCD port).
|
||||
* This flag ensures that the region has been requested by this driver.
|
||||
*/
|
||||
static bool hex7d_reserved;
|
||||
|
||||
/*
|
||||
* This structure is used to describe capabilities of DIO lines,
|
||||
* such as available directions and connected interrupt (if any).
|
||||
*/
|
||||
struct ts5500_dio {
|
||||
const u8 value_addr;
|
||||
const u8 value_mask;
|
||||
const u8 control_addr;
|
||||
const u8 control_mask;
|
||||
const bool no_input;
|
||||
const bool no_output;
|
||||
const u8 irq;
|
||||
};
|
||||
|
||||
#define TS5500_DIO_IN_OUT(vaddr, vbit, caddr, cbit) \
|
||||
{ \
|
||||
.value_addr = vaddr, \
|
||||
.value_mask = BIT(vbit), \
|
||||
.control_addr = caddr, \
|
||||
.control_mask = BIT(cbit), \
|
||||
}
|
||||
|
||||
#define TS5500_DIO_IN(addr, bit) \
|
||||
{ \
|
||||
.value_addr = addr, \
|
||||
.value_mask = BIT(bit), \
|
||||
.no_output = true, \
|
||||
}
|
||||
|
||||
#define TS5500_DIO_IN_IRQ(addr, bit, _irq) \
|
||||
{ \
|
||||
.value_addr = addr, \
|
||||
.value_mask = BIT(bit), \
|
||||
.no_output = true, \
|
||||
.irq = _irq, \
|
||||
}
|
||||
|
||||
#define TS5500_DIO_OUT(addr, bit) \
|
||||
{ \
|
||||
.value_addr = addr, \
|
||||
.value_mask = BIT(bit), \
|
||||
.no_input = true, \
|
||||
}
|
||||
|
||||
/*
|
||||
* Input/Output DIO lines are programmed in groups of 4. Their values are
|
||||
* available through 4 consecutive bits in a value port, whereas the direction
|
||||
* of these 4 lines is driven by only 1 bit in a control port.
|
||||
*/
|
||||
#define TS5500_DIO_GROUP(vaddr, vbitfrom, caddr, cbit) \
|
||||
TS5500_DIO_IN_OUT(vaddr, vbitfrom + 0, caddr, cbit), \
|
||||
TS5500_DIO_IN_OUT(vaddr, vbitfrom + 1, caddr, cbit), \
|
||||
TS5500_DIO_IN_OUT(vaddr, vbitfrom + 2, caddr, cbit), \
|
||||
TS5500_DIO_IN_OUT(vaddr, vbitfrom + 3, caddr, cbit)
|
||||
|
||||
/*
|
||||
* TS-5500 DIO1 block
|
||||
*
|
||||
* value control dir hw
|
||||
* addr bit addr bit in out irq name pin offset
|
||||
*
|
||||
* 0x7b 0 0x7a 0 x x DIO1_0 1 0
|
||||
* 0x7b 1 0x7a 0 x x DIO1_1 3 1
|
||||
* 0x7b 2 0x7a 0 x x DIO1_2 5 2
|
||||
* 0x7b 3 0x7a 0 x x DIO1_3 7 3
|
||||
* 0x7b 4 0x7a 1 x x DIO1_4 9 4
|
||||
* 0x7b 5 0x7a 1 x x DIO1_5 11 5
|
||||
* 0x7b 6 0x7a 1 x x DIO1_6 13 6
|
||||
* 0x7b 7 0x7a 1 x x DIO1_7 15 7
|
||||
* 0x7c 0 0x7a 5 x x DIO1_8 4 8
|
||||
* 0x7c 1 0x7a 5 x x DIO1_9 6 9
|
||||
* 0x7c 2 0x7a 5 x x DIO1_10 8 10
|
||||
* 0x7c 3 0x7a 5 x x DIO1_11 10 11
|
||||
* 0x7c 4 x DIO1_12 12 12
|
||||
* 0x7c 5 x 7 DIO1_13 14 13
|
||||
*/
|
||||
static const struct ts5500_dio ts5500_dio1[] = {
|
||||
TS5500_DIO_GROUP(0x7b, 0, 0x7a, 0),
|
||||
TS5500_DIO_GROUP(0x7b, 4, 0x7a, 1),
|
||||
TS5500_DIO_GROUP(0x7c, 0, 0x7a, 5),
|
||||
TS5500_DIO_IN(0x7c, 4),
|
||||
TS5500_DIO_IN_IRQ(0x7c, 5, 7),
|
||||
};
|
||||
|
||||
/*
|
||||
* TS-5500 DIO2 block
|
||||
*
|
||||
* value control dir hw
|
||||
* addr bit addr bit in out irq name pin offset
|
||||
*
|
||||
* 0x7e 0 0x7d 0 x x DIO2_0 1 0
|
||||
* 0x7e 1 0x7d 0 x x DIO2_1 3 1
|
||||
* 0x7e 2 0x7d 0 x x DIO2_2 5 2
|
||||
* 0x7e 3 0x7d 0 x x DIO2_3 7 3
|
||||
* 0x7e 4 0x7d 1 x x DIO2_4 9 4
|
||||
* 0x7e 5 0x7d 1 x x DIO2_5 11 5
|
||||
* 0x7e 6 0x7d 1 x x DIO2_6 13 6
|
||||
* 0x7e 7 0x7d 1 x x DIO2_7 15 7
|
||||
* 0x7f 0 0x7d 5 x x DIO2_8 4 8
|
||||
* 0x7f 1 0x7d 5 x x DIO2_9 6 9
|
||||
* 0x7f 2 0x7d 5 x x DIO2_10 8 10
|
||||
* 0x7f 3 0x7d 5 x x DIO2_11 10 11
|
||||
* 0x7f 4 x 6 DIO2_13 14 12
|
||||
*/
|
||||
static const struct ts5500_dio ts5500_dio2[] = {
|
||||
TS5500_DIO_GROUP(0x7e, 0, 0x7d, 0),
|
||||
TS5500_DIO_GROUP(0x7e, 4, 0x7d, 1),
|
||||
TS5500_DIO_GROUP(0x7f, 0, 0x7d, 5),
|
||||
TS5500_DIO_IN_IRQ(0x7f, 4, 6),
|
||||
};
|
||||
|
||||
/*
|
||||
* TS-5500 LCD port used as DIO block
|
||||
* TS-5600 LCD port is identical
|
||||
*
|
||||
* value control dir hw
|
||||
* addr bit addr bit in out irq name pin offset
|
||||
*
|
||||
* 0x72 0 0x7d 2 x x LCD_0 8 0
|
||||
* 0x72 1 0x7d 2 x x LCD_1 7 1
|
||||
* 0x72 2 0x7d 2 x x LCD_2 10 2
|
||||
* 0x72 3 0x7d 2 x x LCD_3 9 3
|
||||
* 0x72 4 0x7d 3 x x LCD_4 12 4
|
||||
* 0x72 5 0x7d 3 x x LCD_5 11 5
|
||||
* 0x72 6 0x7d 3 x x LCD_6 14 6
|
||||
* 0x72 7 0x7d 3 x x LCD_7 13 7
|
||||
* 0x73 0 x LCD_EN 5 8
|
||||
* 0x73 6 x LCD_WR 6 9
|
||||
* 0x73 7 x 1 LCD_RS 3 10
|
||||
*/
|
||||
static const struct ts5500_dio ts5500_lcd[] = {
|
||||
TS5500_DIO_GROUP(0x72, 0, 0x7d, 2),
|
||||
TS5500_DIO_GROUP(0x72, 4, 0x7d, 3),
|
||||
TS5500_DIO_OUT(0x73, 0),
|
||||
TS5500_DIO_IN(0x73, 6),
|
||||
TS5500_DIO_IN_IRQ(0x73, 7, 1),
|
||||
};
|
||||
|
||||
static inline void ts5500_set_mask(u8 mask, u8 addr)
|
||||
{
|
||||
u8 val = inb(addr);
|
||||
val |= mask;
|
||||
outb(val, addr);
|
||||
}
|
||||
|
||||
static inline void ts5500_clear_mask(u8 mask, u8 addr)
|
||||
{
|
||||
u8 val = inb(addr);
|
||||
val &= ~mask;
|
||||
outb(val, addr);
|
||||
}
|
||||
|
||||
static int ts5500_gpio_input(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct ts5500_priv *priv = gpiochip_get_data(chip);
|
||||
const struct ts5500_dio line = priv->pinout[offset];
|
||||
unsigned long flags;
|
||||
|
||||
if (line.no_input)
|
||||
return -ENXIO;
|
||||
|
||||
if (line.no_output)
|
||||
return 0;
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
ts5500_clear_mask(line.control_mask, line.control_addr);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ts5500_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct ts5500_priv *priv = gpiochip_get_data(chip);
|
||||
const struct ts5500_dio line = priv->pinout[offset];
|
||||
|
||||
return !!(inb(line.value_addr) & line.value_mask);
|
||||
}
|
||||
|
||||
static int ts5500_gpio_output(struct gpio_chip *chip, unsigned offset, int val)
|
||||
{
|
||||
struct ts5500_priv *priv = gpiochip_get_data(chip);
|
||||
const struct ts5500_dio line = priv->pinout[offset];
|
||||
unsigned long flags;
|
||||
|
||||
if (line.no_output)
|
||||
return -ENXIO;
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
if (!line.no_input)
|
||||
ts5500_set_mask(line.control_mask, line.control_addr);
|
||||
|
||||
if (val)
|
||||
ts5500_set_mask(line.value_mask, line.value_addr);
|
||||
else
|
||||
ts5500_clear_mask(line.value_mask, line.value_addr);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ts5500_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
|
||||
{
|
||||
struct ts5500_priv *priv = gpiochip_get_data(chip);
|
||||
const struct ts5500_dio line = priv->pinout[offset];
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
if (val)
|
||||
ts5500_set_mask(line.value_mask, line.value_addr);
|
||||
else
|
||||
ts5500_clear_mask(line.value_mask, line.value_addr);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ts5500_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct ts5500_priv *priv = gpiochip_get_data(chip);
|
||||
const struct ts5500_dio *block = priv->pinout;
|
||||
const struct ts5500_dio line = block[offset];
|
||||
|
||||
/* Only one pin is connected to an interrupt */
|
||||
if (line.irq)
|
||||
return line.irq;
|
||||
|
||||
/* As this pin is input-only, we may strap it to another in/out pin */
|
||||
if (priv->strap)
|
||||
return priv->hwirq;
|
||||
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
static int ts5500_enable_irq(struct ts5500_priv *priv)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
if (priv->hwirq == 7)
|
||||
ts5500_set_mask(BIT(7), 0x7a); /* DIO1_13 on IRQ7 */
|
||||
else if (priv->hwirq == 6)
|
||||
ts5500_set_mask(BIT(7), 0x7d); /* DIO2_13 on IRQ6 */
|
||||
else if (priv->hwirq == 1)
|
||||
ts5500_set_mask(BIT(6), 0x7d); /* LCD_RS on IRQ1 */
|
||||
else
|
||||
ret = -EINVAL;
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ts5500_disable_irq(struct ts5500_priv *priv)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
if (priv->hwirq == 7)
|
||||
ts5500_clear_mask(BIT(7), 0x7a); /* DIO1_13 on IRQ7 */
|
||||
else if (priv->hwirq == 6)
|
||||
ts5500_clear_mask(BIT(7), 0x7d); /* DIO2_13 on IRQ6 */
|
||||
else if (priv->hwirq == 1)
|
||||
ts5500_clear_mask(BIT(6), 0x7d); /* LCD_RS on IRQ1 */
|
||||
else
|
||||
dev_err(priv->gpio_chip.parent, "invalid hwirq %d\n",
|
||||
priv->hwirq);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
}
|
||||
|
||||
static int ts5500_dio_probe(struct platform_device *pdev)
|
||||
{
|
||||
enum ts5500_blocks block = platform_get_device_id(pdev)->driver_data;
|
||||
struct device *dev = &pdev->dev;
|
||||
const char *name = dev_name(dev);
|
||||
struct ts5500_priv *priv;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(struct ts5500_priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
priv->hwirq = ret;
|
||||
spin_lock_init(&priv->lock);
|
||||
|
||||
priv->gpio_chip.owner = THIS_MODULE;
|
||||
priv->gpio_chip.label = name;
|
||||
priv->gpio_chip.parent = dev;
|
||||
priv->gpio_chip.direction_input = ts5500_gpio_input;
|
||||
priv->gpio_chip.direction_output = ts5500_gpio_output;
|
||||
priv->gpio_chip.get = ts5500_gpio_get;
|
||||
priv->gpio_chip.set = ts5500_gpio_set;
|
||||
priv->gpio_chip.to_irq = ts5500_gpio_to_irq;
|
||||
priv->gpio_chip.base = -1;
|
||||
|
||||
switch (block) {
|
||||
case TS5500_DIO1:
|
||||
priv->pinout = ts5500_dio1;
|
||||
priv->gpio_chip.ngpio = ARRAY_SIZE(ts5500_dio1);
|
||||
|
||||
if (!devm_request_region(dev, 0x7a, 3, name)) {
|
||||
dev_err(dev, "failed to request %s ports\n", name);
|
||||
return -EBUSY;
|
||||
}
|
||||
break;
|
||||
case TS5500_DIO2:
|
||||
priv->pinout = ts5500_dio2;
|
||||
priv->gpio_chip.ngpio = ARRAY_SIZE(ts5500_dio2);
|
||||
|
||||
if (!devm_request_region(dev, 0x7e, 2, name)) {
|
||||
dev_err(dev, "failed to request %s ports\n", name);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (hex7d_reserved)
|
||||
break;
|
||||
|
||||
if (!devm_request_region(dev, 0x7d, 1, name)) {
|
||||
dev_err(dev, "failed to request %s 7D\n", name);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
hex7d_reserved = true;
|
||||
break;
|
||||
case TS5500_LCD:
|
||||
case TS5600_LCD:
|
||||
priv->pinout = ts5500_lcd;
|
||||
priv->gpio_chip.ngpio = ARRAY_SIZE(ts5500_lcd);
|
||||
|
||||
if (!devm_request_region(dev, 0x72, 2, name)) {
|
||||
dev_err(dev, "failed to request %s ports\n", name);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (!hex7d_reserved) {
|
||||
if (!devm_request_region(dev, 0x7d, 1, name)) {
|
||||
dev_err(dev, "failed to request %s 7D\n", name);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
hex7d_reserved = true;
|
||||
}
|
||||
|
||||
/* Ensure usage of LCD port as DIO */
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
ts5500_clear_mask(BIT(4), 0x7d);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
break;
|
||||
}
|
||||
|
||||
ret = devm_gpiochip_add_data(dev, &priv->gpio_chip, priv);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to register the gpio chip\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ts5500_enable_irq(priv);
|
||||
if (ret) {
|
||||
dev_err(dev, "invalid interrupt %d\n", priv->hwirq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ts5500_dio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ts5500_priv *priv = platform_get_drvdata(pdev);
|
||||
|
||||
ts5500_disable_irq(priv);
|
||||
}
|
||||
|
||||
static const struct platform_device_id ts5500_dio_ids[] = {
|
||||
{ "ts5500-dio1", TS5500_DIO1 },
|
||||
{ "ts5500-dio2", TS5500_DIO2 },
|
||||
{ "ts5500-dio-lcd", TS5500_LCD },
|
||||
{ "ts5600-dio-lcd", TS5600_LCD },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, ts5500_dio_ids);
|
||||
|
||||
static struct platform_driver ts5500_dio_driver = {
|
||||
.driver = {
|
||||
.name = "ts5500-dio",
|
||||
},
|
||||
.probe = ts5500_dio_probe,
|
||||
.remove = ts5500_dio_remove,
|
||||
.id_table = ts5500_dio_ids,
|
||||
};
|
||||
|
||||
module_platform_driver(ts5500_dio_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Savoir-faire Linux Inc. <kernel@savoirfairelinux.com>");
|
||||
MODULE_DESCRIPTION("Technologic Systems TS-5500 Digital I/O driver");
|
||||
@@ -31,6 +31,7 @@ static const struct acpi_device_id usbio_gpio_acpi_hids[] = {
|
||||
{ "INTC10B5" }, /* LNL */
|
||||
{ "INTC10D1" }, /* MTL-CVF */
|
||||
{ "INTC10E2" }, /* PTL */
|
||||
{ "INTC1116" }, /* NVL */
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
208
drivers/gpio/gpio-waveshare-dsi.c
Normal file
208
drivers/gpio/gpio-waveshare-dsi.c
Normal file
@@ -0,0 +1,208 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2024 Waveshare International Limited
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
*/
|
||||
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
/* I2C registers of the microcontroller. */
|
||||
#define REG_TP 0x94
|
||||
#define REG_LCD 0x95
|
||||
#define REG_PWM 0x96
|
||||
#define REG_SIZE 0x97
|
||||
#define REG_ID 0x98
|
||||
#define REG_VERSION 0x99
|
||||
|
||||
enum {
|
||||
GPIO_AVDD = 0,
|
||||
GPIO_PANEL_RESET = 1,
|
||||
GPIO_BL_ENABLE = 2,
|
||||
GPIO_IOVCC = 4,
|
||||
GPIO_VCC = 8,
|
||||
GPIO_TS_RESET = 9,
|
||||
};
|
||||
|
||||
#define NUM_GPIO 16
|
||||
|
||||
struct waveshare_gpio {
|
||||
struct mutex dir_lock;
|
||||
struct mutex pwr_lock;
|
||||
struct regmap *regmap;
|
||||
u16 poweron_state;
|
||||
|
||||
struct gpio_chip gc;
|
||||
};
|
||||
|
||||
static const struct regmap_config waveshare_gpio_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = REG_VERSION,
|
||||
};
|
||||
|
||||
static int waveshare_gpio_get(struct waveshare_gpio *state, unsigned int offset)
|
||||
{
|
||||
u16 pwr_state;
|
||||
|
||||
guard(mutex)(&state->pwr_lock);
|
||||
pwr_state = state->poweron_state & BIT(offset);
|
||||
|
||||
return !!pwr_state;
|
||||
}
|
||||
|
||||
static int waveshare_gpio_set(struct waveshare_gpio *state, unsigned int offset, int value)
|
||||
{
|
||||
u16 last_val;
|
||||
int err;
|
||||
|
||||
guard(mutex)(&state->pwr_lock);
|
||||
|
||||
last_val = state->poweron_state;
|
||||
if (value)
|
||||
last_val |= BIT(offset);
|
||||
else
|
||||
last_val &= ~BIT(offset);
|
||||
|
||||
state->poweron_state = last_val;
|
||||
|
||||
err = regmap_write(state->regmap, REG_TP, last_val >> 8);
|
||||
if (!err)
|
||||
err = regmap_write(state->regmap, REG_LCD, last_val & 0xff);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int waveshare_gpio_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static int waveshare_gpio_gpio_get(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
struct waveshare_gpio *state = gpiochip_get_data(gc);
|
||||
|
||||
return waveshare_gpio_get(state, offset);
|
||||
}
|
||||
|
||||
static int waveshare_gpio_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
|
||||
{
|
||||
struct waveshare_gpio *state = gpiochip_get_data(gc);
|
||||
|
||||
return waveshare_gpio_set(state, offset, value);
|
||||
}
|
||||
|
||||
static int waveshare_gpio_update_status(struct backlight_device *bl)
|
||||
{
|
||||
struct waveshare_gpio *state = bl_get_data(bl);
|
||||
int brightness = backlight_get_brightness(bl);
|
||||
|
||||
waveshare_gpio_set(state, GPIO_BL_ENABLE, brightness);
|
||||
|
||||
return regmap_write(state->regmap, REG_PWM, brightness);
|
||||
}
|
||||
|
||||
static const struct backlight_ops waveshare_gpio_bl = {
|
||||
.update_status = waveshare_gpio_update_status,
|
||||
};
|
||||
|
||||
static int waveshare_gpio_probe(struct i2c_client *i2c)
|
||||
{
|
||||
struct backlight_properties props = {};
|
||||
struct waveshare_gpio *state;
|
||||
struct device *dev = &i2c->dev;
|
||||
struct backlight_device *bl;
|
||||
struct regmap *regmap;
|
||||
unsigned int data;
|
||||
int ret;
|
||||
|
||||
state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
|
||||
if (!state)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = devm_mutex_init(dev, &state->dir_lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_mutex_init(dev, &state->pwr_lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
regmap = devm_regmap_init_i2c(i2c, &waveshare_gpio_regmap_config);
|
||||
if (IS_ERR(regmap))
|
||||
return dev_err_probe(dev, PTR_ERR(regmap), "Failed to allocate register map\n");
|
||||
|
||||
state->regmap = regmap;
|
||||
i2c_set_clientdata(i2c, state);
|
||||
|
||||
ret = regmap_read(regmap, REG_ID, &data);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret, "Failed to read register\n");
|
||||
|
||||
dev_dbg(dev, "waveshare panel hw id = 0x%x\n", data);
|
||||
|
||||
ret = regmap_read(regmap, REG_SIZE, &data);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret, "Failed to read register\n");
|
||||
|
||||
dev_dbg(dev, "waveshare panel size = %d\n", data);
|
||||
|
||||
ret = regmap_read(regmap, REG_VERSION, &data);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret, "Failed to read register\n");
|
||||
|
||||
dev_dbg(dev, "waveshare panel mcu version = 0x%x\n", data);
|
||||
|
||||
ret = waveshare_gpio_set(state, GPIO_TS_RESET, 1);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to program GPIOs\n");
|
||||
|
||||
msleep(20);
|
||||
|
||||
state->gc.parent = dev;
|
||||
state->gc.label = i2c->name;
|
||||
state->gc.owner = THIS_MODULE;
|
||||
state->gc.base = -1;
|
||||
state->gc.ngpio = NUM_GPIO;
|
||||
|
||||
/* it is output only */
|
||||
state->gc.get = waveshare_gpio_gpio_get;
|
||||
state->gc.set = waveshare_gpio_gpio_set;
|
||||
state->gc.get_direction = waveshare_gpio_gpio_get_direction;
|
||||
state->gc.can_sleep = true;
|
||||
|
||||
ret = devm_gpiochip_add_data(dev, &state->gc, state);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to create gpiochip\n");
|
||||
|
||||
props.type = BACKLIGHT_RAW;
|
||||
props.max_brightness = 255;
|
||||
props.brightness = 255;
|
||||
bl = devm_backlight_device_register(dev, dev_name(dev), dev, state,
|
||||
&waveshare_gpio_bl, &props);
|
||||
return PTR_ERR_OR_ZERO(bl);
|
||||
}
|
||||
|
||||
static const struct of_device_id waveshare_gpio_dt_ids[] = {
|
||||
{ .compatible = "waveshare,dsi-touch-gpio" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, waveshare_gpio_dt_ids);
|
||||
|
||||
static struct i2c_driver waveshare_gpio_regulator_driver = {
|
||||
.driver = {
|
||||
.name = "waveshare-regulator",
|
||||
.of_match_table = of_match_ptr(waveshare_gpio_dt_ids),
|
||||
},
|
||||
.probe = waveshare_gpio_probe,
|
||||
};
|
||||
|
||||
module_i2c_driver(waveshare_gpio_regulator_driver);
|
||||
|
||||
MODULE_DESCRIPTION("GPIO controller driver for Waveshare DSI touch panels");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -495,13 +495,11 @@ static void xgpio_irqhandler(struct irq_desc *desc)
|
||||
|
||||
xgpio_read_ch_all(chip, XGPIO_DATA_OFFSET, hw);
|
||||
|
||||
bitmap_complement(rising, chip->last_irq_read, 64);
|
||||
bitmap_and(rising, rising, hw, 64);
|
||||
bitmap_andnot(rising, hw, chip->last_irq_read, 64);
|
||||
bitmap_and(rising, rising, chip->enable, 64);
|
||||
bitmap_and(rising, rising, chip->rising_edge, 64);
|
||||
|
||||
bitmap_complement(falling, hw, 64);
|
||||
bitmap_and(falling, falling, chip->last_irq_read, 64);
|
||||
bitmap_andnot(falling, chip->last_irq_read, hw, 64);
|
||||
bitmap_and(falling, falling, chip->enable, 64);
|
||||
bitmap_and(falling, falling, chip->falling_edge, 64);
|
||||
|
||||
|
||||
@@ -64,14 +64,14 @@ static inline u32 zevio_gpio_port_get(struct zevio_gpio *c, unsigned pin,
|
||||
unsigned port_offset)
|
||||
{
|
||||
unsigned section_offset = ((pin >> 3) & 3)*ZEVIO_GPIO_SECTION_SIZE;
|
||||
return readl(IOMEM(c->regs + section_offset + port_offset));
|
||||
return readl(c->regs + section_offset + port_offset);
|
||||
}
|
||||
|
||||
static inline void zevio_gpio_port_set(struct zevio_gpio *c, unsigned pin,
|
||||
unsigned port_offset, u32 val)
|
||||
{
|
||||
unsigned section_offset = ((pin >> 3) & 3)*ZEVIO_GPIO_SECTION_SIZE;
|
||||
writel(val, IOMEM(c->regs + section_offset + port_offset));
|
||||
writel(val, c->regs + section_offset + port_offset);
|
||||
}
|
||||
|
||||
/* Functions for struct gpio_chip */
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#define VERSAL_GPIO_MAX_BANK 4
|
||||
#define PMC_GPIO_MAX_BANK 5
|
||||
#define VERSAL_UNUSED_BANKS 2
|
||||
#define EIO_GPIO_MAX_BANK 2
|
||||
|
||||
#define ZYNQ_GPIO_BANK0_NGPIO 32
|
||||
#define ZYNQ_GPIO_BANK1_NGPIO 22
|
||||
@@ -818,6 +819,16 @@ static const struct dev_pm_ops zynq_gpio_dev_pm_ops = {
|
||||
RUNTIME_PM_OPS(zynq_gpio_runtime_suspend, zynq_gpio_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static const struct zynq_platform_data eio_gpio_def = {
|
||||
.label = "eio_gpio",
|
||||
.ngpio = 52,
|
||||
.max_bank = EIO_GPIO_MAX_BANK,
|
||||
.bank_min[0] = 0,
|
||||
.bank_max[0] = 25, /* 0 to 25 are connected to MIOs (26 pins) */
|
||||
.bank_min[1] = 26,
|
||||
.bank_max[1] = 51, /* Bank 1 are connected to MIOs (26 pins) */
|
||||
};
|
||||
|
||||
static const struct zynq_platform_data versal_gpio_def = {
|
||||
.label = "versal_gpio",
|
||||
.quirks = GPIO_QUIRK_VERSAL,
|
||||
@@ -882,6 +893,7 @@ static const struct of_device_id zynq_gpio_of_match[] = {
|
||||
{ .compatible = "xlnx,zynqmp-gpio-1.0", .data = &zynqmp_gpio_def },
|
||||
{ .compatible = "xlnx,versal-gpio-1.0", .data = &versal_gpio_def },
|
||||
{ .compatible = "xlnx,pmc-gpio-1.0", .data = &pmc_gpio_def },
|
||||
{ .compatible = "xlnx,eio-gpio-1.0", .data = &eio_gpio_def },
|
||||
{ /* end of table */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, zynq_gpio_of_match);
|
||||
|
||||
@@ -142,10 +142,6 @@ static struct gpio_desc *acpi_get_gpiod(char *path, unsigned int pin)
|
||||
if (!gdev)
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
|
||||
/*
|
||||
* FIXME: keep track of the reference to the GPIO device somehow
|
||||
* instead of putting it here.
|
||||
*/
|
||||
return gpio_device_get_desc(gdev, pin);
|
||||
}
|
||||
|
||||
|
||||
@@ -353,6 +353,13 @@ int devm_gpiochip_add_data_with_key(struct device *dev, struct gpio_chip *gc, vo
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* We are passing the devres device here so if the user did not pass
|
||||
* another parent, it's this one.
|
||||
*/
|
||||
if (!gc->parent)
|
||||
gc->parent = dev;
|
||||
|
||||
ret = gpiochip_add_data_with_key(gc, data, lock_key, request_key);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
358
drivers/gpio/gpiolib-kunit.c
Normal file
358
drivers/gpio/gpiolib-kunit.c
Normal file
@@ -0,0 +1,358 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) Qualcomm Technologies, Inc. and/or its subsidiaries
|
||||
*/
|
||||
|
||||
#include <linux/fwnode.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/gpio/property.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
|
||||
#include <kunit/platform_device.h>
|
||||
#include <kunit/test.h>
|
||||
|
||||
#define GPIO_TEST_PROVIDER "gpio-test-provider"
|
||||
#define GPIO_SWNODE_TEST_CONSUMER "gpio-swnode-test-consumer"
|
||||
#define GPIO_UNBIND_TEST_CONSUMER "gpio-unbind-test-consumer"
|
||||
|
||||
static int gpio_test_provider_get_direction(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static int gpio_test_provider_set(struct gpio_chip *gc, unsigned int offset, int value)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_test_provider_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct gpio_chip *gc;
|
||||
|
||||
gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL);
|
||||
if (!gc)
|
||||
return -ENOMEM;
|
||||
|
||||
gc->base = -1;
|
||||
gc->ngpio = 4;
|
||||
gc->label = "gpio-swnode-consumer-test-device";
|
||||
gc->parent = dev;
|
||||
gc->owner = THIS_MODULE;
|
||||
|
||||
gc->get_direction = gpio_test_provider_get_direction;
|
||||
gc->set = gpio_test_provider_set;
|
||||
|
||||
return devm_gpiochip_add_data(dev, gc, NULL);
|
||||
}
|
||||
|
||||
static struct platform_driver gpio_test_provider_driver = {
|
||||
.probe = gpio_test_provider_probe,
|
||||
.driver = {
|
||||
.name = GPIO_TEST_PROVIDER,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct software_node gpio_test_provider_swnode = {
|
||||
.name = "gpio-test-provider-primary",
|
||||
};
|
||||
|
||||
struct gpio_swnode_consumer_pdata {
|
||||
bool gpio_ok;
|
||||
};
|
||||
|
||||
static const struct gpio_swnode_consumer_pdata gpio_swnode_pdata_template = {
|
||||
.gpio_ok = false,
|
||||
};
|
||||
|
||||
static int gpio_swnode_consumer_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct gpio_swnode_consumer_pdata *pdata = dev_get_platdata(dev);
|
||||
struct gpio_desc *desc;
|
||||
|
||||
desc = devm_gpiod_get(dev, "foo", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(desc))
|
||||
return PTR_ERR(desc);
|
||||
|
||||
pdata->gpio_ok = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver gpio_swnode_consumer_driver = {
|
||||
.probe = gpio_swnode_consumer_probe,
|
||||
.driver = {
|
||||
.name = GPIO_SWNODE_TEST_CONSUMER,
|
||||
},
|
||||
};
|
||||
|
||||
static void gpio_swnode_lookup_by_primary(struct kunit *test)
|
||||
{
|
||||
struct gpio_swnode_consumer_pdata *pdata;
|
||||
struct platform_device_info pdevinfo;
|
||||
struct property_entry properties[2];
|
||||
struct platform_device *pdev;
|
||||
bool bound = false;
|
||||
int ret;
|
||||
|
||||
ret = kunit_platform_driver_register(test, &gpio_test_provider_driver);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
ret = kunit_platform_driver_register(test, &gpio_swnode_consumer_driver);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
pdevinfo = (struct platform_device_info){
|
||||
.name = GPIO_TEST_PROVIDER,
|
||||
.id = PLATFORM_DEVID_NONE,
|
||||
.swnode = &gpio_test_provider_swnode,
|
||||
};
|
||||
|
||||
pdev = kunit_platform_device_register_full(test, &pdevinfo);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
|
||||
|
||||
properties[0] = PROPERTY_ENTRY_GPIO("foo-gpios",
|
||||
&gpio_test_provider_swnode,
|
||||
0, GPIO_ACTIVE_HIGH);
|
||||
properties[1] = (struct property_entry){ };
|
||||
|
||||
pdevinfo = (struct platform_device_info){
|
||||
.name = GPIO_SWNODE_TEST_CONSUMER,
|
||||
.id = PLATFORM_DEVID_NONE,
|
||||
.data = &gpio_swnode_pdata_template,
|
||||
.size_data = sizeof(gpio_swnode_pdata_template),
|
||||
.properties = properties,
|
||||
};
|
||||
|
||||
pdev = kunit_platform_device_register_full(test, &pdevinfo);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
|
||||
|
||||
wait_for_device_probe();
|
||||
scoped_guard(device, &pdev->dev)
|
||||
bound = device_is_bound(&pdev->dev);
|
||||
|
||||
KUNIT_ASSERT_TRUE(test, bound);
|
||||
|
||||
pdata = dev_get_platdata(&pdev->dev);
|
||||
KUNIT_ASSERT_TRUE(test, pdata->gpio_ok);
|
||||
}
|
||||
|
||||
static void gpio_swnode_lookup_by_secondary(struct kunit *test)
|
||||
{
|
||||
struct gpio_swnode_consumer_pdata *pdata;
|
||||
struct platform_device_info pdevinfo;
|
||||
struct property_entry properties[2];
|
||||
struct fwnode_handle *primary;
|
||||
struct platform_device *pdev;
|
||||
bool bound = false;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Can't live on the stack as it will still get referenced in cleanup
|
||||
* path after this function returns.
|
||||
*/
|
||||
primary = kunit_kzalloc(test, sizeof(*primary), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, primary);
|
||||
|
||||
ret = kunit_platform_driver_register(test, &gpio_test_provider_driver);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
ret = kunit_platform_driver_register(test, &gpio_swnode_consumer_driver);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
fwnode_init(primary, NULL);
|
||||
|
||||
pdevinfo = (struct platform_device_info){
|
||||
.name = GPIO_TEST_PROVIDER,
|
||||
.id = PLATFORM_DEVID_NONE,
|
||||
.fwnode = primary,
|
||||
.swnode = &gpio_test_provider_swnode,
|
||||
};
|
||||
|
||||
pdev = kunit_platform_device_register_full(test, &pdevinfo);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
|
||||
|
||||
properties[0] = PROPERTY_ENTRY_GPIO("foo-gpios",
|
||||
&gpio_test_provider_swnode,
|
||||
0, GPIO_ACTIVE_HIGH);
|
||||
properties[1] = (struct property_entry){ };
|
||||
|
||||
pdevinfo = (struct platform_device_info){
|
||||
.name = GPIO_SWNODE_TEST_CONSUMER,
|
||||
.id = PLATFORM_DEVID_NONE,
|
||||
.data = &gpio_swnode_pdata_template,
|
||||
.size_data = sizeof(gpio_swnode_pdata_template),
|
||||
.properties = properties,
|
||||
};
|
||||
|
||||
pdev = kunit_platform_device_register_full(test, &pdevinfo);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
|
||||
|
||||
wait_for_device_probe();
|
||||
scoped_guard(device, &pdev->dev)
|
||||
bound = device_is_bound(&pdev->dev);
|
||||
|
||||
KUNIT_ASSERT_TRUE(test, bound);
|
||||
|
||||
pdata = dev_get_platdata(&pdev->dev);
|
||||
KUNIT_ASSERT_TRUE(test, pdata->gpio_ok);
|
||||
}
|
||||
|
||||
static struct kunit_case gpio_swnode_lookup_tests[] = {
|
||||
KUNIT_CASE(gpio_swnode_lookup_by_primary),
|
||||
KUNIT_CASE(gpio_swnode_lookup_by_secondary),
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct kunit_suite gpio_swnode_lookup_test_suite = {
|
||||
.name = "gpio-swnode-lookup",
|
||||
.test_cases = gpio_swnode_lookup_tests,
|
||||
};
|
||||
|
||||
static BLOCKING_NOTIFIER_HEAD(gpio_unbind_notifier);
|
||||
|
||||
struct gpio_unbind_consumer_drvdata {
|
||||
struct device *dev;
|
||||
struct gpio_desc *desc;
|
||||
struct notifier_block nb;
|
||||
int set_retval;
|
||||
};
|
||||
|
||||
static int gpio_unbind_notify(struct notifier_block *nb, unsigned long action,
|
||||
void *data)
|
||||
{
|
||||
struct gpio_unbind_consumer_drvdata *drvdata =
|
||||
container_of(nb, struct gpio_unbind_consumer_drvdata, nb);
|
||||
struct device *dev = data;
|
||||
|
||||
if (dev != drvdata->dev)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
drvdata->set_retval = gpiod_set_value_cansleep(drvdata->desc, 0);
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static void gpio_unbind_unregister_notifier(void *data)
|
||||
{
|
||||
struct notifier_block *nb = data;
|
||||
|
||||
blocking_notifier_chain_unregister(&gpio_unbind_notifier, nb);
|
||||
}
|
||||
|
||||
static int gpio_unbind_consumer_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct gpio_unbind_consumer_drvdata *data;
|
||||
struct device *dev = &pdev->dev;
|
||||
int ret;
|
||||
|
||||
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->dev = dev;
|
||||
|
||||
data->desc = devm_gpiod_get(dev, "foo", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(data->desc))
|
||||
return PTR_ERR(data->desc);
|
||||
|
||||
data->nb.notifier_call = gpio_unbind_notify;
|
||||
ret = blocking_notifier_chain_register(&gpio_unbind_notifier, &data->nb);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(dev, gpio_unbind_unregister_notifier, &data->nb);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
platform_set_drvdata(pdev, data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver gpio_unbind_consumer_driver = {
|
||||
.probe = gpio_unbind_consumer_probe,
|
||||
.driver = {
|
||||
.name = GPIO_UNBIND_TEST_CONSUMER,
|
||||
},
|
||||
};
|
||||
|
||||
static void gpio_unbind_with_consumers(struct kunit *test)
|
||||
{
|
||||
struct gpio_unbind_consumer_drvdata *cons_data;
|
||||
struct platform_device_info pdevinfo;
|
||||
struct property_entry properties[2];
|
||||
struct platform_device *prvd, *cons;
|
||||
bool bound = false;
|
||||
int ret;
|
||||
|
||||
ret = kunit_platform_driver_register(test, &gpio_test_provider_driver);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
ret = kunit_platform_driver_register(test, &gpio_unbind_consumer_driver);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
pdevinfo = (struct platform_device_info){
|
||||
.name = GPIO_TEST_PROVIDER,
|
||||
.id = PLATFORM_DEVID_NONE,
|
||||
.swnode = &gpio_test_provider_swnode,
|
||||
};
|
||||
|
||||
prvd = kunit_platform_device_register_full(test, &pdevinfo);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, prvd);
|
||||
|
||||
properties[0] = PROPERTY_ENTRY_GPIO("foo-gpios",
|
||||
&gpio_test_provider_swnode,
|
||||
0, GPIO_ACTIVE_HIGH);
|
||||
properties[1] = (struct property_entry){ };
|
||||
|
||||
pdevinfo = (struct platform_device_info){
|
||||
.name = GPIO_UNBIND_TEST_CONSUMER,
|
||||
.id = PLATFORM_DEVID_NONE,
|
||||
.properties = properties,
|
||||
};
|
||||
|
||||
cons = kunit_platform_device_register_full(test, &pdevinfo);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cons);
|
||||
|
||||
wait_for_device_probe();
|
||||
scoped_guard(device, &cons->dev)
|
||||
bound = device_is_bound(&cons->dev);
|
||||
|
||||
KUNIT_ASSERT_TRUE(test, bound);
|
||||
|
||||
kunit_platform_device_unregister(test, prvd);
|
||||
|
||||
ret = blocking_notifier_call_chain(&gpio_unbind_notifier, 0, &cons->dev);
|
||||
KUNIT_ASSERT_EQ(test, ret, NOTIFY_OK);
|
||||
|
||||
scoped_guard(device, &cons->dev) {
|
||||
cons_data = platform_get_drvdata(cons);
|
||||
ret = cons_data->set_retval;
|
||||
}
|
||||
|
||||
KUNIT_ASSERT_EQ(test, ret, -ENODEV);
|
||||
}
|
||||
|
||||
static struct kunit_case gpio_unbind_with_consumers_tests[] = {
|
||||
KUNIT_CASE(gpio_unbind_with_consumers),
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct kunit_suite gpio_unbind_with_consumers_test_suite = {
|
||||
.name = "gpio-unbind-with-consumers",
|
||||
.test_cases = gpio_unbind_with_consumers_tests,
|
||||
};
|
||||
|
||||
kunit_test_suites(
|
||||
&gpio_swnode_lookup_test_suite,
|
||||
&gpio_unbind_with_consumers_test_suite,
|
||||
);
|
||||
|
||||
MODULE_DESCRIPTION("Test module for the GPIO subsystem");
|
||||
MODULE_AUTHOR("Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -240,6 +240,14 @@ static void of_gpio_try_fixup_polarity(const struct device_node *np,
|
||||
* treats it as "active low".
|
||||
*/
|
||||
{ "ti,tsc2005", "reset-gpios", false },
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_WSA881X)
|
||||
/*
|
||||
* WSA881 powerdown is always active low, but some device trees
|
||||
* missed this when first contributed. It also has a very strange
|
||||
* compatible.
|
||||
*/
|
||||
{ "sdw10217201000", "powerdown-gpios", false },
|
||||
#endif
|
||||
};
|
||||
unsigned int i;
|
||||
|
||||
@@ -114,10 +114,6 @@ struct gpio_desc *swnode_find_gpio(struct fwnode_handle *fwnode,
|
||||
if (IS_ERR(gdev))
|
||||
return ERR_CAST(gdev);
|
||||
|
||||
/*
|
||||
* FIXME: The GPIO device reference is put at return but the descriptor
|
||||
* is passed on. Find a proper solution.
|
||||
*/
|
||||
desc = gpio_device_get_desc(gdev, args.args[0]);
|
||||
*flags = args.args[1]; /* We expect native GPIO flags */
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
|
||||
/* Device and char device-related information */
|
||||
static DEFINE_IDA(gpio_ida);
|
||||
static dev_t gpio_devt;
|
||||
static dev_t gpio_devt __ro_after_init;
|
||||
#define GPIO_DEV_MAX 256 /* 256 GPIO chip devices supported */
|
||||
|
||||
static int gpio_bus_match(struct device *dev, const struct device_driver *drv)
|
||||
@@ -114,7 +114,7 @@ static int gpiochip_irqchip_init_hw(struct gpio_chip *gc);
|
||||
static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gc);
|
||||
static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gc);
|
||||
|
||||
static bool gpiolib_initialized;
|
||||
static bool gpiolib_initialized __ro_after_init;
|
||||
|
||||
const char *gpiod_get_label(struct gpio_desc *desc)
|
||||
{
|
||||
@@ -143,13 +143,15 @@ static void desc_free_label(struct rcu_head *rh)
|
||||
static int desc_set_label(struct gpio_desc *desc, const char *label)
|
||||
{
|
||||
struct gpio_desc_label *new = NULL, *old;
|
||||
size_t len;
|
||||
|
||||
if (label) {
|
||||
new = kzalloc_flex(*new, str, strlen(label) + 1);
|
||||
len = strlen(label);
|
||||
new = kzalloc_flex(*new, str, len + 1);
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
|
||||
strcpy(new->str, label);
|
||||
memcpy(new->str, label, len);
|
||||
}
|
||||
|
||||
old = rcu_replace_pointer(desc->label, new, 1);
|
||||
@@ -491,6 +493,28 @@ int gpiod_get_direction(struct gpio_desc *desc)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_get_direction);
|
||||
|
||||
/**
|
||||
* gpiod_is_single_ended - check if the GPIO is configured as single-ended
|
||||
* @desc: the GPIO descriptor to check
|
||||
*
|
||||
* Returns true if the GPIO is configured as either Open Drain or Open Source.
|
||||
* In these modes, the direction of the line cannot always be reliably
|
||||
* determined by reading hardware registers, as the "off" state (High-Z)
|
||||
* is physically indistinguishable from an input state.
|
||||
*/
|
||||
bool gpiod_is_single_ended(struct gpio_desc *desc)
|
||||
{
|
||||
if (!desc)
|
||||
return false;
|
||||
|
||||
if (test_bit(GPIOD_FLAG_OPEN_DRAIN, &desc->flags) ||
|
||||
test_bit(GPIOD_FLAG_OPEN_SOURCE, &desc->flags))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_is_single_ended);
|
||||
|
||||
/*
|
||||
* Add a new chip to the global chips list, keeping the list of chips sorted
|
||||
* by range(means [base, base + ngpio - 1]) order.
|
||||
@@ -3414,20 +3438,13 @@ static int gpio_chip_get_value(struct gpio_chip *gc, const struct gpio_desc *des
|
||||
|
||||
static int gpiod_get_raw_value_commit(const struct gpio_desc *desc)
|
||||
{
|
||||
struct gpio_device *gdev;
|
||||
struct gpio_chip *gc;
|
||||
int value;
|
||||
|
||||
/* FIXME Unable to use gpio_chip_guard due to const desc. */
|
||||
gdev = desc->gdev;
|
||||
|
||||
guard(srcu)(&gdev->srcu);
|
||||
|
||||
gc = srcu_dereference(gdev->chip, &gdev->srcu);
|
||||
if (!gc)
|
||||
CLASS(gpio_chip_guard, guard)(desc);
|
||||
if (!guard.gc)
|
||||
return -ENODEV;
|
||||
|
||||
value = gpio_chip_get_value(gc, desc);
|
||||
value = gpio_chip_get_value(guard.gc, desc);
|
||||
value = value < 0 ? value : !!value;
|
||||
trace_gpio_value(desc_to_gpio(desc), 1, value);
|
||||
return value;
|
||||
@@ -4134,8 +4151,6 @@ EXPORT_SYMBOL_GPL(gpiod_is_shared);
|
||||
*/
|
||||
int gpiod_to_irq(const struct gpio_desc *desc)
|
||||
{
|
||||
struct gpio_device *gdev;
|
||||
struct gpio_chip *gc;
|
||||
int offset;
|
||||
int ret;
|
||||
|
||||
@@ -4143,16 +4158,13 @@ int gpiod_to_irq(const struct gpio_desc *desc)
|
||||
if (ret <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
gdev = desc->gdev;
|
||||
/* FIXME Cannot use gpio_chip_guard due to const desc. */
|
||||
guard(srcu)(&gdev->srcu);
|
||||
gc = srcu_dereference(gdev->chip, &gdev->srcu);
|
||||
if (!gc)
|
||||
CLASS(gpio_chip_guard, guard)(desc);
|
||||
if (!guard.gc)
|
||||
return -ENODEV;
|
||||
|
||||
offset = gpiod_hwgpio(desc);
|
||||
if (gc->to_irq) {
|
||||
ret = gc->to_irq(gc, offset);
|
||||
if (guard.gc->to_irq) {
|
||||
ret = guard.gc->to_irq(guard.gc, offset);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -4160,7 +4172,7 @@ int gpiod_to_irq(const struct gpio_desc *desc)
|
||||
return -ENXIO;
|
||||
}
|
||||
#ifdef CONFIG_GPIOLIB_IRQCHIP
|
||||
if (gc->irq.chip) {
|
||||
if (guard.gc->irq.chip) {
|
||||
/*
|
||||
* Avoid race condition with other code, which tries to lookup
|
||||
* an IRQ before the irqchip has been properly registered,
|
||||
@@ -5348,7 +5360,7 @@ EXPORT_SYMBOL_GPL(gpiod_put_array);
|
||||
* gpio_device of the GPIO chip with the firmware node and then simply
|
||||
* bind it to this stub driver.
|
||||
*/
|
||||
static struct device_driver gpio_stub_drv = {
|
||||
static struct device_driver gpio_stub_drv __ro_after_init = {
|
||||
.name = "gpio_stub_drv",
|
||||
.bus = &gpio_bus_type,
|
||||
};
|
||||
@@ -5506,8 +5518,8 @@ static int gpiolib_seq_show(struct seq_file *s, void *v)
|
||||
if (gc->label)
|
||||
seq_printf(s, ", %s", gc->label);
|
||||
if (gc->can_sleep)
|
||||
seq_printf(s, ", can sleep");
|
||||
seq_printf(s, ":\n");
|
||||
seq_puts(s, ", can sleep");
|
||||
seq_puts(s, ":\n");
|
||||
|
||||
if (gc->dbg_show)
|
||||
gc->dbg_show(s, gc);
|
||||
|
||||
@@ -244,7 +244,7 @@ DEFINE_CLASS(gpio_chip_guard,
|
||||
|
||||
_guard;
|
||||
}),
|
||||
struct gpio_desc *desc)
|
||||
const struct gpio_desc *desc)
|
||||
|
||||
int gpiod_request(struct gpio_desc *desc, const char *label);
|
||||
int gpiod_request_commit(struct gpio_desc *desc, const char *label);
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
#include <linux/property.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <linux/timb_gpio.h>
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/platform_data/i2c-ocores.h>
|
||||
#include <linux/platform_data/i2c-xiic.h>
|
||||
@@ -37,6 +35,10 @@
|
||||
|
||||
#define DRIVER_NAME "timberdale"
|
||||
|
||||
#define GPIO_NR_PINS 16
|
||||
#define GPIO_BASE 0
|
||||
#define IRQ_BASE 200
|
||||
|
||||
struct timberdale_device {
|
||||
resource_size_t ctl_mapbase;
|
||||
unsigned char __iomem *ctl_membase;
|
||||
@@ -174,11 +176,16 @@ static const struct resource timberdale_eth_resources[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct timbgpio_platform_data
|
||||
timberdale_gpio_platform_data = {
|
||||
.gpio_base = 0,
|
||||
.nr_pins = GPIO_NR_PINS,
|
||||
.irq_base = 200,
|
||||
static const struct property_entry timberdale_gpio_properties[] = {
|
||||
PROPERTY_ENTRY_U32("ngpios", GPIO_NR_PINS),
|
||||
PROPERTY_ENTRY_U32("gpio-base", GPIO_BASE),
|
||||
PROPERTY_ENTRY_U32("irq-base", IRQ_BASE),
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct software_node timberdale_gpio_swnode = {
|
||||
.name = "timb-gpio",
|
||||
.properties = timberdale_gpio_properties,
|
||||
};
|
||||
|
||||
static const struct resource timberdale_gpio_resources[] = {
|
||||
@@ -390,8 +397,7 @@ static const struct mfd_cell timberdale_cells_bar0_cfg0[] = {
|
||||
.name = "timb-gpio",
|
||||
.num_resources = ARRAY_SIZE(timberdale_gpio_resources),
|
||||
.resources = timberdale_gpio_resources,
|
||||
.platform_data = &timberdale_gpio_platform_data,
|
||||
.pdata_size = sizeof(timberdale_gpio_platform_data),
|
||||
.swnode = &timberdale_gpio_swnode,
|
||||
},
|
||||
{
|
||||
.name = "timb-video",
|
||||
@@ -452,8 +458,7 @@ static const struct mfd_cell timberdale_cells_bar0_cfg1[] = {
|
||||
.name = "timb-gpio",
|
||||
.num_resources = ARRAY_SIZE(timberdale_gpio_resources),
|
||||
.resources = timberdale_gpio_resources,
|
||||
.platform_data = &timberdale_gpio_platform_data,
|
||||
.pdata_size = sizeof(timberdale_gpio_platform_data),
|
||||
.swnode = &timberdale_gpio_swnode,
|
||||
},
|
||||
{
|
||||
.name = "timb-mlogicore",
|
||||
@@ -514,8 +519,7 @@ static const struct mfd_cell timberdale_cells_bar0_cfg2[] = {
|
||||
.name = "timb-gpio",
|
||||
.num_resources = ARRAY_SIZE(timberdale_gpio_resources),
|
||||
.resources = timberdale_gpio_resources,
|
||||
.platform_data = &timberdale_gpio_platform_data,
|
||||
.pdata_size = sizeof(timberdale_gpio_platform_data),
|
||||
.swnode = &timberdale_gpio_swnode,
|
||||
},
|
||||
{
|
||||
.name = "timb-video",
|
||||
@@ -564,8 +568,7 @@ static const struct mfd_cell timberdale_cells_bar0_cfg3[] = {
|
||||
.name = "timb-gpio",
|
||||
.num_resources = ARRAY_SIZE(timberdale_gpio_resources),
|
||||
.resources = timberdale_gpio_resources,
|
||||
.platform_data = &timberdale_gpio_platform_data,
|
||||
.pdata_size = sizeof(timberdale_gpio_platform_data),
|
||||
.swnode = &timberdale_gpio_swnode,
|
||||
},
|
||||
{
|
||||
.name = "timb-video",
|
||||
|
||||
@@ -113,7 +113,6 @@
|
||||
#define GPIO_PIN_ASCB 8
|
||||
#define GPIO_PIN_INIC_RST 14
|
||||
#define GPIO_PIN_BT_RST 15
|
||||
#define GPIO_NR_PINS 16
|
||||
|
||||
/* DMA Channels */
|
||||
#define DMA_UART_RX 0
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
config VIDEO_MAX96712
|
||||
tristate "Maxim MAX96712 Quad GMSL2 Deserializer support"
|
||||
depends on I2C
|
||||
depends on OF_GPIO
|
||||
depends on VIDEO_DEV
|
||||
select V4L2_FWNODE
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#define GPIOAO_11 11
|
||||
#define GPIOAO_12 12
|
||||
#define GPIOAO_13 13
|
||||
#define GPIO_TEST_N 14
|
||||
#define GPIO_TEST_N 14
|
||||
|
||||
/* Second GPIO chip */
|
||||
#define GPIOZ_0 0
|
||||
@@ -52,7 +52,7 @@
|
||||
#define BOOT_12 23
|
||||
#define BOOT_13 24
|
||||
#define BOOT_14 25
|
||||
#define GPIOA_0 26
|
||||
#define GPIOA_0 26
|
||||
#define GPIOA_1 27
|
||||
#define GPIOA_2 28
|
||||
#define GPIOA_3 29
|
||||
|
||||
58
include/dt-bindings/gpio/nvidia,tegra238-gpio.h
Normal file
58
include/dt-bindings/gpio/nvidia,tegra238-gpio.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
|
||||
/* Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. */
|
||||
|
||||
/*
|
||||
* This header provides constants for binding nvidia,tegra238-gpio*.
|
||||
*
|
||||
* The first cell in Tegra's GPIO specifier is the GPIO ID. The macros below
|
||||
* provide names for this.
|
||||
*
|
||||
* The second cell contains standard flag values specified in gpio.h.
|
||||
*/
|
||||
|
||||
#ifndef _DT_BINDINGS_GPIO_TEGRA238_GPIO_H
|
||||
#define _DT_BINDINGS_GPIO_TEGRA238_GPIO_H
|
||||
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
/* GPIOs implemented by main GPIO controller */
|
||||
#define TEGRA238_MAIN_GPIO_PORT_A 0
|
||||
#define TEGRA238_MAIN_GPIO_PORT_B 1
|
||||
#define TEGRA238_MAIN_GPIO_PORT_C 2
|
||||
#define TEGRA238_MAIN_GPIO_PORT_D 3
|
||||
#define TEGRA238_MAIN_GPIO_PORT_E 4
|
||||
#define TEGRA238_MAIN_GPIO_PORT_F 5
|
||||
#define TEGRA238_MAIN_GPIO_PORT_G 6
|
||||
#define TEGRA238_MAIN_GPIO_PORT_H 7
|
||||
#define TEGRA238_MAIN_GPIO_PORT_J 8
|
||||
#define TEGRA238_MAIN_GPIO_PORT_K 9
|
||||
#define TEGRA238_MAIN_GPIO_PORT_L 10
|
||||
#define TEGRA238_MAIN_GPIO_PORT_M 11
|
||||
#define TEGRA238_MAIN_GPIO_PORT_N 12
|
||||
#define TEGRA238_MAIN_GPIO_PORT_P 13
|
||||
#define TEGRA238_MAIN_GPIO_PORT_Q 14
|
||||
#define TEGRA238_MAIN_GPIO_PORT_R 15
|
||||
#define TEGRA238_MAIN_GPIO_PORT_S 16
|
||||
#define TEGRA238_MAIN_GPIO_PORT_T 17
|
||||
#define TEGRA238_MAIN_GPIO_PORT_U 18
|
||||
#define TEGRA238_MAIN_GPIO_PORT_V 19
|
||||
#define TEGRA238_MAIN_GPIO_PORT_W 20
|
||||
#define TEGRA238_MAIN_GPIO_PORT_X 21
|
||||
|
||||
#define TEGRA238_MAIN_GPIO(port, offset) \
|
||||
((TEGRA238_MAIN_GPIO_PORT_##port * 8) + (offset))
|
||||
|
||||
/* GPIOs implemented by AON GPIO controller */
|
||||
#define TEGRA238_AON_GPIO_PORT_AA 0
|
||||
#define TEGRA238_AON_GPIO_PORT_BB 1
|
||||
#define TEGRA238_AON_GPIO_PORT_CC 2
|
||||
#define TEGRA238_AON_GPIO_PORT_DD 3
|
||||
#define TEGRA238_AON_GPIO_PORT_EE 4
|
||||
#define TEGRA238_AON_GPIO_PORT_FF 5
|
||||
#define TEGRA238_AON_GPIO_PORT_GG 6
|
||||
#define TEGRA238_AON_GPIO_PORT_HH 7
|
||||
|
||||
#define TEGRA238_AON_GPIO(port, offset) \
|
||||
((TEGRA238_AON_GPIO_PORT_##port * 8) + (offset))
|
||||
|
||||
#endif
|
||||
@@ -6,10 +6,16 @@ struct completion;
|
||||
struct kunit;
|
||||
struct platform_device;
|
||||
struct platform_driver;
|
||||
struct platform_device_info;
|
||||
|
||||
struct platform_device *
|
||||
kunit_platform_device_alloc(struct kunit *test, const char *name, int id);
|
||||
int kunit_platform_device_add(struct kunit *test, struct platform_device *pdev);
|
||||
struct platform_device *
|
||||
kunit_platform_device_register_full(struct kunit *test,
|
||||
const struct platform_device_info *pdevinfo);
|
||||
void kunit_platform_device_unregister(struct kunit *test,
|
||||
struct platform_device *pdev);
|
||||
|
||||
int kunit_platform_device_prepare_wait_for_probe(struct kunit *test,
|
||||
struct platform_device *pdev,
|
||||
|
||||
@@ -2,13 +2,11 @@
|
||||
/*
|
||||
* NOTE: This header *must not* be included.
|
||||
*
|
||||
* This is the LEGACY GPIO bulk include file, including legacy APIs. It is
|
||||
* used for GPIO drivers still referencing the global GPIO numberspace,
|
||||
* and should not be included in new code.
|
||||
*
|
||||
* If you're implementing a GPIO driver, only include <linux/gpio/driver.h>
|
||||
* If you're implementing a GPIO consumer, only include <linux/gpio/consumer.h>
|
||||
* If you're using the legacy interfaces, include <linux/gpio/legacy.h>
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_GPIO_H
|
||||
#define __LINUX_GPIO_H
|
||||
|
||||
@@ -18,159 +16,7 @@
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_GPIOLIB_LEGACY
|
||||
|
||||
struct device;
|
||||
|
||||
/* make these flag values available regardless of GPIO kconfig options */
|
||||
#define GPIOF_IN ((1 << 0))
|
||||
#define GPIOF_OUT_INIT_LOW ((0 << 0) | (0 << 1))
|
||||
#define GPIOF_OUT_INIT_HIGH ((0 << 0) | (1 << 1))
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
/*
|
||||
* "valid" GPIO numbers are nonnegative and may be passed to
|
||||
* setup routines like gpio_request(). Only some valid numbers
|
||||
* can successfully be requested and used.
|
||||
*
|
||||
* Invalid GPIO numbers are useful for indicating no-such-GPIO in
|
||||
* platform data and other tables.
|
||||
*/
|
||||
static inline bool gpio_is_valid(int number)
|
||||
{
|
||||
/* only non-negative numbers are valid */
|
||||
return number >= 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Platforms may implement their GPIO interface with library code,
|
||||
* at a small performance cost for non-inlined operations and some
|
||||
* extra memory (for code and for per-GPIO table entries).
|
||||
*/
|
||||
|
||||
/* Always use the library code for GPIO management calls,
|
||||
* or when sleeping may be involved.
|
||||
*/
|
||||
int gpio_request(unsigned gpio, const char *label);
|
||||
void gpio_free(unsigned gpio);
|
||||
|
||||
static inline int gpio_direction_input(unsigned gpio)
|
||||
{
|
||||
return gpiod_direction_input(gpio_to_desc(gpio));
|
||||
}
|
||||
static inline int gpio_direction_output(unsigned gpio, int value)
|
||||
{
|
||||
return gpiod_direction_output_raw(gpio_to_desc(gpio), value);
|
||||
}
|
||||
|
||||
static inline int gpio_get_value_cansleep(unsigned gpio)
|
||||
{
|
||||
return gpiod_get_raw_value_cansleep(gpio_to_desc(gpio));
|
||||
}
|
||||
static inline void gpio_set_value_cansleep(unsigned gpio, int value)
|
||||
{
|
||||
gpiod_set_raw_value_cansleep(gpio_to_desc(gpio), value);
|
||||
}
|
||||
|
||||
static inline int gpio_get_value(unsigned gpio)
|
||||
{
|
||||
return gpiod_get_raw_value(gpio_to_desc(gpio));
|
||||
}
|
||||
static inline void gpio_set_value(unsigned gpio, int value)
|
||||
{
|
||||
gpiod_set_raw_value(gpio_to_desc(gpio), value);
|
||||
}
|
||||
|
||||
static inline int gpio_to_irq(unsigned gpio)
|
||||
{
|
||||
return gpiod_to_irq(gpio_to_desc(gpio));
|
||||
}
|
||||
|
||||
int gpio_request_one(unsigned gpio, unsigned long flags, const char *label);
|
||||
|
||||
int devm_gpio_request_one(struct device *dev, unsigned gpio,
|
||||
unsigned long flags, const char *label);
|
||||
|
||||
#else /* ! CONFIG_GPIOLIB */
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include <asm/bug.h>
|
||||
#include <asm/errno.h>
|
||||
|
||||
static inline bool gpio_is_valid(int number)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline int gpio_request(unsigned gpio, const char *label)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline int gpio_request_one(unsigned gpio,
|
||||
unsigned long flags, const char *label)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline void gpio_free(unsigned gpio)
|
||||
{
|
||||
might_sleep();
|
||||
|
||||
/* GPIO can never have been requested */
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
static inline int gpio_direction_input(unsigned gpio)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline int gpio_direction_output(unsigned gpio, int value)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline int gpio_get_value(unsigned gpio)
|
||||
{
|
||||
/* GPIO can never have been requested or set as {in,out}put */
|
||||
WARN_ON(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void gpio_set_value(unsigned gpio, int value)
|
||||
{
|
||||
/* GPIO can never have been requested or set as output */
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
static inline int gpio_get_value_cansleep(unsigned gpio)
|
||||
{
|
||||
/* GPIO can never have been requested or set as {in,out}put */
|
||||
WARN_ON(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void gpio_set_value_cansleep(unsigned gpio, int value)
|
||||
{
|
||||
/* GPIO can never have been requested or set as output */
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
static inline int gpio_to_irq(unsigned gpio)
|
||||
{
|
||||
/* GPIO can never have been requested or set as input */
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int devm_gpio_request_one(struct device *dev, unsigned gpio,
|
||||
unsigned long flags, const char *label)
|
||||
{
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#endif /* ! CONFIG_GPIOLIB */
|
||||
#include <linux/gpio/legacy.h>
|
||||
#endif /* CONFIG_GPIOLIB_LEGACY */
|
||||
|
||||
#endif /* __LINUX_GPIO_H */
|
||||
|
||||
@@ -111,6 +111,7 @@ void devm_gpiod_unhinge(struct device *dev, struct gpio_desc *desc);
|
||||
void devm_gpiod_put_array(struct device *dev, struct gpio_descs *descs);
|
||||
|
||||
int gpiod_get_direction(struct gpio_desc *desc);
|
||||
bool gpiod_is_single_ended(struct gpio_desc *desc);
|
||||
int gpiod_direction_input(struct gpio_desc *desc);
|
||||
int gpiod_direction_output(struct gpio_desc *desc, int value);
|
||||
int gpiod_direction_output_raw(struct gpio_desc *desc, int value);
|
||||
@@ -337,6 +338,10 @@ static inline int gpiod_get_direction(const struct gpio_desc *desc)
|
||||
WARN_ON(desc);
|
||||
return -ENOSYS;
|
||||
}
|
||||
static inline bool gpiod_is_single_ended(struct gpio_desc *desc)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
static inline int gpiod_direction_input(struct gpio_desc *desc)
|
||||
{
|
||||
/* GPIO can never have been requested */
|
||||
@@ -598,6 +603,15 @@ static inline int gpiod_disable_hw_timestamp_ns(struct gpio_desc *desc,
|
||||
}
|
||||
#endif /* CONFIG_GPIOLIB && CONFIG_HTE */
|
||||
|
||||
static inline
|
||||
struct gpio_desc *fwnode_gpiod_get(struct fwnode_handle *fwnode,
|
||||
const char *con_id,
|
||||
enum gpiod_flags flags,
|
||||
const char *label)
|
||||
{
|
||||
return fwnode_gpiod_get_index(fwnode, con_id, 0, flags, label);
|
||||
}
|
||||
|
||||
static inline
|
||||
struct gpio_desc *devm_fwnode_gpiod_get(struct device *dev,
|
||||
struct fwnode_handle *fwnode,
|
||||
|
||||
@@ -32,9 +32,6 @@ struct fwnode_handle;
|
||||
#define NMK_GPIO_RWIMSC 0x50
|
||||
#define NMK_GPIO_FWIMSC 0x54
|
||||
#define NMK_GPIO_WKS 0x58
|
||||
/* These appear in DB8540 and later ASICs */
|
||||
#define NMK_GPIO_EDGELEVEL 0x5C
|
||||
#define NMK_GPIO_LEVEL 0x60
|
||||
|
||||
/* Pull up/down values */
|
||||
enum nmk_gpio_pull {
|
||||
@@ -236,19 +233,6 @@ nmk_pinctrl_db8500_init(const struct nmk_pinctrl_soc_data **soc)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PINCTRL_DB8540
|
||||
|
||||
void nmk_pinctrl_db8540_init(const struct nmk_pinctrl_soc_data **soc);
|
||||
|
||||
#else
|
||||
|
||||
static inline void
|
||||
nmk_pinctrl_db8540_init(const struct nmk_pinctrl_soc_data **soc)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
struct platform_device;
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
||||
173
include/linux/gpio/legacy.h
Normal file
173
include/linux/gpio/legacy.h
Normal file
@@ -0,0 +1,173 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* This is the LEGACY GPIO include file, used only for legacy APIs.
|
||||
*
|
||||
* No new code should use this, but instead use the linux/gpio/consumer.h
|
||||
* interfaces directly.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_GPIO_LEGACY_H
|
||||
#define __LINUX_GPIO_LEGACY_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#ifdef CONFIG_GPIOLIB_LEGACY
|
||||
|
||||
struct device;
|
||||
|
||||
/* make these flag values available regardless of GPIO kconfig options */
|
||||
#define GPIOF_IN ((1 << 0))
|
||||
#define GPIOF_OUT_INIT_LOW ((0 << 0) | (0 << 1))
|
||||
#define GPIOF_OUT_INIT_HIGH ((0 << 0) | (1 << 1))
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
|
||||
#include <linux/gpio/consumer.h>
|
||||
|
||||
/*
|
||||
* "valid" GPIO numbers are nonnegative and may be passed to
|
||||
* setup routines like gpio_request(). Only some valid numbers
|
||||
* can successfully be requested and used.
|
||||
*
|
||||
* Invalid GPIO numbers are useful for indicating no-such-GPIO in
|
||||
* platform data and other tables.
|
||||
*/
|
||||
static inline bool gpio_is_valid(int number)
|
||||
{
|
||||
/* only non-negative numbers are valid */
|
||||
return number >= 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Platforms may implement their GPIO interface with library code,
|
||||
* at a small performance cost for non-inlined operations and some
|
||||
* extra memory (for code and for per-GPIO table entries).
|
||||
*/
|
||||
|
||||
/* Always use the library code for GPIO management calls,
|
||||
* or when sleeping may be involved.
|
||||
*/
|
||||
int gpio_request(unsigned gpio, const char *label);
|
||||
void gpio_free(unsigned gpio);
|
||||
|
||||
static inline int gpio_direction_input(unsigned gpio)
|
||||
{
|
||||
return gpiod_direction_input(gpio_to_desc(gpio));
|
||||
}
|
||||
static inline int gpio_direction_output(unsigned gpio, int value)
|
||||
{
|
||||
return gpiod_direction_output_raw(gpio_to_desc(gpio), value);
|
||||
}
|
||||
|
||||
static inline int gpio_get_value_cansleep(unsigned gpio)
|
||||
{
|
||||
return gpiod_get_raw_value_cansleep(gpio_to_desc(gpio));
|
||||
}
|
||||
static inline void gpio_set_value_cansleep(unsigned gpio, int value)
|
||||
{
|
||||
gpiod_set_raw_value_cansleep(gpio_to_desc(gpio), value);
|
||||
}
|
||||
|
||||
static inline int gpio_get_value(unsigned gpio)
|
||||
{
|
||||
return gpiod_get_raw_value(gpio_to_desc(gpio));
|
||||
}
|
||||
static inline void gpio_set_value(unsigned gpio, int value)
|
||||
{
|
||||
gpiod_set_raw_value(gpio_to_desc(gpio), value);
|
||||
}
|
||||
|
||||
static inline int gpio_to_irq(unsigned gpio)
|
||||
{
|
||||
return gpiod_to_irq(gpio_to_desc(gpio));
|
||||
}
|
||||
|
||||
int gpio_request_one(unsigned gpio, unsigned long flags, const char *label);
|
||||
|
||||
int devm_gpio_request_one(struct device *dev, unsigned gpio,
|
||||
unsigned long flags, const char *label);
|
||||
|
||||
#else /* ! CONFIG_GPIOLIB */
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include <asm/bug.h>
|
||||
#include <asm/errno.h>
|
||||
|
||||
static inline bool gpio_is_valid(int number)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline int gpio_request(unsigned gpio, const char *label)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline int gpio_request_one(unsigned gpio,
|
||||
unsigned long flags, const char *label)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline void gpio_free(unsigned gpio)
|
||||
{
|
||||
might_sleep();
|
||||
|
||||
/* GPIO can never have been requested */
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
static inline int gpio_direction_input(unsigned gpio)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline int gpio_direction_output(unsigned gpio, int value)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline int gpio_get_value(unsigned gpio)
|
||||
{
|
||||
/* GPIO can never have been requested or set as {in,out}put */
|
||||
WARN_ON(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void gpio_set_value(unsigned gpio, int value)
|
||||
{
|
||||
/* GPIO can never have been requested or set as output */
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
static inline int gpio_get_value_cansleep(unsigned gpio)
|
||||
{
|
||||
/* GPIO can never have been requested or set as {in,out}put */
|
||||
WARN_ON(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void gpio_set_value_cansleep(unsigned gpio, int value)
|
||||
{
|
||||
/* GPIO can never have been requested or set as output */
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
static inline int gpio_to_irq(unsigned gpio)
|
||||
{
|
||||
/* GPIO can never have been requested or set as input */
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int devm_gpio_request_one(struct device *dev, unsigned gpio,
|
||||
unsigned long flags, const char *label)
|
||||
{
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#endif /* ! CONFIG_GPIOLIB */
|
||||
#endif /* CONFIG_GPIOLIB_LEGACY */
|
||||
#endif /* __LINUX_GPIO_LEGAGY_H */
|
||||
@@ -38,6 +38,12 @@ struct regmap;
|
||||
* offset to a register/bitmask pair. If not
|
||||
* given the default gpio_regmap_simple_xlate()
|
||||
* is used.
|
||||
* @fixed_direction_mask:
|
||||
* (Optional) Bitmap representing the GPIO lines that
|
||||
* make use of the @fixed_direction_output list to
|
||||
* enforce direction of the GPIO. If this is NULL
|
||||
* and @fixed_direction_output is defined, ALL GPIOs
|
||||
* are assumed to be fixed direction (out or in).
|
||||
* @fixed_direction_output:
|
||||
* (Optional) Bitmap representing the fixed direction of
|
||||
* the GPIO lines. Useful when there are GPIO lines with a
|
||||
@@ -89,6 +95,7 @@ struct gpio_regmap_config {
|
||||
int reg_stride;
|
||||
int ngpio_per_reg;
|
||||
struct irq_domain *irq_domain;
|
||||
unsigned long *fixed_direction_mask;
|
||||
unsigned long *fixed_direction_output;
|
||||
|
||||
#ifdef CONFIG_REGMAP_IRQ
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* timb_gpio.h timberdale FPGA GPIO driver, platform data definition
|
||||
* Copyright (c) 2009 Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_TIMB_GPIO_H
|
||||
#define _LINUX_TIMB_GPIO_H
|
||||
|
||||
/**
|
||||
* struct timbgpio_platform_data - Platform data of the Timberdale GPIO driver
|
||||
* @gpio_base: The number of the first GPIO pin, set to -1 for
|
||||
* dynamic number allocation.
|
||||
* @nr_pins: Number of pins that is supported by the hardware (1-32)
|
||||
* @irq_base: If IRQ is supported by the hardware, this is the base
|
||||
* number of IRQ:s. One IRQ per pin will be used. Set to
|
||||
* -1 if IRQ:s is not supported.
|
||||
*/
|
||||
struct timbgpio_platform_data {
|
||||
int gpio_base;
|
||||
int nr_pins;
|
||||
int irq_base;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <linux/completion.h>
|
||||
#include <linux/device/bus.h>
|
||||
#include <linux/device/driver.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <kunit/platform_device.h>
|
||||
@@ -130,6 +131,69 @@ int kunit_platform_device_add(struct kunit *test, struct platform_device *pdev)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kunit_platform_device_add);
|
||||
|
||||
/**
|
||||
* kunit_platform_device_register_full() - Register a KUnit test-managed platform
|
||||
* device described by platform device info
|
||||
* @test: test context
|
||||
* @pdevinfo: platform device information describing the new device
|
||||
*
|
||||
* Register a test-managed platform device. The device is unregistered when the
|
||||
* test completes.
|
||||
*
|
||||
* Return: New platform device on success, IS_ERR() on error.
|
||||
*/
|
||||
struct platform_device *
|
||||
kunit_platform_device_register_full(struct kunit *test,
|
||||
const struct platform_device_info *pdevinfo)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
int ret;
|
||||
|
||||
pdev = platform_device_register_full(pdevinfo);
|
||||
if (IS_ERR(pdev))
|
||||
return pdev;
|
||||
|
||||
ret = kunit_add_action_or_reset(test, platform_device_unregister_wrapper, pdev);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
return pdev;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kunit_platform_device_register_full);
|
||||
|
||||
static bool
|
||||
kunit_platform_device_add_match(struct kunit *test, struct kunit_resource *res,
|
||||
void *match_data)
|
||||
{
|
||||
struct platform_device *pdev = match_data;
|
||||
|
||||
return res->data == pdev && res->free == kunit_platform_device_add_exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* kunit_platform_device_unregister() - Unregister a KUnit-managed platform device
|
||||
* @test: test context
|
||||
* @pdev: platform device to unregister
|
||||
*
|
||||
* Unregister a test-managed platform device and cancel its release action.
|
||||
*/
|
||||
void kunit_platform_device_unregister(struct kunit *test,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct kunit_resource *res;
|
||||
|
||||
res = kunit_find_resource(test, kunit_platform_device_add_match, pdev);
|
||||
if (res) {
|
||||
res->free = NULL;
|
||||
kunit_put_resource(res);
|
||||
} else {
|
||||
kunit_remove_action(test, platform_device_unregister_wrapper, pdev);
|
||||
}
|
||||
|
||||
platform_device_unregister(pdev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kunit_platform_device_unregister);
|
||||
|
||||
struct kunit_platform_device_probe_nb {
|
||||
struct completion *x;
|
||||
struct device *dev;
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
// Copyright (c) 2019, Linaro Limited
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
@@ -672,11 +671,6 @@ struct wsa881x_priv {
|
||||
struct sdw_stream_runtime *sruntime;
|
||||
struct sdw_port_config port_config[WSA881X_MAX_SWR_PORTS];
|
||||
struct gpio_desc *sd_n;
|
||||
/*
|
||||
* Logical state for SD_N GPIO: high for shutdown, low for enable.
|
||||
* For backwards compatibility.
|
||||
*/
|
||||
unsigned int sd_n_val;
|
||||
int active_ports;
|
||||
bool hw_init;
|
||||
bool port_prepared[WSA881X_MAX_SWR_PORTS];
|
||||
@@ -1121,31 +1115,11 @@ static int wsa881x_probe(struct sdw_slave *pdev,
|
||||
if (!wsa881x)
|
||||
return -ENOMEM;
|
||||
|
||||
wsa881x->sd_n = devm_gpiod_get_optional(dev, "powerdown", 0);
|
||||
wsa881x->sd_n = devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(wsa881x->sd_n))
|
||||
return dev_err_probe(dev, PTR_ERR(wsa881x->sd_n),
|
||||
"Shutdown Control GPIO not found\n");
|
||||
|
||||
/*
|
||||
* Backwards compatibility work-around.
|
||||
*
|
||||
* The SD_N GPIO is active low, however upstream DTS used always active
|
||||
* high. Changing the flag in driver and DTS will break backwards
|
||||
* compatibility, so add a simple value inversion to work with both old
|
||||
* and new DTS.
|
||||
*
|
||||
* This won't work properly with DTS using the flags properly in cases:
|
||||
* 1. Old DTS with proper ACTIVE_LOW, however such case was broken
|
||||
* before as the driver required the active high.
|
||||
* 2. New DTS with proper ACTIVE_HIGH (intended), which is rare case
|
||||
* (not existing upstream) but possible. This is the price of
|
||||
* backwards compatibility, therefore this hack should be removed at
|
||||
* some point.
|
||||
*/
|
||||
wsa881x->sd_n_val = gpiod_is_active_low(wsa881x->sd_n);
|
||||
if (!wsa881x->sd_n_val)
|
||||
dev_warn(dev, "Using ACTIVE_HIGH for shutdown GPIO. Your DTB might be outdated or you use unsupported configuration for the GPIO.");
|
||||
|
||||
dev_set_drvdata(dev, wsa881x);
|
||||
wsa881x->slave = pdev;
|
||||
wsa881x->dev = dev;
|
||||
@@ -1158,7 +1132,6 @@ static int wsa881x_probe(struct sdw_slave *pdev,
|
||||
pdev->prop.sink_dpn_prop = wsa_sink_dpn_prop;
|
||||
pdev->prop.scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
|
||||
pdev->prop.clk_stop_mode1 = true;
|
||||
gpiod_direction_output(wsa881x->sd_n, !wsa881x->sd_n_val);
|
||||
|
||||
wsa881x->regmap = devm_regmap_init_sdw(pdev, &wsa881x_regmap_config);
|
||||
if (IS_ERR(wsa881x->regmap))
|
||||
@@ -1181,7 +1154,7 @@ static int wsa881x_runtime_suspend(struct device *dev)
|
||||
struct regmap *regmap = dev_get_regmap(dev, NULL);
|
||||
struct wsa881x_priv *wsa881x = dev_get_drvdata(dev);
|
||||
|
||||
gpiod_direction_output(wsa881x->sd_n, wsa881x->sd_n_val);
|
||||
gpiod_direction_output(wsa881x->sd_n, 1);
|
||||
|
||||
regcache_cache_only(regmap, true);
|
||||
regcache_mark_dirty(regmap);
|
||||
@@ -1196,13 +1169,13 @@ static int wsa881x_runtime_resume(struct device *dev)
|
||||
struct wsa881x_priv *wsa881x = dev_get_drvdata(dev);
|
||||
unsigned long time;
|
||||
|
||||
gpiod_direction_output(wsa881x->sd_n, !wsa881x->sd_n_val);
|
||||
gpiod_direction_output(wsa881x->sd_n, 0);
|
||||
|
||||
time = wait_for_completion_timeout(&slave->initialization_complete,
|
||||
msecs_to_jiffies(WSA881X_PROBE_TIMEOUT));
|
||||
if (!time) {
|
||||
dev_err(dev, "Initialization not complete, timed out\n");
|
||||
gpiod_direction_output(wsa881x->sd_n, wsa881x->sd_n_val);
|
||||
gpiod_direction_output(wsa881x->sd_n, 1);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user