summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpio/Kconfig55
-rw-r--r--drivers/gpio/Makefile2
-rw-r--r--drivers/gpio/gpio-adnp.c2
-rw-r--r--drivers/gpio/gpio-aggregator.c110
-rw-r--r--drivers/gpio/gpio-brcmstb.c3
-rw-r--r--drivers/gpio/gpio-davinci.c4
-rw-r--r--drivers/gpio/gpio-fxl6408.c2
-rw-r--r--drivers/gpio/gpio-gw-pld.c2
-rw-r--r--drivers/gpio/gpio-ixp4xx.c4
-rw-r--r--drivers/gpio/gpio-lpc18xx.c1
-rw-r--r--drivers/gpio/gpio-max7300.c2
-rw-r--r--drivers/gpio/gpio-max732x.c2
-rw-r--r--drivers/gpio/gpio-mlxbf3.c248
-rw-r--r--drivers/gpio/gpio-mpc8xxx.c7
-rw-r--r--drivers/gpio/gpio-pca953x.c2
-rw-r--r--drivers/gpio/gpio-pca9570.c2
-rw-r--r--drivers/gpio/gpio-pcf857x.c2
-rw-r--r--drivers/gpio/gpio-sa1100.c1
-rw-r--r--drivers/gpio/gpio-sch311x.c26
-rw-r--r--drivers/gpio/gpio-tangier.c4
-rw-r--r--drivers/gpio/gpio-tegra186.c78
-rw-r--r--drivers/gpio/gpio-tpic2810.c27
-rw-r--r--drivers/gpio/gpio-tps65086.c27
-rw-r--r--drivers/gpio/gpio-tps65219.c185
-rw-r--r--drivers/gpio/gpio-ts4900.c2
-rw-r--r--drivers/gpio/gpio-twl4030.c64
-rw-r--r--drivers/gpio/gpio-xra1403.c1
-rw-r--r--drivers/gpio/gpio-zynq.c46
-rw-r--r--drivers/gpio/gpiolib-legacy.c12
-rw-r--r--drivers/gpio/gpiolib.c44
-rw-r--r--drivers/input/touchscreen/ads7846.c113
-rw-r--r--drivers/mfd/tps65010.c14
-rw-r--r--drivers/mmc/host/omap.c46
-rw-r--r--drivers/of/unittest.c28
-rw-r--r--drivers/usb/musb/musb_core.c1
-rw-r--r--drivers/usb/musb/musb_core.h2
-rw-r--r--drivers/usb/musb/tusb6010.c53
-rw-r--r--drivers/video/fbdev/omap/lcd_mipid.c10
38 files changed, 898 insertions, 336 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index f45c6a36551c..e382dfebad7c 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -704,18 +704,6 @@ config GPIO_VISCONTI
help
Say yes here to support GPIO on Tohisba Visconti.
-config GPIO_VX855
- tristate "VIA VX855/VX875 GPIO"
- depends on (X86 || COMPILE_TEST) && PCI
- select MFD_CORE
- select MFD_VX855
- help
- Support access to the VX855/VX875 GPIO lines through the GPIO library.
-
- This driver provides common support for accessing the device.
- Additional drivers must be enabled in order to use the
- functionality of the device.
-
config GPIO_WCD934X
tristate "Qualcomm Technologies Inc WCD9340/WCD9341 GPIO controller driver"
depends on MFD_WCD934X && OF_GPIO
@@ -835,7 +823,19 @@ config GPIO_IDT3243X
endmenu
menu "Port-mapped I/O GPIO drivers"
- depends on X86 # Unconditional I/O space access
+ depends on X86 && HAS_IOPORT # I/O space access
+
+config GPIO_VX855
+ tristate "VIA VX855/VX875 GPIO"
+ depends on PCI
+ select MFD_CORE
+ select MFD_VX855
+ help
+ Support access to the VX855/VX875 GPIO lines through the GPIO library.
+
+ This driver provides common support for accessing the device.
+ Additional drivers must be enabled in order to use the
+ functionality of the device.
config GPIO_I8255
tristate
@@ -1440,6 +1440,22 @@ config GPIO_TPS65218
Select this option to enable GPIO driver for the TPS65218
chip family.
+config GPIO_TPS65219
+ tristate "TPS65219 GPIO"
+ depends on MFD_TPS65219
+ default MFD_TPS65219
+ help
+ Select this option to enable GPIO driver for the TPS65219 chip
+ family.
+ GPIO0 is statically configured as either input or output prior to
+ Linux boot. It is used for MULTI_DEVICE_ENABLE function. This setting
+ is statically configured by NVM. GPIO0 can't be used as a generic
+ GPIO. It's either a GPO when MULTI_DEVICE_EN=0 or a GPI when
+ MULTI_DEVICE_EN=1.
+
+ This driver can also be built as a module. If so, the module will be
+ called gpio_tps65219.
+
config GPIO_TPS6586X
bool "TPS6586X GPIO"
depends on MFD_TPS6586X
@@ -1583,6 +1599,19 @@ config GPIO_MLXBF2
help
Say Y here if you want GPIO support on Mellanox BlueField 2 SoC.
+config GPIO_MLXBF3
+ tristate "Mellanox BlueField 3 SoC GPIO"
+ depends on (MELLANOX_PLATFORM && ARM64) || COMPILE_TEST
+ select GPIO_GENERIC
+ select GPIOLIB_IRQCHIP
+ help
+ Say Y if you want GPIO support on Mellanox BlueField 3 SoC.
+ This GPIO controller supports interrupt handling and enables the
+ manipulation of certain GPIO pins.
+ This controller should be used in parallel with pinctrl-mlxbf3 to
+ control the desired GPIOs.
+ This driver can also be built as a module called mlxbf3-gpio.
+
config GPIO_ML_IOH
tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support"
depends on X86 || COMPILE_TEST
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 20036af3acb1..c3ac51d47aa9 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -104,6 +104,7 @@ obj-$(CONFIG_GPIO_MERRIFIELD) += gpio-merrifield.o
obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o
obj-$(CONFIG_GPIO_MLXBF) += gpio-mlxbf.o
obj-$(CONFIG_GPIO_MLXBF2) += gpio-mlxbf2.o
+obj-$(CONFIG_GPIO_MLXBF3) += gpio-mlxbf3.o
obj-$(CONFIG_GPIO_MM_LANTIQ) += gpio-mm-lantiq.o
obj-$(CONFIG_GPIO_MOCKUP) += gpio-mockup.o
obj-$(CONFIG_GPIO_MOXTET) += gpio-moxtet.o
@@ -160,6 +161,7 @@ obj-$(CONFIG_GPIO_TN48M_CPLD) += gpio-tn48m.o
obj-$(CONFIG_GPIO_TPIC2810) += gpio-tpic2810.o
obj-$(CONFIG_GPIO_TPS65086) += gpio-tps65086.o
obj-$(CONFIG_GPIO_TPS65218) += gpio-tps65218.o
+obj-$(CONFIG_GPIO_TPS65219) += gpio-tps65219.o
obj-$(CONFIG_GPIO_TPS6586X) += gpio-tps6586x.o
obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o
obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o
diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c
index 9b01c391efce..6dafab0cf964 100644
--- a/drivers/gpio/gpio-adnp.c
+++ b/drivers/gpio/gpio-adnp.c
@@ -535,7 +535,7 @@ static struct i2c_driver adnp_i2c_driver = {
.name = "gpio-adnp",
.of_match_table = adnp_of_match,
},
- .probe_new = adnp_i2c_probe,
+ .probe = adnp_i2c_probe,
.id_table = adnp_i2c_id,
};
module_i2c_driver(adnp_i2c_driver);
diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c
index 20a686f12df7..38e0fff9afe7 100644
--- a/drivers/gpio/gpio-aggregator.c
+++ b/drivers/gpio/gpio-aggregator.c
@@ -10,12 +10,15 @@
#include <linux/bitmap.h>
#include <linux/bitops.h>
#include <linux/ctype.h>
+#include <linux/delay.h>
#include <linux/idr.h>
#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/overflow.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/string.h>
@@ -239,6 +242,11 @@ static void __exit gpio_aggregator_remove_all(void)
* GPIO Forwarder
*/
+struct gpiochip_fwd_timing {
+ u32 ramp_up_us;
+ u32 ramp_down_us;
+};
+
struct gpiochip_fwd {
struct gpio_chip chip;
struct gpio_desc **descs;
@@ -246,6 +254,7 @@ struct gpiochip_fwd {
struct mutex mlock; /* protects tmp[] if can_sleep */
spinlock_t slock; /* protects tmp[] if !can_sleep */
};
+ struct gpiochip_fwd_timing *delay_timings;
unsigned long tmp[]; /* values and descs for multiple ops */
};
@@ -330,6 +339,27 @@ static int gpio_fwd_get_multiple_locked(struct gpio_chip *chip,
return error;
}
+static void gpio_fwd_delay(struct gpio_chip *chip, unsigned int offset, int value)
+{
+ struct gpiochip_fwd *fwd = gpiochip_get_data(chip);
+ const struct gpiochip_fwd_timing *delay_timings;
+ bool is_active_low = gpiod_is_active_low(fwd->descs[offset]);
+ u32 delay_us;
+
+ delay_timings = &fwd->delay_timings[offset];
+ if ((!is_active_low && value) || (is_active_low && !value))
+ delay_us = delay_timings->ramp_up_us;
+ else
+ delay_us = delay_timings->ramp_down_us;
+ if (!delay_us)
+ return;
+
+ if (chip->can_sleep)
+ fsleep(delay_us);
+ else
+ udelay(delay_us);
+}
+
static void gpio_fwd_set(struct gpio_chip *chip, unsigned int offset, int value)
{
struct gpiochip_fwd *fwd = gpiochip_get_data(chip);
@@ -338,6 +368,9 @@ static void gpio_fwd_set(struct gpio_chip *chip, unsigned int offset, int value)
gpiod_set_value_cansleep(fwd->descs[offset], value);
else
gpiod_set_value(fwd->descs[offset], value);
+
+ if (fwd->delay_timings)
+ gpio_fwd_delay(chip, offset, value);
}
static void gpio_fwd_set_multiple(struct gpiochip_fwd *fwd, unsigned long *mask,
@@ -390,6 +423,59 @@ static int gpio_fwd_to_irq(struct gpio_chip *chip, unsigned int offset)
return gpiod_to_irq(fwd->descs[offset]);
}
+/*
+ * The GPIO delay provides a way to configure platform specific delays
+ * for the GPIO ramp-up or ramp-down delays. This can serve the following
+ * purposes:
+ * - Open-drain output using an RC filter
+ */
+#define FWD_FEATURE_DELAY BIT(0)
+
+#ifdef CONFIG_OF_GPIO
+static int gpiochip_fwd_delay_of_xlate(struct gpio_chip *chip,
+ const struct of_phandle_args *gpiospec,
+ u32 *flags)
+{
+ struct gpiochip_fwd *fwd = gpiochip_get_data(chip);
+ struct gpiochip_fwd_timing *timings;
+ u32 line;
+
+ if (gpiospec->args_count != chip->of_gpio_n_cells)
+ return -EINVAL;
+
+ line = gpiospec->args[0];
+ if (line >= chip->ngpio)
+ return -EINVAL;
+
+ timings = &fwd->delay_timings[line];
+ timings->ramp_up_us = gpiospec->args[1];
+ timings->ramp_down_us = gpiospec->args[2];
+
+ return line;
+}
+
+static int gpiochip_fwd_setup_delay_line(struct device *dev, struct gpio_chip *chip,
+ struct gpiochip_fwd *fwd)
+{
+ fwd->delay_timings = devm_kcalloc(dev, chip->ngpio,
+ sizeof(*fwd->delay_timings),
+ GFP_KERNEL);
+ if (!fwd->delay_timings)
+ return -ENOMEM;
+
+ chip->of_xlate = gpiochip_fwd_delay_of_xlate;
+ chip->of_gpio_n_cells = 3;
+
+ return 0;
+}
+#else
+static int gpiochip_fwd_setup_delay_line(struct device *dev, struct gpio_chip *chip,
+ struct gpiochip_fwd *fwd)
+{
+ return 0;
+}
+#endif /* !CONFIG_OF_GPIO */
+
/**
* gpiochip_fwd_create() - Create a new GPIO forwarder
* @dev: Parent device pointer
@@ -397,6 +483,7 @@ static int gpio_fwd_to_irq(struct gpio_chip *chip, unsigned int offset)
* @descs: Array containing the GPIO descriptors to forward to.
* This array must contain @ngpios entries, and must not be deallocated
* before the forwarder has been destroyed again.
+ * @features: Bitwise ORed features as defined with FWD_FEATURE_*.
*
* This function creates a new gpiochip, which forwards all GPIO operations to
* the passed GPIO descriptors.
@@ -406,7 +493,8 @@ static int gpio_fwd_to_irq(struct gpio_chip *chip, unsigned int offset)
*/
static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev,
unsigned int ngpios,
- struct gpio_desc *descs[])
+ struct gpio_desc *descs[],
+ unsigned long features)
{
const char *label = dev_name(dev);
struct gpiochip_fwd *fwd;
@@ -459,6 +547,12 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev,
else
spin_lock_init(&fwd->slock);
+ if (features & FWD_FEATURE_DELAY) {
+ error = gpiochip_fwd_setup_delay_line(dev, chip, fwd);
+ if (error)
+ return ERR_PTR(error);
+ }
+
error = devm_gpiochip_add_data(dev, chip, fwd);
if (error)
return ERR_PTR(error);
@@ -476,6 +570,7 @@ static int gpio_aggregator_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct gpio_desc **descs;
struct gpiochip_fwd *fwd;
+ unsigned long features;
int i, n;
n = gpiod_count(dev, NULL);
@@ -492,7 +587,8 @@ static int gpio_aggregator_probe(struct platform_device *pdev)
return PTR_ERR(descs[i]);
}
- fwd = gpiochip_fwd_create(dev, n, descs);
+ features = (uintptr_t)device_get_match_data(dev);
+ fwd = gpiochip_fwd_create(dev, n, descs, features);
if (IS_ERR(fwd))
return PTR_ERR(fwd);
@@ -500,23 +596,25 @@ static int gpio_aggregator_probe(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_OF
static const struct of_device_id gpio_aggregator_dt_ids[] = {
+ {
+ .compatible = "gpio-delay",
+ .data = (void *)FWD_FEATURE_DELAY,
+ },
/*
* Add GPIO-operated devices controlled from userspace below,
- * or use "driver_override" in sysfs
+ * or use "driver_override" in sysfs.
*/
{}
};
MODULE_DEVICE_TABLE(of, gpio_aggregator_dt_ids);
-#endif
static struct platform_driver gpio_aggregator_driver = {
.probe = gpio_aggregator_probe,
.driver = {
.name = DRV_NAME,
.groups = gpio_aggregator_groups,
- .of_match_table = of_match_ptr(gpio_aggregator_dt_ids),
+ .of_match_table = gpio_aggregator_dt_ids,
},
};
diff --git a/drivers/gpio/gpio-brcmstb.c b/drivers/gpio/gpio-brcmstb.c
index c55b35da61a0..6566517fe0d8 100644
--- a/drivers/gpio/gpio-brcmstb.c
+++ b/drivers/gpio/gpio-brcmstb.c
@@ -609,8 +609,7 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, priv);
INIT_LIST_HEAD(&priv->bank_list);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- reg_base = devm_ioremap_resource(dev, res);
+ reg_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(reg_base))
return PTR_ERR(reg_base);
diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c
index aaaf61dc2632..fff510d86e31 100644
--- a/drivers/gpio/gpio-davinci.c
+++ b/drivers/gpio/gpio-davinci.c
@@ -692,7 +692,7 @@ static int davinci_gpio_resume(struct device *dev)
return 0;
}
-DEFINE_SIMPLE_DEV_PM_OPS(davinci_gpio_dev_pm_ops, davinci_gpio_suspend,
+static DEFINE_SIMPLE_DEV_PM_OPS(davinci_gpio_dev_pm_ops, davinci_gpio_suspend,
davinci_gpio_resume);
static const struct of_device_id davinci_gpio_ids[] = {
@@ -712,7 +712,7 @@ static struct platform_driver davinci_gpio_driver = {
},
};
-/**
+/*
* GPIO driver registration needs to be done before machine_init functions
* access GPIO. Hence davinci_gpio_drv_reg() is a postcore_initcall.
*/
diff --git a/drivers/gpio/gpio-fxl6408.c b/drivers/gpio/gpio-fxl6408.c
index 208fa851e82a..c14b5cc5e519 100644
--- a/drivers/gpio/gpio-fxl6408.c
+++ b/drivers/gpio/gpio-fxl6408.c
@@ -148,7 +148,7 @@ static struct i2c_driver fxl6408_driver = {
.name = "fxl6408",
.of_match_table = fxl6408_dt_ids,
},
- .probe_new = fxl6408_probe,
+ .probe = fxl6408_probe,
.id_table = fxl6408_id,
};
module_i2c_driver(fxl6408_driver);
diff --git a/drivers/gpio/gpio-gw-pld.c b/drivers/gpio/gpio-gw-pld.c
index 5057fa9ad610..899335da93c7 100644
--- a/drivers/gpio/gpio-gw-pld.c
+++ b/drivers/gpio/gpio-gw-pld.c
@@ -125,7 +125,7 @@ static struct i2c_driver gw_pld_driver = {
.name = "gw_pld",
.of_match_table = gw_pld_dt_ids,
},
- .probe_new = gw_pld_probe,
+ .probe = gw_pld_probe,
.id_table = gw_pld_id,
};
module_i2c_driver(gw_pld_driver);
diff --git a/drivers/gpio/gpio-ixp4xx.c b/drivers/gpio/gpio-ixp4xx.c
index 56656fb519f8..1e29de1671d4 100644
--- a/drivers/gpio/gpio-ixp4xx.c
+++ b/drivers/gpio/gpio-ixp4xx.c
@@ -199,7 +199,6 @@ static int ixp4xx_gpio_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct irq_domain *parent;
- struct resource *res;
struct ixp4xx_gpio *g;
struct gpio_irq_chip *girq;
struct device_node *irq_parent;
@@ -210,8 +209,7 @@ static int ixp4xx_gpio_probe(struct platform_device *pdev)
return -ENOMEM;
g->dev = dev;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- g->base = devm_ioremap_resource(dev, res);
+ g->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(g->base))
return PTR_ERR(g->base);
diff --git a/drivers/gpio/gpio-lpc18xx.c b/drivers/gpio/gpio-lpc18xx.c
index d711ae06747e..ed3f653a1dfc 100644
--- a/drivers/gpio/gpio-lpc18xx.c
+++ b/drivers/gpio/gpio-lpc18xx.c
@@ -14,7 +14,6 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
diff --git a/drivers/gpio/gpio-max7300.c b/drivers/gpio/gpio-max7300.c
index cf482f4f0098..31c2b95321cc 100644
--- a/drivers/gpio/gpio-max7300.c
+++ b/drivers/gpio/gpio-max7300.c
@@ -62,7 +62,7 @@ static struct i2c_driver max7300_driver = {
.driver = {
.name = "max7300",
},
- .probe_new = max7300_probe,
+ .probe = max7300_probe,
.remove = max7300_remove,
.id_table = max7300_id,
};
diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c
index 7f2fde191755..fca9ca68e387 100644
--- a/drivers/gpio/gpio-max732x.c
+++ b/drivers/gpio/gpio-max732x.c
@@ -711,7 +711,7 @@ static struct i2c_driver max732x_driver = {
.name = "max732x",
.of_match_table = of_match_ptr(max732x_of_table),
},
- .probe_new = max732x_probe,
+ .probe = max732x_probe,
.id_table = max732x_id,
};
diff --git a/drivers/gpio/gpio-mlxbf3.c b/drivers/gpio/gpio-mlxbf3.c
new file mode 100644
index 000000000000..e30cee108986
--- /dev/null
+++ b/drivers/gpio/gpio-mlxbf3.c
@@ -0,0 +1,248 @@
+// SPDX-License-Identifier: GPL-2.0-only or BSD-3-Clause
+/* Copyright (C) 2022 NVIDIA CORPORATION & AFFILIATES */
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio/driver.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+/*
+ * There are 2 YU GPIO blocks:
+ * gpio[0]: HOST_GPIO0->HOST_GPIO31
+ * gpio[1]: HOST_GPIO32->HOST_GPIO55
+ */
+#define MLXBF3_GPIO_MAX_PINS_PER_BLOCK 32
+
+/*
+ * fw_gpio[x] block registers and their offset
+ */
+#define MLXBF_GPIO_FW_OUTPUT_ENABLE_SET 0x00
+#define MLXBF_GPIO_FW_DATA_OUT_SET 0x04
+
+#define MLXBF_GPIO_FW_OUTPUT_ENABLE_CLEAR 0x00
+#define MLXBF_GPIO_FW_DATA_OUT_CLEAR 0x04
+
+#define MLXBF_GPIO_CAUSE_RISE_EN 0x00
+#define MLXBF_GPIO_CAUSE_FALL_EN 0x04
+#define MLXBF_GPIO_READ_DATA_IN 0x08
+
+#define MLXBF_GPIO_CAUSE_OR_CAUSE_EVTEN0 0x00
+#define MLXBF_GPIO_CAUSE_OR_EVTEN0 0x14
+#define MLXBF_GPIO_CAUSE_OR_CLRCAUSE 0x18
+
+struct mlxbf3_gpio_context {
+ struct gpio_chip gc;
+
+ /* YU GPIO block address */
+ void __iomem *gpio_set_io;
+ void __iomem *gpio_clr_io;
+ void __iomem *gpio_io;
+
+ /* YU GPIO cause block address */
+ void __iomem *gpio_cause_io;
+};
+
+static void mlxbf3_gpio_irq_enable(struct irq_data *irqd)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+ struct mlxbf3_gpio_context *gs = gpiochip_get_data(gc);
+ irq_hw_number_t offset = irqd_to_hwirq(irqd);
+ unsigned long flags;
+ u32 val;
+
+ gpiochip_enable_irq(gc, offset);
+
+ raw_spin_lock_irqsave(&gs->gc.bgpio_lock, flags);
+ writel(BIT(offset), gs->gpio_cause_io + MLXBF_GPIO_CAUSE_OR_CLRCAUSE);
+
+ val = readl(gs->gpio_cause_io + MLXBF_GPIO_CAUSE_OR_EVTEN0);
+ val |= BIT(offset);
+ writel(val, gs->gpio_cause_io + MLXBF_GPIO_CAUSE_OR_EVTEN0);
+ raw_spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags);
+}
+
+static void mlxbf3_gpio_irq_disable(struct irq_data *irqd)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+ struct mlxbf3_gpio_context *gs = gpiochip_get_data(gc);
+ irq_hw_number_t offset = irqd_to_hwirq(irqd);
+ unsigned long flags;
+ u32 val;
+
+ raw_spin_lock_irqsave(&gs->gc.bgpio_lock, flags);
+ val = readl(gs->gpio_cause_io + MLXBF_GPIO_CAUSE_OR_EVTEN0);
+ val &= ~BIT(offset);
+ writel(val, gs->gpio_cause_io + MLXBF_GPIO_CAUSE_OR_EVTEN0);
+ raw_spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags);
+
+ gpiochip_disable_irq(gc, offset);
+}
+
+static irqreturn_t mlxbf3_gpio_irq_handler(int irq, void *ptr)
+{
+ struct mlxbf3_gpio_context *gs = ptr;
+ struct gpio_chip *gc = &gs->gc;
+ unsigned long pending;
+ u32 level;
+
+ pending = readl(gs->gpio_cause_io + MLXBF_GPIO_CAUSE_OR_CAUSE_EVTEN0);
+ writel(pending, gs->gpio_cause_io + MLXBF_GPIO_CAUSE_OR_CLRCAUSE);
+
+ for_each_set_bit(level, &pending, gc->ngpio)
+ generic_handle_domain_irq(gc->irq.domain, level);
+
+ return IRQ_RETVAL(pending);
+}
+
+static int
+mlxbf3_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+ struct mlxbf3_gpio_context *gs = gpiochip_get_data(gc);
+ irq_hw_number_t offset = irqd_to_hwirq(irqd);
+ unsigned long flags;
+ u32 val;
+
+ raw_spin_lock_irqsave(&gs->gc.bgpio_lock, flags);
+
+ switch (type & IRQ_TYPE_SENSE_MASK) {
+ case IRQ_TYPE_EDGE_BOTH:
+ val = readl(gs->gpio_io + MLXBF_GPIO_CAUSE_FALL_EN);
+ val |= BIT(offset);
+ writel(val, gs->gpio_io + MLXBF_GPIO_CAUSE_FALL_EN);
+ val = readl(gs->gpio_io + MLXBF_GPIO_CAUSE_RISE_EN);
+ val |= BIT(offset);
+ writel(val, gs->gpio_io + MLXBF_GPIO_CAUSE_RISE_EN);
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ val = readl(gs->gpio_io + MLXBF_GPIO_CAUSE_RISE_EN);
+ val |= BIT(offset);
+ writel(val, gs->gpio_io + MLXBF_GPIO_CAUSE_RISE_EN);
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ val = readl(gs->gpio_io + MLXBF_GPIO_CAUSE_FALL_EN);
+ val |= BIT(offset);
+ writel(val, gs->gpio_io + MLXBF_GPIO_CAUSE_FALL_EN);
+ break;
+ default:
+ raw_spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags);
+ return -EINVAL;
+ }
+
+ raw_spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags);
+
+ irq_set_handler_locked(irqd, handle_edge_irq);
+
+ return 0;
+}
+
+/* This function needs to be defined for handle_edge_irq() */
+static void mlxbf3_gpio_irq_ack(struct irq_data *data)
+{
+}
+
+static const struct irq_chip gpio_mlxbf3_irqchip = {
+ .name = "MLNXBF33",
+ .irq_ack = mlxbf3_gpio_irq_ack,
+ .irq_set_type = mlxbf3_gpio_irq_set_type,
+ .irq_enable = mlxbf3_gpio_irq_enable,
+ .irq_disable = mlxbf3_gpio_irq_disable,
+ .flags = IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
+static int mlxbf3_gpio_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mlxbf3_gpio_context *gs;
+ struct gpio_irq_chip *girq;
+ struct gpio_chip *gc;
+ int ret, irq;
+
+ gs = devm_kzalloc(dev, sizeof(*gs), GFP_KERNEL);
+ if (!gs)
+ return -ENOMEM;
+
+ gs->gpio_io = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(gs->gpio_io))
+ return PTR_ERR(gs->gpio_io);
+
+ gs->gpio_cause_io = devm_platform_ioremap_resource(pdev, 1);
+ if (IS_ERR(gs->gpio_cause_io))
+ return PTR_ERR(gs->gpio_cause_io);
+
+ gs->gpio_set_io = devm_platform_ioremap_resource(pdev, 2);
+ if (IS_ERR(gs->gpio_set_io))
+ return PTR_ERR(gs->gpio_set_io);
+
+ gs->gpio_clr_io = devm_platform_ioremap_resource(pdev, 3);
+ if (IS_ERR(gs->gpio_clr_io))
+ return PTR_ERR(gs->gpio_clr_io);
+ gc = &gs->gc;
+
+ ret = bgpio_init(gc, dev, 4,
+ gs->gpio_io + MLXBF_GPIO_READ_DATA_IN,
+ gs->gpio_set_io + MLXBF_GPIO_FW_DATA_OUT_SET,
+ gs->gpio_clr_io + MLXBF_GPIO_FW_DATA_OUT_CLEAR,
+ gs->gpio_set_io + MLXBF_GPIO_FW_OUTPUT_ENABLE_SET,
+ gs->gpio_clr_io + MLXBF_GPIO_FW_OUTPUT_ENABLE_CLEAR, 0);
+
+ gc->request = gpiochip_generic_request;
+ gc->free = gpiochip_generic_free;
+ gc->owner = THIS_MODULE;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq >= 0) {
+ girq = &gs->gc.irq;
+ gpio_irq_chip_set_chip(girq, &gpio_mlxbf3_irqchip);
+ girq->default_type = IRQ_TYPE_NONE;
+ /* This will let us handle the parent IRQ in the driver */
+ girq->num_parents = 0;
+ girq->parents = NULL;
+ girq->parent_handler = NULL;
+ girq->handler = handle_bad_irq;
+
+ /*
+ * Directly request the irq here instead of passing
+ * a flow-handler because the irq is shared.
+ */
+ ret = devm_request_irq(dev, irq, mlxbf3_gpio_irq_handler,
+ IRQF_SHARED, dev_name(dev), gs);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to request IRQ");
+ }
+
+ platform_set_drvdata(pdev, gs);
+
+ ret = devm_gpiochip_add_data(dev, &gs->gc, gs);
+ if (ret)
+ dev_err_probe(dev, ret, "Failed adding memory mapped gpiochip\n");
+
+ return 0;
+}
+
+static const struct acpi_device_id mlxbf3_gpio_acpi_match[] = {
+ { "MLNXBF33", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(acpi, mlxbf3_gpio_acpi_match);
+
+static struct platform_driver mlxbf3_gpio_driver = {
+ .driver = {
+ .name = "mlxbf3_gpio",
+ .acpi_match_table = mlxbf3_gpio_acpi_match,
+ },
+ .probe = mlxbf3_gpio_probe,
+};
+module_platform_driver(mlxbf3_gpio_driver);
+
+MODULE_DESCRIPTION("NVIDIA BlueField-3 GPIO Driver");
+MODULE_AUTHOR("Asmaa Mnebhi <asmaa@nvidia.com>");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c
index 3eb08cd1fdc0..5979a36bf754 100644
--- a/drivers/gpio/gpio-mpc8xxx.c
+++ b/drivers/gpio/gpio-mpc8xxx.c
@@ -12,7 +12,6 @@
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
@@ -375,8 +374,12 @@ static int mpc8xxx_probe(struct platform_device *pdev)
if (of_device_is_compatible(np, "fsl,qoriq-gpio") ||
of_device_is_compatible(np, "fsl,ls1028a-gpio") ||
of_device_is_compatible(np, "fsl,ls1088a-gpio") ||
- is_acpi_node(fwnode))
+ is_acpi_node(fwnode)) {
gc->write_reg(mpc8xxx_gc->regs + GPIO_IBE, 0xffffffff);
+ /* Also, latch state of GPIOs configured as output by bootloader. */
+ gc->bgpio_data = gc->read_reg(mpc8xxx_gc->regs + GPIO_DAT) &
+ gc->read_reg(mpc8xxx_gc->regs + GPIO_DIR);
+ }
ret = devm_gpiochip_add_data(&pdev->dev, gc, mpc8xxx_gc);
if (ret) {
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index 1286b22ef23a..a806a3c1b801 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -1375,7 +1375,7 @@ static struct i2c_driver pca953x_driver = {
.of_match_table = pca953x_dt_ids,
.acpi_match_table = pca953x_acpi_ids,
},
- .probe_new = pca953x_probe,
+ .probe = pca953x_probe,
.remove = pca953x_remove,
.id_table = pca953x_id,
};
diff --git a/drivers/gpio/gpio-pca9570.c b/drivers/gpio/gpio-pca9570.c
index 6a5a8e593ed5..d8db80ef1293 100644
--- a/drivers/gpio/gpio-pca9570.c
+++ b/drivers/gpio/gpio-pca9570.c
@@ -175,7 +175,7 @@ static struct i2c_driver pca9570_driver = {
.name = "pca9570",
.of_match_table = pca9570_of_match_table,
},
- .probe_new = pca9570_probe,
+ .probe = pca9570_probe,
.id_table = pca9570_id_table,
};
module_i2c_driver(pca9570_driver);
diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c
index 3de1d3ad7472..c4c785548408 100644
--- a/drivers/gpio/gpio-pcf857x.c
+++ b/drivers/gpio/gpio-pcf857x.c
@@ -419,7 +419,7 @@ static struct i2c_driver pcf857x_driver = {
.name = "pcf857x",
.of_match_table = pcf857x_of_table,
},
- .probe_new = pcf857x_probe,
+ .probe = pcf857x_probe,
.shutdown = pcf857x_shutdown,
.id_table = pcf857x_id,
};
diff --git a/drivers/gpio/gpio-sa1100.c b/drivers/gpio/gpio-sa1100.c
index edff5e81489f..242dad763ac4 100644
--- a/drivers/gpio/gpio-sa1100.c
+++ b/drivers/gpio/gpio-sa1100.c
@@ -12,6 +12,7 @@
#include <soc/sa1100/pwer.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
+#include <mach/generic.h>
struct sa1100_gpio_chip {
struct gpio_chip chip;
diff --git a/drivers/gpio/gpio-sch311x.c b/drivers/gpio/gpio-sch311x.c
index da01e1cad7cb..ba4fccf3cc94 100644
--- a/drivers/gpio/gpio-sch311x.c
+++ b/drivers/gpio/gpio-sch311x.c
@@ -281,8 +281,6 @@ static int sch311x_gpio_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
- platform_set_drvdata(pdev, priv);
-
for (i = 0; i < ARRAY_SIZE(priv->blocks); i++) {
block = &priv->blocks[i];
@@ -305,42 +303,22 @@ static int sch311x_gpio_probe(struct platform_device *pdev)
block->data_reg = sch311x_gpio_blocks[i].data_reg;
block->runtime_reg = pdata->runtime_reg;
- err = gpiochip_add_data(&block->chip, block);
+ err = devm_gpiochip_add_data(&pdev->dev, &block->chip, block);
if (err < 0) {
dev_err(&pdev->dev,
"Could not register gpiochip, %d\n", err);
- goto exit_err;
+ return err;
}
dev_info(&pdev->dev,
"SMSC SCH311x GPIO block %d registered.\n", i);
}
return 0;
-
-exit_err:
- /* release already registered chips */
- for (--i; i >= 0; i--)
- gpiochip_remove(&priv->blocks[i].chip);
- return err;
-}
-
-static int sch311x_gpio_remove(struct platform_device *pdev)
-{
- struct sch311x_gpio_priv *priv = platform_get_drvdata(pdev);
- int i;
-
- for (i = 0; i < ARRAY_SIZE(priv->blocks); i++) {
- gpiochip_remove(&priv->blocks[i].chip);
- dev_info(&pdev->dev,
- "SMSC SCH311x GPIO block %d unregistered.\n", i);
- }
- return 0;
}
static struct platform_driver sch311x_gpio_driver = {
.driver.name = DRV_NAME,
.probe = sch311x_gpio_probe,
- .remove = sch311x_gpio_remove,
};
diff --git a/drivers/gpio/gpio-tangier.c b/drivers/gpio/gpio-tangier.c
index e990781935ba..7ce3eddaed25 100644
--- a/drivers/gpio/gpio-tangier.c
+++ b/drivers/gpio/gpio-tangier.c
@@ -16,6 +16,7 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
+#include <linux/math.h>
#include <linux/module.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/spinlock.h>
@@ -428,10 +429,11 @@ static int tng_gpio_add_pin_ranges(struct gpio_chip *chip)
int devm_tng_gpio_probe(struct device *dev, struct tng_gpio *gpio)
{
const struct tng_gpio_info *info = &gpio->info;
+ size_t nctx = DIV_ROUND_UP(info->ngpio, 32);
struct gpio_irq_chip *girq;
int ret;
- gpio->ctx = devm_kcalloc(dev, DIV_ROUND_UP(info->ngpio, 32), sizeof(*gpio->ctx), GFP_KERNEL);
+ gpio->ctx = devm_kcalloc(dev, nctx, sizeof(*gpio->ctx), GFP_KERNEL);
if (!gpio->ctx)
return -ENOMEM;
diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c
index b904de0b1784..464b0ea3b6f1 100644
--- a/drivers/gpio/gpio-tegra186.c
+++ b/drivers/gpio/gpio-tegra186.c
@@ -27,6 +27,22 @@
#define TEGRA186_GPIO_INT_ROUTE_MAPPING(p, x) (0x14 + (p) * 0x20 + (x) * 4)
+#define TEGRA186_GPIO_VM 0x00
+#define TEGRA186_GPIO_VM_RW_MASK 0x03
+#define TEGRA186_GPIO_SCR 0x04
+#define TEGRA186_GPIO_SCR_PIN_SIZE 0x08
+#define TEGRA186_GPIO_SCR_PORT_SIZE 0x40
+#define TEGRA186_GPIO_SCR_SEC_WEN BIT(28)
+#define TEGRA186_GPIO_SCR_SEC_REN BIT(27)
+#define TEGRA186_GPIO_SCR_SEC_G1W BIT(9)
+#define TEGRA186_GPIO_SCR_SEC_G1R BIT(1)
+#define TEGRA186_GPIO_FULL_ACCESS (TEGRA186_GPIO_SCR_SEC_WEN | \
+ TEGRA186_GPIO_SCR_SEC_REN | \
+ TEGRA186_GPIO_SCR_SEC_G1R | \
+ TEGRA186_GPIO_SCR_SEC_G1W)
+#define TEGRA186_GPIO_SCR_SEC_ENABLE (TEGRA186_GPIO_SCR_SEC_WEN | \
+ TEGRA186_GPIO_SCR_SEC_REN)
+
/* control registers */
#define TEGRA186_GPIO_ENABLE_CONFIG 0x00
#define TEGRA186_GPIO_ENABLE_CONFIG_ENABLE BIT(0)
@@ -81,6 +97,7 @@ struct tegra_gpio_soc {
unsigned int num_pin_ranges;
const char *pinmux;
bool has_gte;
+ bool has_vm_support;
};
struct tegra_gpio {
@@ -130,6 +147,58 @@ static void __iomem *tegra186_gpio_get_base(struct tegra_gpio *gpio,
return gpio->base + offset + pin * 0x20;
}
+static void __iomem *tegra186_gpio_get_secure_base(struct tegra_gpio *gpio,
+ unsigned int pin)
+{
+ const struct tegra_gpio_port *port;
+ unsigned int offset;
+
+ port = tegra186_gpio_get_port(gpio, &pin);
+ if (!port)
+ return NULL;
+
+ offset = port->bank * 0x1000 + port->port * TEGRA186_GPIO_SCR_PORT_SIZE;
+
+ return gpio->secure + offset + pin * TEGRA186_GPIO_SCR_PIN_SIZE;
+}
+
+static inline bool tegra186_gpio_is_accessible(struct tegra_gpio *gpio, unsigned int pin)
+{
+ void __iomem *secure;
+ u32 value;
+
+ secure = tegra186_gpio_get_secure_base(gpio, pin);
+
+ if (gpio->soc->has_vm_support) {
+ value = readl(secure + TEGRA186_GPIO_VM);
+ if ((value & TEGRA186_GPIO_VM_RW_MASK) != TEGRA186_GPIO_VM_RW_MASK)
+ return false;
+ }
+
+ value = __raw_readl(secure + TEGRA186_GPIO_SCR);
+
+ if ((value & TEGRA186_GPIO_SCR_SEC_ENABLE) == 0)
+ return true;
+
+ if ((value & TEGRA186_GPIO_FULL_ACCESS) == TEGRA186_GPIO_FULL_ACCESS)
+ return true;
+
+ return false;
+}
+
+static int tegra186_init_valid_mask(struct gpio_chip *chip,
+ unsigned long *valid_mask, unsigned int ngpios)
+{
+ struct tegra_gpio *gpio = gpiochip_get_data(chip);
+ unsigned int j;
+
+ for (j = 0; j < ngpios; j++) {
+ if (!tegra186_gpio_is_accessible(gpio, j))
+ clear_bit(j, valid_mask);
+ }
+ return 0;
+}
+
static int tegra186_gpio_get_direction(struct gpio_chip *chip,
unsigned int offset)
{
@@ -816,6 +885,7 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
gpio->gpio.set = tegra186_gpio_set;
gpio->gpio.set_config = tegra186_gpio_set_config;
gpio->gpio.add_pin_ranges = tegra186_gpio_add_pin_ranges;
+ gpio->gpio.init_valid_mask = tegra186_init_valid_mask;
if (gpio->soc->has_gte) {
gpio->gpio.en_hw_timestamp = tegra186_gpio_en_hw_ts;
gpio->gpio.dis_hw_timestamp = tegra186_gpio_dis_hw_ts;
@@ -958,6 +1028,7 @@ static const struct tegra_gpio_soc tegra186_main_soc = {
.name = "tegra186-gpio",
.instance = 0,
.num_irqs_per_bank = 1,
+ .has_vm_support = false,
};
#define TEGRA186_AON_GPIO_PORT(_name, _bank, _port, _pins) \
@@ -985,6 +1056,7 @@ static const struct tegra_gpio_soc tegra186_aon_soc = {
.name = "tegra186-gpio-aon",
.instance = 1,
.num_irqs_per_bank = 1,
+ .has_vm_support = false,
};
#define TEGRA194_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \
@@ -1040,6 +1112,7 @@ static const struct tegra_gpio_soc tegra194_main_soc = {
.num_pin_ranges = ARRAY_SIZE(tegra194_main_pin_ranges),
.pin_ranges = tegra194_main_pin_ranges,
.pinmux = "nvidia,tegra194-pinmux",
+ .has_vm_support = true,
};
#define TEGRA194_AON_GPIO_PORT(_name, _bank, _port, _pins) \
@@ -1065,6 +1138,7 @@ static const struct tegra_gpio_soc tegra194_aon_soc = {
.instance = 1,
.num_irqs_per_bank = 8,
.has_gte = true,
+ .has_vm_support = false,
};
#define TEGRA234_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \
@@ -1109,6 +1183,7 @@ static const struct tegra_gpio_soc tegra234_main_soc = {
.name = "tegra234-gpio",
.instance = 0,
.num_irqs_per_bank = 8,
+ .has_vm_support = true,
};
#define TEGRA234_AON_GPIO_PORT(_name, _bank, _port, _pins) \
@@ -1135,6 +1210,7 @@ static const struct tegra_gpio_soc tegra234_aon_soc = {
.instance = 1,
.num_irqs_per_bank = 8,
.has_gte = true,
+ .has_vm_support = false,
};
#define TEGRA241_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \
@@ -1165,6 +1241,7 @@ static const struct tegra_gpio_soc tegra241_main_soc = {
.name = "tegra241-gpio",
.instance = 0,
.num_irqs_per_bank = 8,
+ .has_vm_support = false,
};
#define TEGRA241_AON_GPIO_PORT(_name, _bank, _port, _pins) \
@@ -1186,6 +1263,7 @@ static const struct tegra_gpio_soc tegra241_aon_soc = {
.name = "tegra241-gpio-aon",
.instance = 1,
.num_irqs_per_bank = 8,
+ .has_vm_support = false,
};
static const struct of_device_id tegra186_gpio_of_match[] = {
diff --git a/drivers/gpio/gpio-tpic2810.c b/drivers/gpio/gpio-tpic2810.c
index 349c5fbd9b02..effb7b8ff81f 100644
--- a/drivers/gpio/gpio-tpic2810.c
+++ b/drivers/gpio/gpio-tpic2810.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
- * Andrew F. Davis <afd@ti.com>
+ * Copyright (C) 2015-2023 Texas Instruments Incorporated - https://www.ti.com/
+ * Andrew Davis <afd@ti.com>
*/
#include <linux/gpio/driver.h>
@@ -101,14 +101,11 @@ MODULE_DEVICE_TABLE(of, tpic2810_of_match_table);
static int tpic2810_probe(struct i2c_client *client)
{
struct tpic2810 *gpio;
- int ret;
gpio = devm_kzalloc(&client->dev, sizeof(*gpio), GFP_KERNEL);
if (!gpio)
return -ENOMEM;
- i2c_set_clientdata(client, gpio);
-
gpio->chip = template_chip;
gpio->chip.parent = &client->dev;
@@ -116,20 +113,7 @@ static int tpic2810_probe(struct i2c_client *client)
mutex_init(&gpio->lock);
- ret = gpiochip_add_data(&gpio->chip, gpio);
- if (ret < 0) {
- dev_err(&client->dev, "Unable to register gpiochip\n");
- return ret;
- }
-
- return 0;
-}
-
-static void tpic2810_remove(struct i2c_client *client)
-{
- struct tpic2810 *gpio = i2c_get_clientdata(client);
-
- gpiochip_remove(&gpio->chip);
+ return devm_gpiochip_add_data(&client->dev, &gpio->chip, gpio);
}
static const struct i2c_device_id tpic2810_id_table[] = {
@@ -143,12 +127,11 @@ static struct i2c_driver tpic2810_driver = {
.name = "tpic2810",
.of_match_table = tpic2810_of_match_table,
},
- .probe_new = tpic2810_probe,
- .remove = tpic2810_remove,
+ .probe = tpic2810_probe,
.id_table = tpic2810_id_table,
};
module_i2c_driver(tpic2810_driver);
-MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
+MODULE_AUTHOR("Andrew Davis <afd@ti.com>");
MODULE_DESCRIPTION("TPIC2810 8-Bit LED Driver GPIO Driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-tps65086.c b/drivers/gpio/gpio-tps65086.c
index 1e9d8262d0ff..8f5827554e1e 100644
--- a/drivers/gpio/gpio-tps65086.c
+++ b/drivers/gpio/gpio-tps65086.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
- * Andrew F. Davis <afd@ti.com>
+ * Copyright (C) 2015-2023 Texas Instruments Incorporated - https://www.ti.com/
+ * Andrew Davis <afd@ti.com>
*
* Based on the TPS65912 driver
*/
@@ -80,34 +80,16 @@ static const struct gpio_chip template_chip = {
static int tps65086_gpio_probe(struct platform_device *pdev)
{
struct tps65086_gpio *gpio;
- int ret;
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
if (!gpio)
return -ENOMEM;
- platform_set_drvdata(pdev, gpio);
-
gpio->tps = dev_get_drvdata(pdev->dev.parent);
gpio->chip = template_chip;
gpio->chip.parent = gpio->tps->dev;
- ret = gpiochip_add_data(&gpio->chip, gpio);
- if (ret < 0) {
- dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
- return ret;
- }
-
- return 0;
-}
-
-static int tps65086_gpio_remove(struct platform_device *pdev)
-{
- struct tps65086_gpio *gpio = platform_get_drvdata(pdev);
-
- gpiochip_remove(&gpio->chip);
-
- return 0;
+ return devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
}
static const struct platform_device_id tps65086_gpio_id_table[] = {
@@ -121,11 +103,10 @@ static struct platform_driver tps65086_gpio_driver = {
.name = "tps65086-gpio",
},
.probe = tps65086_gpio_probe,
- .remove = tps65086_gpio_remove,
.id_table = tps65086_gpio_id_table,
};
module_platform_driver(tps65086_gpio_driver);
-MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
+MODULE_AUTHOR("Andrew Davis <afd@ti.com>");
MODULE_DESCRIPTION("TPS65086 GPIO driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-tps65219.c b/drivers/gpio/gpio-tps65219.c
new file mode 100644
index 000000000000..7b38aa360112
--- /dev/null
+++ b/drivers/gpio/gpio-tps65219.c
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * GPIO driver for TI TPS65219 PMICs
+ *
+ * Copyright (C) 2022 Texas Instruments Incorporated - http://www.ti.com/
+ */
+
+#include <linux/bits.h>
+#include <linux/gpio/driver.h>
+#include <linux/mfd/tps65219.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define TPS65219_GPIO0_DIR_MASK BIT(3)
+#define TPS65219_GPIO0_OFFSET 2
+#define TPS65219_GPIO0_IDX 0
+#define TPS65219_GPIO_DIR_IN 1
+#define TPS65219_GPIO_DIR_OUT 0
+
+struct tps65219_gpio {
+ struct gpio_chip gpio_chip;
+ struct tps65219 *tps;
+};
+
+static int tps65219_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+ struct tps65219_gpio *gpio = gpiochip_get_data(gc);
+ int ret, val;
+
+ if (offset != TPS65219_GPIO0_IDX)
+ return GPIO_LINE_DIRECTION_OUT;
+
+ ret = regmap_read(gpio->tps->regmap, TPS65219_REG_MFP_1_CONFIG, &val);
+ if (ret)
+ return ret;
+
+ return !!(val & TPS65219_GPIO0_DIR_MASK);
+}
+
+static int tps65219_gpio_get(struct gpio_chip *gc, unsigned int offset)
+{
+ struct tps65219_gpio *gpio = gpiochip_get_data(gc);
+ struct device *dev = gpio->tps->dev;
+ int ret, val;
+
+ if (offset != TPS65219_GPIO0_IDX) {
+ dev_err(dev, "GPIO%d is output only, cannot get\n", offset);
+ return -ENOTSUPP;
+ }
+
+ ret = regmap_read(gpio->tps->regmap, TPS65219_REG_MFP_CTRL, &val);
+ if (ret)
+ return ret;
+
+ ret = !!(val & BIT(TPS65219_MFP_GPIO_STATUS_MASK));
+ dev_warn(dev, "GPIO%d = %d, MULTI_DEVICE_ENABLE, not a standard GPIO\n", offset, ret);
+
+ /*
+ * Depending on NVM config, return an error if direction is output, otherwise the GPIO0
+ * status bit.
+ */
+
+ if (tps65219_gpio_get_direction(gc, offset) == TPS65219_GPIO_DIR_OUT)
+ return -ENOTSUPP;
+
+ return ret;
+}
+
+static void tps65219_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
+{
+ struct tps65219_gpio *gpio = gpiochip_get_data(gc);
+ struct device *dev = gpio->tps->dev;
+ int v, mask, bit;
+
+ bit = (offset == TPS65219_GPIO0_IDX) ? TPS65219_GPIO0_OFFSET : offset - 1;
+
+ mask = BIT(bit);
+ v = value ? mask : 0;
+
+ if (regmap_update_bits(gpio->tps->regmap, TPS65219_REG_GENERAL_CONFIG, mask, v))
+ dev_err(dev, "GPIO%d, set to value %d failed.\n", offset, value);
+}
+
+static int tps65219_gpio_change_direction(struct gpio_chip *gc, unsigned int offset,
+ unsigned int direction)
+{
+ struct tps65219_gpio *gpio = gpiochip_get_data(gc);
+ struct device *dev = gpio->tps->dev;
+
+ /*
+ * Documentation is stating that GPIO0 direction must not be changed in Linux:
+ * Table 8-34. MFP_1_CONFIG(3): MULTI_DEVICE_ENABLE, should only be changed in INITIALIZE
+ * state (prior to ON Request).
+ * Set statically by NVM, changing direction in application can cause a hang.
+ * Below can be used for test purpose only.
+ */
+
+ if (IS_ENABLED(CONFIG_DEBUG_GPIO)) {
+ int ret = regmap_update_bits(gpio->tps->regmap, TPS65219_REG_MFP_1_CONFIG,
+ TPS65219_GPIO0_DIR_MASK, direction);
+ if (ret) {
+ dev_err(dev,
+ "GPIO DEBUG enabled: Fail to change direction to %u for GPIO%d.\n",
+ direction, offset);
+ return ret;
+ }
+ }
+
+ dev_err(dev,
+ "GPIO%d direction set by NVM, change to %u failed, not allowed by specification\n",
+ offset, direction);
+
+ return -ENOTSUPP;
+}
+
+static int tps65219_gpio_direction_input(struct gpio_chip *gc, unsigned int offset)
+{
+ struct tps65219_gpio *gpio = gpiochip_get_data(gc);
+ struct device *dev = gpio->tps->dev;
+
+ if (offset != TPS65219_GPIO0_IDX) {
+ dev_err(dev, "GPIO%d is output only, cannot change to input\n", offset);
+ return -ENOTSUPP;
+ }
+
+ if (tps65219_gpio_get_direction(gc, offset) == TPS65219_GPIO_DIR_IN)
+ return 0;
+
+ return tps65219_gpio_change_direction(gc, offset, TPS65219_GPIO_DIR_IN);
+}
+
+static int tps65219_gpio_direction_output(struct gpio_chip *gc, unsigned int offset, int value)
+{
+ tps65219_gpio_set(gc, offset, value);
+ if (offset != TPS65219_GPIO0_IDX)
+ return 0;
+
+ if (tps65219_gpio_get_direction(gc, offset) == TPS65219_GPIO_DIR_OUT)
+ return 0;
+
+ return tps65219_gpio_change_direction(gc, offset, TPS65219_GPIO_DIR_OUT);
+}
+
+static const struct gpio_chip tps65219_template_chip = {
+ .label = "tps65219-gpio",
+ .owner = THIS_MODULE,
+ .get_direction = tps65219_gpio_get_direction,
+ .direction_input = tps65219_gpio_direction_input,
+ .direction_output = tps65219_gpio_direction_output,
+ .get = tps65219_gpio_get,
+ .set = tps65219_gpio_set,
+ .base = -1,
+ .ngpio = 3,
+ .can_sleep = true,
+};
+
+static int tps65219_gpio_probe(struct platform_device *pdev)
+{
+ struct tps65219 *tps = dev_get_drvdata(pdev->dev.parent);
+ struct tps65219_gpio *gpio;
+
+ gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
+ if (!gpio)
+ return -ENOMEM;
+
+ gpio->tps = tps;
+ gpio->gpio_chip = tps65219_template_chip;
+ gpio->gpio_chip.parent = tps->dev;
+
+ return devm_gpiochip_add_data(&pdev->dev, &gpio->gpio_chip, gpio);
+}
+
+static struct platform_driver tps65219_gpio_driver = {
+ .driver = {
+ .name = "tps65219-gpio",
+ },
+ .probe = tps65219_gpio_probe,
+};
+module_platform_driver(tps65219_gpio_driver);
+
+MODULE_ALIAS("platform:tps65219-gpio");
+MODULE_AUTHOR("Jonathan Cormier <jcormier@criticallink.com>");
+MODULE_DESCRIPTION("TPS65219 GPIO driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-ts4900.c b/drivers/gpio/gpio-ts4900.c
index 43e8b66e04f7..eba96319dac2 100644
--- a/drivers/gpio/gpio-ts4900.c
+++ b/drivers/gpio/gpio-ts4900.c
@@ -185,7 +185,7 @@ static struct i2c_driver ts4900_gpio_driver = {
.name = "ts4900-gpio",
.of_match_table = ts4900_gpio_of_match_table,
},
- .probe_new = ts4900_gpio_probe,
+ .probe = ts4900_gpio_probe,
.id_table = ts4900_gpio_id_table,
};
module_i2c_driver(ts4900_gpio_driver);
diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c
index c1bb2c3ca6f2..bcd692229c7c 100644
--- a/drivers/gpio/gpio-twl4030.c
+++ b/drivers/gpio/gpio-twl4030.c
@@ -17,7 +17,9 @@
#include <linux/interrupt.h>
#include <linux/kthread.h>
#include <linux/irq.h>
+#include <linux/gpio/machine.h>
#include <linux/gpio/driver.h>
+#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/irqdomain.h>
@@ -465,8 +467,7 @@ static int gpio_twl4030_debounce(u32 debounce, u8 mmc_cd)
REG_GPIO_DEBEN1, 3);
}
-static struct twl4030_gpio_platform_data *of_gpio_twl4030(struct device *dev,
- struct twl4030_gpio_platform_data *pdata)
+static struct twl4030_gpio_platform_data *of_gpio_twl4030(struct device *dev)
{
struct twl4030_gpio_platform_data *omap_twl_info;
@@ -474,9 +475,6 @@ static struct twl4030_gpio_platform_data *of_gpio_twl4030(struct device *dev,
if (!omap_twl_info)
return NULL;
- if (pdata)
- *omap_twl_info = *pdata;
-
omap_twl_info->use_leds = of_property_read_bool(dev->of_node,
"ti,use-leds");
@@ -492,21 +490,18 @@ static struct twl4030_gpio_platform_data *of_gpio_twl4030(struct device *dev,
return omap_twl_info;
}
-/* Cannot use as gpio_twl4030_probe() calls us */
-static int gpio_twl4030_remove(struct platform_device *pdev)
+/* Called from the registered devm action */
+static void gpio_twl4030_power_off_action(void *data)
{
- struct gpio_twl4030_priv *priv = platform_get_drvdata(pdev);
-
- gpiochip_remove(&priv->gpio_chip);
+ struct gpio_desc *d = data;
- /* REVISIT no support yet for deregistering all the IRQs */
- WARN_ON(!is_module());
- return 0;
+ gpiod_unexport(d);
+ gpiochip_free_own_desc(d);
}
static int gpio_twl4030_probe(struct platform_device *pdev)
{
- struct twl4030_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
+ struct twl4030_gpio_platform_data *pdata;
struct device_node *node = pdev->dev.of_node;
struct gpio_twl4030_priv *priv;
int ret, irq_base;
@@ -546,9 +541,7 @@ no_irqs:
mutex_init(&priv->mutex);
- if (node)
- pdata = of_gpio_twl4030(&pdev->dev, pdata);
-
+ pdata = of_gpio_twl4030(&pdev->dev);
if (pdata == NULL) {
dev_err(&pdev->dev, "Platform data is missing\n");
return -ENXIO;
@@ -577,27 +570,39 @@ no_irqs:
if (pdata->use_leds)
priv->gpio_chip.ngpio += 2;
- ret = gpiochip_add_data(&priv->gpio_chip, priv);
+ ret = devm_gpiochip_add_data(&pdev->dev, &priv->gpio_chip, priv);
if (ret < 0) {
dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret);
priv->gpio_chip.ngpio = 0;
- gpio_twl4030_remove(pdev);
- goto out;
+ return ret;
}
- platform_set_drvdata(pdev, priv);
+ /*
+ * Special quirk for the OMAP3 to hog and export a WLAN power
+ * GPIO.
+ */
+ if (IS_ENABLED(CONFIG_ARCH_OMAP3) &&
+ of_machine_is_compatible("compulab,omap3-sbc-t3730")) {
+ struct gpio_desc *d;
+
+ d = gpiochip_request_own_desc(&priv->gpio_chip,
+ 2, "wlan pwr",
+ GPIO_ACTIVE_HIGH,
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(d))
+ return dev_err_probe(&pdev->dev, PTR_ERR(d),
+ "unable to hog wlan pwr GPIO\n");
+
+ gpiod_export(d, 0);
- if (pdata->setup) {
- int status;
+ ret = devm_add_action_or_reset(&pdev->dev, gpio_twl4030_power_off_action, d);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "failed to install power off handler\n");
- status = pdata->setup(&pdev->dev, priv->gpio_chip.base,
- TWL4030_GPIO_MAX);
- if (status)
- dev_dbg(&pdev->dev, "setup --> %d\n", status);
}
-out:
- return ret;
+ return 0;
}
static const struct of_device_id twl_gpio_match[] = {
@@ -615,7 +620,6 @@ static struct platform_driver gpio_twl4030_driver = {
.of_match_table = twl_gpio_match,
},
.probe = gpio_twl4030_probe,
- .remove = gpio_twl4030_remove,
};
static int __init gpio_twl4030_init(void)
diff --git a/drivers/gpio/gpio-xra1403.c b/drivers/gpio/gpio-xra1403.c
index 51d6119e1bb4..bbc06cdd9634 100644
--- a/drivers/gpio/gpio-xra1403.c
+++ b/drivers/gpio/gpio-xra1403.c
@@ -11,7 +11,6 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of_device.h>
-#include <linux/of_gpio.h>
#include <linux/seq_file.h>
#include <linux/spi/spi.h>
#include <linux/regmap.h>
diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c
index 06c6401f02b8..0a7264aabe48 100644
--- a/drivers/gpio/gpio-zynq.c
+++ b/drivers/gpio/gpio-zynq.c
@@ -151,8 +151,8 @@ struct zynq_platform_data {
int bank_max[ZYNQMP_GPIO_MAX_BANK];
};
-static struct irq_chip zynq_gpio_level_irqchip;
-static struct irq_chip zynq_gpio_edge_irqchip;
+static const struct irq_chip zynq_gpio_level_irqchip;
+static const struct irq_chip zynq_gpio_edge_irqchip;
/**
* zynq_gpio_is_zynq - test if HW is zynq or zynqmp
@@ -404,9 +404,12 @@ static int zynq_gpio_get_direction(struct gpio_chip *chip, unsigned int pin)
static void zynq_gpio_irq_mask(struct irq_data *irq_data)
{
unsigned int device_pin_num, bank_num, bank_pin_num;
+ const unsigned long offset = irqd_to_hwirq(irq_data);
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(irq_data);
struct zynq_gpio *gpio =
gpiochip_get_data(irq_data_get_irq_chip_data(irq_data));
+ gpiochip_disable_irq(chip, offset);
device_pin_num = irq_data->hwirq;
zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio);
writel_relaxed(BIT(bank_pin_num),
@@ -425,9 +428,12 @@ static void zynq_gpio_irq_mask(struct irq_data *irq_data)
static void zynq_gpio_irq_unmask(struct irq_data *irq_data)
{
unsigned int device_pin_num, bank_num, bank_pin_num;
+ const unsigned long offset = irqd_to_hwirq(irq_data);
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(irq_data);
struct zynq_gpio *gpio =
gpiochip_get_data(irq_data_get_irq_chip_data(irq_data));
+ gpiochip_enable_irq(chip, offset);
device_pin_num = irq_data->hwirq;
zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio);
writel_relaxed(BIT(bank_pin_num),
@@ -569,28 +575,8 @@ static int zynq_gpio_set_wake(struct irq_data *data, unsigned int on)
return 0;
}
-static int zynq_gpio_irq_reqres(struct irq_data *d)
-{
- struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
- int ret;
-
- ret = pm_runtime_resume_and_get(chip->parent);
- if (ret < 0)
- return ret;
-
- return gpiochip_reqres_irq(chip, d->hwirq);
-}
-
-static void zynq_gpio_irq_relres(struct irq_data *d)
-{
- struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
-
- gpiochip_relres_irq(chip, d->hwirq);
- pm_runtime_put(chip->parent);
-}
-
/* irq chip descriptor */
-static struct irq_chip zynq_gpio_level_irqchip = {
+static const struct irq_chip zynq_gpio_level_irqchip = {
.name = DRIVER_NAME,
.irq_enable = zynq_gpio_irq_enable,
.irq_eoi = zynq_gpio_irq_ack,
@@ -598,13 +584,12 @@ static struct irq_chip zynq_gpio_level_irqchip = {
.irq_unmask = zynq_gpio_irq_unmask,
.irq_set_type = zynq_gpio_set_irq_type,
.irq_set_wake = zynq_gpio_set_wake,
- .irq_request_resources = zynq_gpio_irq_reqres,
- .irq_release_resources = zynq_gpio_irq_relres,
.flags = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED |
- IRQCHIP_MASK_ON_SUSPEND,
+ IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
-static struct irq_chip zynq_gpio_edge_irqchip = {
+static const struct irq_chip zynq_gpio_edge_irqchip = {
.name = DRIVER_NAME,
.irq_enable = zynq_gpio_irq_enable,
.irq_ack = zynq_gpio_irq_ack,
@@ -612,9 +597,8 @@ static struct irq_chip zynq_gpio_edge_irqchip = {
.irq_unmask = zynq_gpio_irq_unmask,
.irq_set_type = zynq_gpio_set_irq_type,
.irq_set_wake = zynq_gpio_set_wake,
- .irq_request_resources = zynq_gpio_irq_reqres,
- .irq_release_resources = zynq_gpio_irq_relres,
- .flags = IRQCHIP_MASK_ON_SUSPEND,
+ .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
static void zynq_gpio_handle_bank_irq(struct zynq_gpio *gpio,
@@ -962,7 +946,7 @@ static int zynq_gpio_probe(struct platform_device *pdev)
/* Set up the GPIO irqchip */
girq = &chip->irq;
- girq->chip = &zynq_gpio_edge_irqchip;
+ gpio_irq_chip_set_chip(girq, &zynq_gpio_edge_irqchip);
girq->parent_handler = zynq_gpio_irqhandler;
girq->num_parents = 1;
girq->parents = devm_kcalloc(&pdev->dev, 1,
diff --git a/drivers/gpio/gpiolib-legacy.c b/drivers/gpio/gpiolib-legacy.c
index 30e2476a6dc4..97f4b498e343 100644
--- a/drivers/gpio/gpiolib-legacy.c
+++ b/drivers/gpio/gpiolib-legacy.c
@@ -33,12 +33,6 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
if (err)
return err;
- if (flags & GPIOF_OPEN_DRAIN)
- set_bit(FLAG_OPEN_DRAIN, &desc->flags);
-
- if (flags & GPIOF_OPEN_SOURCE)
- set_bit(FLAG_OPEN_SOURCE, &desc->flags);
-
if (flags & GPIOF_ACTIVE_LOW)
set_bit(FLAG_ACTIVE_LOW, &desc->flags);
@@ -51,12 +45,6 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
if (err)
goto free_gpio;
- if (flags & GPIOF_EXPORT) {
- err = gpiod_export(desc, flags & GPIOF_EXPORT_CHANGEABLE);
- if (err)
- goto free_gpio;
- }
-
return 0;
free_gpio:
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 5be8ad61523e..251c875b5c34 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -465,6 +465,12 @@ static unsigned long *gpiochip_allocate_mask(struct gpio_chip *gc)
return p;
}
+static void gpiochip_free_mask(unsigned long **p)
+{
+ bitmap_free(*p);
+ *p = NULL;
+}
+
static unsigned int gpiochip_count_reserved_ranges(struct gpio_chip *gc)
{
struct device *dev = &gc->gpiodev->dev;
@@ -478,18 +484,6 @@ static unsigned int gpiochip_count_reserved_ranges(struct gpio_chip *gc)
return 0;
}
-static int gpiochip_alloc_valid_mask(struct gpio_chip *gc)
-{
- if (!(gpiochip_count_reserved_ranges(gc) || gc->init_valid_mask))
- return 0;
-
- gc->valid_mask = gpiochip_allocate_mask(gc);
- if (!gc->valid_mask)
- return -ENOMEM;
-
- return 0;
-}
-
static int gpiochip_apply_reserved_ranges(struct gpio_chip *gc)
{
struct device *dev = &gc->gpiodev->dev;
@@ -530,6 +524,13 @@ static int gpiochip_init_valid_mask(struct gpio_chip *gc)
{
int ret;
+ if (!(gpiochip_count_reserved_ranges(gc) || gc->init_valid_mask))
+ return 0;
+
+ gc->valid_mask = gpiochip_allocate_mask(gc);
+ if (!gc->valid_mask)
+ return -ENOMEM;
+
ret = gpiochip_apply_reserved_ranges(gc);
if (ret)
return ret;
@@ -544,8 +545,7 @@ static int gpiochip_init_valid_mask(struct gpio_chip *gc)
static void gpiochip_free_valid_mask(struct gpio_chip *gc)
{
- bitmap_free(gc->valid_mask);
- gc->valid_mask = NULL;
+ gpiochip_free_mask(&gc->valid_mask);
}
static int gpiochip_add_pin_ranges(struct gpio_chip *gc)
@@ -857,7 +857,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
if (ret)
goto err_remove_from_list;
- ret = gpiochip_alloc_valid_mask(gc);
+ ret = gpiochip_init_valid_mask(gc);
if (ret)
goto err_remove_from_list;
@@ -865,10 +865,6 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
if (ret)
goto err_free_gpiochip_mask;
- ret = gpiochip_init_valid_mask(gc);
- if (ret)
- goto err_remove_of_chip;
-
for (i = 0; i < gc->ngpio; i++) {
struct gpio_desc *desc = &gdev->descs[i];
@@ -1089,8 +1085,7 @@ static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gc)
static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gc)
{
- bitmap_free(gc->irq.valid_mask);
- gc->irq.valid_mask = NULL;
+ gpiochip_free_mask(&gc->irq.valid_mask);
}
bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gc,
@@ -1676,11 +1671,10 @@ static int gpiochip_add_irqchip(struct gpio_chip *gc,
if (ret)
return ret;
} else {
- /* Some drivers provide custom irqdomain ops */
gc->irq.domain = irq_domain_create_simple(fwnode,
gc->ngpio,
gc->irq.first,
- gc->irq.domain_ops ?: &gpiochip_domain_ops,
+ &gpiochip_domain_ops,
gc);
if (!gc->irq.domain)
return -EINVAL;
@@ -2133,8 +2127,6 @@ static bool gpiod_free_commit(struct gpio_desc *desc)
might_sleep();
- gpiod_unexport(desc);
-
spin_lock_irqsave(&gpio_lock, flags);
gc = desc->gdev->chip;
@@ -4252,7 +4244,7 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,
/* Mark GPIO as hogged so it can be identified and removed later */
set_bit(FLAG_IS_HOGGED, &desc->flags);
- gpiod_info(desc, "hogged as %s%s\n",
+ gpiod_dbg(desc, "hogged as %s%s\n",
(dflags & GPIOD_FLAGS_BIT_DIR_OUT) ? "output" : "input",
(dflags & GPIOD_FLAGS_BIT_DIR_OUT) ?
(dflags & GPIOD_FLAGS_BIT_DIR_VAL) ? "/high" : "/low" : "");
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index bb1058b1e7fd..40eb27f1b23f 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -24,11 +24,8 @@
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/pm.h>
-#include <linux/of.h>
-#include <linux/of_gpio.h>
-#include <linux/of_device.h>
+#include <linux/property.h>
#include <linux/gpio/consumer.h>
-#include <linux/gpio.h>
#include <linux/spi/spi.h>
#include <linux/spi/ads7846.h>
#include <linux/regulator/consumer.h>
@@ -140,7 +137,7 @@ struct ads7846 {
int (*filter)(void *data, int data_idx, int *val);
void *filter_data;
int (*get_pendown_state)(void);
- int gpio_pendown;
+ struct gpio_desc *gpio_pendown;
void (*wait_for_sync)(void);
};
@@ -223,7 +220,7 @@ static int get_pendown_state(struct ads7846 *ts)
if (ts->get_pendown_state)
return ts->get_pendown_state();
- return !gpio_get_value(ts->gpio_pendown);
+ return gpiod_get_value(ts->gpio_pendown);
}
static void ads7846_report_pen_up(struct ads7846 *ts)
@@ -989,8 +986,6 @@ static int ads7846_setup_pendown(struct spi_device *spi,
struct ads7846 *ts,
const struct ads7846_platform_data *pdata)
{
- int err;
-
/*
* REVISIT when the irq can be triggered active-low, or if for some
* reason the touchscreen isn't hooked up, we don't need to access
@@ -999,25 +994,15 @@ static int ads7846_setup_pendown(struct spi_device *spi,
if (pdata->get_pendown_state) {
ts->get_pendown_state = pdata->get_pendown_state;
- } else if (gpio_is_valid(pdata->gpio_pendown)) {
-
- err = devm_gpio_request_one(&spi->dev, pdata->gpio_pendown,
- GPIOF_IN, "ads7846_pendown");
- if (err) {
- dev_err(&spi->dev,
- "failed to request/setup pendown GPIO%d: %d\n",
- pdata->gpio_pendown, err);
- return err;
+ } else {
+ ts->gpio_pendown = gpiod_get(&spi->dev, "pendown", GPIOD_IN);
+ if (IS_ERR(ts->gpio_pendown)) {
+ dev_err(&spi->dev, "failed to request pendown GPIO\n");
+ return PTR_ERR(ts->gpio_pendown);
}
-
- ts->gpio_pendown = pdata->gpio_pendown;
-
if (pdata->gpio_pendown_debounce)
- gpiod_set_debounce(gpio_to_desc(ts->gpio_pendown),
+ gpiod_set_debounce(ts->gpio_pendown,
pdata->gpio_pendown_debounce);
- } else {
- dev_err(&spi->dev, "no get_pendown_state nor gpio_pendown?\n");
- return -EINVAL;
}
return 0;
@@ -1119,7 +1104,6 @@ static int ads7846_setup_spi_msg(struct ads7846 *ts,
return 0;
}
-#ifdef CONFIG_OF
static const struct of_device_id ads7846_dt_ids[] = {
{ .compatible = "ti,tsc2046", .data = (void *) 7846 },
{ .compatible = "ti,ads7843", .data = (void *) 7843 },
@@ -1130,20 +1114,14 @@ static const struct of_device_id ads7846_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, ads7846_dt_ids);
-static const struct ads7846_platform_data *ads7846_probe_dt(struct device *dev)
+static const struct ads7846_platform_data *ads7846_get_props(struct device *dev)
{
struct ads7846_platform_data *pdata;
- struct device_node *node = dev->of_node;
- const struct of_device_id *match;
+ const struct platform_device_id *pdev_id;
u32 value;
- if (!node) {
- dev_err(dev, "Device does not have associated DT data\n");
- return ERR_PTR(-EINVAL);
- }
-
- match = of_match_device(ads7846_dt_ids, dev);
- if (!match) {
+ pdev_id = device_get_match_data(dev);
+ if (!pdev_id) {
dev_err(dev, "Unknown device model\n");
return ERR_PTR(-EINVAL);
}
@@ -1152,60 +1130,51 @@ static const struct ads7846_platform_data *ads7846_probe_dt(struct device *dev)
if (!pdata)
return ERR_PTR(-ENOMEM);
- pdata->model = (unsigned long)match->data;
+ pdata->model = (unsigned long)pdev_id->driver_data;
- of_property_read_u16(node, "ti,vref-delay-usecs",
- &pdata->vref_delay_usecs);
- of_property_read_u16(node, "ti,vref-mv", &pdata->vref_mv);
- pdata->keep_vref_on = of_property_read_bool(node, "ti,keep-vref-on");
+ device_property_read_u16(dev, "ti,vref-delay-usecs",
+ &pdata->vref_delay_usecs);
+ device_property_read_u16(dev, "ti,vref-mv", &pdata->vref_mv);
+ pdata->keep_vref_on = device_property_read_bool(dev, "ti,keep-vref-on");
- pdata->swap_xy = of_property_read_bool(node, "ti,swap-xy");
+ pdata->swap_xy = device_property_read_bool(dev, "ti,swap-xy");
- of_property_read_u16(node, "ti,settle-delay-usec",
- &pdata->settle_delay_usecs);
- of_property_read_u16(node, "ti,penirq-recheck-delay-usecs",
- &pdata->penirq_recheck_delay_usecs);
+ device_property_read_u16(dev, "ti,settle-delay-usec",
+ &pdata->settle_delay_usecs);
+ device_property_read_u16(dev, "ti,penirq-recheck-delay-usecs",
+ &pdata->penirq_recheck_delay_usecs);
- of_property_read_u16(node, "ti,x-plate-ohms", &pdata->x_plate_ohms);
- of_property_read_u16(node, "ti,y-plate-ohms", &pdata->y_plate_ohms);
+ device_property_read_u16(dev, "ti,x-plate-ohms", &pdata->x_plate_ohms);
+ device_property_read_u16(dev, "ti,y-plate-ohms", &pdata->y_plate_ohms);
- of_property_read_u16(node, "ti,x-min", &pdata->x_min);
- of_property_read_u16(node, "ti,y-min", &pdata->y_min);
- of_property_read_u16(node, "ti,x-max", &pdata->x_max);
- of_property_read_u16(node, "ti,y-max", &pdata->y_max);
+ device_property_read_u16(dev, "ti,x-min", &pdata->x_min);
+ device_property_read_u16(dev, "ti,y-min", &pdata->y_min);
+ device_property_read_u16(dev, "ti,x-max", &pdata->x_max);
+ device_property_read_u16(dev, "ti,y-max", &pdata->y_max);
/*
* touchscreen-max-pressure gets parsed during
* touchscreen_parse_properties()
*/
- of_property_read_u16(node, "ti,pressure-min", &pdata->pressure_min);
- if (!of_property_read_u32(node, "touchscreen-min-pressure", &value))
+ device_property_read_u16(dev, "ti,pressure-min", &pdata->pressure_min);
+ if (!device_property_read_u32(dev, "touchscreen-min-pressure", &value))
pdata->pressure_min = (u16) value;
- of_property_read_u16(node, "ti,pressure-max", &pdata->pressure_max);
+ device_property_read_u16(dev, "ti,pressure-max", &pdata->pressure_max);
- of_property_read_u16(node, "ti,debounce-max", &pdata->debounce_max);
- if (!of_property_read_u32(node, "touchscreen-average-samples", &value))
+ device_property_read_u16(dev, "ti,debounce-max", &pdata->debounce_max);
+ if (!device_property_read_u32(dev, "touchscreen-average-samples", &value))
pdata->debounce_max = (u16) value;
- of_property_read_u16(node, "ti,debounce-tol", &pdata->debounce_tol);
- of_property_read_u16(node, "ti,debounce-rep", &pdata->debounce_rep);
+ device_property_read_u16(dev, "ti,debounce-tol", &pdata->debounce_tol);
+ device_property_read_u16(dev, "ti,debounce-rep", &pdata->debounce_rep);
- of_property_read_u32(node, "ti,pendown-gpio-debounce",
+ device_property_read_u32(dev, "ti,pendown-gpio-debounce",
&pdata->gpio_pendown_debounce);
- pdata->wakeup = of_property_read_bool(node, "wakeup-source") ||
- of_property_read_bool(node, "linux,wakeup");
-
- pdata->gpio_pendown = of_get_named_gpio(dev->of_node, "pendown-gpio", 0);
+ pdata->wakeup = device_property_read_bool(dev, "wakeup-source") ||
+ device_property_read_bool(dev, "linux,wakeup");
return pdata;
}
-#else
-static const struct ads7846_platform_data *ads7846_probe_dt(struct device *dev)
-{
- dev_err(dev, "no platform data defined\n");
- return ERR_PTR(-EINVAL);
-}
-#endif
static void ads7846_regulator_disable(void *regulator)
{
@@ -1269,7 +1238,7 @@ static int ads7846_probe(struct spi_device *spi)
pdata = dev_get_platdata(dev);
if (!pdata) {
- pdata = ads7846_probe_dt(dev);
+ pdata = ads7846_get_props(dev);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
}
@@ -1426,7 +1395,7 @@ static struct spi_driver ads7846_driver = {
.driver = {
.name = "ads7846",
.pm = pm_sleep_ptr(&ads7846_pm),
- .of_match_table = of_match_ptr(ads7846_dt_ids),
+ .of_match_table = ads7846_dt_ids,
},
.probe = ads7846_probe,
.remove = ads7846_remove,
diff --git a/drivers/mfd/tps65010.c b/drivers/mfd/tps65010.c
index fb733288cca3..faea4ff44c6f 100644
--- a/drivers/mfd/tps65010.c
+++ b/drivers/mfd/tps65010.c
@@ -506,12 +506,8 @@ static void tps65010_remove(struct i2c_client *client)
struct tps65010 *tps = i2c_get_clientdata(client);
struct tps65010_board *board = dev_get_platdata(&client->dev);
- if (board && board->teardown) {
- int status = board->teardown(client, board->context);
- if (status < 0)
- dev_dbg(&client->dev, "board %s %s err %d\n",
- "teardown", client->name, status);
- }
+ if (board && board->teardown)
+ board->teardown(client, &tps->chip);
if (client->irq > 0)
free_irq(client->irq, tps);
cancel_delayed_work_sync(&tps->work);
@@ -619,7 +615,7 @@ static int tps65010_probe(struct i2c_client *client)
tps, DEBUG_FOPS);
/* optionally register GPIOs */
- if (board && board->base != 0) {
+ if (board) {
tps->outmask = board->outmask;
tps->chip.label = client->name;
@@ -632,7 +628,7 @@ static int tps65010_probe(struct i2c_client *client)
/* NOTE: only partial support for inputs; nyet IRQs */
tps->chip.get = tps65010_gpio_get;
- tps->chip.base = board->base;
+ tps->chip.base = -1;
tps->chip.ngpio = 7;
tps->chip.can_sleep = 1;
@@ -641,7 +637,7 @@ static int tps65010_probe(struct i2c_client *client)
dev_err(&client->dev, "can't add gpiochip, err %d\n",
status);
else if (board->setup) {
- status = board->setup(client, board->context);
+ status = board->setup(client, &tps->chip);
if (status < 0) {
dev_dbg(&client->dev,
"board %s %s err %d\n",
diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c
index 86454f1182bb..6a259563690d 100644
--- a/drivers/mmc/host/omap.c
+++ b/drivers/mmc/host/omap.c
@@ -26,6 +26,7 @@
#include <linux/clk.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
+#include <linux/gpio/consumer.h>
#include <linux/platform_data/mmc-omap.h>
@@ -111,6 +112,9 @@ struct mmc_omap_slot {
struct mmc_request *mrq;
struct mmc_omap_host *host;
struct mmc_host *mmc;
+ struct gpio_desc *vsd;
+ struct gpio_desc *vio;
+ struct gpio_desc *cover;
struct omap_mmc_slot_data *pdata;
};
@@ -133,6 +137,7 @@ struct mmc_omap_host {
int irq;
unsigned char bus_mode;
unsigned int reg_shift;
+ struct gpio_desc *slot_switch;
struct work_struct cmd_abort_work;
unsigned abort:1;
@@ -216,8 +221,13 @@ no_claim:
if (host->current_slot != slot) {
OMAP_MMC_WRITE(host, CON, slot->saved_con & 0xFC00);
- if (host->pdata->switch_slot != NULL)
- host->pdata->switch_slot(mmc_dev(slot->mmc), slot->id);
+ if (host->slot_switch)
+ /*
+ * With two slots and a simple GPIO switch, setting
+ * the GPIO to 0 selects slot ID 0, setting it to 1
+ * selects slot ID 1.
+ */
+ gpiod_set_value(host->slot_switch, slot->id);
host->current_slot = slot;
}
@@ -297,6 +307,9 @@ static void mmc_omap_release_slot(struct mmc_omap_slot *slot, int clk_enabled)
static inline
int mmc_omap_cover_is_open(struct mmc_omap_slot *slot)
{
+ /* If we have a GPIO then use that */
+ if (slot->cover)
+ return gpiod_get_value(slot->cover);
if (slot->pdata->get_cover_state)
return slot->pdata->get_cover_state(mmc_dev(slot->mmc),
slot->id);
@@ -1106,6 +1119,11 @@ static void mmc_omap_set_power(struct mmc_omap_slot *slot, int power_on,
host = slot->host;
+ if (slot->vsd)
+ gpiod_set_value(slot->vsd, power_on);
+ if (slot->vio)
+ gpiod_set_value(slot->vio, power_on);
+
if (slot->pdata->set_power != NULL)
slot->pdata->set_power(mmc_dev(slot->mmc), slot->id, power_on,
vdd);
@@ -1240,6 +1258,23 @@ static int mmc_omap_new_slot(struct mmc_omap_host *host, int id)
slot->power_mode = MMC_POWER_UNDEFINED;
slot->pdata = &host->pdata->slots[id];
+ /* Check for some optional GPIO controls */
+ slot->vsd = gpiod_get_index_optional(host->dev, "vsd",
+ id, GPIOD_OUT_LOW);
+ if (IS_ERR(slot->vsd))
+ return dev_err_probe(host->dev, PTR_ERR(slot->vsd),
+ "error looking up VSD GPIO\n");
+ slot->vio = gpiod_get_index_optional(host->dev, "vio",
+ id, GPIOD_OUT_LOW);
+ if (IS_ERR(slot->vio))
+ return dev_err_probe(host->dev, PTR_ERR(slot->vio),
+ "error looking up VIO GPIO\n");
+ slot->cover = gpiod_get_index_optional(host->dev, "cover",
+ id, GPIOD_IN);
+ if (IS_ERR(slot->cover))
+ return dev_err_probe(host->dev, PTR_ERR(slot->cover),
+ "error looking up cover switch GPIO\n");
+
host->slots[id] = slot;
mmc->caps = 0;
@@ -1349,6 +1384,13 @@ static int mmc_omap_probe(struct platform_device *pdev)
if (IS_ERR(host->virt_base))
return PTR_ERR(host->virt_base);
+ host->slot_switch = gpiod_get_optional(host->dev, "switch",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(host->slot_switch))
+ return dev_err_probe(host->dev, PTR_ERR(host->slot_switch),
+ "error looking up slot switch GPIO\n");
+
+
INIT_WORK(&host->slot_release_work, mmc_omap_slot_release_work);
INIT_WORK(&host->send_stop_work, mmc_omap_send_stop_work);
diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
index 2191c0136531..5386efeaf710 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -1844,26 +1844,10 @@ static void __init of_unittest_overlay_gpio(void)
unittest(overlay_data_apply("overlay_gpio_02b", NULL),
"Adding overlay 'overlay_gpio_02b' failed\n");
- /*
- * messages are the result of the probes, after the
- * driver is registered
- */
-
- EXPECT_BEGIN(KERN_INFO,
- "gpio-<<int>> (line-B-input): hogged as input\n");
-
- EXPECT_BEGIN(KERN_INFO,
- "gpio-<<int>> (line-A-input): hogged as input\n");
-
ret = platform_driver_register(&unittest_gpio_driver);
if (unittest(ret == 0, "could not register unittest gpio driver\n"))
return;
- EXPECT_END(KERN_INFO,
- "gpio-<<int>> (line-A-input): hogged as input\n");
- EXPECT_END(KERN_INFO,
- "gpio-<<int>> (line-B-input): hogged as input\n");
-
unittest(probe_pass_count + 2 == unittest_gpio_probe_pass_count,
"unittest_gpio_probe() failed or not called\n");
@@ -1888,17 +1872,11 @@ static void __init of_unittest_overlay_gpio(void)
probe_pass_count = unittest_gpio_probe_pass_count;
chip_request_count = unittest_gpio_chip_request_count;
- EXPECT_BEGIN(KERN_INFO,
- "gpio-<<int>> (line-D-input): hogged as input\n");
-
/* overlay_gpio_03 contains gpio node and child gpio hog node */
unittest(overlay_data_apply("overlay_gpio_03", NULL),
"Adding overlay 'overlay_gpio_03' failed\n");
- EXPECT_END(KERN_INFO,
- "gpio-<<int>> (line-D-input): hogged as input\n");
-
unittest(probe_pass_count + 1 == unittest_gpio_probe_pass_count,
"unittest_gpio_probe() failed or not called\n");
@@ -1935,17 +1913,11 @@ static void __init of_unittest_overlay_gpio(void)
* - processing gpio for overlay_gpio_04b
*/
- EXPECT_BEGIN(KERN_INFO,
- "gpio-<<int>> (line-C-input): hogged as input\n");
-
/* overlay_gpio_04b contains child gpio hog node */
unittest(overlay_data_apply("overlay_gpio_04b", NULL),
"Adding overlay 'overlay_gpio_04b' failed\n");
- EXPECT_END(KERN_INFO,
- "gpio-<<int>> (line-C-input): hogged as input\n");
-
unittest(chip_request_count + 1 == unittest_gpio_chip_request_count,
"unittest_gpio_chip_request() called %d times (expected 1 time)\n",
unittest_gpio_chip_request_count - chip_request_count);
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index d162afbbe19f..ecbd3784bec3 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -2330,7 +2330,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
spin_lock_init(&musb->lock);
spin_lock_init(&musb->list_lock);
- musb->board_set_power = plat->set_power;
musb->min_power = plat->min_power;
musb->ops = plat->platform_ops;
musb->port_mode = plat->mode;
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index b7588d11cfc5..91b5b6b66f96 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -352,8 +352,6 @@ struct musb {
u16 epmask;
u8 nr_endpoints;
- int (*board_set_power)(int state);
-
u8 min_power; /* vbus for periph, in mA/2 */
enum musb_mode port_mode;
diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
index a1f29dbc62e6..cbc707fe570f 100644
--- a/drivers/usb/musb/tusb6010.c
+++ b/drivers/usb/musb/tusb6010.c
@@ -11,6 +11,8 @@
* interface.
*/
+#include <linux/gpio/consumer.h>
+#include <linux/delay.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
@@ -30,6 +32,8 @@ struct tusb6010_glue {
struct device *dev;
struct platform_device *musb;
struct platform_device *phy;
+ struct gpio_desc *enable;
+ struct gpio_desc *intpin;
};
static void tusb_musb_set_vbus(struct musb *musb, int is_on);
@@ -1021,16 +1025,29 @@ static void tusb_setup_cpu_interface(struct musb *musb)
static int tusb_musb_start(struct musb *musb)
{
+ struct tusb6010_glue *glue = dev_get_drvdata(musb->controller->parent);
void __iomem *tbase = musb->ctrl_base;
- int ret = 0;
unsigned long flags;
u32 reg;
+ int i;
- if (musb->board_set_power)
- ret = musb->board_set_power(1);
- if (ret != 0) {
- printk(KERN_ERR "tusb: Cannot enable TUSB6010\n");
- return ret;
+ /*
+ * Enable or disable power to TUSB6010. When enabling, turn on 3.3 V and
+ * 1.5 V voltage regulators of PM companion chip. Companion chip will then
+ * provide then PGOOD signal to TUSB6010 which will release it from reset.
+ */
+ gpiod_set_value(glue->enable, 1);
+ msleep(1);
+
+ /* Wait for 100ms until TUSB6010 pulls INT pin down */
+ i = 100;
+ while (i && gpiod_get_value(glue->intpin)) {
+ msleep(1);
+ i--;
+ }
+ if (!i) {
+ pr_err("tusb: Powerup respones failed\n");
+ return -ENODEV;
}
spin_lock_irqsave(&musb->lock, flags);
@@ -1083,8 +1100,8 @@ static int tusb_musb_start(struct musb *musb)
err:
spin_unlock_irqrestore(&musb->lock, flags);
- if (musb->board_set_power)
- musb->board_set_power(0);
+ gpiod_set_value(glue->enable, 0);
+ msleep(10);
return -ENODEV;
}
@@ -1158,11 +1175,13 @@ done:
static int tusb_musb_exit(struct musb *musb)
{
+ struct tusb6010_glue *glue = dev_get_drvdata(musb->controller->parent);
+
del_timer_sync(&musb->dev_timer);
the_musb = NULL;
- if (musb->board_set_power)
- musb->board_set_power(0);
+ gpiod_set_value(glue->enable, 0);
+ msleep(10);
iounmap(musb->sync_va);
@@ -1218,6 +1237,15 @@ static int tusb_probe(struct platform_device *pdev)
glue->dev = &pdev->dev;
+ glue->enable = devm_gpiod_get(glue->dev, "enable", GPIOD_OUT_LOW);
+ if (IS_ERR(glue->enable))
+ return dev_err_probe(glue->dev, PTR_ERR(glue->enable),
+ "could not obtain power on/off GPIO\n");
+ glue->intpin = devm_gpiod_get(glue->dev, "int", GPIOD_IN);
+ if (IS_ERR(glue->intpin))
+ return dev_err_probe(glue->dev, PTR_ERR(glue->intpin),
+ "could not obtain INT GPIO\n");
+
pdata->platform_ops = &tusb_ops;
usb_phy_generic_register();
@@ -1236,10 +1264,7 @@ static int tusb_probe(struct platform_device *pdev)
musb_resources[1].end = pdev->resource[1].end;
musb_resources[1].flags = pdev->resource[1].flags;
- musb_resources[2].name = pdev->resource[2].name;
- musb_resources[2].start = pdev->resource[2].start;
- musb_resources[2].end = pdev->resource[2].end;
- musb_resources[2].flags = pdev->resource[2].flags;
+ musb_resources[2] = DEFINE_RES_IRQ_NAMED(gpiod_to_irq(glue->intpin), "mc");
pinfo = tusb_dev_info;
pinfo.parent = &pdev->dev;
diff --git a/drivers/video/fbdev/omap/lcd_mipid.c b/drivers/video/fbdev/omap/lcd_mipid.c
index 03cff39d392d..e4a7f0b824ff 100644
--- a/drivers/video/fbdev/omap/lcd_mipid.c
+++ b/drivers/video/fbdev/omap/lcd_mipid.c
@@ -7,6 +7,7 @@
*/
#include <linux/device.h>
#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/spi/spi.h>
@@ -41,6 +42,7 @@ struct mipid_device {
when we can issue the
next sleep in/out command */
unsigned long hw_guard_wait; /* max guard time in jiffies */
+ struct gpio_desc *reset;
struct omapfb_device *fbdev;
struct spi_device *spi;
@@ -556,6 +558,12 @@ static int mipid_spi_probe(struct spi_device *spi)
return -ENOMEM;
}
+ /* This will de-assert RESET if active */
+ md->reset = gpiod_get(&spi->dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(md->reset))
+ return dev_err_probe(&spi->dev, PTR_ERR(md->reset),
+ "no reset GPIO line\n");
+
spi->mode = SPI_MODE_0;
md->spi = spi;
dev_set_drvdata(&spi->dev, md);
@@ -574,6 +582,8 @@ static void mipid_spi_remove(struct spi_device *spi)
{
struct mipid_device *md = dev_get_drvdata(&spi->dev);
+ /* Asserts RESET */
+ gpiod_set_value(md->reset, 1);
mipid_disable(&md->panel);
kfree(md);
}