mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-25 05:04:09 +08:00
Changes queued in gpio/next for the start of the 3.3 merge window
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJPBSJSAAoJEEFnBt12D9kBDmIP/R6PWxg+NrJaGDmxRWBBkOch iI4Et7GT3Sk5hYqPz0kehiSz1F4bqpYK3JmdfqotJIhQCM2znXM+BaDLzgFnMsRf g4t70PIZQMpk3pj4gtIkMpZCkRdA9VFriIf1cEdHcLiRdNVsXlTE6CcQT4fbE1P/ JTAGBrVDwbchuoPsf7Mbu8SYT+cQdWLKpgzC4fAzI++QoYyYBtfvuCHTE4VvasNS jMDOfT+u0Gwp6LW34v0gKk7MXEQzeq07r1VZxMyuaWbRQoiLr5d1fy97+Fh5+4dU Rb9C6zGIoBzRdiJLlfNYrls/FueDHwPyIwXuapMp5QbaGN5fkhVpIVIhYICOLdHW IXH2V3saK1s6QbD7nErNT2lCWZQSCUKq/PR9W40dj3PYAI0oxbRBSoPdfGuW1Bl7 fYqClUza1Bln8bEmmsvAOnIDdfs6zpkWmfouwx4AGaHTfzIAg4VRdoxdUpS8h+/d sNEYi99IuYfl3KWCwQbWJMgCOvoBdOGZSCsTrXnjLf1HJCsQOt/Md69Ff6DLn1VR gDp0EeqgDH5oXJmQTW1WjXaJJair2j8pY8mlmGxl1AqA4aY8C3dxIfHxlBPzdxii I6KTPaIUSXZaOo6e7XDjjjTzabL4q0aQGT5ahpKj928Rnx00QZNXoTy4FmYkL+0k j7QZfM/p6+vfxekKUR17 =9ugo -----END PGP SIGNATURE----- Merge tag 'gpio-for-linus' of git://git.secretlab.ca/git/linux-2.6 Changes queued in gpio/next for the start of the 3.3 merge window * tag 'gpio-for-linus-20120104' of git://git.secretlab.ca/git/linux-2.6: gpio: Add decode of WM8994 GPIO configuration gpio: Convert GPIO drivers to module_platform_driver gpio: Fix typo in comment in Samsung driver gpio: Explicitly index samsung_gpio_cfgs gpio: Add Linus Walleij as gpio co-maintainer of: Add device tree selftests of: create of_phandle_args to simplify return of phandle parsing data gpio/powerpc: Eliminate duplication of of_get_named_gpio_flags() gpio/microblaze: Eliminate duplication of of_get_named_gpio_flags() gpiolib: output basic details and consolidate gpio device drivers pch_gpio: Change company name OKI SEMICONDUCTOR to LAPIS Semiconductor pch_gpio: Support new device LAPIS Semiconductor ML7831 IOH spi/pl022: make the chip deselect handling thread safe spi/pl022: add support for pm_runtime autosuspend spi/pl022: disable the PL022 block when unused spi/pl022: move device disable to workqueue thread spi/pl022: skip default configuration before suspending spi/pl022: fix build warnings spi/pl022: only enable RX interrupts when TX is complete
This commit is contained in:
commit
fbce1c234f
@ -2912,6 +2912,7 @@ F: include/linux/gigaset_dev.h
|
||||
|
||||
GPIO SUBSYSTEM
|
||||
M: Grant Likely <grant.likely@secretlab.ca>
|
||||
M: Linus Walleij <linus.walleij@stericsson.com>
|
||||
S: Maintained
|
||||
T: git git://git.secretlab.ca/git/linux-2.6.git
|
||||
F: Documentation/gpio.txt
|
||||
|
37
arch/arm/boot/dts/testcases/tests-phandle.dtsi
Normal file
37
arch/arm/boot/dts/testcases/tests-phandle.dtsi
Normal file
@ -0,0 +1,37 @@
|
||||
|
||||
/ {
|
||||
testcase-data {
|
||||
phandle-tests {
|
||||
provider0: provider0 {
|
||||
#phandle-cells = <0>;
|
||||
};
|
||||
|
||||
provider1: provider1 {
|
||||
#phandle-cells = <1>;
|
||||
};
|
||||
|
||||
provider2: provider2 {
|
||||
#phandle-cells = <2>;
|
||||
};
|
||||
|
||||
provider3: provider3 {
|
||||
#phandle-cells = <3>;
|
||||
};
|
||||
|
||||
consumer-a {
|
||||
phandle-list = <&provider1 1>,
|
||||
<&provider2 2 0>,
|
||||
<0>,
|
||||
<&provider3 4 4 3>,
|
||||
<&provider2 5 100>,
|
||||
<&provider0>,
|
||||
<&provider1 7>;
|
||||
phandle-list-names = "first", "second", "third";
|
||||
|
||||
phandle-list-bad-phandle = <12345678 0 0>;
|
||||
phandle-list-bad-args = <&provider2 1 0>,
|
||||
<&provider3 0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
1
arch/arm/boot/dts/testcases/tests.dtsi
Normal file
1
arch/arm/boot/dts/testcases/tests.dtsi
Normal file
@ -0,0 +1 @@
|
||||
/include/ "tests-phandle.dtsi"
|
@ -46,3 +46,5 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/include/ "testcases/tests.dtsi"
|
||||
|
@ -19,50 +19,11 @@
|
||||
static int handle; /* reset pin handle */
|
||||
static unsigned int reset_val;
|
||||
|
||||
static int of_reset_gpio_handle(void)
|
||||
{
|
||||
int ret; /* variable which stored handle reset gpio pin */
|
||||
struct device_node *root; /* root node */
|
||||
struct device_node *gpio; /* gpio node */
|
||||
struct gpio_chip *gc;
|
||||
u32 flags;
|
||||
const void *gpio_spec;
|
||||
|
||||
/* find out root node */
|
||||
root = of_find_node_by_path("/");
|
||||
|
||||
/* give me handle for gpio node to be possible allocate pin */
|
||||
ret = of_parse_phandles_with_args(root, "hard-reset-gpios",
|
||||
"#gpio-cells", 0, &gpio, &gpio_spec);
|
||||
if (ret) {
|
||||
pr_debug("%s: can't parse gpios property\n", __func__);
|
||||
goto err0;
|
||||
}
|
||||
|
||||
gc = of_node_to_gpiochip(gpio);
|
||||
if (!gc) {
|
||||
pr_debug("%s: gpio controller %s isn't registered\n",
|
||||
root->full_name, gpio->full_name);
|
||||
ret = -ENODEV;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
ret = gc->of_xlate(gc, root, gpio_spec, &flags);
|
||||
if (ret < 0)
|
||||
goto err1;
|
||||
|
||||
ret += gc->base;
|
||||
err1:
|
||||
of_node_put(gpio);
|
||||
err0:
|
||||
pr_debug("%s exited with status %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void of_platform_reset_gpio_probe(void)
|
||||
{
|
||||
int ret;
|
||||
handle = of_reset_gpio_handle();
|
||||
handle = of_get_named_gpio(of_find_node_by_path("/"),
|
||||
"hard-reset-gpios", 0);
|
||||
|
||||
if (!gpio_is_valid(handle)) {
|
||||
printk(KERN_INFO "Skipping unavailable RESET gpio %d (%s)\n",
|
||||
|
@ -139,14 +139,10 @@ struct qe_pin {
|
||||
struct qe_pin *qe_pin_request(struct device_node *np, int index)
|
||||
{
|
||||
struct qe_pin *qe_pin;
|
||||
struct device_node *gpio_np;
|
||||
struct gpio_chip *gc;
|
||||
struct of_mm_gpio_chip *mm_gc;
|
||||
struct qe_gpio_chip *qe_gc;
|
||||
int err;
|
||||
int size;
|
||||
const void *gpio_spec;
|
||||
const u32 *gpio_cells;
|
||||
unsigned long flags;
|
||||
|
||||
qe_pin = kzalloc(sizeof(*qe_pin), GFP_KERNEL);
|
||||
@ -155,45 +151,25 @@ struct qe_pin *qe_pin_request(struct device_node *np, int index)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
err = of_parse_phandles_with_args(np, "gpios", "#gpio-cells", index,
|
||||
&gpio_np, &gpio_spec);
|
||||
if (err) {
|
||||
pr_debug("%s: can't parse gpios property\n", __func__);
|
||||
err = of_get_gpio(np, index);
|
||||
if (err < 0)
|
||||
goto err0;
|
||||
gc = gpio_to_chip(err);
|
||||
if (WARN_ON(!gc))
|
||||
goto err0;
|
||||
}
|
||||
|
||||
if (!of_device_is_compatible(gpio_np, "fsl,mpc8323-qe-pario-bank")) {
|
||||
if (!of_device_is_compatible(gc->of_node, "fsl,mpc8323-qe-pario-bank")) {
|
||||
pr_debug("%s: tried to get a non-qe pin\n", __func__);
|
||||
err = -EINVAL;
|
||||
goto err1;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
gc = of_node_to_gpiochip(gpio_np);
|
||||
if (!gc) {
|
||||
pr_debug("%s: gpio controller %s isn't registered\n",
|
||||
np->full_name, gpio_np->full_name);
|
||||
err = -ENODEV;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
gpio_cells = of_get_property(gpio_np, "#gpio-cells", &size);
|
||||
if (!gpio_cells || size != sizeof(*gpio_cells) ||
|
||||
*gpio_cells != gc->of_gpio_n_cells) {
|
||||
pr_debug("%s: wrong #gpio-cells for %s\n",
|
||||
np->full_name, gpio_np->full_name);
|
||||
err = -EINVAL;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
err = gc->of_xlate(gc, np, gpio_spec, NULL);
|
||||
if (err < 0)
|
||||
goto err1;
|
||||
|
||||
mm_gc = to_of_mm_gpio_chip(gc);
|
||||
qe_gc = to_qe_gpio_chip(mm_gc);
|
||||
|
||||
spin_lock_irqsave(&qe_gc->lock, flags);
|
||||
|
||||
err -= gc->base;
|
||||
if (test_and_set_bit(QE_PIN_REQUESTED, &qe_gc->pin_flags[err]) == 0) {
|
||||
qe_pin->controller = qe_gc;
|
||||
qe_pin->num = err;
|
||||
@ -206,8 +182,6 @@ struct qe_pin *qe_pin_request(struct device_node *np, int index)
|
||||
|
||||
if (!err)
|
||||
return qe_pin;
|
||||
err1:
|
||||
of_node_put(gpio_np);
|
||||
err0:
|
||||
kfree(qe_pin);
|
||||
pr_debug("%s failed with status %d\n", __func__, err);
|
||||
|
@ -387,7 +387,7 @@ config GPIO_LANGWELL
|
||||
Say Y here to support Intel Langwell/Penwell GPIO.
|
||||
|
||||
config GPIO_PCH
|
||||
tristate "Intel EG20T PCH / OKI SEMICONDUCTOR ML7223 IOH GPIO"
|
||||
tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7223/ML7831) GPIO"
|
||||
depends on PCI && X86
|
||||
select GENERIC_IRQ_CHIP
|
||||
help
|
||||
@ -395,11 +395,12 @@ config GPIO_PCH
|
||||
which is an IOH(Input/Output Hub) for x86 embedded processor.
|
||||
This driver can access PCH GPIO device.
|
||||
|
||||
This driver also can be used for OKI SEMICONDUCTOR IOH(Input/
|
||||
Output Hub), ML7223.
|
||||
This driver also can be used for LAPIS Semiconductor IOH(Input/
|
||||
Output Hub), ML7223 and ML7831.
|
||||
ML7223 IOH is for MP(Media Phone) use.
|
||||
ML7223 is companion chip for Intel Atom E6xx series.
|
||||
ML7223 is completely compatible for Intel EG20T PCH.
|
||||
ML7831 IOH is for general purpose use.
|
||||
ML7223/ML7831 is companion chip for Intel Atom E6xx series.
|
||||
ML7223/ML7831 is completely compatible for Intel EG20T PCH.
|
||||
|
||||
config GPIO_ML_IOH
|
||||
tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support"
|
||||
|
@ -193,17 +193,7 @@ static struct platform_driver adp5520_gpio_driver = {
|
||||
.remove = __devexit_p(adp5520_gpio_remove),
|
||||
};
|
||||
|
||||
static int __init adp5520_gpio_init(void)
|
||||
{
|
||||
return platform_driver_register(&adp5520_gpio_driver);
|
||||
}
|
||||
module_init(adp5520_gpio_init);
|
||||
|
||||
static void __exit adp5520_gpio_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&adp5520_gpio_driver);
|
||||
}
|
||||
module_exit(adp5520_gpio_exit);
|
||||
module_platform_driver(adp5520_gpio_driver);
|
||||
|
||||
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
|
||||
MODULE_DESCRIPTION("GPIO ADP5520 Driver");
|
||||
|
@ -418,9 +418,8 @@ static int __devinit adp5588_gpio_probe(struct i2c_client *client,
|
||||
if (ret)
|
||||
goto err_irq;
|
||||
|
||||
dev_info(&client->dev, "gpios %d..%d (IRQ Base %d) on a %s Rev. %d\n",
|
||||
gc->base, gc->base + gc->ngpio - 1,
|
||||
pdata->irq_base, client->name, revid);
|
||||
dev_info(&client->dev, "IRQ Base: %d Rev.: %d\n",
|
||||
pdata->irq_base, revid);
|
||||
|
||||
if (pdata->setup) {
|
||||
ret = pdata->setup(client, gc->base, gc->ngpio, pdata->context);
|
||||
|
@ -223,9 +223,6 @@ static int bt8xxgpio_probe(struct pci_dev *dev,
|
||||
goto err_release_mem;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "bt8xxgpio: Abusing BT8xx card for GPIOs %d to %d\n",
|
||||
bg->gpio.base, bg->gpio.base + BT8XXGPIO_NR_GPIOS - 1);
|
||||
|
||||
return 0;
|
||||
|
||||
err_release_mem:
|
||||
|
@ -347,7 +347,6 @@ static int __devinit cs5535_gpio_probe(struct platform_device *pdev)
|
||||
if (err)
|
||||
goto release_region;
|
||||
|
||||
dev_info(&pdev->dev, "GPIO support successfully loaded.\n");
|
||||
return 0;
|
||||
|
||||
release_region:
|
||||
@ -382,18 +381,7 @@ static struct platform_driver cs5535_gpio_driver = {
|
||||
.remove = __devexit_p(cs5535_gpio_remove),
|
||||
};
|
||||
|
||||
static int __init cs5535_gpio_init(void)
|
||||
{
|
||||
return platform_driver_register(&cs5535_gpio_driver);
|
||||
}
|
||||
|
||||
static void __exit cs5535_gpio_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&cs5535_gpio_driver);
|
||||
}
|
||||
|
||||
module_init(cs5535_gpio_init);
|
||||
module_exit(cs5535_gpio_exit);
|
||||
module_platform_driver(cs5535_gpio_driver);
|
||||
|
||||
MODULE_AUTHOR("Andres Salomon <dilinger@queued.net>");
|
||||
MODULE_DESCRIPTION("AMD CS5535/CS5536 GPIO driver");
|
||||
|
@ -254,17 +254,7 @@ static struct platform_driver da9052_gpio_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
static int __init da9052_gpio_init(void)
|
||||
{
|
||||
return platform_driver_register(&da9052_gpio_driver);
|
||||
}
|
||||
module_init(da9052_gpio_init);
|
||||
|
||||
static void __exit da9052_gpio_exit(void)
|
||||
{
|
||||
return platform_driver_unregister(&da9052_gpio_driver);
|
||||
}
|
||||
module_exit(da9052_gpio_exit);
|
||||
module_platform_driver(da9052_gpio_driver);
|
||||
|
||||
MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
|
||||
MODULE_DESCRIPTION("DA9052 GPIO Device Driver");
|
||||
|
@ -524,17 +524,7 @@ static struct platform_driver bgpio_driver = {
|
||||
.remove = __devexit_p(bgpio_pdev_remove),
|
||||
};
|
||||
|
||||
static int __init bgpio_platform_init(void)
|
||||
{
|
||||
return platform_driver_register(&bgpio_driver);
|
||||
}
|
||||
module_init(bgpio_platform_init);
|
||||
|
||||
static void __exit bgpio_platform_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&bgpio_driver);
|
||||
}
|
||||
module_exit(bgpio_platform_exit);
|
||||
module_platform_driver(bgpio_driver);
|
||||
|
||||
#endif /* CONFIG_GPIO_GENERIC_PLATFORM */
|
||||
|
||||
|
@ -201,8 +201,6 @@ static int __devinit ttl_probe(struct platform_device *pdev)
|
||||
goto out_iounmap_regs;
|
||||
}
|
||||
|
||||
dev_info(&pdev->dev, "module %d: registered GPIO device\n",
|
||||
pdata->modno);
|
||||
return 0;
|
||||
|
||||
out_iounmap_regs:
|
||||
@ -239,20 +237,9 @@ static struct platform_driver ttl_driver = {
|
||||
.remove = __devexit_p(ttl_remove),
|
||||
};
|
||||
|
||||
static int __init ttl_init(void)
|
||||
{
|
||||
return platform_driver_register(&ttl_driver);
|
||||
}
|
||||
|
||||
static void __exit ttl_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&ttl_driver);
|
||||
}
|
||||
module_platform_driver(ttl_driver);
|
||||
|
||||
MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>");
|
||||
MODULE_DESCRIPTION("Janz MODULbus VMOD-TTL Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:janz-ttl");
|
||||
|
||||
module_init(ttl_init);
|
||||
module_exit(ttl_exit);
|
||||
|
@ -1150,8 +1150,8 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev)
|
||||
|
||||
nmk_gpio_init_irq(nmk_chip);
|
||||
|
||||
dev_info(&dev->dev, "Bits %i-%i at address %p\n",
|
||||
nmk_chip->chip.base, nmk_chip->chip.base+31, nmk_chip->addr);
|
||||
dev_info(&dev->dev, "at address %p\n",
|
||||
nmk_chip->addr);
|
||||
return 0;
|
||||
|
||||
out_free:
|
||||
|
@ -290,10 +290,7 @@ static int pcf857x_probe(struct i2c_client *client,
|
||||
* methods can't be called from sleeping contexts.
|
||||
*/
|
||||
|
||||
dev_info(&client->dev, "gpios %d..%d on a %s%s\n",
|
||||
gpio->chip.base,
|
||||
gpio->chip.base + gpio->chip.ngpio - 1,
|
||||
client->name,
|
||||
dev_info(&client->dev, "%s\n",
|
||||
client->irq ? " (irq ignored)" : "");
|
||||
|
||||
/* Let platform code set up the GPIOs and their users.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
|
||||
* Copyright (C) 2011 LAPIS Semiconductor Co., Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -49,8 +49,8 @@ struct pch_regs {
|
||||
|
||||
enum pch_type_t {
|
||||
INTEL_EG20T_PCH,
|
||||
OKISEMI_ML7223m_IOH, /* OKISEMI ML7223 IOH PCIe Bus-m */
|
||||
OKISEMI_ML7223n_IOH /* OKISEMI ML7223 IOH PCIe Bus-n */
|
||||
OKISEMI_ML7223m_IOH, /* LAPIS Semiconductor ML7223 IOH PCIe Bus-m */
|
||||
OKISEMI_ML7223n_IOH /* LAPIS Semiconductor ML7223 IOH PCIe Bus-n */
|
||||
};
|
||||
|
||||
/* Specifies number of GPIO PINS */
|
||||
@ -524,6 +524,7 @@ static DEFINE_PCI_DEVICE_TABLE(pch_gpio_pcidev_id) = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8803) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8014) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8043) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8803) },
|
||||
{ 0, }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, pch_gpio_pcidev_id);
|
||||
|
@ -227,18 +227,7 @@ static struct platform_driver rdc321x_gpio_driver = {
|
||||
.remove = __devexit_p(rdc321x_gpio_remove),
|
||||
};
|
||||
|
||||
static int __init rdc321x_gpio_init(void)
|
||||
{
|
||||
return platform_driver_register(&rdc321x_gpio_driver);
|
||||
}
|
||||
|
||||
static void __exit rdc321x_gpio_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&rdc321x_gpio_driver);
|
||||
}
|
||||
|
||||
module_init(rdc321x_gpio_init);
|
||||
module_exit(rdc321x_gpio_exit);
|
||||
module_platform_driver(rdc321x_gpio_driver);
|
||||
|
||||
MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
|
||||
MODULE_DESCRIPTION("RDC321x GPIO driver");
|
||||
|
@ -230,7 +230,7 @@ static int samsung_gpio_setcfg_2bit(struct samsung_gpio_chip *chip,
|
||||
* @chip: The gpio chip that is being configured.
|
||||
* @off: The offset for the GPIO being configured.
|
||||
*
|
||||
* The reverse of samsung_gpio_setcfg_2bit(). Will return a value whicg
|
||||
* The reverse of samsung_gpio_setcfg_2bit(). Will return a value which
|
||||
* could be directly passed back to samsung_gpio_setcfg_2bit(), from the
|
||||
* S3C_GPIO_SPECIAL() macro.
|
||||
*/
|
||||
@ -467,33 +467,42 @@ static struct samsung_gpio_cfg s5p64x0_gpio_cfg_rbank = {
|
||||
#endif
|
||||
|
||||
static struct samsung_gpio_cfg samsung_gpio_cfgs[] = {
|
||||
{
|
||||
[0] = {
|
||||
.cfg_eint = 0x0,
|
||||
}, {
|
||||
},
|
||||
[1] = {
|
||||
.cfg_eint = 0x3,
|
||||
}, {
|
||||
},
|
||||
[2] = {
|
||||
.cfg_eint = 0x7,
|
||||
}, {
|
||||
},
|
||||
[3] = {
|
||||
.cfg_eint = 0xF,
|
||||
}, {
|
||||
},
|
||||
[4] = {
|
||||
.cfg_eint = 0x0,
|
||||
.set_config = samsung_gpio_setcfg_2bit,
|
||||
.get_config = samsung_gpio_getcfg_2bit,
|
||||
}, {
|
||||
},
|
||||
[5] = {
|
||||
.cfg_eint = 0x2,
|
||||
.set_config = samsung_gpio_setcfg_2bit,
|
||||
.get_config = samsung_gpio_getcfg_2bit,
|
||||
}, {
|
||||
},
|
||||
[6] = {
|
||||
.cfg_eint = 0x3,
|
||||
.set_config = samsung_gpio_setcfg_2bit,
|
||||
.get_config = samsung_gpio_getcfg_2bit,
|
||||
}, {
|
||||
},
|
||||
[7] = {
|
||||
.set_config = samsung_gpio_setcfg_2bit,
|
||||
.get_config = samsung_gpio_getcfg_2bit,
|
||||
}, {
|
||||
},
|
||||
[8] = {
|
||||
.set_pull = exynos4_gpio_setpull,
|
||||
.get_pull = exynos4_gpio_getpull,
|
||||
}, {
|
||||
},
|
||||
[9] = {
|
||||
.cfg_eint = 0x3,
|
||||
.set_pull = exynos4_gpio_setpull,
|
||||
.get_pull = exynos4_gpio_getpull,
|
||||
|
@ -297,18 +297,7 @@ static struct platform_driver sch_gpio_driver = {
|
||||
.remove = __devexit_p(sch_gpio_remove),
|
||||
};
|
||||
|
||||
static int __init sch_gpio_init(void)
|
||||
{
|
||||
return platform_driver_register(&sch_gpio_driver);
|
||||
}
|
||||
|
||||
static void __exit sch_gpio_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&sch_gpio_driver);
|
||||
}
|
||||
|
||||
module_init(sch_gpio_init);
|
||||
module_exit(sch_gpio_exit);
|
||||
module_platform_driver(sch_gpio_driver);
|
||||
|
||||
MODULE_AUTHOR("Denis Turischev <denis@compulab.co.il>");
|
||||
MODULE_DESCRIPTION("GPIO interface for Intel Poulsbo SCH");
|
||||
|
@ -359,18 +359,7 @@ static struct platform_driver timbgpio_platform_driver = {
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
static int __init timbgpio_init(void)
|
||||
{
|
||||
return platform_driver_register(&timbgpio_platform_driver);
|
||||
}
|
||||
|
||||
static void __exit timbgpio_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&timbgpio_platform_driver);
|
||||
}
|
||||
|
||||
module_init(timbgpio_init);
|
||||
module_exit(timbgpio_exit);
|
||||
module_platform_driver(timbgpio_platform_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Timberdale GPIO driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -103,23 +103,12 @@ static struct platform_driver ucb1400_gpio_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
static int __init ucb1400_gpio_init(void)
|
||||
{
|
||||
return platform_driver_register(&ucb1400_gpio_driver);
|
||||
}
|
||||
|
||||
static void __exit ucb1400_gpio_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&ucb1400_gpio_driver);
|
||||
}
|
||||
|
||||
void __init ucb1400_gpio_set_data(struct ucb1400_gpio_data *data)
|
||||
{
|
||||
ucbdata = data;
|
||||
}
|
||||
|
||||
module_init(ucb1400_gpio_init);
|
||||
module_exit(ucb1400_gpio_exit);
|
||||
module_platform_driver(ucb1400_gpio_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Philips UCB1400 GPIO driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -571,15 +571,4 @@ static struct platform_driver giu_device_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
static int __init vr41xx_giu_init(void)
|
||||
{
|
||||
return platform_driver_register(&giu_device_driver);
|
||||
}
|
||||
|
||||
static void __exit vr41xx_giu_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&giu_device_driver);
|
||||
}
|
||||
|
||||
module_init(vr41xx_giu_init);
|
||||
module_exit(vr41xx_giu_exit);
|
||||
module_platform_driver(giu_device_driver);
|
||||
|
@ -315,17 +315,7 @@ static struct platform_driver vx855gpio_driver = {
|
||||
.remove = __devexit_p(vx855gpio_remove),
|
||||
};
|
||||
|
||||
static int vx855gpio_init(void)
|
||||
{
|
||||
return platform_driver_register(&vx855gpio_driver);
|
||||
}
|
||||
module_init(vx855gpio_init);
|
||||
|
||||
static void vx855gpio_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&vx855gpio_driver);
|
||||
}
|
||||
module_exit(vx855gpio_exit);
|
||||
module_platform_driver(vx855gpio_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Harald Welte <HaraldWelte@viatech.com>");
|
||||
|
@ -117,6 +117,60 @@ static int wm8994_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
|
||||
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
static const char *wm8994_gpio_fn(u16 fn)
|
||||
{
|
||||
switch (fn) {
|
||||
case WM8994_GP_FN_PIN_SPECIFIC:
|
||||
return "pin-specific";
|
||||
case WM8994_GP_FN_GPIO:
|
||||
return "GPIO";
|
||||
case WM8994_GP_FN_SDOUT:
|
||||
return "SDOUT";
|
||||
case WM8994_GP_FN_IRQ:
|
||||
return "IRQ";
|
||||
case WM8994_GP_FN_TEMPERATURE:
|
||||
return "Temperature";
|
||||
case WM8994_GP_FN_MICBIAS1_DET:
|
||||
return "MICBIAS1 detect";
|
||||
case WM8994_GP_FN_MICBIAS1_SHORT:
|
||||
return "MICBIAS1 short";
|
||||
case WM8994_GP_FN_MICBIAS2_DET:
|
||||
return "MICBIAS2 detect";
|
||||
case WM8994_GP_FN_MICBIAS2_SHORT:
|
||||
return "MICBIAS2 short";
|
||||
case WM8994_GP_FN_FLL1_LOCK:
|
||||
return "FLL1 lock";
|
||||
case WM8994_GP_FN_FLL2_LOCK:
|
||||
return "FLL2 lock";
|
||||
case WM8994_GP_FN_SRC1_LOCK:
|
||||
return "SRC1 lock";
|
||||
case WM8994_GP_FN_SRC2_LOCK:
|
||||
return "SRC2 lock";
|
||||
case WM8994_GP_FN_DRC1_ACT:
|
||||
return "DRC1 activity";
|
||||
case WM8994_GP_FN_DRC2_ACT:
|
||||
return "DRC2 activity";
|
||||
case WM8994_GP_FN_DRC3_ACT:
|
||||
return "DRC3 activity";
|
||||
case WM8994_GP_FN_WSEQ_STATUS:
|
||||
return "Write sequencer";
|
||||
case WM8994_GP_FN_FIFO_ERROR:
|
||||
return "FIFO error";
|
||||
case WM8994_GP_FN_OPCLK:
|
||||
return "OPCLK";
|
||||
case WM8994_GP_FN_THW:
|
||||
return "Thermal warning";
|
||||
case WM8994_GP_FN_DCS_DONE:
|
||||
return "DC servo";
|
||||
case WM8994_GP_FN_FLL1_OUT:
|
||||
return "FLL1 output";
|
||||
case WM8994_GP_FN_FLL2_OUT:
|
||||
return "FLL1 output";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static void wm8994_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
||||
{
|
||||
struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
|
||||
@ -148,8 +202,29 @@ static void wm8994_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* No decode yet; note that GPIO2 is special */
|
||||
seq_printf(s, "(%x)\n", reg);
|
||||
if (reg & WM8994_GPN_DIR)
|
||||
seq_printf(s, "in ");
|
||||
else
|
||||
seq_printf(s, "out ");
|
||||
|
||||
if (reg & WM8994_GPN_PU)
|
||||
seq_printf(s, "pull up ");
|
||||
|
||||
if (reg & WM8994_GPN_PD)
|
||||
seq_printf(s, "pull down ");
|
||||
|
||||
if (reg & WM8994_GPN_POL)
|
||||
seq_printf(s, "inverted ");
|
||||
else
|
||||
seq_printf(s, "noninverted ");
|
||||
|
||||
if (reg & WM8994_GPN_OP_CFG)
|
||||
seq_printf(s, "open drain ");
|
||||
else
|
||||
seq_printf(s, "CMOS ");
|
||||
|
||||
seq_printf(s, "%s (%x)\n",
|
||||
wm8994_gpio_fn(reg & WM8994_GPN_FN_MASK), reg);
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
@ -206,7 +206,6 @@ static int __devinit xgpio_of_probe(struct device_node *np)
|
||||
np->full_name, status);
|
||||
return status;
|
||||
}
|
||||
pr_info("XGpio: %s: registered\n", np->full_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -114,7 +114,7 @@ static int gpio_ensure_requested(struct gpio_desc *desc, unsigned offset)
|
||||
}
|
||||
|
||||
/* caller holds gpio_lock *OR* gpio is marked as requested */
|
||||
static inline struct gpio_chip *gpio_to_chip(unsigned gpio)
|
||||
struct gpio_chip *gpio_to_chip(unsigned gpio)
|
||||
{
|
||||
return gpio_desc[gpio].chip;
|
||||
}
|
||||
@ -1089,6 +1089,10 @@ unlock:
|
||||
if (status)
|
||||
goto fail;
|
||||
|
||||
pr_info("gpiochip_add: registered GPIOs %d to %d on device: %s\n",
|
||||
chip->base, chip->base + chip->ngpio - 1,
|
||||
chip->label ? : "generic");
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
/* failures here can mean systems won't boot... */
|
||||
|
@ -15,6 +15,15 @@ config PROC_DEVICETREE
|
||||
an image of the device tree that the kernel copies from Open
|
||||
Firmware or other boot firmware. If unsure, say Y here.
|
||||
|
||||
config OF_SELFTEST
|
||||
bool "Device Tree Runtime self tests"
|
||||
help
|
||||
This option builds in test cases for the device tree infrastructure
|
||||
that are executed one at boot time, and the results dumped to the
|
||||
console.
|
||||
|
||||
If unsure, say N here, but this option is safe to enable.
|
||||
|
||||
config OF_FLATTREE
|
||||
bool
|
||||
select DTC
|
||||
|
@ -8,6 +8,7 @@ obj-$(CONFIG_OF_GPIO) += gpio.o
|
||||
obj-$(CONFIG_OF_I2C) += of_i2c.o
|
||||
obj-$(CONFIG_OF_NET) += of_net.o
|
||||
obj-$(CONFIG_OF_SPI) += of_spi.o
|
||||
obj-$(CONFIG_OF_SELFTEST) += selftest.o
|
||||
obj-$(CONFIG_OF_MDIO) += of_mdio.o
|
||||
obj-$(CONFIG_OF_PCI) += of_pci.o
|
||||
obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o
|
||||
|
@ -824,17 +824,19 @@ of_parse_phandle(struct device_node *np, const char *phandle_name, int index)
|
||||
EXPORT_SYMBOL(of_parse_phandle);
|
||||
|
||||
/**
|
||||
* of_parse_phandles_with_args - Find a node pointed by phandle in a list
|
||||
* of_parse_phandle_with_args() - Find a node pointed by phandle in a list
|
||||
* @np: pointer to a device tree node containing a list
|
||||
* @list_name: property name that contains a list
|
||||
* @cells_name: property name that specifies phandles' arguments count
|
||||
* @index: index of a phandle to parse out
|
||||
* @out_node: optional pointer to device_node struct pointer (will be filled)
|
||||
* @out_args: optional pointer to arguments pointer (will be filled)
|
||||
* @out_args: optional pointer to output arguments structure (will be filled)
|
||||
*
|
||||
* This function is useful to parse lists of phandles and their arguments.
|
||||
* Returns 0 on success and fills out_node and out_args, on error returns
|
||||
* appropriate errno value.
|
||||
* Returns 0 on success and fills out_args, on error returns appropriate
|
||||
* errno value.
|
||||
*
|
||||
* Caller is responsible to call of_node_put() on the returned out_args->node
|
||||
* pointer.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
@ -851,94 +853,96 @@ EXPORT_SYMBOL(of_parse_phandle);
|
||||
* }
|
||||
*
|
||||
* To get a device_node of the `node2' node you may call this:
|
||||
* of_parse_phandles_with_args(node3, "list", "#list-cells", 2, &node2, &args);
|
||||
* of_parse_phandle_with_args(node3, "list", "#list-cells", 1, &args);
|
||||
*/
|
||||
int of_parse_phandles_with_args(struct device_node *np, const char *list_name,
|
||||
int of_parse_phandle_with_args(struct device_node *np, const char *list_name,
|
||||
const char *cells_name, int index,
|
||||
struct device_node **out_node,
|
||||
const void **out_args)
|
||||
struct of_phandle_args *out_args)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
const __be32 *list;
|
||||
const __be32 *list_end;
|
||||
int size;
|
||||
int cur_index = 0;
|
||||
const __be32 *list, *list_end;
|
||||
int size, cur_index = 0;
|
||||
uint32_t count = 0;
|
||||
struct device_node *node = NULL;
|
||||
const void *args = NULL;
|
||||
phandle phandle;
|
||||
|
||||
/* Retrieve the phandle list property */
|
||||
list = of_get_property(np, list_name, &size);
|
||||
if (!list) {
|
||||
ret = -ENOENT;
|
||||
goto err0;
|
||||
}
|
||||
if (!list)
|
||||
return -EINVAL;
|
||||
list_end = list + size / sizeof(*list);
|
||||
|
||||
/* Loop over the phandles until all the requested entry is found */
|
||||
while (list < list_end) {
|
||||
const __be32 *cells;
|
||||
phandle phandle;
|
||||
count = 0;
|
||||
|
||||
/*
|
||||
* If phandle is 0, then it is an empty entry with no
|
||||
* arguments. Skip forward to the next entry.
|
||||
*/
|
||||
phandle = be32_to_cpup(list++);
|
||||
args = list;
|
||||
if (phandle) {
|
||||
/*
|
||||
* Find the provider node and parse the #*-cells
|
||||
* property to determine the argument length
|
||||
*/
|
||||
node = of_find_node_by_phandle(phandle);
|
||||
if (!node) {
|
||||
pr_err("%s: could not find phandle\n",
|
||||
np->full_name);
|
||||
break;
|
||||
}
|
||||
if (of_property_read_u32(node, cells_name, &count)) {
|
||||
pr_err("%s: could not get %s for %s\n",
|
||||
np->full_name, cells_name,
|
||||
node->full_name);
|
||||
break;
|
||||
}
|
||||
|
||||
/* one cell hole in the list = <>; */
|
||||
if (!phandle)
|
||||
goto next;
|
||||
|
||||
node = of_find_node_by_phandle(phandle);
|
||||
if (!node) {
|
||||
pr_debug("%s: could not find phandle\n",
|
||||
np->full_name);
|
||||
goto err0;
|
||||
/*
|
||||
* Make sure that the arguments actually fit in the
|
||||
* remaining property data length
|
||||
*/
|
||||
if (list + count > list_end) {
|
||||
pr_err("%s: arguments longer than property\n",
|
||||
np->full_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cells = of_get_property(node, cells_name, &size);
|
||||
if (!cells || size != sizeof(*cells)) {
|
||||
pr_debug("%s: could not get %s for %s\n",
|
||||
np->full_name, cells_name, node->full_name);
|
||||
goto err1;
|
||||
}
|
||||
/*
|
||||
* All of the error cases above bail out of the loop, so at
|
||||
* this point, the parsing is successful. If the requested
|
||||
* index matches, then fill the out_args structure and return,
|
||||
* or return -ENOENT for an empty entry.
|
||||
*/
|
||||
if (cur_index == index) {
|
||||
if (!phandle)
|
||||
return -ENOENT;
|
||||
|
||||
list += be32_to_cpup(cells);
|
||||
if (list > list_end) {
|
||||
pr_debug("%s: insufficient arguments length\n",
|
||||
np->full_name);
|
||||
goto err1;
|
||||
if (out_args) {
|
||||
int i;
|
||||
if (WARN_ON(count > MAX_PHANDLE_ARGS))
|
||||
count = MAX_PHANDLE_ARGS;
|
||||
out_args->np = node;
|
||||
out_args->args_count = count;
|
||||
for (i = 0; i < count; i++)
|
||||
out_args->args[i] = be32_to_cpup(list++);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
next:
|
||||
if (cur_index == index)
|
||||
break;
|
||||
|
||||
of_node_put(node);
|
||||
node = NULL;
|
||||
args = NULL;
|
||||
list += count;
|
||||
cur_index++;
|
||||
}
|
||||
|
||||
if (!node) {
|
||||
/*
|
||||
* args w/o node indicates that the loop above has stopped at
|
||||
* the 'hole' cell. Report this differently.
|
||||
*/
|
||||
if (args)
|
||||
ret = -EEXIST;
|
||||
else
|
||||
ret = -ENOENT;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
if (out_node)
|
||||
*out_node = node;
|
||||
if (out_args)
|
||||
*out_args = args;
|
||||
|
||||
return 0;
|
||||
err1:
|
||||
of_node_put(node);
|
||||
err0:
|
||||
pr_debug("%s failed with status %d\n", __func__, ret);
|
||||
return ret;
|
||||
/* Loop exited without finding a valid entry; return an error */
|
||||
if (node)
|
||||
of_node_put(node);
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL(of_parse_phandles_with_args);
|
||||
EXPORT_SYMBOL(of_parse_phandle_with_args);
|
||||
|
||||
/**
|
||||
* prom_add_property - Add a property to a node
|
||||
|
@ -35,32 +35,27 @@ int of_get_named_gpio_flags(struct device_node *np, const char *propname,
|
||||
int index, enum of_gpio_flags *flags)
|
||||
{
|
||||
int ret;
|
||||
struct device_node *gpio_np;
|
||||
struct gpio_chip *gc;
|
||||
int size;
|
||||
const void *gpio_spec;
|
||||
const __be32 *gpio_cells;
|
||||
struct of_phandle_args gpiospec;
|
||||
|
||||
ret = of_parse_phandles_with_args(np, propname, "#gpio-cells", index,
|
||||
&gpio_np, &gpio_spec);
|
||||
ret = of_parse_phandle_with_args(np, propname, "#gpio-cells", index,
|
||||
&gpiospec);
|
||||
if (ret) {
|
||||
pr_debug("%s: can't parse gpios property\n", __func__);
|
||||
goto err0;
|
||||
}
|
||||
|
||||
gc = of_node_to_gpiochip(gpio_np);
|
||||
gc = of_node_to_gpiochip(gpiospec.np);
|
||||
if (!gc) {
|
||||
pr_debug("%s: gpio controller %s isn't registered\n",
|
||||
np->full_name, gpio_np->full_name);
|
||||
np->full_name, gpiospec.np->full_name);
|
||||
ret = -ENODEV;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
gpio_cells = of_get_property(gpio_np, "#gpio-cells", &size);
|
||||
if (!gpio_cells || size != sizeof(*gpio_cells) ||
|
||||
be32_to_cpup(gpio_cells) != gc->of_gpio_n_cells) {
|
||||
if (gpiospec.args_count != gc->of_gpio_n_cells) {
|
||||
pr_debug("%s: wrong #gpio-cells for %s\n",
|
||||
np->full_name, gpio_np->full_name);
|
||||
np->full_name, gpiospec.np->full_name);
|
||||
ret = -EINVAL;
|
||||
goto err1;
|
||||
}
|
||||
@ -69,13 +64,13 @@ int of_get_named_gpio_flags(struct device_node *np, const char *propname,
|
||||
if (flags)
|
||||
*flags = 0;
|
||||
|
||||
ret = gc->of_xlate(gc, np, gpio_spec, flags);
|
||||
ret = gc->of_xlate(gc, &gpiospec, flags);
|
||||
if (ret < 0)
|
||||
goto err1;
|
||||
|
||||
ret += gc->base;
|
||||
err1:
|
||||
of_node_put(gpio_np);
|
||||
of_node_put(gpiospec.np);
|
||||
err0:
|
||||
pr_debug("%s exited with status %d\n", __func__, ret);
|
||||
return ret;
|
||||
@ -105,8 +100,8 @@ unsigned int of_gpio_count(struct device_node *np)
|
||||
do {
|
||||
int ret;
|
||||
|
||||
ret = of_parse_phandles_with_args(np, "gpios", "#gpio-cells",
|
||||
cnt, NULL, NULL);
|
||||
ret = of_parse_phandle_with_args(np, "gpios", "#gpio-cells",
|
||||
cnt, NULL);
|
||||
/* A hole in the gpios = <> counts anyway. */
|
||||
if (ret < 0 && ret != -EEXIST)
|
||||
break;
|
||||
@ -127,12 +122,9 @@ EXPORT_SYMBOL(of_gpio_count);
|
||||
* gpio chips. This function performs only one sanity check: whether gpio
|
||||
* is less than ngpios (that is specified in the gpio_chip).
|
||||
*/
|
||||
int of_gpio_simple_xlate(struct gpio_chip *gc, struct device_node *np,
|
||||
const void *gpio_spec, u32 *flags)
|
||||
int of_gpio_simple_xlate(struct gpio_chip *gc,
|
||||
const struct of_phandle_args *gpiospec, u32 *flags)
|
||||
{
|
||||
const __be32 *gpio = gpio_spec;
|
||||
const u32 n = be32_to_cpup(gpio);
|
||||
|
||||
/*
|
||||
* We're discouraging gpio_cells < 2, since that way you'll have to
|
||||
* write your own xlate function (that will have to retrive the GPIO
|
||||
@ -144,13 +136,16 @@ int of_gpio_simple_xlate(struct gpio_chip *gc, struct device_node *np,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (n > gc->ngpio)
|
||||
if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells))
|
||||
return -EINVAL;
|
||||
|
||||
if (gpiospec->args[0] > gc->ngpio)
|
||||
return -EINVAL;
|
||||
|
||||
if (flags)
|
||||
*flags = be32_to_cpu(gpio[1]);
|
||||
*flags = gpiospec->args[1];
|
||||
|
||||
return n;
|
||||
return gpiospec->args[0];
|
||||
}
|
||||
EXPORT_SYMBOL(of_gpio_simple_xlate);
|
||||
|
||||
@ -198,8 +193,6 @@ int of_mm_gpiochip_add(struct device_node *np,
|
||||
if (ret)
|
||||
goto err2;
|
||||
|
||||
pr_debug("%s: registered as generic GPIO chip, base is %d\n",
|
||||
np->full_name, gc->base);
|
||||
return 0;
|
||||
err2:
|
||||
iounmap(mm_gc->regs);
|
||||
|
139
drivers/of/selftest.c
Normal file
139
drivers/of/selftest.c
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Self tests for device tree subsystem
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "### %s(): " fmt, __func__
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
static bool selftest_passed = true;
|
||||
#define selftest(result, fmt, ...) { \
|
||||
selftest_passed &= (result); \
|
||||
if (!(result)) \
|
||||
pr_err("FAIL %s:%i " fmt, __FILE__, __LINE__, ##__VA_ARGS__); \
|
||||
}
|
||||
|
||||
static void __init of_selftest_parse_phandle_with_args(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
struct of_phandle_args args;
|
||||
int rc, i;
|
||||
bool passed_all = true;
|
||||
|
||||
pr_info("start\n");
|
||||
np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a");
|
||||
if (!np) {
|
||||
pr_err("missing testcase data\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < 7; i++) {
|
||||
bool passed = true;
|
||||
rc = of_parse_phandle_with_args(np, "phandle-list",
|
||||
"#phandle-cells", i, &args);
|
||||
|
||||
/* Test the values from tests-phandle.dtsi */
|
||||
switch (i) {
|
||||
case 0:
|
||||
passed &= !rc;
|
||||
passed &= (args.args_count == 1);
|
||||
passed &= (args.args[0] == (i + 1));
|
||||
break;
|
||||
case 1:
|
||||
passed &= !rc;
|
||||
passed &= (args.args_count == 2);
|
||||
passed &= (args.args[0] == (i + 1));
|
||||
passed &= (args.args[1] == 0);
|
||||
break;
|
||||
case 2:
|
||||
passed &= (rc == -ENOENT);
|
||||
break;
|
||||
case 3:
|
||||
passed &= !rc;
|
||||
passed &= (args.args_count == 3);
|
||||
passed &= (args.args[0] == (i + 1));
|
||||
passed &= (args.args[1] == 4);
|
||||
passed &= (args.args[2] == 3);
|
||||
break;
|
||||
case 4:
|
||||
passed &= !rc;
|
||||
passed &= (args.args_count == 2);
|
||||
passed &= (args.args[0] == (i + 1));
|
||||
passed &= (args.args[1] == 100);
|
||||
break;
|
||||
case 5:
|
||||
passed &= !rc;
|
||||
passed &= (args.args_count == 0);
|
||||
break;
|
||||
case 6:
|
||||
passed &= !rc;
|
||||
passed &= (args.args_count == 1);
|
||||
passed &= (args.args[0] == (i + 1));
|
||||
break;
|
||||
case 7:
|
||||
passed &= (rc == -EINVAL);
|
||||
break;
|
||||
default:
|
||||
passed = false;
|
||||
}
|
||||
|
||||
if (!passed) {
|
||||
int j;
|
||||
pr_err("index %i - data error on node %s rc=%i regs=[",
|
||||
i, args.np->full_name, rc);
|
||||
for (j = 0; j < args.args_count; j++)
|
||||
printk(" %i", args.args[j]);
|
||||
printk(" ]\n");
|
||||
|
||||
passed_all = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for missing list property */
|
||||
rc = of_parse_phandle_with_args(np, "phandle-list-missing",
|
||||
"#phandle-cells", 0, &args);
|
||||
passed_all &= (rc == -EINVAL);
|
||||
|
||||
/* Check for missing cells property */
|
||||
rc = of_parse_phandle_with_args(np, "phandle-list",
|
||||
"#phandle-cells-missing", 0, &args);
|
||||
passed_all &= (rc == -EINVAL);
|
||||
|
||||
/* Check for bad phandle in list */
|
||||
rc = of_parse_phandle_with_args(np, "phandle-list-bad-phandle",
|
||||
"#phandle-cells", 0, &args);
|
||||
passed_all &= (rc == -EINVAL);
|
||||
|
||||
/* Check for incorrectly formed argument list */
|
||||
rc = of_parse_phandle_with_args(np, "phandle-list-bad-args",
|
||||
"#phandle-cells", 1, &args);
|
||||
passed_all &= (rc == -EINVAL);
|
||||
|
||||
pr_info("end - %s\n", passed_all ? "PASS" : "FAIL");
|
||||
}
|
||||
|
||||
static int __init of_selftest(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
|
||||
np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a");
|
||||
if (!np) {
|
||||
pr_info("No testcase data in device tree; not running tests\n");
|
||||
return 0;
|
||||
}
|
||||
of_node_put(np);
|
||||
|
||||
pr_info("start of selftest - you will see error messages\n");
|
||||
of_selftest_parse_phandle_with_args();
|
||||
pr_info("end of selftest - %s\n", selftest_passed ? "PASS" : "FAIL");
|
||||
return 0;
|
||||
}
|
||||
late_initcall(of_selftest);
|
@ -340,6 +340,10 @@ struct vendor_data {
|
||||
* @cur_msg: Pointer to current spi_message being processed
|
||||
* @cur_transfer: Pointer to current spi_transfer
|
||||
* @cur_chip: pointer to current clients chip(assigned from controller_state)
|
||||
* @next_msg_cs_active: the next message in the queue has been examined
|
||||
* and it was found that it uses the same chip select as the previous
|
||||
* message, so we left it active after the previous transfer, and it's
|
||||
* active already.
|
||||
* @tx: current position in TX buffer to be read
|
||||
* @tx_end: end position in TX buffer to be read
|
||||
* @rx: current position in RX buffer to be written
|
||||
@ -373,6 +377,7 @@ struct pl022 {
|
||||
struct spi_message *cur_msg;
|
||||
struct spi_transfer *cur_transfer;
|
||||
struct chip_data *cur_chip;
|
||||
bool next_msg_cs_active;
|
||||
void *tx;
|
||||
void *tx_end;
|
||||
void *rx;
|
||||
@ -445,23 +450,9 @@ static void giveback(struct pl022 *pl022)
|
||||
struct spi_transfer *last_transfer;
|
||||
unsigned long flags;
|
||||
struct spi_message *msg;
|
||||
void (*curr_cs_control) (u32 command);
|
||||
pl022->next_msg_cs_active = false;
|
||||
|
||||
/*
|
||||
* This local reference to the chip select function
|
||||
* is needed because we set curr_chip to NULL
|
||||
* as a step toward termininating the message.
|
||||
*/
|
||||
curr_cs_control = pl022->cur_chip->cs_control;
|
||||
spin_lock_irqsave(&pl022->queue_lock, flags);
|
||||
msg = pl022->cur_msg;
|
||||
pl022->cur_msg = NULL;
|
||||
pl022->cur_transfer = NULL;
|
||||
pl022->cur_chip = NULL;
|
||||
queue_work(pl022->workqueue, &pl022->pump_messages);
|
||||
spin_unlock_irqrestore(&pl022->queue_lock, flags);
|
||||
|
||||
last_transfer = list_entry(msg->transfers.prev,
|
||||
last_transfer = list_entry(pl022->cur_msg->transfers.prev,
|
||||
struct spi_transfer,
|
||||
transfer_list);
|
||||
|
||||
@ -473,18 +464,13 @@ static void giveback(struct pl022 *pl022)
|
||||
*/
|
||||
udelay(last_transfer->delay_usecs);
|
||||
|
||||
/*
|
||||
* Drop chip select UNLESS cs_change is true or we are returning
|
||||
* a message with an error, or next message is for another chip
|
||||
*/
|
||||
if (!last_transfer->cs_change)
|
||||
curr_cs_control(SSP_CHIP_DESELECT);
|
||||
else {
|
||||
if (!last_transfer->cs_change) {
|
||||
struct spi_message *next_msg;
|
||||
|
||||
/* Holding of cs was hinted, but we need to make sure
|
||||
* the next message is for the same chip. Don't waste
|
||||
* time with the following tests unless this was hinted.
|
||||
/*
|
||||
* cs_change was not set. We can keep the chip select
|
||||
* enabled if there is message in the queue and it is
|
||||
* for the same spi device.
|
||||
*
|
||||
* We cannot postpone this until pump_messages, because
|
||||
* after calling msg->complete (below) the driver that
|
||||
@ -501,19 +487,29 @@ static void giveback(struct pl022 *pl022)
|
||||
struct spi_message, queue);
|
||||
spin_unlock_irqrestore(&pl022->queue_lock, flags);
|
||||
|
||||
/* see if the next and current messages point
|
||||
* to the same chip
|
||||
/*
|
||||
* see if the next and current messages point
|
||||
* to the same spi device.
|
||||
*/
|
||||
if (next_msg && next_msg->spi != msg->spi)
|
||||
if (next_msg && next_msg->spi != pl022->cur_msg->spi)
|
||||
next_msg = NULL;
|
||||
if (!next_msg || msg->state == STATE_ERROR)
|
||||
curr_cs_control(SSP_CHIP_DESELECT);
|
||||
if (!next_msg || pl022->cur_msg->state == STATE_ERROR)
|
||||
pl022->cur_chip->cs_control(SSP_CHIP_DESELECT);
|
||||
else
|
||||
pl022->next_msg_cs_active = true;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&pl022->queue_lock, flags);
|
||||
msg = pl022->cur_msg;
|
||||
pl022->cur_msg = NULL;
|
||||
pl022->cur_transfer = NULL;
|
||||
pl022->cur_chip = NULL;
|
||||
queue_work(pl022->workqueue, &pl022->pump_messages);
|
||||
spin_unlock_irqrestore(&pl022->queue_lock, flags);
|
||||
|
||||
msg->state = NULL;
|
||||
if (msg->complete)
|
||||
msg->complete(msg->context);
|
||||
/* This message is completed, so let's turn off the clocks & power */
|
||||
pm_runtime_put(&pl022->adev->dev);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1244,9 +1240,9 @@ static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id)
|
||||
|
||||
if ((pl022->tx == pl022->tx_end) && (flag == 0)) {
|
||||
flag = 1;
|
||||
/* Disable Transmit interrupt */
|
||||
writew(readw(SSP_IMSC(pl022->virtbase)) &
|
||||
(~SSP_IMSC_MASK_TXIM),
|
||||
/* Disable Transmit interrupt, enable receive interrupt */
|
||||
writew((readw(SSP_IMSC(pl022->virtbase)) &
|
||||
~SSP_IMSC_MASK_TXIM) | SSP_IMSC_MASK_RXIM,
|
||||
SSP_IMSC(pl022->virtbase));
|
||||
}
|
||||
|
||||
@ -1352,7 +1348,7 @@ static void pump_transfers(unsigned long data)
|
||||
*/
|
||||
udelay(previous->delay_usecs);
|
||||
|
||||
/* Drop chip select only if cs_change is requested */
|
||||
/* Reselect chip select only if cs_change was requested */
|
||||
if (previous->cs_change)
|
||||
pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
|
||||
} else {
|
||||
@ -1379,15 +1375,22 @@ static void pump_transfers(unsigned long data)
|
||||
}
|
||||
|
||||
err_config_dma:
|
||||
writew(ENABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase));
|
||||
/* enable all interrupts except RX */
|
||||
writew(ENABLE_ALL_INTERRUPTS & ~SSP_IMSC_MASK_RXIM, SSP_IMSC(pl022->virtbase));
|
||||
}
|
||||
|
||||
static void do_interrupt_dma_transfer(struct pl022 *pl022)
|
||||
{
|
||||
u32 irqflags = ENABLE_ALL_INTERRUPTS;
|
||||
/*
|
||||
* Default is to enable all interrupts except RX -
|
||||
* this will be enabled once TX is complete
|
||||
*/
|
||||
u32 irqflags = ENABLE_ALL_INTERRUPTS & ~SSP_IMSC_MASK_RXIM;
|
||||
|
||||
/* Enable target chip, if not already active */
|
||||
if (!pl022->next_msg_cs_active)
|
||||
pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
|
||||
|
||||
/* Enable target chip */
|
||||
pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
|
||||
if (set_up_next_transfer(pl022, pl022->cur_transfer)) {
|
||||
/* Error path */
|
||||
pl022->cur_msg->state = STATE_ERROR;
|
||||
@ -1442,7 +1445,8 @@ static void do_polling_transfer(struct pl022 *pl022)
|
||||
} else {
|
||||
/* STATE_START */
|
||||
message->state = STATE_RUNNING;
|
||||
pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
|
||||
if (!pl022->next_msg_cs_active)
|
||||
pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
|
||||
}
|
||||
|
||||
/* Configuration Changing Per Transfer */
|
||||
@ -1504,14 +1508,28 @@ static void pump_messages(struct work_struct *work)
|
||||
struct pl022 *pl022 =
|
||||
container_of(work, struct pl022, pump_messages);
|
||||
unsigned long flags;
|
||||
bool was_busy = false;
|
||||
|
||||
/* Lock queue and check for queue work */
|
||||
spin_lock_irqsave(&pl022->queue_lock, flags);
|
||||
if (list_empty(&pl022->queue) || !pl022->running) {
|
||||
if (pl022->busy) {
|
||||
/* nothing more to do - disable spi/ssp and power off */
|
||||
writew((readw(SSP_CR1(pl022->virtbase)) &
|
||||
(~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase));
|
||||
|
||||
if (pl022->master_info->autosuspend_delay > 0) {
|
||||
pm_runtime_mark_last_busy(&pl022->adev->dev);
|
||||
pm_runtime_put_autosuspend(&pl022->adev->dev);
|
||||
} else {
|
||||
pm_runtime_put(&pl022->adev->dev);
|
||||
}
|
||||
}
|
||||
pl022->busy = false;
|
||||
spin_unlock_irqrestore(&pl022->queue_lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Make sure we are not already running a message */
|
||||
if (pl022->cur_msg) {
|
||||
spin_unlock_irqrestore(&pl022->queue_lock, flags);
|
||||
@ -1522,7 +1540,10 @@ static void pump_messages(struct work_struct *work)
|
||||
list_entry(pl022->queue.next, struct spi_message, queue);
|
||||
|
||||
list_del_init(&pl022->cur_msg->queue);
|
||||
pl022->busy = true;
|
||||
if (pl022->busy)
|
||||
was_busy = true;
|
||||
else
|
||||
pl022->busy = true;
|
||||
spin_unlock_irqrestore(&pl022->queue_lock, flags);
|
||||
|
||||
/* Initial message state */
|
||||
@ -1532,12 +1553,14 @@ static void pump_messages(struct work_struct *work)
|
||||
|
||||
/* Setup the SPI using the per chip configuration */
|
||||
pl022->cur_chip = spi_get_ctldata(pl022->cur_msg->spi);
|
||||
/*
|
||||
* We enable the core voltage and clocks here, then the clocks
|
||||
* and core will be disabled when giveback() is called in each method
|
||||
* (poll/interrupt/DMA)
|
||||
*/
|
||||
pm_runtime_get_sync(&pl022->adev->dev);
|
||||
if (!was_busy)
|
||||
/*
|
||||
* We enable the core voltage and clocks here, then the clocks
|
||||
* and core will be disabled when this workqueue is run again
|
||||
* and there is no more work to be done.
|
||||
*/
|
||||
pm_runtime_get_sync(&pl022->adev->dev);
|
||||
|
||||
restore_state(pl022);
|
||||
flush(pl022);
|
||||
|
||||
@ -1582,6 +1605,7 @@ static int start_queue(struct pl022 *pl022)
|
||||
pl022->cur_msg = NULL;
|
||||
pl022->cur_transfer = NULL;
|
||||
pl022->cur_chip = NULL;
|
||||
pl022->next_msg_cs_active = false;
|
||||
spin_unlock_irqrestore(&pl022->queue_lock, flags);
|
||||
|
||||
queue_work(pl022->workqueue, &pl022->pump_messages);
|
||||
@ -1881,7 +1905,7 @@ static int pl022_setup(struct spi_device *spi)
|
||||
{
|
||||
struct pl022_config_chip const *chip_info;
|
||||
struct chip_data *chip;
|
||||
struct ssp_clock_params clk_freq = {0, };
|
||||
struct ssp_clock_params clk_freq = { .cpsdvsr = 0, .scr = 0};
|
||||
int status = 0;
|
||||
struct pl022 *pl022 = spi_master_get_devdata(spi->master);
|
||||
unsigned int bits = spi->bits_per_word;
|
||||
@ -2231,7 +2255,17 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
dev_dbg(dev, "probe succeeded\n");
|
||||
|
||||
/* let runtime pm put suspend */
|
||||
pm_runtime_put(dev);
|
||||
if (platform_info->autosuspend_delay > 0) {
|
||||
dev_info(&adev->dev,
|
||||
"will use autosuspend for runtime pm, delay %dms\n",
|
||||
platform_info->autosuspend_delay);
|
||||
pm_runtime_set_autosuspend_delay(dev,
|
||||
platform_info->autosuspend_delay);
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
} else {
|
||||
pm_runtime_put(dev);
|
||||
}
|
||||
return 0;
|
||||
|
||||
err_spi_register:
|
||||
@ -2305,11 +2339,6 @@ static int pl022_suspend(struct device *dev)
|
||||
return status;
|
||||
}
|
||||
|
||||
amba_vcore_enable(pl022->adev);
|
||||
amba_pclk_enable(pl022->adev);
|
||||
load_ssp_default_config(pl022);
|
||||
amba_pclk_disable(pl022->adev);
|
||||
amba_vcore_disable(pl022->adev);
|
||||
dev_dbg(dev, "suspended\n");
|
||||
return 0;
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
|
||||
@ -128,13 +129,14 @@ struct gpio_chip {
|
||||
*/
|
||||
struct device_node *of_node;
|
||||
int of_gpio_n_cells;
|
||||
int (*of_xlate)(struct gpio_chip *gc, struct device_node *np,
|
||||
const void *gpio_spec, u32 *flags);
|
||||
int (*of_xlate)(struct gpio_chip *gc,
|
||||
const struct of_phandle_args *gpiospec, u32 *flags);
|
||||
#endif
|
||||
};
|
||||
|
||||
extern const char *gpiochip_is_requested(struct gpio_chip *chip,
|
||||
unsigned offset);
|
||||
extern struct gpio_chip *gpio_to_chip(unsigned gpio);
|
||||
extern int __must_check gpiochip_reserve(int start, int ngpio);
|
||||
|
||||
/* add/remove chips */
|
||||
|
@ -238,6 +238,9 @@ struct dma_chan;
|
||||
* @enable_dma: if true enables DMA driven transfers.
|
||||
* @dma_rx_param: parameter to locate an RX DMA channel.
|
||||
* @dma_tx_param: parameter to locate a TX DMA channel.
|
||||
* @autosuspend_delay: delay in ms following transfer completion before the
|
||||
* runtime power management system suspends the device. A setting of 0
|
||||
* indicates no delay and the device will be suspended immediately.
|
||||
*/
|
||||
struct pl022_ssp_controller {
|
||||
u16 bus_id;
|
||||
@ -246,6 +249,7 @@ struct pl022_ssp_controller {
|
||||
bool (*dma_filter)(struct dma_chan *chan, void *filter_param);
|
||||
void *dma_rx_param;
|
||||
void *dma_tx_param;
|
||||
int autosuspend_delay;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -65,6 +65,13 @@ struct device_node {
|
||||
#endif
|
||||
};
|
||||
|
||||
#define MAX_PHANDLE_ARGS 8
|
||||
struct of_phandle_args {
|
||||
struct device_node *np;
|
||||
int args_count;
|
||||
uint32_t args[MAX_PHANDLE_ARGS];
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
|
||||
/* Pointer for first entry in chain of all nodes. */
|
||||
@ -230,9 +237,9 @@ extern int of_modalias_node(struct device_node *node, char *modalias, int len);
|
||||
extern struct device_node *of_parse_phandle(struct device_node *np,
|
||||
const char *phandle_name,
|
||||
int index);
|
||||
extern int of_parse_phandles_with_args(struct device_node *np,
|
||||
extern int of_parse_phandle_with_args(struct device_node *np,
|
||||
const char *list_name, const char *cells_name, int index,
|
||||
struct device_node **out_node, const void **out_args);
|
||||
struct of_phandle_args *out_args);
|
||||
|
||||
extern void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align));
|
||||
extern int of_alias_get_id(struct device_node *np, const char *stem);
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
struct device_node;
|
||||
|
||||
@ -57,8 +58,9 @@ extern int of_mm_gpiochip_add(struct device_node *np,
|
||||
extern void of_gpiochip_add(struct gpio_chip *gc);
|
||||
extern void of_gpiochip_remove(struct gpio_chip *gc);
|
||||
extern struct gpio_chip *of_node_to_gpiochip(struct device_node *np);
|
||||
extern int of_gpio_simple_xlate(struct gpio_chip *gc, struct device_node *np,
|
||||
const void *gpio_spec, u32 *flags);
|
||||
extern int of_gpio_simple_xlate(struct gpio_chip *gc,
|
||||
const struct of_phandle_args *gpiospec,
|
||||
u32 *flags);
|
||||
|
||||
#else /* CONFIG_OF_GPIO */
|
||||
|
||||
@ -75,8 +77,8 @@ static inline unsigned int of_gpio_count(struct device_node *np)
|
||||
}
|
||||
|
||||
static inline int of_gpio_simple_xlate(struct gpio_chip *gc,
|
||||
struct device_node *np,
|
||||
const void *gpio_spec, u32 *flags)
|
||||
const struct of_phandle_args *gpiospec,
|
||||
u32 *flags)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user