From b9c7aff481f19dd655ae3ce6513817d625e2d47c Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 29 May 2012 11:18:51 -0700 Subject: drivers/thermal/spear_thermal.c: add Device Tree probing capability SPEAr platforms now support DT and so must convert all drivers to support DT. This patch adds DT probing support for SPEAr thermal sensor driver and updates its documentation too. Also, as SPEAr is the only user of this driver and is only available with DT, make this an only DT driver. So, platform_data is completely removed and passed via DT now. Signed-off-by: Viresh Kumar Cc: Dan Carpenter Reviewed-by: Vincenzo Frascino Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- .../devicetree/bindings/thermal/spear-thermal.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 Documentation/devicetree/bindings/thermal/spear-thermal.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/thermal/spear-thermal.txt b/Documentation/devicetree/bindings/thermal/spear-thermal.txt new file mode 100644 index 00000000000..93e3b67c102 --- /dev/null +++ b/Documentation/devicetree/bindings/thermal/spear-thermal.txt @@ -0,0 +1,14 @@ +* SPEAr Thermal + +Required properties: +- compatible : "st,thermal-spear1340" +- reg : Address range of the thermal registers +- st,thermal-flags: flags used to enable thermal sensor + +Example: + + thermal@fc000000 { + compatible = "st,thermal-spear1340"; + reg = <0xfc000000 0x1000>; + st,thermal-flags = <0x7000>; + }; -- cgit v1.2.3-70-g09d2 From e7ec014a47e4d68fc01561d0541a50650646317c Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 12 Jun 2012 01:10:02 -0700 Subject: Input: twl6040-vibra - update for device tree support The twl6040 DT support implementation has been changed from the originally planned. None of the child devices going to have compatible_of property which means that the child devices of twl6040 will be created as traditional MFD devices. The mfd core driver will decide (based on the DT blob) to create a device for the twl6040-vibra or not. If the DT blob has 'vibra' section the device will be created without pdata. In this case the vibra driver will reach up to the parent node to get the needed properties. With DT booted kernel we no longer be able to link the regulators to the vibra driver, they can be only linked to the MFD device (probed via DT). From the vibra driver we ned to use pdev->dev.parent to get the regulators. Signed-off-by: Peter Ujfalusi Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/twl6040-vibra.txt | 37 ------------------- drivers/input/misc/twl6040-vibra.c | 42 ++++++++++++---------- 2 files changed, 24 insertions(+), 55 deletions(-) delete mode 100644 Documentation/devicetree/bindings/input/twl6040-vibra.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/input/twl6040-vibra.txt b/Documentation/devicetree/bindings/input/twl6040-vibra.txt deleted file mode 100644 index 5b1918b818f..00000000000 --- a/Documentation/devicetree/bindings/input/twl6040-vibra.txt +++ /dev/null @@ -1,37 +0,0 @@ -Vibra driver for the twl6040 family - -The vibra driver is a child of the twl6040 MFD dirver. -Documentation/devicetree/bindings/mfd/twl6040.txt - -Required properties: -- compatible : Must be "ti,twl6040-vibra"; -- interrupts: 4, Vibra overcurrent interrupt -- vddvibl-supply: Regulator supplying the left vibra motor -- vddvibr-supply: Regulator supplying the right vibra motor -- vibldrv_res: Board specific left driver resistance -- vibrdrv_res: Board specific right driver resistance -- viblmotor_res: Board specific left motor resistance -- vibrmotor_res: Board specific right motor resistance - -Optional properties: -- vddvibl_uV: If the vddvibl default voltage need to be changed -- vddvibr_uV: If the vddvibr default voltage need to be changed - -Example: -/* - * 8-channel high quality low-power audio codec - * http://www.ti.com/lit/ds/symlink/twl6040.pdf - */ -twl6040: twl6040@4b { - ... - twl6040_vibra: twl6040@1 { - compatible = "ti,twl6040-vibra"; - interrupts = <4>; - vddvibl-supply = <&vbat>; - vddvibr-supply = <&vbat>; - vibldrv_res = <8>; - vibrdrv_res = <3>; - viblmotor_res = <10>; - vibrmotor_res = <10>; - }; -}; diff --git a/drivers/input/misc/twl6040-vibra.c b/drivers/input/misc/twl6040-vibra.c index c34f6c0371c..c8a288ae1d5 100644 --- a/drivers/input/misc/twl6040-vibra.c +++ b/drivers/input/misc/twl6040-vibra.c @@ -251,7 +251,6 @@ static int twl6040_vibra_suspend(struct device *dev) return 0; } - #endif static SIMPLE_DEV_PM_OPS(twl6040_vibra_pm_ops, twl6040_vibra_suspend, NULL); @@ -259,13 +258,19 @@ static SIMPLE_DEV_PM_OPS(twl6040_vibra_pm_ops, twl6040_vibra_suspend, NULL); static int __devinit twl6040_vibra_probe(struct platform_device *pdev) { struct twl6040_vibra_data *pdata = pdev->dev.platform_data; - struct device_node *node = pdev->dev.of_node; + struct device *twl6040_core_dev = pdev->dev.parent; + struct device_node *twl6040_core_node = NULL; struct vibra_info *info; int vddvibl_uV = 0; int vddvibr_uV = 0; int ret; - if (!pdata && !node) { +#ifdef CONFIG_OF + twl6040_core_node = of_find_node_by_name(twl6040_core_dev->of_node, + "vibra"); +#endif + + if (!pdata && !twl6040_core_node) { dev_err(&pdev->dev, "platform_data not available\n"); return -EINVAL; } @@ -287,14 +292,18 @@ static int __devinit twl6040_vibra_probe(struct platform_device *pdev) vddvibl_uV = pdata->vddvibl_uV; vddvibr_uV = pdata->vddvibr_uV; } else { - of_property_read_u32(node, "vibldrv_res", &info->vibldrv_res); - of_property_read_u32(node, "vibrdrv_res", &info->vibrdrv_res); - of_property_read_u32(node, "viblmotor_res", + of_property_read_u32(twl6040_core_node, "ti,vibldrv-res", + &info->vibldrv_res); + of_property_read_u32(twl6040_core_node, "ti,vibrdrv-res", + &info->vibrdrv_res); + of_property_read_u32(twl6040_core_node, "ti,viblmotor-res", &info->viblmotor_res); - of_property_read_u32(node, "vibrmotor_res", + of_property_read_u32(twl6040_core_node, "ti,vibrmotor-res", &info->vibrmotor_res); - of_property_read_u32(node, "vddvibl_uV", &vddvibl_uV); - of_property_read_u32(node, "vddvibr_uV", &vddvibr_uV); + of_property_read_u32(twl6040_core_node, "ti,vddvibl-uV", + &vddvibl_uV); + of_property_read_u32(twl6040_core_node, "ti,vddvibr-uV", + &vddvibr_uV); } if ((!info->vibldrv_res && !info->viblmotor_res) || @@ -351,8 +360,12 @@ static int __devinit twl6040_vibra_probe(struct platform_device *pdev) info->supplies[0].supply = "vddvibl"; info->supplies[1].supply = "vddvibr"; - ret = regulator_bulk_get(info->dev, ARRAY_SIZE(info->supplies), - info->supplies); + /* + * When booted with Device tree the regulators are attached to the + * parent device (twl6040 MFD core) + */ + ret = regulator_bulk_get(pdata ? info->dev : twl6040_core_dev, + ARRAY_SIZE(info->supplies), info->supplies); if (ret) { dev_err(info->dev, "couldn't get regulators %d\n", ret); goto err_regulator; @@ -418,12 +431,6 @@ static int __devexit twl6040_vibra_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id twl6040_vibra_of_match[] = { - {.compatible = "ti,twl6040-vibra", }, - { }, -}; -MODULE_DEVICE_TABLE(of, twl6040_vibra_of_match); - static struct platform_driver twl6040_vibra_driver = { .probe = twl6040_vibra_probe, .remove = __devexit_p(twl6040_vibra_remove), @@ -431,7 +438,6 @@ static struct platform_driver twl6040_vibra_driver = { .name = "twl6040-vibra", .owner = THIS_MODULE, .pm = &twl6040_vibra_pm_ops, - .of_match_table = twl6040_vibra_of_match, }, }; module_platform_driver(twl6040_vibra_driver); -- cgit v1.2.3-70-g09d2 From 002176db8113c92d0bda02a47e3d2a4b8f9f55ea Mon Sep 17 00:00:00 2001 From: Alexandre Pereira da Silva Date: Thu, 14 Jun 2012 09:59:23 -0300 Subject: misc: at25: Parse dt settings This adds dt support to the at25 eeprom driver. Signed-off-by: Alexandre Pereira da Silva Tested-by: Roland Stigge Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/misc/at25.txt | 21 +++++++++ drivers/misc/eeprom/at25.c | 61 ++++++++++++++++++------- 2 files changed, 66 insertions(+), 16 deletions(-) create mode 100644 Documentation/devicetree/bindings/misc/at25.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/misc/at25.txt b/Documentation/devicetree/bindings/misc/at25.txt new file mode 100644 index 00000000000..ab3c327929d --- /dev/null +++ b/Documentation/devicetree/bindings/misc/at25.txt @@ -0,0 +1,21 @@ +Atmel AT25 eeprom + +Required properties: +- compatible : "atmel,at25". +- reg : chip select number +- spi-max-frequency : max spi frequency to use + +- at25,byte-len : total eeprom size in bytes +- at25,addr-mode : addr-mode flags, as defined in include/linux/spi/eeprom.h +- at25,page-size : size of the eeprom page + +Examples: +at25@0 { + compatible = "atmel,at25"; + reg = <0> + spi-max-frequency = <5000000>; + + at25,byte-len = <0x8000>; + at25,addr-mode = <2>; + at25,page-size = <64>; +}; diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c index 0842c2994ee..25003d6ceb5 100644 --- a/drivers/misc/eeprom/at25.c +++ b/drivers/misc/eeprom/at25.c @@ -19,7 +19,7 @@ #include #include - +#include /* * NOTE: this is an *EEPROM* driver. The vagaries of product naming @@ -305,25 +305,54 @@ static ssize_t at25_mem_write(struct memory_accessor *mem, const char *buf, static int at25_probe(struct spi_device *spi) { struct at25_data *at25 = NULL; - const struct spi_eeprom *chip; + struct spi_eeprom chip; + struct device_node *np = spi->dev.of_node; int err; int sr; int addrlen; /* Chip description */ - chip = spi->dev.platform_data; - if (!chip) { - dev_dbg(&spi->dev, "no chip description\n"); - err = -ENODEV; - goto fail; - } + if (!spi->dev.platform_data) { + if (np) { + u32 val; + + memset(&chip, 0, sizeof(chip)); + strncpy(chip.name, np->name, 10); + + err = of_property_read_u32(np, "at25,byte-len", &val); + if (err) { + dev_dbg(&spi->dev, "invalid chip dt description\n"); + goto fail; + } + chip.byte_len = val; + + err = of_property_read_u32(np, "at25,addr-mode", &val); + if (err) { + dev_dbg(&spi->dev, "invalid chip dt description\n"); + goto fail; + } + chip.flags = (u16)val; + + err = of_property_read_u32(np, "at25,page-size", &val); + if (err) { + dev_dbg(&spi->dev, "invalid chip dt description\n"); + goto fail; + } + chip.page_size = (u16)val; + } else { + dev_dbg(&spi->dev, "no chip description\n"); + err = -ENODEV; + goto fail; + } + } else + chip = *(struct spi_eeprom *)spi->dev.platform_data; /* For now we only support 8/16/24 bit addressing */ - if (chip->flags & EE_ADDR1) + if (chip.flags & EE_ADDR1) addrlen = 1; - else if (chip->flags & EE_ADDR2) + else if (chip.flags & EE_ADDR2) addrlen = 2; - else if (chip->flags & EE_ADDR3) + else if (chip.flags & EE_ADDR3) addrlen = 3; else { dev_dbg(&spi->dev, "unsupported address type\n"); @@ -348,7 +377,7 @@ static int at25_probe(struct spi_device *spi) } mutex_init(&at25->lock); - at25->chip = *chip; + at25->chip = chip; at25->spi = spi_dev_get(spi); dev_set_drvdata(&spi->dev, at25); at25->addrlen = addrlen; @@ -369,7 +398,7 @@ static int at25_probe(struct spi_device *spi) at25->mem.read = at25_mem_read; at25->bin.size = at25->chip.byte_len; - if (!(chip->flags & EE_READONLY)) { + if (!(chip.flags & EE_READONLY)) { at25->bin.write = at25_bin_write; at25->bin.attr.mode |= S_IWUSR; at25->mem.write = at25_mem_write; @@ -379,8 +408,8 @@ static int at25_probe(struct spi_device *spi) if (err) goto fail; - if (chip->setup) - chip->setup(&at25->mem, chip->context); + if (chip.setup) + chip.setup(&at25->mem, chip.context); dev_info(&spi->dev, "%Zd %s %s eeprom%s, pagesize %u\n", (at25->bin.size < 1024) @@ -388,7 +417,7 @@ static int at25_probe(struct spi_device *spi) : (at25->bin.size / 1024), (at25->bin.size < 1024) ? "Byte" : "KByte", at25->chip.name, - (chip->flags & EE_READONLY) ? " (readonly)" : "", + (chip.flags & EE_READONLY) ? " (readonly)" : "", at25->chip.page_size); return 0; fail: -- cgit v1.2.3-70-g09d2 From 7299ab70e68e20e70cb45fe4ab4b6029fe964acd Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 14 Dec 2011 11:10:32 +0100 Subject: pwm: Add device tree support This patch adds helpers to support device tree bindings for the generic PWM API. Device tree binding documentation for PWM controllers is also provided. Acked-by: Arnd Bergmann Reviewed-by: Shawn Guo Signed-off-by: Thierry Reding --- Documentation/devicetree/bindings/pwm/pwm.txt | 57 ++++++++++ drivers/pwm/core.c | 148 +++++++++++++++++++++++++- include/linux/pwm.h | 6 ++ 3 files changed, 209 insertions(+), 2 deletions(-) create mode 100644 Documentation/devicetree/bindings/pwm/pwm.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/pwm/pwm.txt b/Documentation/devicetree/bindings/pwm/pwm.txt new file mode 100644 index 00000000000..73ec962bfe8 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/pwm.txt @@ -0,0 +1,57 @@ +Specifying PWM information for devices +====================================== + +1) PWM user nodes +----------------- + +PWM users should specify a list of PWM devices that they want to use +with a property containing a 'pwm-list': + + pwm-list ::= [pwm-list] + single-pwm ::= + pwm-phandle : phandle to PWM controller node + pwm-specifier : array of #pwm-cells specifying the given PWM + (controller specific) + +PWM properties should be named "pwms". The exact meaning of each pwms +property must be documented in the device tree binding for each device. +An optional property "pwm-names" may contain a list of strings to label +each of the PWM devices listed in the "pwms" property. If no "pwm-names" +property is given, the name of the user node will be used as fallback. + +Drivers for devices that use more than a single PWM device can use the +"pwm-names" property to map the name of the PWM device requested by the +pwm_get() call to an index into the list given by the "pwms" property. + +The following example could be used to describe a PWM-based backlight +device: + + pwm: pwm { + #pwm-cells = <2>; + }; + + [...] + + bl: backlight { + pwms = <&pwm 0 5000000>; + pwm-names = "backlight"; + }; + +pwm-specifier typically encodes the chip-relative PWM number and the PWM +period in nanoseconds. Note that in the example above, specifying the +"pwm-names" is redundant because the name "backlight" would be used as +fallback anyway. + +2) PWM controller nodes +----------------------- + +PWM controller nodes must specify the number of cells used for the +specifier using the '#pwm-cells' property. + +An example PWM controller might look like this: + + pwm: pwm@7000a000 { + compatible = "nvidia,tegra20-pwm"; + reg = <0x7000a000 0x100>; + #pwm-cells = <2>; + }; diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index a2af599e61a..dbab53005da 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -129,6 +129,45 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label) return 0; } +static struct pwm_device *of_pwm_simple_xlate(struct pwm_chip *pc, + const struct of_phandle_args *args) +{ + struct pwm_device *pwm; + + if (pc->of_pwm_n_cells < 2) + return ERR_PTR(-EINVAL); + + if (args->args[0] >= pc->npwm) + return ERR_PTR(-EINVAL); + + pwm = pwm_request_from_chip(pc, args->args[0], NULL); + if (IS_ERR(pwm)) + return pwm; + + pwm_set_period(pwm, args->args[1]); + + return pwm; +} + +void of_pwmchip_add(struct pwm_chip *chip) +{ + if (!chip->dev || !chip->dev->of_node) + return; + + if (!chip->of_xlate) { + chip->of_xlate = of_pwm_simple_xlate; + chip->of_pwm_n_cells = 2; + } + + of_node_get(chip->dev->of_node); +} + +void of_pwmchip_remove(struct pwm_chip *chip) +{ + if (chip->dev && chip->dev->of_node) + of_node_put(chip->dev->of_node); +} + /** * pwm_set_chip_data() - set private chip data for a PWM * @pwm: PWM device @@ -201,6 +240,9 @@ int pwmchip_add(struct pwm_chip *chip) ret = 0; + if (IS_ENABLED(CONFIG_OF)) + of_pwmchip_add(chip); + out: mutex_unlock(&pwm_lock); return ret; @@ -231,6 +273,10 @@ int pwmchip_remove(struct pwm_chip *chip) } list_del_init(&chip->list); + + if (IS_ENABLED(CONFIG_OF)) + of_pwmchip_remove(chip); + free_pwms(chip); out: @@ -356,6 +402,99 @@ void pwm_disable(struct pwm_device *pwm) } EXPORT_SYMBOL_GPL(pwm_disable); +static struct pwm_chip *of_node_to_pwmchip(struct device_node *np) +{ + struct pwm_chip *chip; + + mutex_lock(&pwm_lock); + + list_for_each_entry(chip, &pwm_chips, list) + if (chip->dev && chip->dev->of_node == np) { + mutex_unlock(&pwm_lock); + return chip; + } + + mutex_unlock(&pwm_lock); + + return ERR_PTR(-EPROBE_DEFER); +} + +/** + * of_pwm_request() - request a PWM via the PWM framework + * @np: device node to get the PWM from + * @con_id: consumer name + * + * Returns the PWM device parsed from the phandle and index specified in the + * "pwms" property of a device tree node or a negative error-code on failure. + * Values parsed from the device tree are stored in the returned PWM device + * object. + * + * If con_id is NULL, the first PWM device listed in the "pwms" property will + * be requested. Otherwise the "pwm-names" property is used to do a reverse + * lookup of the PWM index. This also means that the "pwm-names" property + * becomes mandatory for devices that look up the PWM device via the con_id + * parameter. + */ +static struct pwm_device *of_pwm_request(struct device_node *np, + const char *con_id) +{ + struct pwm_device *pwm = NULL; + struct of_phandle_args args; + struct pwm_chip *pc; + int index = 0; + int err; + + if (con_id) { + index = of_property_match_string(np, "pwm-names", con_id); + if (index < 0) + return ERR_PTR(index); + } + + err = of_parse_phandle_with_args(np, "pwms", "#pwm-cells", index, + &args); + if (err) { + pr_debug("%s(): can't parse \"pwms\" property\n", __func__); + return ERR_PTR(err); + } + + pc = of_node_to_pwmchip(args.np); + if (IS_ERR(pc)) { + pr_debug("%s(): PWM chip not found\n", __func__); + pwm = ERR_CAST(pc); + goto put; + } + + if (args.args_count != pc->of_pwm_n_cells) { + pr_debug("%s: wrong #pwm-cells for %s\n", np->full_name, + args.np->full_name); + pwm = ERR_PTR(-EINVAL); + goto put; + } + + pwm = pc->of_xlate(pc, &args); + if (IS_ERR(pwm)) + goto put; + + /* + * If a consumer name was not given, try to look it up from the + * "pwm-names" property if it exists. Otherwise use the name of + * the user device node. + */ + if (!con_id) { + err = of_property_read_string_index(np, "pwm-names", index, + &con_id); + if (err < 0) + con_id = np->name; + } + + pwm->label = con_id; + +put: + of_node_put(args.np); + + return pwm; +} + /** * pwm_add_table() - register PWM device consumers * @table: array of consumers to register @@ -378,8 +517,9 @@ void __init pwm_add_table(struct pwm_lookup *table, size_t num) * @dev: device for PWM consumer * @con_id: consumer name * - * Look up a PWM chip and a relative index via a table supplied by board setup - * code (see pwm_add_table()). + * Lookup is first attempted using DT. If the device was not instantiated from + * a device tree, a PWM chip and a relative index is looked up via a table + * supplied by board setup code (see pwm_add_table()). * * Once a PWM chip has been found the specified PWM device will be requested * and is ready to be used. @@ -394,6 +534,10 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id) unsigned int index; unsigned int match; + /* look up via DT first */ + if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node) + return of_pwm_request(dev->of_node, con_id); + /* * We look up the provider in the static table typically provided by * board setup code. We first try to lookup the consumer device by diff --git a/include/linux/pwm.h b/include/linux/pwm.h index 2947a4fea6a..21d076c5089 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -1,6 +1,8 @@ #ifndef __LINUX_PWM_H #define __LINUX_PWM_H +#include + struct pwm_device; struct seq_file; @@ -105,6 +107,10 @@ struct pwm_chip { unsigned int npwm; struct pwm_device *pwms; + + struct pwm_device * (*of_xlate)(struct pwm_chip *pc, + const struct of_phandle_args *args); + unsigned int of_pwm_n_cells; }; int pwm_set_chip_data(struct pwm_device *pwm, void *data); -- cgit v1.2.3-70-g09d2 From a1b01edb274518c7da6d69b84e7558c092282aad Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 13 Jun 2012 12:01:55 -0500 Subject: edac: add support for Calxeda highbank memory controller Add support for memory controller on Calxeda Highbank platforms. Highbank platforms support a single 4GB mini-DIMM with 1-bit correction and 2-bit detection. Signed-off-by: Rob Herring Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/arm/calxeda/mem-ctrlr.txt | 14 ++ arch/arm/boot/dts/highbank.dts | 6 + drivers/edac/Kconfig | 9 +- drivers/edac/Makefile | 2 + drivers/edac/highbank_mc_edac.c | 264 +++++++++++++++++++++ 5 files changed, 294 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/arm/calxeda/mem-ctrlr.txt create mode 100644 drivers/edac/highbank_mc_edac.c (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/arm/calxeda/mem-ctrlr.txt b/Documentation/devicetree/bindings/arm/calxeda/mem-ctrlr.txt new file mode 100644 index 00000000000..f770ac0893d --- /dev/null +++ b/Documentation/devicetree/bindings/arm/calxeda/mem-ctrlr.txt @@ -0,0 +1,14 @@ +Calxeda DDR memory controller + +Properties: +- compatible : Should be "calxeda,hb-ddr-ctrl" +- reg : Address and size for DDR controller registers. +- interrupts : Interrupt for DDR controller. + +Example: + + memory-controller@fff00000 { + compatible = "calxeda,hb-ddr-ctrl"; + reg = <0xfff00000 0x1000>; + interrupts = <0 91 4>; + }; diff --git a/arch/arm/boot/dts/highbank.dts b/arch/arm/boot/dts/highbank.dts index 83e72294aef..d4b4941c78e 100644 --- a/arch/arm/boot/dts/highbank.dts +++ b/arch/arm/boot/dts/highbank.dts @@ -118,6 +118,12 @@ interrupts = <0 90 4>; }; + memory-controller@fff00000 { + compatible = "calxeda,hb-ddr-ctrl"; + reg = <0xfff00000 0x1000>; + interrupts = <0 91 4>; + }; + ipc@fff20000 { compatible = "arm,pl320", "arm,primecell"; reg = <0xfff20000 0x1000>; diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 3b3f84ff351..f7efa8b282f 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -7,7 +7,7 @@ menuconfig EDAC bool "EDAC (Error Detection And Correction) reporting" depends on HAS_IOMEM - depends on X86 || PPC || TILE + depends on X86 || PPC || TILE || ARM help EDAC is designed to report errors in the core system. These are low-level errors that are reported in the CPU or @@ -302,4 +302,11 @@ config EDAC_TILE Support for error detection and correction on the Tilera memory controller. +config EDAC_HIGHBANK_MC + tristate "Highbank Memory Controller" + depends on EDAC_MM_EDAC && ARCH_HIGHBANK + help + Support for error detection and correction on the + Calxeda Highbank memory controller. + endif # EDAC diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index 196a63dd37c..44f2044d407 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile @@ -55,3 +55,5 @@ obj-$(CONFIG_EDAC_AMD8111) += amd8111_edac.o obj-$(CONFIG_EDAC_AMD8131) += amd8131_edac.o obj-$(CONFIG_EDAC_TILE) += tile_edac.o + +obj-$(CONFIG_EDAC_HIGHBANK_MC) += highbank_mc_edac.o diff --git a/drivers/edac/highbank_mc_edac.c b/drivers/edac/highbank_mc_edac.c new file mode 100644 index 00000000000..c769f477fd2 --- /dev/null +++ b/drivers/edac/highbank_mc_edac.c @@ -0,0 +1,264 @@ +/* + * Copyright 2011-2012 Calxeda, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "edac_core.h" +#include "edac_module.h" + +/* DDR Ctrlr Error Registers */ +#define HB_DDR_ECC_OPT 0x128 +#define HB_DDR_ECC_U_ERR_ADDR 0x130 +#define HB_DDR_ECC_U_ERR_STAT 0x134 +#define HB_DDR_ECC_U_ERR_DATAL 0x138 +#define HB_DDR_ECC_U_ERR_DATAH 0x13c +#define HB_DDR_ECC_C_ERR_ADDR 0x140 +#define HB_DDR_ECC_C_ERR_STAT 0x144 +#define HB_DDR_ECC_C_ERR_DATAL 0x148 +#define HB_DDR_ECC_C_ERR_DATAH 0x14c +#define HB_DDR_ECC_INT_STATUS 0x180 +#define HB_DDR_ECC_INT_ACK 0x184 +#define HB_DDR_ECC_U_ERR_ID 0x424 +#define HB_DDR_ECC_C_ERR_ID 0x428 + +#define HB_DDR_ECC_INT_STAT_CE 0x8 +#define HB_DDR_ECC_INT_STAT_DOUBLE_CE 0x10 +#define HB_DDR_ECC_INT_STAT_UE 0x20 +#define HB_DDR_ECC_INT_STAT_DOUBLE_UE 0x40 + +#define HB_DDR_ECC_OPT_MODE_MASK 0x3 +#define HB_DDR_ECC_OPT_FWC 0x100 +#define HB_DDR_ECC_OPT_XOR_SHIFT 16 + +struct hb_mc_drvdata { + void __iomem *mc_vbase; +}; + +static irqreturn_t highbank_mc_err_handler(int irq, void *dev_id) +{ + struct mem_ctl_info *mci = dev_id; + struct hb_mc_drvdata *drvdata = mci->pvt_info; + u32 status, err_addr; + + /* Read the interrupt status register */ + status = readl(drvdata->mc_vbase + HB_DDR_ECC_INT_STATUS); + + if (status & HB_DDR_ECC_INT_STAT_UE) { + err_addr = readl(drvdata->mc_vbase + HB_DDR_ECC_U_ERR_ADDR); + edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, + err_addr >> PAGE_SHIFT, + err_addr & ~PAGE_MASK, 0, + 0, 0, -1, + mci->ctl_name, ""); + } + if (status & HB_DDR_ECC_INT_STAT_CE) { + u32 syndrome = readl(drvdata->mc_vbase + HB_DDR_ECC_C_ERR_STAT); + syndrome = (syndrome >> 8) & 0xff; + err_addr = readl(drvdata->mc_vbase + HB_DDR_ECC_C_ERR_ADDR); + edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, + err_addr >> PAGE_SHIFT, + err_addr & ~PAGE_MASK, syndrome, + 0, 0, -1, + mci->ctl_name, ""); + } + + /* clear the error, clears the interrupt */ + writel(status, drvdata->mc_vbase + HB_DDR_ECC_INT_ACK); + return IRQ_HANDLED; +} + +#ifdef CONFIG_EDAC_DEBUG +static ssize_t highbank_mc_err_inject_write(struct file *file, + const char __user *data, + size_t count, loff_t *ppos) +{ + struct mem_ctl_info *mci = file->private_data; + struct hb_mc_drvdata *pdata = mci->pvt_info; + char buf[32]; + size_t buf_size; + u32 reg; + u8 synd; + + buf_size = min(count, (sizeof(buf)-1)); + if (copy_from_user(buf, data, buf_size)) + return -EFAULT; + buf[buf_size] = 0; + + if (!kstrtou8(buf, 16, &synd)) { + reg = readl(pdata->mc_vbase + HB_DDR_ECC_OPT); + reg &= HB_DDR_ECC_OPT_MODE_MASK; + reg |= (synd << HB_DDR_ECC_OPT_XOR_SHIFT) | HB_DDR_ECC_OPT_FWC; + writel(reg, pdata->mc_vbase + HB_DDR_ECC_OPT); + } + + return count; +} + +static int debugfs_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static const struct file_operations highbank_mc_debug_inject_fops = { + .open = debugfs_open, + .write = highbank_mc_err_inject_write, + .llseek = generic_file_llseek, +}; + +static void __devinit highbank_mc_create_debugfs_nodes(struct mem_ctl_info *mci) +{ + if (mci->debugfs) + debugfs_create_file("inject_ctrl", S_IWUSR, mci->debugfs, mci, + &highbank_mc_debug_inject_fops); +; +} +#else +static void __devinit highbank_mc_create_debugfs_nodes(struct mem_ctl_info *mci) +{} +#endif + +static int __devinit highbank_mc_probe(struct platform_device *pdev) +{ + struct edac_mc_layer layers[2]; + struct mem_ctl_info *mci; + struct hb_mc_drvdata *drvdata; + struct dimm_info *dimm; + struct resource *r; + u32 control; + int irq; + int res = 0; + + layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; + layers[0].size = 1; + layers[0].is_virt_csrow = true; + layers[1].type = EDAC_MC_LAYER_CHANNEL; + layers[1].size = 1; + layers[1].is_virt_csrow = false; + mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, + sizeof(struct hb_mc_drvdata)); + if (!mci) + return -ENOMEM; + + mci->pdev = &pdev->dev; + drvdata = mci->pvt_info; + platform_set_drvdata(pdev, mci); + + if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL)) + return -ENOMEM; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) { + dev_err(&pdev->dev, "Unable to get mem resource\n"); + res = -ENODEV; + goto err; + } + + if (!devm_request_mem_region(&pdev->dev, r->start, + resource_size(r), dev_name(&pdev->dev))) { + dev_err(&pdev->dev, "Error while requesting mem region\n"); + res = -EBUSY; + goto err; + } + + drvdata->mc_vbase = devm_ioremap(&pdev->dev, + r->start, resource_size(r)); + if (!drvdata->mc_vbase) { + dev_err(&pdev->dev, "Unable to map regs\n"); + res = -ENOMEM; + goto err; + } + + control = readl(drvdata->mc_vbase + HB_DDR_ECC_OPT) & 0x3; + if (!control || (control == 0x2)) { + dev_err(&pdev->dev, "No ECC present, or ECC disabled\n"); + res = -ENODEV; + goto err; + } + + irq = platform_get_irq(pdev, 0); + res = devm_request_irq(&pdev->dev, irq, highbank_mc_err_handler, + 0, dev_name(&pdev->dev), mci); + if (res < 0) { + dev_err(&pdev->dev, "Unable to request irq %d\n", irq); + goto err; + } + + mci->mtype_cap = MEM_FLAG_DDR3; + mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; + mci->edac_cap = EDAC_FLAG_SECDED; + mci->mod_name = dev_name(&pdev->dev); + mci->mod_ver = "1"; + mci->ctl_name = dev_name(&pdev->dev); + mci->scrub_mode = SCRUB_SW_SRC; + + /* Only a single 4GB DIMM is supported */ + dimm = *mci->dimms; + dimm->nr_pages = (~0UL >> PAGE_SHIFT) + 1; + dimm->grain = 8; + dimm->dtype = DEV_X8; + dimm->mtype = MEM_DDR3; + dimm->edac_mode = EDAC_SECDED; + + res = edac_mc_add_mc(mci); + if (res < 0) + goto err; + + highbank_mc_create_debugfs_nodes(mci); + + devres_close_group(&pdev->dev, NULL); + return 0; +err: + devres_release_group(&pdev->dev, NULL); + edac_mc_free(mci); + return res; +} + +static int highbank_mc_remove(struct platform_device *pdev) +{ + struct mem_ctl_info *mci = platform_get_drvdata(pdev); + + edac_mc_del_mc(&pdev->dev); + edac_mc_free(mci); + return 0; +} + +static const struct of_device_id hb_ddr_ctrl_of_match[] = { + { .compatible = "calxeda,hb-ddr-ctrl", }, + {}, +}; +MODULE_DEVICE_TABLE(of, hb_ddr_ctrl_of_match); + +static struct platform_driver highbank_mc_edac_driver = { + .probe = highbank_mc_probe, + .remove = highbank_mc_remove, + .driver = { + .name = "hb_mc_edac", + .of_match_table = hb_ddr_ctrl_of_match, + }, +}; + +module_platform_driver(highbank_mc_edac_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Calxeda, Inc."); +MODULE_DESCRIPTION("EDAC Driver for Calxeda Highbank"); -- cgit v1.2.3-70-g09d2 From 69154d069869b612383cef9d594f39b34ffba6dd Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 11 Jun 2012 21:32:14 -0500 Subject: edac: add support for Calxeda highbank L2 cache ecc Add support for L2 ECC on Calxeda highbank platform. Signed-off-by: Rob Herring Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/arm/calxeda/l2ecc.txt | 15 +++ arch/arm/boot/dts/highbank.dts | 6 + drivers/edac/Kconfig | 7 + drivers/edac/Makefile | 1 + drivers/edac/highbank_l2_edac.c | 149 +++++++++++++++++++++ 5 files changed, 178 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/calxeda/l2ecc.txt create mode 100644 drivers/edac/highbank_l2_edac.c (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/arm/calxeda/l2ecc.txt b/Documentation/devicetree/bindings/arm/calxeda/l2ecc.txt new file mode 100644 index 00000000000..94e642a33db --- /dev/null +++ b/Documentation/devicetree/bindings/arm/calxeda/l2ecc.txt @@ -0,0 +1,15 @@ +Calxeda Highbank L2 cache ECC + +Properties: +- compatible : Should be "calxeda,hb-sregs-l2-ecc" +- reg : Address and size for ECC error interrupt clear registers. +- interrupts : Should be single bit error interrupt, then double bit error + interrupt. + +Example: + + sregs@fff3c200 { + compatible = "calxeda,hb-sregs-l2-ecc"; + reg = <0xfff3c200 0x100>; + interrupts = <0 71 4 0 72 4>; + }; diff --git a/arch/arm/boot/dts/highbank.dts b/arch/arm/boot/dts/highbank.dts index d4b4941c78e..4d641ea4e27 100644 --- a/arch/arm/boot/dts/highbank.dts +++ b/arch/arm/boot/dts/highbank.dts @@ -194,6 +194,12 @@ reg = <0xfff3c000 0x1000>; }; + sregs@fff3c200 { + compatible = "calxeda,hb-sregs-l2-ecc"; + reg = <0xfff3c200 0x100>; + interrupts = <0 71 4 0 72 4>; + }; + dma@fff3d000 { compatible = "arm,pl330", "arm,primecell"; reg = <0xfff3d000 0x1000>; diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index f7efa8b282f..409b92b8d34 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -309,4 +309,11 @@ config EDAC_HIGHBANK_MC Support for error detection and correction on the Calxeda Highbank memory controller. +config EDAC_HIGHBANK_L2 + tristate "Highbank L2 Cache" + depends on EDAC_MM_EDAC && ARCH_HIGHBANK + help + Support for error detection and correction on the + Calxeda Highbank memory controller. + endif # EDAC diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index 44f2044d407..7e5129a733f 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile @@ -57,3 +57,4 @@ obj-$(CONFIG_EDAC_AMD8131) += amd8131_edac.o obj-$(CONFIG_EDAC_TILE) += tile_edac.o obj-$(CONFIG_EDAC_HIGHBANK_MC) += highbank_mc_edac.o +obj-$(CONFIG_EDAC_HIGHBANK_L2) += highbank_l2_edac.o diff --git a/drivers/edac/highbank_l2_edac.c b/drivers/edac/highbank_l2_edac.c new file mode 100644 index 00000000000..e599b00c05a --- /dev/null +++ b/drivers/edac/highbank_l2_edac.c @@ -0,0 +1,149 @@ +/* + * Copyright 2011-2012 Calxeda, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ +#include +#include +#include +#include +#include +#include +#include + +#include "edac_core.h" +#include "edac_module.h" + +#define SR_CLR_SB_ECC_INTR 0x0 +#define SR_CLR_DB_ECC_INTR 0x4 + +struct hb_l2_drvdata { + void __iomem *base; + int sb_irq; + int db_irq; +}; + +static irqreturn_t highbank_l2_err_handler(int irq, void *dev_id) +{ + struct edac_device_ctl_info *dci = dev_id; + struct hb_l2_drvdata *drvdata = dci->pvt_info; + + if (irq == drvdata->sb_irq) { + writel(1, drvdata->base + SR_CLR_SB_ECC_INTR); + edac_device_handle_ce(dci, 0, 0, dci->ctl_name); + } + if (irq == drvdata->db_irq) { + writel(1, drvdata->base + SR_CLR_DB_ECC_INTR); + edac_device_handle_ue(dci, 0, 0, dci->ctl_name); + } + + return IRQ_HANDLED; +} + +static int __devinit highbank_l2_err_probe(struct platform_device *pdev) +{ + struct edac_device_ctl_info *dci; + struct hb_l2_drvdata *drvdata; + struct resource *r; + int res = 0; + + dci = edac_device_alloc_ctl_info(sizeof(*drvdata), "cpu", + 1, "L", 1, 2, NULL, 0, 0); + if (!dci) + return -ENOMEM; + + drvdata = dci->pvt_info; + dci->dev = &pdev->dev; + platform_set_drvdata(pdev, dci); + + if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL)) + return -ENOMEM; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) { + dev_err(&pdev->dev, "Unable to get mem resource\n"); + res = -ENODEV; + goto err; + } + + if (!devm_request_mem_region(&pdev->dev, r->start, + resource_size(r), dev_name(&pdev->dev))) { + dev_err(&pdev->dev, "Error while requesting mem region\n"); + res = -EBUSY; + goto err; + } + + drvdata->base = devm_ioremap(&pdev->dev, r->start, resource_size(r)); + if (!drvdata->base) { + dev_err(&pdev->dev, "Unable to map regs\n"); + res = -ENOMEM; + goto err; + } + + drvdata->db_irq = platform_get_irq(pdev, 0); + res = devm_request_irq(&pdev->dev, drvdata->db_irq, + highbank_l2_err_handler, + 0, dev_name(&pdev->dev), dci); + if (res < 0) + goto err; + + drvdata->sb_irq = platform_get_irq(pdev, 1); + res = devm_request_irq(&pdev->dev, drvdata->sb_irq, + highbank_l2_err_handler, + 0, dev_name(&pdev->dev), dci); + if (res < 0) + goto err; + + dci->mod_name = dev_name(&pdev->dev); + dci->dev_name = dev_name(&pdev->dev); + + if (edac_device_add_device(dci)) + goto err; + + devres_close_group(&pdev->dev, NULL); + return 0; +err: + devres_release_group(&pdev->dev, NULL); + edac_device_free_ctl_info(dci); + return res; +} + +static int highbank_l2_err_remove(struct platform_device *pdev) +{ + struct edac_device_ctl_info *dci = platform_get_drvdata(pdev); + + edac_device_del_device(&pdev->dev); + edac_device_free_ctl_info(dci); + return 0; +} + +static const struct of_device_id hb_l2_err_of_match[] = { + { .compatible = "calxeda,hb-sregs-l2-ecc", }, + {}, +}; +MODULE_DEVICE_TABLE(of, hb_l2_err_of_match); + +static struct platform_driver highbank_l2_edac_driver = { + .probe = highbank_l2_err_probe, + .remove = highbank_l2_err_remove, + .driver = { + .name = "hb_l2_edac", + .of_match_table = hb_l2_err_of_match, + }, +}; + +module_platform_driver(highbank_l2_edac_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Calxeda, Inc."); +MODULE_DESCRIPTION("EDAC Driver for Calxeda Highbank L2 Cache"); -- cgit v1.2.3-70-g09d2 From 140fd977dc46bc750258f082cdf1cfea79dc1d14 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 21 Dec 2011 08:04:13 +0100 Subject: pwm: tegra: Add device tree support Add auxdata to instantiate the PWFM controller from a device tree, include the corresponding nodes in the dtsi files for Tegra 20 and Tegra 30 and add binding documentation. Acked-by: Stephen Warren Signed-off-by: Thierry Reding --- .../devicetree/bindings/pwm/nvidia,tegra20-pwm.txt | 18 ++++++++++++++++++ arch/arm/boot/dts/tegra20.dtsi | 6 ++++++ arch/arm/boot/dts/tegra30.dtsi | 6 ++++++ arch/arm/mach-tegra/board-dt-tegra20.c | 1 + arch/arm/mach-tegra/board-dt-tegra30.c | 3 +++ drivers/pwm/pwm-tegra.c | 11 +++++++++++ 6 files changed, 45 insertions(+) create mode 100644 Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt b/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt new file mode 100644 index 00000000000..bbbeedb4ec0 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt @@ -0,0 +1,18 @@ +Tegra SoC PWFM controller + +Required properties: +- compatible: should be one of: + - "nvidia,tegra20-pwm" + - "nvidia,tegra30-pwm" +- reg: physical base address and length of the controller's registers +- #pwm-cells: On Tegra the number of cells used to specify a PWM is 2. The + first cell specifies the per-chip index of the PWM to use and the second + cell is the duty cycle in nanoseconds. + +Example: + + pwm: pwm@7000a000 { + compatible = "nvidia,tegra20-pwm"; + reg = <0x7000a000 0x100>; + #pwm-cells = <2>; + }; diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index c417d67e902..846af573f64 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -123,6 +123,12 @@ status = "disable"; }; + pwm { + compatible = "nvidia,tegra20-pwm"; + reg = <0x7000a000 0x100>; + #pwm-cells = <2>; + }; + i2c@7000c000 { compatible = "nvidia,tegra20-i2c"; reg = <0x7000c000 0x100>; diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi index 2dcc09e784b..f7f428e81e3 100644 --- a/arch/arm/boot/dts/tegra30.dtsi +++ b/arch/arm/boot/dts/tegra30.dtsi @@ -117,6 +117,12 @@ status = "disable"; }; + pwm { + compatible = "nvidia,tegra30-pwm", "nvidia,tegra20-pwm"; + reg = <0x7000a000 0x100>; + #pwm-cells = <2>; + }; + i2c@7000c000 { compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c"; reg = <0x7000c000 0x100>; diff --git a/arch/arm/mach-tegra/board-dt-tegra20.c b/arch/arm/mach-tegra/board-dt-tegra20.c index eb7249db50a..962f1a1b12e 100644 --- a/arch/arm/mach-tegra/board-dt-tegra20.c +++ b/arch/arm/mach-tegra/board-dt-tegra20.c @@ -64,6 +64,7 @@ struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = { &tegra_ehci2_pdata), OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB3_BASE, "tegra-ehci.2", &tegra_ehci3_pdata), + OF_DEV_AUXDATA("nvidia,tegra20-pwm", TEGRA_PWFM_BASE, "tegra-pwm", NULL), {} }; diff --git a/arch/arm/mach-tegra/board-dt-tegra30.c b/arch/arm/mach-tegra/board-dt-tegra30.c index 4f76fa7a5da..ffc6cae3eb2 100644 --- a/arch/arm/mach-tegra/board-dt-tegra30.c +++ b/arch/arm/mach-tegra/board-dt-tegra30.c @@ -33,6 +33,8 @@ #include #include +#include + #include "board.h" #include "clock.h" @@ -52,6 +54,7 @@ struct of_dev_auxdata tegra30_auxdata_lookup[] __initdata = { OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C700, "tegra-i2c.3", NULL), OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000D000, "tegra-i2c.4", NULL), OF_DEV_AUXDATA("nvidia,tegra30-ahub", 0x70080000, "tegra30-ahub", NULL), + OF_DEV_AUXDATA("nvidia,tegra30-pwm", TEGRA_PWFM_BASE, "tegra-pwm", NULL), {} }; diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c index 0950142d191..472b74e8221 100644 --- a/drivers/pwm/pwm-tegra.c +++ b/drivers/pwm/pwm-tegra.c @@ -239,9 +239,20 @@ static int __devexit tegra_pwm_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_OF +static struct of_device_id tegra_pwm_of_match[] = { + { .compatible = "nvidia,tegra20-pwm" }, + { .compatible = "nvidia,tegra30-pwm" }, + { } +}; + +MODULE_DEVICE_TABLE(of, tegra_pwm_of_match); +#endif + static struct platform_driver tegra_pwm_driver = { .driver = { .name = "tegra-pwm", + .of_match_table = of_match_ptr(tegra_pwm_of_match), }, .probe = tegra_pwm_probe, .remove = __devexit_p(tegra_pwm_remove), -- cgit v1.2.3-70-g09d2 From 4dce82c1e84007d38747533673c2289bfc6497d2 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Wed, 4 Apr 2012 10:50:52 +0800 Subject: pwm: add pwm-mxs support Add generic PWM framework driver (DT only) for Freescale MXS. Signed-off-by: Sascha Hauer Signed-off-by: Shawn Guo Signed-off-by: Thierry Reding --- Documentation/devicetree/bindings/pwm/mxs-pwm.txt | 17 ++ drivers/pwm/Kconfig | 9 + drivers/pwm/Makefile | 1 + drivers/pwm/pwm-mxs.c | 207 ++++++++++++++++++++++ 4 files changed, 234 insertions(+) create mode 100644 Documentation/devicetree/bindings/pwm/mxs-pwm.txt create mode 100644 drivers/pwm/pwm-mxs.c (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/pwm/mxs-pwm.txt b/Documentation/devicetree/bindings/pwm/mxs-pwm.txt new file mode 100644 index 00000000000..48ead0db178 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/mxs-pwm.txt @@ -0,0 +1,17 @@ +Freescale MXS PWM controller + +Required properties: +- compatible: should be "fsl,mxs-pwm" +- reg: physical base address and length of the controller's registers +- #pwm-cells: should be 2. The first cell specifies the per-chip index + of the PWM to use and the second cell is the duty cycle in nanoseconds. +- fsl,pwm-number: the number of PWM devices + +Example: + +pwm: pwm@80064000 { + compatible = "fsl,imx28-pwm", "fsl,mxs-pwm"; + reg = <0x80064000 2000>; + #pwm-cells = <2>; + fsl,pwm-number = <8>; +}; diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index a93feffbc36..39bdebc0cb2 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -27,6 +27,15 @@ config PWM_IMX To compile this driver as a module, choose M here: the module will be called pwm-imx. +config PWM_MXS + tristate "Freescale MXS PWM support" + depends on ARCH_MXS && OF + help + Generic PWM framework driver for Freescale MXS. + + To compile this driver as a module, choose M here: the module + will be called pwm-mxs. + config PWM_PXA tristate "PXA PWM support" depends on ARCH_PXA diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index b7c0fcf4de1..cec250091cf 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_PWM) += core.o obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o obj-$(CONFIG_PWM_IMX) += pwm-imx.o +obj-$(CONFIG_PWM_MXS) += pwm-mxs.o obj-$(CONFIG_PWM_PXA) += pwm-pxa.o obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o diff --git a/drivers/pwm/pwm-mxs.c b/drivers/pwm/pwm-mxs.c new file mode 100644 index 00000000000..9602708372b --- /dev/null +++ b/drivers/pwm/pwm-mxs.c @@ -0,0 +1,207 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SET 0x4 +#define CLR 0x8 +#define TOG 0xc + +#define PWM_CTRL 0x0 +#define PWM_ACTIVE0 0x10 +#define PWM_PERIOD0 0x20 +#define PERIOD_PERIOD(p) ((p) & 0xffff) +#define PERIOD_PERIOD_MAX 0x10000 +#define PERIOD_ACTIVE_HIGH (3 << 16) +#define PERIOD_INACTIVE_LOW (2 << 18) +#define PERIOD_CDIV(div) (((div) & 0x7) << 20) +#define PERIOD_CDIV_MAX 8 + +struct mxs_pwm_chip { + struct pwm_chip chip; + struct device *dev; + struct clk *clk; + void __iomem *base; +}; + +#define to_mxs_pwm_chip(_chip) container_of(_chip, struct mxs_pwm_chip, chip) + +static int mxs_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, + int duty_ns, int period_ns) +{ + struct mxs_pwm_chip *mxs = to_mxs_pwm_chip(chip); + int ret, div = 0; + unsigned int period_cycles, duty_cycles; + unsigned long rate; + unsigned long long c; + + rate = clk_get_rate(mxs->clk); + while (1) { + c = rate / (1 << div); + c = c * period_ns; + do_div(c, 1000000000); + if (c < PERIOD_PERIOD_MAX) + break; + div++; + if (div > PERIOD_CDIV_MAX) + return -EINVAL; + } + + period_cycles = c; + c *= duty_ns; + do_div(c, period_ns); + duty_cycles = c; + + /* + * If the PWM channel is disabled, make sure to turn on the clock + * before writing the register. Otherwise, keep it enabled. + */ + if (!test_bit(PWMF_ENABLED, &pwm->flags)) { + ret = clk_prepare_enable(mxs->clk); + if (ret) + return ret; + } + + writel(duty_cycles << 16, + mxs->base + PWM_ACTIVE0 + pwm->hwpwm * 0x20); + writel(PERIOD_PERIOD(period_cycles) | PERIOD_ACTIVE_HIGH | + PERIOD_INACTIVE_LOW | PERIOD_CDIV(div), + mxs->base + PWM_PERIOD0 + pwm->hwpwm * 0x20); + + /* + * If the PWM is not enabled, turn the clock off again to save power. + */ + if (!test_bit(PWMF_ENABLED, &pwm->flags)) + clk_disable_unprepare(mxs->clk); + + return 0; +} + +static int mxs_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct mxs_pwm_chip *mxs = to_mxs_pwm_chip(chip); + int ret; + + ret = clk_prepare_enable(mxs->clk); + if (ret) + return ret; + + writel(1 << pwm->hwpwm, mxs->base + PWM_CTRL + SET); + + return 0; +} + +static void mxs_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct mxs_pwm_chip *mxs = to_mxs_pwm_chip(chip); + + writel(1 << pwm->hwpwm, mxs->base + PWM_CTRL + CLR); + + clk_disable_unprepare(mxs->clk); +} + +static const struct pwm_ops mxs_pwm_ops = { + .config = mxs_pwm_config, + .enable = mxs_pwm_enable, + .disable = mxs_pwm_disable, + .owner = THIS_MODULE, +}; + +static int mxs_pwm_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct mxs_pwm_chip *mxs; + int ret; + + mxs = devm_kzalloc(&pdev->dev, sizeof(*mxs), GFP_KERNEL); + if (!mxs) + return -ENOMEM; + + mxs->base = of_iomap(np, 0); + if (!mxs->base) + return -EADDRNOTAVAIL; + + mxs->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(mxs->clk)) { + ret = PTR_ERR(mxs->clk); + goto iounmap; + } + + mxs->chip.dev = &pdev->dev; + mxs->chip.ops = &mxs_pwm_ops; + mxs->chip.base = -1; + ret = of_property_read_u32(np, "fsl,pwm-number", &mxs->chip.npwm); + if (ret < 0) { + dev_err(&pdev->dev, "failed to get pwm number: %d\n", ret); + goto clk_put; + } + + ret = pwmchip_add(&mxs->chip); + if (ret < 0) { + dev_err(&pdev->dev, "failed to add pwm chip %d\n", ret); + goto clk_put; + } + + mxs->dev = &pdev->dev; + platform_set_drvdata(pdev, mxs); + + mxs_reset_block(mxs->base); + + return 0; + +clk_put: + clk_put(mxs->clk); +iounmap: + iounmap(mxs->base); + return ret; +} + +static int __devexit mxs_pwm_remove(struct platform_device *pdev) +{ + struct mxs_pwm_chip *mxs = platform_get_drvdata(pdev); + + pwmchip_remove(&mxs->chip); + clk_put(mxs->clk); + iounmap(mxs->base); + + return 0; +} + +static struct of_device_id mxs_pwm_dt_ids[] = { + { .compatible = "fsl,mxs-pwm", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mxs_pwm_dt_ids); + +static struct platform_driver mxs_pwm_driver = { + .driver = { + .name = "mxs-pwm", + .of_match_table = of_match_ptr(mxs_pwm_dt_ids), + }, + .probe = mxs_pwm_probe, + .remove = __devexit_p(mxs_pwm_remove), +}; +module_platform_driver(mxs_pwm_driver); + +MODULE_ALIAS("platform:mxs-pwm"); +MODULE_AUTHOR("Shawn Guo "); +MODULE_DESCRIPTION("Freescale MXS PWM Driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-70-g09d2 From f14cf2fb8d30f9dad2e532a4e3f1ed4ca82fbc3b Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 20 Apr 2012 17:08:02 +0200 Subject: devicetree: bindings: gpio-i2c belongs to i2c not gpio gpio-i2c describes an I2C controller (using gpios for data and clock), so it must be described in i2c, not gpio. Signed-off-by: Wolfram Sang Acked-by: Rob Herring --- .../devicetree/bindings/gpio/gpio_i2c.txt | 32 ---------------------- Documentation/devicetree/bindings/i2c/gpio-i2c.txt | 32 ++++++++++++++++++++++ 2 files changed, 32 insertions(+), 32 deletions(-) delete mode 100644 Documentation/devicetree/bindings/gpio/gpio_i2c.txt create mode 100644 Documentation/devicetree/bindings/i2c/gpio-i2c.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/gpio/gpio_i2c.txt b/Documentation/devicetree/bindings/gpio/gpio_i2c.txt deleted file mode 100644 index 4f8ec947c6b..00000000000 --- a/Documentation/devicetree/bindings/gpio/gpio_i2c.txt +++ /dev/null @@ -1,32 +0,0 @@ -Device-Tree bindings for i2c gpio driver - -Required properties: - - compatible = "i2c-gpio"; - - gpios: sda and scl gpio - - -Optional properties: - - i2c-gpio,sda-open-drain: sda as open drain - - i2c-gpio,scl-open-drain: scl as open drain - - i2c-gpio,scl-output-only: scl as output only - - i2c-gpio,delay-us: delay between GPIO operations (may depend on each platform) - - i2c-gpio,timeout-ms: timeout to get data - -Example nodes: - -i2c@0 { - compatible = "i2c-gpio"; - gpios = <&pioA 23 0 /* sda */ - &pioA 24 0 /* scl */ - >; - i2c-gpio,sda-open-drain; - i2c-gpio,scl-open-drain; - i2c-gpio,delay-us = <2>; /* ~100 kHz */ - #address-cells = <1>; - #size-cells = <0>; - - rv3029c2@56 { - compatible = "rv3029c2"; - reg = <0x56>; - }; -}; diff --git a/Documentation/devicetree/bindings/i2c/gpio-i2c.txt b/Documentation/devicetree/bindings/i2c/gpio-i2c.txt new file mode 100644 index 00000000000..4f8ec947c6b --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/gpio-i2c.txt @@ -0,0 +1,32 @@ +Device-Tree bindings for i2c gpio driver + +Required properties: + - compatible = "i2c-gpio"; + - gpios: sda and scl gpio + + +Optional properties: + - i2c-gpio,sda-open-drain: sda as open drain + - i2c-gpio,scl-open-drain: scl as open drain + - i2c-gpio,scl-output-only: scl as output only + - i2c-gpio,delay-us: delay between GPIO operations (may depend on each platform) + - i2c-gpio,timeout-ms: timeout to get data + +Example nodes: + +i2c@0 { + compatible = "i2c-gpio"; + gpios = <&pioA 23 0 /* sda */ + &pioA 24 0 /* scl */ + >; + i2c-gpio,sda-open-drain; + i2c-gpio,scl-open-drain; + i2c-gpio,delay-us = <2>; /* ~100 kHz */ + #address-cells = <1>; + #size-cells = <0>; + + rv3029c2@56 { + compatible = "rv3029c2"; + reg = <0x56>; + }; +}; -- cgit v1.2.3-70-g09d2 From bcc1dd4cd77ec168894ea325b4e89b15a8b5b4f6 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 28 Jun 2012 12:20:22 +0200 Subject: mfd: Add device-tree entry to enable tps65910 external 32-kHz oscillator Add device-tree entry to enable external 32-kHz crystal oscillator input. Compile-only tested. Signed-off-by: Johan Hovold Signed-off-by: Samuel Ortiz --- Documentation/devicetree/bindings/mfd/tps65910.txt | 4 +++- drivers/mfd/tps65910.c | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/mfd/tps65910.txt b/Documentation/devicetree/bindings/mfd/tps65910.txt index 645f5eaadb3..0f5d9b74f4b 100644 --- a/Documentation/devicetree/bindings/mfd/tps65910.txt +++ b/Documentation/devicetree/bindings/mfd/tps65910.txt @@ -29,6 +29,8 @@ Optional properties: comparator. (see VMBCH_VSEL in TPS65910 datasheet) - ti,vmbch2-threshold: (tps65911) main battery discharged threshold comparator. (see VMBCH_VSEL in TPS65910 datasheet) +- ti,en-ck32k-xtal: enable external 32-kHz crystal oscillator (see CK32K_CTRL + in TPS6591X datasheet) - ti,en-gpio-sleep: enable sleep control for gpios There should be 9 entries here, one for each gpio. @@ -53,7 +55,7 @@ Example: ti,vmbch-threshold = 0; ti,vmbch2-threshold = 0; - + ti,en-ck32k-xtal; ti,en-gpio-sleep = <0 0 1 0 0 0 0 0 0>; regulators { diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index b0526b7d655..3f27ea1f1ba 100644 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -194,6 +194,9 @@ static struct tps65910_board *tps65910_parse_dt(struct i2c_client *client, else if (*chip_id == TPS65911) dev_warn(&client->dev, "VMBCH2-Threshold not specified"); + prop = of_property_read_bool(np, "ti,en-ck32k-xtal"); + board_info->en_ck32k_xtal = prop; + board_info->irq = client->irq; board_info->irq_base = -1; -- cgit v1.2.3-70-g09d2 From c1516f840dcd91e76712a047993e09d95034a66d Mon Sep 17 00:00:00 2001 From: Yadwinder Singh Brar Date: Fri, 6 Jul 2012 17:02:55 +0530 Subject: mfd: Add device tree support for max77686 This patch adds device tree support for mfd driver and adds Documentation/devicetree/bindings/mfd/max77686.txt. This patch also intialize max77686 pointer to NULL in max77686_i2c_probe to silent a compile time warning. Signed-off-by: Yadwinder Singh Brar Reviwed-by: Mark Brown Signed-off-by: Samuel Ortiz --- Documentation/devicetree/bindings/mfd/max77686.txt | 59 ++++++++++++++++++++++ drivers/mfd/max77686.c | 45 ++++++++++++++--- 2 files changed, 98 insertions(+), 6 deletions(-) create mode 100644 Documentation/devicetree/bindings/mfd/max77686.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/mfd/max77686.txt b/Documentation/devicetree/bindings/mfd/max77686.txt new file mode 100644 index 00000000000..c6a3469d343 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/max77686.txt @@ -0,0 +1,59 @@ +Maxim MAX77686 multi-function device + +MAX77686 is a Mulitifunction device with PMIC, RTC and Charger on chip. It is +interfaced to host controller using i2c interface. PMIC and Charger submodules +are addressed using same i2c slave address whereas RTC submodule uses +different i2c slave address,presently for which we are statically creating i2c +client while probing.This document describes the binding for mfd device and +PMIC submodule. + +Required properties: +- compatible : Must be "maxim,max77686"; +- reg : Specifies the i2c slave address of PMIC block. +- interrupts : This i2c device has an IRQ line connected to the main SoC. +- interrupt-parent : The parent interrupt controller. + +Optional node: +- voltage-regulators : The regulators of max77686 have to be instantiated + under subnode named "voltage-regulators" using the following format. + + regulator_name { + regulator-compatible = LDOn/BUCKn + standard regulator constraints.... + }; + refer Documentation/devicetree/bindings/regulator/regulator.txt + + The regulator-compatible property of regulator should initialized with string +to get matched with their hardware counterparts as follow: + + -LDOn : for LDOs, where n can lie in range 1 to 26. + example: LDO1, LDO2, LDO26. + -BUCKn : for BUCKs, where n can lie in range 1 to 9. + example: BUCK1, BUCK5, BUCK9. + +Example: + + max77686@09 { + compatible = "maxim,max77686"; + interrupt-parent = <&wakeup_eint>; + interrupts = <26 0>; + reg = <0x09>; + + voltage-regulators { + ldo11_reg { + regulator-compatible = "LDO11"; + regulator-name = "vdd_ldo11"; + regulator-min-microvolt = <1900000>; + regulator-max-microvolt = <1900000>; + regulator-always-on; + }; + + buck1_reg { + regulator-compatible = "BUCK1"; + regulator-name = "vdd_mif"; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1300000>; + regulator-always-on; + regulator-boot-on; + }; + } diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c index c66639d681e..3e31d05906b 100644 --- a/drivers/mfd/max77686.c +++ b/drivers/mfd/max77686.c @@ -34,6 +34,11 @@ #define I2C_ADDR_RTC (0x0C >> 1) +static struct of_device_id __devinitdata max77686_pmic_dt_match[] = { + {.compatible = "maxim,max77686", .data = 0}, + {}, +}; + static struct mfd_cell max77686_devs[] = { { .name = "max77686-pmic", }, { .name = "max77686-rtc", }, @@ -44,14 +49,46 @@ static struct regmap_config max77686_regmap_config = { .val_bits = 8, }; +#ifdef CONFIG_OF +static struct max77686_platform_data *max77686_i2c_parse_dt_pdata(struct device + *dev) +{ + struct max77686_platform_data *pd; + + pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); + if (!pd) { + dev_err(dev, "could not allocate memory for pdata\n"); + return NULL; + } + + dev->platform_data = pd; + return pd; +} +#else +static struct max77686_platform_data *max77686_i2c_parse_dt_pdata(struct device + *dev) +{ + return 0; +} +#endif + static int max77686_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { - struct max77686_dev *max77686; + struct max77686_dev *max77686 = NULL; struct max77686_platform_data *pdata = i2c->dev.platform_data; unsigned int data; int ret = 0; + if (i2c->dev.of_node) + pdata = max77686_i2c_parse_dt_pdata(&i2c->dev); + + if (!pdata) { + ret = -EIO; + dev_err(&i2c->dev, "No platform data found.\n"); + goto err; + } + max77686 = kzalloc(sizeof(struct max77686_dev), GFP_KERNEL); if (max77686 == NULL) return -ENOMEM; @@ -70,11 +107,6 @@ static int max77686_i2c_probe(struct i2c_client *i2c, max77686->i2c = i2c; max77686->type = id->driver_data; - if (!pdata) { - ret = -EIO; - goto err; - } - max77686->wakeup = pdata->wakeup; max77686->irq_gpio = pdata->irq_gpio; max77686->irq = i2c->irq; @@ -130,6 +162,7 @@ static struct i2c_driver max77686_i2c_driver = { .driver = { .name = "max77686", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(max77686_pmic_dt_match), }, .probe = max77686_i2c_probe, .remove = max77686_i2c_remove, -- cgit v1.2.3-70-g09d2 From b3d99681227a8c5e1f50bccae0f55930aad2ca77 Mon Sep 17 00:00:00 2001 From: Richard Zhao Date: Sat, 7 Jul 2012 22:56:47 +0800 Subject: usb: otg: add basic mxs phy driver support mxs phy is used in Freescale i.MX SoCs, for example imx23, imx28, imx6Q. This patch adds the basic host support. Signed-off-by: Richard Zhao Signed-off-by: Marek Vasut Cc: Peter Chen Acked-by: Felipe Balbi Tested-by: Subodh Nijsure Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/mxs-phy.txt | 13 ++ drivers/usb/otg/Kconfig | 10 ++ drivers/usb/otg/Makefile | 1 + drivers/usb/otg/mxs-phy.c | 186 ++++++++++++++++++++++ 4 files changed, 210 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/mxs-phy.txt create mode 100644 drivers/usb/otg/mxs-phy.c (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/usb/mxs-phy.txt b/Documentation/devicetree/bindings/usb/mxs-phy.txt new file mode 100644 index 00000000000..5835b27146e --- /dev/null +++ b/Documentation/devicetree/bindings/usb/mxs-phy.txt @@ -0,0 +1,13 @@ +* Freescale MXS USB Phy Device + +Required properties: +- compatible: Should be "fsl,imx23-usbphy" +- reg: Should contain registers location and length +- interrupts: Should contain phy interrupt + +Example: +usbphy1: usbphy@020c9000 { + compatible = "fsl,imx6q-usbphy", "fsl,imx23-usbphy"; + reg = <0x020c9000 0x1000>; + interrupts = <0 44 0x04>; +}; diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig index 5c87db06b59..13fd1ddf742 100644 --- a/drivers/usb/otg/Kconfig +++ b/drivers/usb/otg/Kconfig @@ -116,6 +116,16 @@ config FSL_USB2_OTG help Enable this to support Freescale USB OTG transceiver. +config USB_MXS_PHY + tristate "Freescale MXS USB PHY support" + depends on ARCH_MXC || ARCH_MXS + select STMP_DEVICE + select USB_OTG_UTILS + help + Enable this to support the Freescale MXS USB PHY. + + MXS Phy is used by some of the i.MX SoCs, for example imx23/28/6x. + config USB_MV_OTG tristate "Marvell USB OTG support" depends on USB_EHCI_MV && USB_MV_UDC && USB_SUSPEND diff --git a/drivers/usb/otg/Makefile b/drivers/usb/otg/Makefile index 41aa5098b13..a844b8d35d1 100644 --- a/drivers/usb/otg/Makefile +++ b/drivers/usb/otg/Makefile @@ -20,4 +20,5 @@ obj-$(CONFIG_USB_MSM_OTG) += msm_otg.o obj-$(CONFIG_AB8500_USB) += ab8500-usb.o fsl_usb2_otg-objs := fsl_otg.o otg_fsm.o obj-$(CONFIG_FSL_USB2_OTG) += fsl_usb2_otg.o +obj-$(CONFIG_USB_MXS_PHY) += mxs-phy.o obj-$(CONFIG_USB_MV_OTG) += mv_otg.o diff --git a/drivers/usb/otg/mxs-phy.c b/drivers/usb/otg/mxs-phy.c new file mode 100644 index 00000000000..c1a67cb8e24 --- /dev/null +++ b/drivers/usb/otg/mxs-phy.c @@ -0,0 +1,186 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * Copyright (C) 2012 Marek Vasut + * on behalf of DENX Software Engineering GmbH + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "mxs_phy" + +#define HW_USBPHY_PWD 0x00 +#define HW_USBPHY_CTRL 0x30 +#define HW_USBPHY_CTRL_SET 0x34 +#define HW_USBPHY_CTRL_CLR 0x38 + +#define BM_USBPHY_CTRL_SFTRST BIT(31) +#define BM_USBPHY_CTRL_CLKGATE BIT(30) +#define BM_USBPHY_CTRL_ENUTMILEVEL3 BIT(15) +#define BM_USBPHY_CTRL_ENUTMILEVEL2 BIT(14) +#define BM_USBPHY_CTRL_ENHOSTDISCONDETECT BIT(1) + +struct mxs_phy { + struct usb_phy phy; + struct clk *clk; +}; + +#define to_mxs_phy(p) container_of((p), struct mxs_phy, phy) + +static void mxs_phy_hw_init(struct mxs_phy *mxs_phy) +{ + void __iomem *base = mxs_phy->phy.io_priv; + + stmp_reset_block(base + HW_USBPHY_CTRL); + + /* Power up the PHY */ + writel_relaxed(0, base + HW_USBPHY_PWD); + + /* enable FS/LS device */ + writel_relaxed(BM_USBPHY_CTRL_ENUTMILEVEL2 | + BM_USBPHY_CTRL_ENUTMILEVEL3, + base + HW_USBPHY_CTRL_SET); +} + +static int mxs_phy_init(struct usb_phy *phy) +{ + struct mxs_phy *mxs_phy = to_mxs_phy(phy); + + clk_prepare_enable(mxs_phy->clk); + mxs_phy_hw_init(mxs_phy); + + return 0; +} + +static void mxs_phy_shutdown(struct usb_phy *phy) +{ + struct mxs_phy *mxs_phy = to_mxs_phy(phy); + + writel_relaxed(BM_USBPHY_CTRL_CLKGATE, + phy->io_priv + HW_USBPHY_CTRL_SET); + + clk_disable_unprepare(mxs_phy->clk); +} + +static int mxs_phy_on_connect(struct usb_phy *phy, int port) +{ + dev_dbg(phy->dev, "Connect on port %d\n", port); + + mxs_phy_hw_init(to_mxs_phy(phy)); + writel_relaxed(BM_USBPHY_CTRL_ENHOSTDISCONDETECT, + phy->io_priv + HW_USBPHY_CTRL_SET); + + return 0; +} + +static int mxs_phy_on_disconnect(struct usb_phy *phy, int port) +{ + dev_dbg(phy->dev, "Disconnect on port %d\n", port); + + writel_relaxed(BM_USBPHY_CTRL_ENHOSTDISCONDETECT, + phy->io_priv + HW_USBPHY_CTRL_CLR); + + return 0; +} + +static int mxs_phy_probe(struct platform_device *pdev) +{ + struct resource *res; + void __iomem *base; + struct clk *clk; + struct mxs_phy *mxs_phy; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "can't get device resources\n"); + return -ENOENT; + } + + base = devm_request_and_ioremap(&pdev->dev, res); + if (!base) + return -EBUSY; + + clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, + "can't get the clock, err=%ld", PTR_ERR(clk)); + return PTR_ERR(clk); + } + + mxs_phy = devm_kzalloc(&pdev->dev, sizeof(*mxs_phy), GFP_KERNEL); + if (!mxs_phy) { + dev_err(&pdev->dev, "Failed to allocate USB PHY structure!\n"); + return -ENOMEM; + } + + mxs_phy->phy.io_priv = base; + mxs_phy->phy.dev = &pdev->dev; + mxs_phy->phy.label = DRIVER_NAME; + mxs_phy->phy.init = mxs_phy_init; + mxs_phy->phy.shutdown = mxs_phy_shutdown; + mxs_phy->phy.notify_connect = mxs_phy_on_connect; + mxs_phy->phy.notify_disconnect = mxs_phy_on_disconnect; + + ATOMIC_INIT_NOTIFIER_HEAD(&mxs_phy->phy.notifier); + + mxs_phy->clk = clk; + + platform_set_drvdata(pdev, &mxs_phy->phy); + + return 0; +} + +static int __devexit mxs_phy_remove(struct platform_device *pdev) +{ + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static const struct of_device_id mxs_phy_dt_ids[] = { + { .compatible = "fsl,imx23-usbphy", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mxs_phy_dt_ids); + +static struct platform_driver mxs_phy_driver = { + .probe = mxs_phy_probe, + .remove = __devexit_p(mxs_phy_remove), + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = mxs_phy_dt_ids, + }, +}; + +static int __init mxs_phy_module_init(void) +{ + return platform_driver_register(&mxs_phy_driver); +} +postcore_initcall(mxs_phy_module_init); + +static void __exit mxs_phy_module_exit(void) +{ + platform_driver_unregister(&mxs_phy_driver); +} +module_exit(mxs_phy_module_exit); + +MODULE_ALIAS("platform:mxs-usb-phy"); +MODULE_AUTHOR("Marek Vasut "); +MODULE_AUTHOR("Richard Zhao "); +MODULE_DESCRIPTION("Freescale MXS USB PHY driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-70-g09d2 From 1530280084c3905be6fce802cbfa83fb3bbb8839 Mon Sep 17 00:00:00 2001 From: Richard Zhao Date: Sat, 7 Jul 2012 22:56:48 +0800 Subject: usb: chipidea: add imx platform driver This patch supports only the host-mode functionality so far. Signed-off-by: Richard Zhao Signed-off-by: Marek Vasut Cc: Peter Chen Cc: Alexander Shishkin Cc: Felipe Balbi Tested-by: Subodh Nijsure Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/usb/ci13xxx-imx.txt | 18 ++ drivers/usb/chipidea/Makefile | 3 + drivers/usb/chipidea/ci13xxx_imx.c | 198 +++++++++++++++++++++ 3 files changed, 219 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/ci13xxx-imx.txt create mode 100644 drivers/usb/chipidea/ci13xxx_imx.c (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt b/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt new file mode 100644 index 00000000000..2c290418bb2 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt @@ -0,0 +1,18 @@ +* Freescale i.MX ci13xxx usb controllers + +Required properties: +- compatible: Should be "fsl,imx27-usb" +- reg: Should contain registers location and length +- interrupts: Should contain controller interrupt + +Optional properties: +- fsl,usbphy: phandler of usb phy that connects to the only one port +- vbus-supply: regulator for vbus + +Examples: +usb@02184000 { /* USB OTG */ + compatible = "fsl,imx6q-usb", "fsl,imx27-usb"; + reg = <0x02184000 0x200>; + interrupts = <0 43 0x04>; + fsl,usbphy = <&usbphy1>; +}; diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile index b69900a62a4..5c66d9c330c 100644 --- a/drivers/usb/chipidea/Makefile +++ b/drivers/usb/chipidea/Makefile @@ -14,3 +14,6 @@ ifneq ($(CONFIG_PCI),) obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_pci.o endif +ifneq ($(CONFIG_OF_DEVICE),) + obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_imx.o +endif diff --git a/drivers/usb/chipidea/ci13xxx_imx.c b/drivers/usb/chipidea/ci13xxx_imx.c new file mode 100644 index 00000000000..ef60d06835d --- /dev/null +++ b/drivers/usb/chipidea/ci13xxx_imx.c @@ -0,0 +1,198 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * Copyright (C) 2012 Marek Vasut + * on behalf of DENX Software Engineering GmbH + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ci.h" + +#define pdev_to_phy(pdev) \ + ((struct usb_phy *)platform_get_drvdata(pdev)) + +struct ci13xxx_imx_data { + struct device_node *phy_np; + struct usb_phy *phy; + struct platform_device *ci_pdev; + struct clk *clk; + struct regulator *reg_vbus; +}; + +static struct ci13xxx_platform_data ci13xxx_imx_platdata __devinitdata = { + .name = "ci13xxx_imx", + .flags = CI13XXX_REQUIRE_TRANSCEIVER | + CI13XXX_PULLUP_ON_VBUS | + CI13XXX_DISABLE_STREAMING, + .capoffset = DEF_CAPOFFSET, +}; + +static int __devinit ci13xxx_imx_probe(struct platform_device *pdev) +{ + struct ci13xxx_imx_data *data; + struct platform_device *plat_ci, *phy_pdev; + struct device_node *phy_np; + struct resource *res; + struct regulator *reg_vbus; + int ret; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) { + dev_err(&pdev->dev, "Failed to allocate CI13xxx-IMX data!\n"); + return -ENOMEM; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "Can't get device resources!\n"); + return -ENOENT; + } + + data->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(data->clk)) { + dev_err(&pdev->dev, + "Failed to get clock, err=%ld\n", PTR_ERR(data->clk)); + return PTR_ERR(data->clk); + } + + ret = clk_prepare_enable(data->clk); + if (ret) { + dev_err(&pdev->dev, + "Failed to prepare or enable clock, err=%d\n", ret); + return ret; + } + + phy_np = of_parse_phandle(pdev->dev.of_node, "fsl,usbphy", 0); + if (phy_np) { + data->phy_np = phy_np; + phy_pdev = of_find_device_by_node(phy_np); + if (phy_pdev) { + struct usb_phy *phy; + phy = pdev_to_phy(phy_pdev); + if (phy && + try_module_get(phy_pdev->dev.driver->owner)) { + usb_phy_init(phy); + data->phy = phy; + } + } + } + + /* we only support host now, so enable vbus here */ + reg_vbus = devm_regulator_get(&pdev->dev, "vbus"); + if (!IS_ERR(reg_vbus)) { + ret = regulator_enable(reg_vbus); + if (ret) { + dev_err(&pdev->dev, + "Failed to enable vbus regulator, err=%d\n", + ret); + goto put_np; + } + data->reg_vbus = reg_vbus; + } else { + reg_vbus = NULL; + } + + ci13xxx_imx_platdata.phy = data->phy; + + if (!pdev->dev.dma_mask) { + pdev->dev.dma_mask = devm_kzalloc(&pdev->dev, + sizeof(*pdev->dev.dma_mask), GFP_KERNEL); + if (!pdev->dev.dma_mask) { + ret = -ENOMEM; + dev_err(&pdev->dev, "Failed to alloc dma_mask!\n"); + goto err; + } + *pdev->dev.dma_mask = DMA_BIT_MASK(32); + dma_set_coherent_mask(&pdev->dev, *pdev->dev.dma_mask); + } + plat_ci = ci13xxx_add_device(&pdev->dev, + pdev->resource, pdev->num_resources, + &ci13xxx_imx_platdata); + if (IS_ERR(plat_ci)) { + ret = PTR_ERR(plat_ci); + dev_err(&pdev->dev, + "Can't register ci_hdrc platform device, err=%d\n", + ret); + goto err; + } + + data->ci_pdev = plat_ci; + platform_set_drvdata(pdev, data); + + pm_runtime_no_callbacks(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + return 0; + +err: + if (reg_vbus) + regulator_disable(reg_vbus); +put_np: + if (phy_np) + of_node_put(phy_np); + clk_disable_unprepare(data->clk); + return ret; +} + +static int __devexit ci13xxx_imx_remove(struct platform_device *pdev) +{ + struct ci13xxx_imx_data *data = platform_get_drvdata(pdev); + + pm_runtime_disable(&pdev->dev); + ci13xxx_remove_device(data->ci_pdev); + + if (data->reg_vbus) + regulator_disable(data->reg_vbus); + + if (data->phy) { + usb_phy_shutdown(data->phy); + module_put(data->phy->dev->driver->owner); + } + + of_node_put(data->phy_np); + + clk_disable_unprepare(data->clk); + + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static const struct of_device_id ci13xxx_imx_dt_ids[] = { + { .compatible = "fsl,imx27-usb", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ci13xxx_imx_dt_ids); + +static struct platform_driver ci13xxx_imx_driver = { + .probe = ci13xxx_imx_probe, + .remove = __devexit_p(ci13xxx_imx_remove), + .driver = { + .name = "imx_usb", + .owner = THIS_MODULE, + .of_match_table = ci13xxx_imx_dt_ids, + }, +}; + +module_platform_driver(ci13xxx_imx_driver); + +MODULE_ALIAS("platform:imx-usb"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("CI13xxx i.MX USB binding"); +MODULE_AUTHOR("Marek Vasut "); +MODULE_AUTHOR("Richard Zhao "); -- cgit v1.2.3-70-g09d2 From cd4f2d4aa79ccbb2713f33f9c9f24ed21b5fc8fa Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 9 Jul 2012 18:22:53 +0200 Subject: i2c: mxs: Set I2C timing registers for mxs-i2c This patch configures the I2C bus timing registers according to information passed via DT. Currently, 100kHz and 400kHz modes are supported. The TIMING2 register value is wrong in the documentation for i.MX28! This was found and fixed by: Shawn Guo Signed-off-by: Marek Vasut Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/i2c-mxs.txt | 3 ++ arch/arm/boot/dts/imx28.dtsi | 2 + drivers/i2c/busses/i2c-mxs.c | 66 +++++++++++++++++++++++ 3 files changed, 71 insertions(+) (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/i2c/i2c-mxs.txt b/Documentation/devicetree/bindings/i2c/i2c-mxs.txt index 1bfc02de1b0..30ac3a0557f 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-mxs.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-mxs.txt @@ -4,6 +4,8 @@ Required properties: - compatible: Should be "fsl,-i2c" - reg: Should contain registers location and length - interrupts: Should contain ERROR and DMA interrupts +- clock-frequency: Desired I2C bus clock frequency in Hz. + Only 100000Hz and 400000Hz modes are supported. Examples: @@ -13,4 +15,5 @@ i2c0: i2c@80058000 { compatible = "fsl,imx28-i2c"; reg = <0x80058000 2000>; interrupts = <111 68>; + clock-frequency = <100000>; }; diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi index 4634cb861a5..9af1606b5d3 100644 --- a/arch/arm/boot/dts/imx28.dtsi +++ b/arch/arm/boot/dts/imx28.dtsi @@ -381,6 +381,7 @@ compatible = "fsl,imx28-i2c"; reg = <0x80058000 2000>; interrupts = <111 68>; + clock-frequency = <100000>; status = "disabled"; }; @@ -390,6 +391,7 @@ compatible = "fsl,imx28-i2c"; reg = <0x8005a000 2000>; interrupts = <110 69>; + clock-frequency = <100000>; status = "disabled"; }; diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 02ce1faeeee..088c5c1ed17 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -46,6 +46,10 @@ #define MXS_I2C_CTRL0_DIRECTION 0x00010000 #define MXS_I2C_CTRL0_XFER_COUNT(v) ((v) & 0x0000FFFF) +#define MXS_I2C_TIMING0 (0x10) +#define MXS_I2C_TIMING1 (0x20) +#define MXS_I2C_TIMING2 (0x30) + #define MXS_I2C_CTRL1 (0x40) #define MXS_I2C_CTRL1_SET (0x44) #define MXS_I2C_CTRL1_CLR (0x48) @@ -97,6 +101,35 @@ #define MXS_CMD_I2C_READ (MXS_I2C_CTRL0_SEND_NAK_ON_LAST | \ MXS_I2C_CTRL0_MASTER_MODE) +struct mxs_i2c_speed_config { + uint32_t timing0; + uint32_t timing1; + uint32_t timing2; +}; + +/* + * Timing values for the default 24MHz clock supplied into the i2c block. + * + * The bus can operate at 95kHz or at 400kHz with the following timing + * register configurations. The 100kHz mode isn't present because it's + * values are not stated in the i.MX233/i.MX28 datasheet. The 95kHz mode + * shall be close enough replacement. Therefore when the bus is configured + * for 100kHz operation, 95kHz timing settings are actually loaded. + * + * For details, see i.MX233 [25.4.2 - 25.4.4] and i.MX28 [27.5.2 - 27.5.4]. + */ +static const struct mxs_i2c_speed_config mxs_i2c_95kHz_config = { + .timing0 = 0x00780030, + .timing1 = 0x00800030, + .timing2 = 0x00300030, +}; + +static const struct mxs_i2c_speed_config mxs_i2c_400kHz_config = { + .timing0 = 0x000f0007, + .timing1 = 0x001f000f, + .timing2 = 0x00300030, +}; + /** * struct mxs_i2c_dev - per device, private MXS-I2C data * @@ -112,11 +145,17 @@ struct mxs_i2c_dev { struct completion cmd_complete; u32 cmd_err; struct i2c_adapter adapter; + const struct mxs_i2c_speed_config *speed; }; static void mxs_i2c_reset(struct mxs_i2c_dev *i2c) { stmp_reset_block(i2c->regs); + + writel(i2c->speed->timing0, i2c->regs + MXS_I2C_TIMING0); + writel(i2c->speed->timing1, i2c->regs + MXS_I2C_TIMING1); + writel(i2c->speed->timing2, i2c->regs + MXS_I2C_TIMING2); + writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET); writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE, i2c->regs + MXS_I2C_QUEUECTRL_SET); @@ -319,6 +358,28 @@ static const struct i2c_algorithm mxs_i2c_algo = { .functionality = mxs_i2c_func, }; +static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c) +{ + uint32_t speed; + struct device *dev = i2c->dev; + struct device_node *node = dev->of_node; + int ret; + + if (!node) + return -EINVAL; + + i2c->speed = &mxs_i2c_95kHz_config; + ret = of_property_read_u32(node, "clock-frequency", &speed); + if (ret) + dev_warn(dev, "No I2C speed selected, using 100kHz\n"); + else if (speed == 400000) + i2c->speed = &mxs_i2c_400kHz_config; + else if (speed != 100000) + dev_warn(dev, "Unsupported I2C speed selected, using 100kHz\n"); + + return 0; +} + static int __devinit mxs_i2c_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -358,6 +419,11 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev) return err; i2c->dev = dev; + + err = mxs_i2c_get_ofdata(i2c); + if (err) + return err; + platform_set_drvdata(pdev, i2c); /* Do reset to enforce correct startup after pinmuxing */ -- cgit v1.2.3-70-g09d2 From 9ae97a8996a6d6f66e2fbc221906e2406d6c261f Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Fri, 13 Jul 2012 19:14:22 +0530 Subject: i2c: i2c-ocores: DT bindings and minor fixes. Cleanups to i2c-cores, no change in logic, changes are: * Move i2c-ocores device tree documentation from source file to Documentation/devicetree/bindings/i2c/i2c-ocores.txt. * Add \n to dev_warn and dev_err messages where missing * Minor updates to the text and formatting fixes. Signed-off-by: Jayachandran C Signed-off-by: Wolfram Sang --- .../devicetree/bindings/i2c/i2c-ocores.txt | 27 +++++++++++++ drivers/i2c/busses/i2c-ocores.c | 45 ++++------------------ 2 files changed, 34 insertions(+), 38 deletions(-) create mode 100644 Documentation/devicetree/bindings/i2c/i2c-ocores.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt new file mode 100644 index 00000000000..bfec8941509 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt @@ -0,0 +1,27 @@ +Device tree configuration for i2c-ocores + +Required properties: +- compatible : "opencores,i2c-ocores" +- reg : bus address start and address range size of device +- interrupts : interrupt number +- regstep : size of device registers in bytes +- clock-frequency : frequency of bus clock in Hz +- #address-cells : should be <1> +- #size-cells : should be <0> + +Example: + + i2c0: ocores@a0000000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "opencores,i2c-ocores"; + reg = <0xa0000000 0x8>; + interrupts = <10>; + regstep = <1>; + clock-frequency = <20000000>; + + dummy@60 { + compatible = "dummy"; + reg = <0x60>; + }; + }; diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index d7d21d53255..f6e7ad9f60e 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -10,40 +10,9 @@ */ /* - * Device tree configuration: - * - * Required properties: - * - compatible : "opencores,i2c-ocores" - * - reg : bus address start and address range size of device - * - interrupts : interrupt number - * - regstep : size of device registers in bytes - * - clock-frequency : frequency of bus clock in Hz - * - * Example: - * - * i2c0: ocores@a0000000 { - * compatible = "opencores,i2c-ocores"; - * reg = <0xa0000000 0x8>; - * interrupts = <10>; - * - * regstep = <1>; - * clock-frequency = <20000000>; - * - * -- Devices connected on this I2C bus get - * -- defined here; address- and size-cells - * -- apply to these child devices - * - * #address-cells = <1>; - * #size-cells = <0>; - * - * dummy@60 { - * compatible = "dummy"; - * reg = <60>; - * }; - * }; - * + * This driver can be used from the device tree, see + * Documentation/devicetree/bindings/i2c/ocore-i2c.txt */ - #include #include #include @@ -247,14 +216,14 @@ static struct i2c_adapter ocores_adapter = { }; #ifdef CONFIG_OF -static int ocores_i2c_of_probe(struct platform_device* pdev, - struct ocores_i2c* i2c) +static int ocores_i2c_of_probe(struct platform_device *pdev, + struct ocores_i2c *i2c) { const __be32* val; val = of_get_property(pdev->dev.of_node, "regstep", NULL); if (!val) { - dev_err(&pdev->dev, "Missing required parameter 'regstep'"); + dev_err(&pdev->dev, "Missing required parameter 'regstep'\n"); return -ENODEV; } i2c->regstep = be32_to_cpup(val); @@ -262,7 +231,7 @@ static int ocores_i2c_of_probe(struct platform_device* pdev, val = of_get_property(pdev->dev.of_node, "clock-frequency", NULL); if (!val) { dev_err(&pdev->dev, - "Missing required parameter 'clock-frequency'"); + "Missing required parameter 'clock-frequency'\n"); return -ENODEV; } i2c->clock_khz = be32_to_cpup(val) / 1000; @@ -351,7 +320,7 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) return 0; } -static int __devexit ocores_i2c_remove(struct platform_device* pdev) +static int __devexit ocores_i2c_remove(struct platform_device *pdev) { struct ocores_i2c *i2c = platform_get_drvdata(pdev); -- cgit v1.2.3-70-g09d2 From 8bb986a816148d6e8fbaae23be0fee33d6a1ae3f Mon Sep 17 00:00:00 2001 From: Ganesan Ramalingam Date: Fri, 13 Jul 2012 19:14:23 +0530 Subject: i2c: i2c-ocores: Use reg-shift property Deprecate 'regstep' property and use the standard 'reg-shift' property for register offset shifts. 'regstep' will still be supported as an optional property, but will give a warning when used. Signed-off-by: Ganesan Ramalingam Signed-off-by: Jayachandran C Signed-off-by: Wolfram Sang --- .../devicetree/bindings/i2c/i2c-ocores.txt | 8 +++-- drivers/i2c/busses/i2c-ocores.c | 36 +++++++++++++--------- include/linux/i2c-ocores.h | 2 +- 3 files changed, 29 insertions(+), 17 deletions(-) (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt index bfec8941509..1c9334bfc39 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt @@ -4,11 +4,14 @@ Required properties: - compatible : "opencores,i2c-ocores" - reg : bus address start and address range size of device - interrupts : interrupt number -- regstep : size of device registers in bytes - clock-frequency : frequency of bus clock in Hz - #address-cells : should be <1> - #size-cells : should be <0> +Optional properties: +- reg-shift : device register offsets are shifted by this value +- regstep : deprecated, use reg-shift above + Example: i2c0: ocores@a0000000 { @@ -17,9 +20,10 @@ Example: compatible = "opencores,i2c-ocores"; reg = <0xa0000000 0x8>; interrupts = <10>; - regstep = <1>; clock-frequency = <20000000>; + reg-shift = <0>; /* 8 bit registers */ + dummy@60 { compatible = "dummy"; reg = <0x60>; diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index f6e7ad9f60e..9e0709d5fb3 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -25,10 +25,11 @@ #include #include #include +#include struct ocores_i2c { void __iomem *base; - int regstep; + u32 reg_shift; wait_queue_head_t wait; struct i2c_adapter adap; struct i2c_msg *msg; @@ -71,12 +72,12 @@ struct ocores_i2c { static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value) { - iowrite8(value, i2c->base + reg * i2c->regstep); + iowrite8(value, i2c->base + (reg << i2c->reg_shift)); } static inline u8 oc_getreg(struct ocores_i2c *i2c, int reg) { - return ioread8(i2c->base + reg * i2c->regstep); + return ioread8(i2c->base + (reg << i2c->reg_shift)); } static void ocores_process(struct ocores_i2c *i2c) @@ -219,22 +220,29 @@ static struct i2c_adapter ocores_adapter = { static int ocores_i2c_of_probe(struct platform_device *pdev, struct ocores_i2c *i2c) { - const __be32* val; - - val = of_get_property(pdev->dev.of_node, "regstep", NULL); - if (!val) { - dev_err(&pdev->dev, "Missing required parameter 'regstep'\n"); - return -ENODEV; + struct device_node *np = pdev->dev.of_node; + u32 val; + + if (of_property_read_u32(np, "reg-shift", &i2c->reg_shift)) { + /* no 'reg-shift', check for deprecated 'regstep' */ + if (!of_property_read_u32(np, "regstep", &val)) { + if (!is_power_of_2(val)) { + dev_err(&pdev->dev, "invalid regstep %d\n", + val); + return -EINVAL; + } + i2c->reg_shift = ilog2(val); + dev_warn(&pdev->dev, + "regstep property deprecated, use reg-shift\n"); + } } - i2c->regstep = be32_to_cpup(val); - val = of_get_property(pdev->dev.of_node, "clock-frequency", NULL); - if (!val) { + if (of_property_read_u32(np, "clock-frequency", &val)) { dev_err(&pdev->dev, "Missing required parameter 'clock-frequency'\n"); return -ENODEV; } - i2c->clock_khz = be32_to_cpup(val) / 1000; + i2c->clock_khz = val / 1000; return 0; } @@ -277,7 +285,7 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) pdata = pdev->dev.platform_data; if (pdata) { - i2c->regstep = pdata->regstep; + i2c->reg_shift = pdata->reg_shift; i2c->clock_khz = pdata->clock_khz; } else { ret = ocores_i2c_of_probe(pdev, i2c); diff --git a/include/linux/i2c-ocores.h b/include/linux/i2c-ocores.h index 4d5e57ff661..5d95df2436f 100644 --- a/include/linux/i2c-ocores.h +++ b/include/linux/i2c-ocores.h @@ -12,7 +12,7 @@ #define _LINUX_I2C_OCORES_H struct ocores_i2c_platform_data { - u32 regstep; /* distance between registers */ + u32 reg_shift; /* register offset shift value */ u32 clock_khz; /* input clock in kHz */ u8 num_devices; /* number of devices in the devices list */ struct i2c_board_info const *devices; /* devices connected to the bus */ -- cgit v1.2.3-70-g09d2 From 7326e38ffe894d0cd2904704b7d8c53d4a55d752 Mon Sep 17 00:00:00 2001 From: Ganesan Ramalingam Date: Fri, 13 Jul 2012 19:14:25 +0530 Subject: i2c: i2c-ocores: support for 16bit and 32bit IO Some architectures supports only 16-bit or 32-bit read/write access to their IO space. Add a 'reg-io-width' platform and OF parameter which specifies the IO width to support these platforms. reg-io-width can be specified as 1, 2 or 4, and has a default value of 1 if it is unspecified. Signed-off-by: Ganesan Ramalingam Signed-off-by: Jayachandran C Signed-off-by: Wolfram Sang --- .../devicetree/bindings/i2c/i2c-ocores.txt | 2 ++ drivers/i2c/busses/i2c-ocores.c | 21 +++++++++++++++++++-- include/linux/i2c-ocores.h | 1 + 3 files changed, 22 insertions(+), 2 deletions(-) (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt index 1c9334bfc39..c15781f4dc8 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt @@ -10,6 +10,7 @@ Required properties: Optional properties: - reg-shift : device register offsets are shifted by this value +- reg-io-width : io register width in bytes (1, 2 or 4) - regstep : deprecated, use reg-shift above Example: @@ -23,6 +24,7 @@ Example: clock-frequency = <20000000>; reg-shift = <0>; /* 8 bit registers */ + reg-io-width = <1>; /* 8 bit read/write */ dummy@60 { compatible = "dummy"; diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index 9e0709d5fb3..bffd5501ac2 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -30,6 +30,7 @@ struct ocores_i2c { void __iomem *base; u32 reg_shift; + u32 reg_io_width; wait_queue_head_t wait; struct i2c_adapter adap; struct i2c_msg *msg; @@ -72,12 +73,22 @@ struct ocores_i2c { static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value) { - iowrite8(value, i2c->base + (reg << i2c->reg_shift)); + if (i2c->reg_io_width == 4) + iowrite32(value, i2c->base + (reg << i2c->reg_shift)); + else if (i2c->reg_io_width == 2) + iowrite16(value, i2c->base + (reg << i2c->reg_shift)); + else + iowrite8(value, i2c->base + (reg << i2c->reg_shift)); } static inline u8 oc_getreg(struct ocores_i2c *i2c, int reg) { - return ioread8(i2c->base + (reg << i2c->reg_shift)); + if (i2c->reg_io_width == 4) + return ioread32(i2c->base + (reg << i2c->reg_shift)); + else if (i2c->reg_io_width == 2) + return ioread16(i2c->base + (reg << i2c->reg_shift)); + else + return ioread8(i2c->base + (reg << i2c->reg_shift)); } static void ocores_process(struct ocores_i2c *i2c) @@ -244,6 +255,8 @@ static int ocores_i2c_of_probe(struct platform_device *pdev, } i2c->clock_khz = val / 1000; + of_property_read_u32(pdev->dev.of_node, "reg-io-width", + &i2c->reg_io_width); return 0; } #else @@ -286,6 +299,7 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) pdata = pdev->dev.platform_data; if (pdata) { i2c->reg_shift = pdata->reg_shift; + i2c->reg_io_width = pdata->reg_io_width; i2c->clock_khz = pdata->clock_khz; } else { ret = ocores_i2c_of_probe(pdev, i2c); @@ -293,6 +307,9 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) return ret; } + if (i2c->reg_io_width == 0) + i2c->reg_io_width = 1; /* Set to default value */ + ocores_init(i2c); init_waitqueue_head(&i2c->wait); diff --git a/include/linux/i2c-ocores.h b/include/linux/i2c-ocores.h index 5d95df2436f..1c06b5c7c30 100644 --- a/include/linux/i2c-ocores.h +++ b/include/linux/i2c-ocores.h @@ -13,6 +13,7 @@ struct ocores_i2c_platform_data { u32 reg_shift; /* register offset shift value */ + u32 reg_io_width; /* register io read/write width */ u32 clock_khz; /* input clock in kHz */ u8 num_devices; /* number of devices in the devices list */ struct i2c_board_info const *devices; /* devices connected to the bus */ -- cgit v1.2.3-70-g09d2 From ad95ad10b0881dd317d833dd37ba6706d704073a Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Fri, 13 Jul 2012 12:42:26 +0200 Subject: Documentation: Describe the AB8500 Device Tree bindings Although for the most part, the AB8500 uses common bindings, some of the ways in which they are used differ slightly to the common uses of those bindings. To clear up some of these varying concepts we provide some documentation describing each of the properties and how they are used. Signed-off-by: Lee Jones Acked-by: Arnd Bergmann Acked-by: Linus Walleij Signed-off-by: Samuel Ortiz --- Documentation/devicetree/bindings/mfd/ab8500.txt | 123 +++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 Documentation/devicetree/bindings/mfd/ab8500.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/mfd/ab8500.txt b/Documentation/devicetree/bindings/mfd/ab8500.txt new file mode 100644 index 00000000000..69e757a657a --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/ab8500.txt @@ -0,0 +1,123 @@ +* AB8500 Multi-Functional Device (MFD) + +Required parent device properties: +- compatible : contains "stericsson,ab8500"; +- interrupts : contains the IRQ line for the AB8500 +- interrupt-controller : describes the AB8500 as an Interrupt Controller (has its own domain) +- #interrupt-cells : should be 2, for 2-cell format + - The first cell is the AB8500 local IRQ number + - The second cell is used to specify optional parameters + - bits[3:0] trigger type and level flags: + 1 = low-to-high edge triggered + 2 = high-to-low edge triggered + 4 = active high level-sensitive + 8 = active low level-sensitive + +Optional parent device properties: +- reg : contains the PRCMU mailbox address for the AB8500 i2c port + +The AB8500 consists of a large and varied group of sub-devices: + +Device IRQ Names Supply Names Description +------ --------- ------------ ----------- +ab8500-bm : : : Battery Manager +ab8500-btemp : : : Battery Temperature +ab8500-charger : : : Battery Charger +ab8500-fg : : : Fuel Gauge +ab8500-gpadc : HW_CONV_END : vddadc : Analogue to Digital Converter + SW_CONV_END : : +ab8500-gpio : : : GPIO Controller +ab8500-ponkey : ONKEY_DBF : : Power-on Key + ONKEY_DBR : : +ab8500-pwm : : : Pulse Width Modulator +ab8500-regulator : : : Regulators +ab8500-rtc : 60S : : Real Time Clock + : ALARM : : +ab8500-sysctrl : : : System Control +ab8500-usb : ID_WAKEUP_R : vddulpivio18 : Universal Serial Bus + : ID_WAKEUP_F : v-ape : + : VBUS_DET_F : musb_1v8 : + : VBUS_DET_R : : + : USB_LINK_STATUS : : + : USB_ADP_PROBE_PLUG : : + : USB_ADP_PROBE_UNPLUG : : + +Required child device properties: +- compatible : "stericsson,ab8500-[bm|btemp|charger|fg|gpadc|gpio|ponkey| + pwm|regulator|rtc|sysctrl|usb]"; + +Optional child device properties: +- interrupts : contains the device IRQ(s) using the 2-cell format (see above) +- interrupt-names : contains names of IRQ resource in the order in which they were + supplied in the interrupts property +- -supply : contains a phandle to the regulator supply node in Device Tree + +ab8500@5 { + compatible = "stericsson,ab8500"; + reg = <5>; /* mailbox 5 is i2c */ + interrupts = <0 40 0x4>; + interrupt-controller; + #interrupt-cells = <2>; + + ab8500-rtc { + compatible = "stericsson,ab8500-rtc"; + interrupts = <17 0x4 + 18 0x4>; + interrupt-names = "60S", "ALARM"; + }; + + ab8500-gpadc { + compatible = "stericsson,ab8500-gpadc"; + interrupts = <32 0x4 + 39 0x4>; + interrupt-names = "HW_CONV_END", "SW_CONV_END"; + vddadc-supply = <&ab8500_ldo_tvout_reg>; + }; + + ab8500-usb { + compatible = "stericsson,ab8500-usb"; + interrupts = < 90 0x4 + 96 0x4 + 14 0x4 + 15 0x4 + 79 0x4 + 74 0x4 + 75 0x4>; + interrupt-names = "ID_WAKEUP_R", + "ID_WAKEUP_F", + "VBUS_DET_F", + "VBUS_DET_R", + "USB_LINK_STATUS", + "USB_ADP_PROBE_PLUG", + "USB_ADP_PROBE_UNPLUG"; + vddulpivio18-supply = <&ab8500_ldo_initcore_reg>; + v-ape-supply = <&db8500_vape_reg>; + musb_1v8-supply = <&db8500_vsmps2_reg>; + }; + + ab8500-ponkey { + compatible = "stericsson,ab8500-ponkey"; + interrupts = <6 0x4 + 7 0x4>; + interrupt-names = "ONKEY_DBF", "ONKEY_DBR"; + }; + + ab8500-sysctrl { + compatible = "stericsson,ab8500-sysctrl"; + }; + + ab8500-pwm { + compatible = "stericsson,ab8500-pwm"; + }; + + ab8500-regulators { + compatible = "stericsson,ab8500-regulator"; + + ab8500_ldo_aux1_reg: ab8500_ldo_aux1 { + /* + * See: Documentation/devicetree/bindings/regulator/regulator.txt + * for more information on regulators + */ + }; + }; +}; -- cgit v1.2.3-70-g09d2 From f447ed8b31da7b24c7c75c2d4624598135b41217 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Mon, 25 Jun 2012 21:18:21 -0700 Subject: gpio: samsung: add flags specifier to device-tree binding This adds a flags field to the gpio specifier for Samsung. I didn't want to add yet another field in the already quite long specifier, so I decided to compress it together with the Pull Up/Down settings instead. This is needed to, for example, have a gpio-keys input that is active low. Signed-off-by: Olof Johansson Signed-off-by: Linus Walleij --- Documentation/devicetree/bindings/gpio/gpio-samsung.txt | 9 +++++---- drivers/gpio/gpio-samsung.c | 5 ++++- 2 files changed, 9 insertions(+), 5 deletions(-) (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/gpio/gpio-samsung.txt b/Documentation/devicetree/bindings/gpio/gpio-samsung.txt index 8f50fe5e6c4..5375625e8cd 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-samsung.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-samsung.txt @@ -11,14 +11,15 @@ Required properties: <[phandle of the gpio controller node] [pin number within the gpio controller] [mux function] - [pull up/down] + [flags and pull up/down] [drive strength]> Values for gpio specifier: - Pin number: is a value between 0 to 7. - - Pull Up/Down: 0 - Pull Up/Down Disabled. - 1 - Pull Down Enabled. - 3 - Pull Up Enabled. + - Flags and Pull Up/Down: 0 - Pull Up/Down Disabled. + 1 - Pull Down Enabled. + 3 - Pull Up Enabled. + Bit 16 (0x00010000) - Input is active low. - Drive Strength: 0 - 1x, 1 - 3x, 2 - 2x, diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index b6453d0e44a..92f7b2bb79d 100644 --- a/drivers/gpio/gpio-samsung.c +++ b/drivers/gpio/gpio-samsung.c @@ -2681,11 +2681,14 @@ static int exynos_gpio_xlate(struct gpio_chip *gc, if (s3c_gpio_cfgpin(pin, S3C_GPIO_SFN(gpiospec->args[1]))) pr_warn("gpio_xlate: failed to set pin function\n"); - if (s3c_gpio_setpull(pin, gpiospec->args[2])) + if (s3c_gpio_setpull(pin, gpiospec->args[2] & 0xffff)) pr_warn("gpio_xlate: failed to set pin pull up/down\n"); if (s5p_gpio_set_drvstr(pin, gpiospec->args[3])) pr_warn("gpio_xlate: failed to set pin drive strength\n"); + if (flags) + *flags = gpiospec->args[2] >> 16; + return gpiospec->args[0]; } -- cgit v1.2.3-70-g09d2 From aeb27748e3bc1e89ec590713e574cb6f885cc3c6 Mon Sep 17 00:00:00 2001 From: Benoît Thébaudeau Date: Fri, 22 Jun 2012 21:04:06 +0200 Subject: gpio/mxc: use the edge_sel feature if available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some mxc processors have an edge_sel feature, which allows the IRQ to be triggered by any edge. This patch makes use of this feature if available, which skips mxc_flip_edge(). Cc: Grant Likely Cc: Linus Walleij Acked-by: Sascha Hauer Cc: Signed-off-by: Benoît Thébaudeau Signed-off-by: Linus Walleij --- .../devicetree/bindings/gpio/fsl-imx-gpio.txt | 2 +- arch/arm/boot/dts/imx51.dtsi | 8 +-- arch/arm/boot/dts/imx53.dtsi | 14 ++--- arch/arm/boot/dts/imx6q.dtsi | 14 ++--- arch/arm/mach-imx/mm-imx25.c | 10 +-- arch/arm/mach-imx/mm-imx3.c | 7 +-- arch/arm/mach-imx/mm-imx5.c | 40 ++++++------ drivers/gpio/gpio-mxc.c | 71 +++++++++++++++++----- 8 files changed, 104 insertions(+), 62 deletions(-) (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/gpio/fsl-imx-gpio.txt b/Documentation/devicetree/bindings/gpio/fsl-imx-gpio.txt index 4363ae4b3c1..33a0345eef3 100644 --- a/Documentation/devicetree/bindings/gpio/fsl-imx-gpio.txt +++ b/Documentation/devicetree/bindings/gpio/fsl-imx-gpio.txt @@ -14,7 +14,7 @@ Required properties: Example: gpio0: gpio@73f84000 { - compatible = "fsl,imx51-gpio", "fsl,imx31-gpio"; + compatible = "fsl,imx51-gpio", "fsl,imx35-gpio"; reg = <0x73f84000 0x4000>; interrupts = <50 51>; gpio-controller; diff --git a/arch/arm/boot/dts/imx51.dtsi b/arch/arm/boot/dts/imx51.dtsi index bfa65abe8ef..9c95abcb3ce 100644 --- a/arch/arm/boot/dts/imx51.dtsi +++ b/arch/arm/boot/dts/imx51.dtsi @@ -127,7 +127,7 @@ }; gpio1: gpio@73f84000 { - compatible = "fsl,imx51-gpio", "fsl,imx31-gpio"; + compatible = "fsl,imx51-gpio", "fsl,imx35-gpio"; reg = <0x73f84000 0x4000>; interrupts = <50 51>; gpio-controller; @@ -137,7 +137,7 @@ }; gpio2: gpio@73f88000 { - compatible = "fsl,imx51-gpio", "fsl,imx31-gpio"; + compatible = "fsl,imx51-gpio", "fsl,imx35-gpio"; reg = <0x73f88000 0x4000>; interrupts = <52 53>; gpio-controller; @@ -147,7 +147,7 @@ }; gpio3: gpio@73f8c000 { - compatible = "fsl,imx51-gpio", "fsl,imx31-gpio"; + compatible = "fsl,imx51-gpio", "fsl,imx35-gpio"; reg = <0x73f8c000 0x4000>; interrupts = <54 55>; gpio-controller; @@ -157,7 +157,7 @@ }; gpio4: gpio@73f90000 { - compatible = "fsl,imx51-gpio", "fsl,imx31-gpio"; + compatible = "fsl,imx51-gpio", "fsl,imx35-gpio"; reg = <0x73f90000 0x4000>; interrupts = <56 57>; gpio-controller; diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi index e3e869470cd..506ed5c9364 100644 --- a/arch/arm/boot/dts/imx53.dtsi +++ b/arch/arm/boot/dts/imx53.dtsi @@ -129,7 +129,7 @@ }; gpio1: gpio@53f84000 { - compatible = "fsl,imx53-gpio", "fsl,imx31-gpio"; + compatible = "fsl,imx53-gpio", "fsl,imx35-gpio"; reg = <0x53f84000 0x4000>; interrupts = <50 51>; gpio-controller; @@ -139,7 +139,7 @@ }; gpio2: gpio@53f88000 { - compatible = "fsl,imx53-gpio", "fsl,imx31-gpio"; + compatible = "fsl,imx53-gpio", "fsl,imx35-gpio"; reg = <0x53f88000 0x4000>; interrupts = <52 53>; gpio-controller; @@ -149,7 +149,7 @@ }; gpio3: gpio@53f8c000 { - compatible = "fsl,imx53-gpio", "fsl,imx31-gpio"; + compatible = "fsl,imx53-gpio", "fsl,imx35-gpio"; reg = <0x53f8c000 0x4000>; interrupts = <54 55>; gpio-controller; @@ -159,7 +159,7 @@ }; gpio4: gpio@53f90000 { - compatible = "fsl,imx53-gpio", "fsl,imx31-gpio"; + compatible = "fsl,imx53-gpio", "fsl,imx35-gpio"; reg = <0x53f90000 0x4000>; interrupts = <56 57>; gpio-controller; @@ -197,7 +197,7 @@ }; gpio5: gpio@53fdc000 { - compatible = "fsl,imx53-gpio", "fsl,imx31-gpio"; + compatible = "fsl,imx53-gpio", "fsl,imx35-gpio"; reg = <0x53fdc000 0x4000>; interrupts = <103 104>; gpio-controller; @@ -207,7 +207,7 @@ }; gpio6: gpio@53fe0000 { - compatible = "fsl,imx53-gpio", "fsl,imx31-gpio"; + compatible = "fsl,imx53-gpio", "fsl,imx35-gpio"; reg = <0x53fe0000 0x4000>; interrupts = <105 106>; gpio-controller; @@ -217,7 +217,7 @@ }; gpio7: gpio@53fe4000 { - compatible = "fsl,imx53-gpio", "fsl,imx31-gpio"; + compatible = "fsl,imx53-gpio", "fsl,imx35-gpio"; reg = <0x53fe4000 0x4000>; interrupts = <107 108>; gpio-controller; diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi index 8c90cbac945..da78fd83f62 100644 --- a/arch/arm/boot/dts/imx6q.dtsi +++ b/arch/arm/boot/dts/imx6q.dtsi @@ -260,7 +260,7 @@ }; gpio1: gpio@0209c000 { - compatible = "fsl,imx6q-gpio", "fsl,imx31-gpio"; + compatible = "fsl,imx6q-gpio", "fsl,imx35-gpio"; reg = <0x0209c000 0x4000>; interrupts = <0 66 0x04 0 67 0x04>; gpio-controller; @@ -270,7 +270,7 @@ }; gpio2: gpio@020a0000 { - compatible = "fsl,imx6q-gpio", "fsl,imx31-gpio"; + compatible = "fsl,imx6q-gpio", "fsl,imx35-gpio"; reg = <0x020a0000 0x4000>; interrupts = <0 68 0x04 0 69 0x04>; gpio-controller; @@ -280,7 +280,7 @@ }; gpio3: gpio@020a4000 { - compatible = "fsl,imx6q-gpio", "fsl,imx31-gpio"; + compatible = "fsl,imx6q-gpio", "fsl,imx35-gpio"; reg = <0x020a4000 0x4000>; interrupts = <0 70 0x04 0 71 0x04>; gpio-controller; @@ -290,7 +290,7 @@ }; gpio4: gpio@020a8000 { - compatible = "fsl,imx6q-gpio", "fsl,imx31-gpio"; + compatible = "fsl,imx6q-gpio", "fsl,imx35-gpio"; reg = <0x020a8000 0x4000>; interrupts = <0 72 0x04 0 73 0x04>; gpio-controller; @@ -300,7 +300,7 @@ }; gpio5: gpio@020ac000 { - compatible = "fsl,imx6q-gpio", "fsl,imx31-gpio"; + compatible = "fsl,imx6q-gpio", "fsl,imx35-gpio"; reg = <0x020ac000 0x4000>; interrupts = <0 74 0x04 0 75 0x04>; gpio-controller; @@ -310,7 +310,7 @@ }; gpio6: gpio@020b0000 { - compatible = "fsl,imx6q-gpio", "fsl,imx31-gpio"; + compatible = "fsl,imx6q-gpio", "fsl,imx35-gpio"; reg = <0x020b0000 0x4000>; interrupts = <0 76 0x04 0 77 0x04>; gpio-controller; @@ -320,7 +320,7 @@ }; gpio7: gpio@020b4000 { - compatible = "fsl,imx6q-gpio", "fsl,imx31-gpio"; + compatible = "fsl,imx6q-gpio", "fsl,imx35-gpio"; reg = <0x020b4000 0x4000>; interrupts = <0 78 0x04 0 79 0x04>; gpio-controller; diff --git a/arch/arm/mach-imx/mm-imx25.c b/arch/arm/mach-imx/mm-imx25.c index 6ff37140a4f..8e8ddb81bd0 100644 --- a/arch/arm/mach-imx/mm-imx25.c +++ b/arch/arm/mach-imx/mm-imx25.c @@ -90,11 +90,11 @@ static const struct resource imx25_audmux_res[] __initconst = { void __init imx25_soc_init(void) { - /* i.mx25 has the i.mx31 type gpio */ - mxc_register_gpio("imx31-gpio", 0, MX25_GPIO1_BASE_ADDR, SZ_16K, MX25_INT_GPIO1, 0); - mxc_register_gpio("imx31-gpio", 1, MX25_GPIO2_BASE_ADDR, SZ_16K, MX25_INT_GPIO2, 0); - mxc_register_gpio("imx31-gpio", 2, MX25_GPIO3_BASE_ADDR, SZ_16K, MX25_INT_GPIO3, 0); - mxc_register_gpio("imx31-gpio", 3, MX25_GPIO4_BASE_ADDR, SZ_16K, MX25_INT_GPIO4, 0); + /* i.mx25 has the i.mx35 type gpio */ + mxc_register_gpio("imx35-gpio", 0, MX25_GPIO1_BASE_ADDR, SZ_16K, MX25_INT_GPIO1, 0); + mxc_register_gpio("imx35-gpio", 1, MX25_GPIO2_BASE_ADDR, SZ_16K, MX25_INT_GPIO2, 0); + mxc_register_gpio("imx35-gpio", 2, MX25_GPIO3_BASE_ADDR, SZ_16K, MX25_INT_GPIO3, 0); + mxc_register_gpio("imx35-gpio", 3, MX25_GPIO4_BASE_ADDR, SZ_16K, MX25_INT_GPIO4, 0); pinctrl_provide_dummies(); /* i.mx25 has the i.mx35 type sdma */ diff --git a/arch/arm/mach-imx/mm-imx3.c b/arch/arm/mach-imx/mm-imx3.c index a8983b9778d..8e51e77b3c6 100644 --- a/arch/arm/mach-imx/mm-imx3.c +++ b/arch/arm/mach-imx/mm-imx3.c @@ -273,10 +273,9 @@ void __init imx35_soc_init(void) imx3_init_l2x0(); - /* i.mx35 has the i.mx31 type gpio */ - mxc_register_gpio("imx31-gpio", 0, MX35_GPIO1_BASE_ADDR, SZ_16K, MX35_INT_GPIO1, 0); - mxc_register_gpio("imx31-gpio", 1, MX35_GPIO2_BASE_ADDR, SZ_16K, MX35_INT_GPIO2, 0); - mxc_register_gpio("imx31-gpio", 2, MX35_GPIO3_BASE_ADDR, SZ_16K, MX35_INT_GPIO3, 0); + mxc_register_gpio("imx35-gpio", 0, MX35_GPIO1_BASE_ADDR, SZ_16K, MX35_INT_GPIO1, 0); + mxc_register_gpio("imx35-gpio", 1, MX35_GPIO2_BASE_ADDR, SZ_16K, MX35_INT_GPIO2, 0); + mxc_register_gpio("imx35-gpio", 2, MX35_GPIO3_BASE_ADDR, SZ_16K, MX35_INT_GPIO3, 0); pinctrl_provide_dummies(); if (to_version == 1) { diff --git a/arch/arm/mach-imx/mm-imx5.c b/arch/arm/mach-imx/mm-imx5.c index 1d003053d56..d70d16cb7eb 100644 --- a/arch/arm/mach-imx/mm-imx5.c +++ b/arch/arm/mach-imx/mm-imx5.c @@ -181,13 +181,13 @@ static const struct resource imx53_audmux_res[] __initconst = { void __init imx50_soc_init(void) { - /* i.mx50 has the i.mx31 type gpio */ - mxc_register_gpio("imx31-gpio", 0, MX50_GPIO1_BASE_ADDR, SZ_16K, MX50_INT_GPIO1_LOW, MX50_INT_GPIO1_HIGH); - mxc_register_gpio("imx31-gpio", 1, MX50_GPIO2_BASE_ADDR, SZ_16K, MX50_INT_GPIO2_LOW, MX50_INT_GPIO2_HIGH); - mxc_register_gpio("imx31-gpio", 2, MX50_GPIO3_BASE_ADDR, SZ_16K, MX50_INT_GPIO3_LOW, MX50_INT_GPIO3_HIGH); - mxc_register_gpio("imx31-gpio", 3, MX50_GPIO4_BASE_ADDR, SZ_16K, MX50_INT_GPIO4_LOW, MX50_INT_GPIO4_HIGH); - mxc_register_gpio("imx31-gpio", 4, MX50_GPIO5_BASE_ADDR, SZ_16K, MX50_INT_GPIO5_LOW, MX50_INT_GPIO5_HIGH); - mxc_register_gpio("imx31-gpio", 5, MX50_GPIO6_BASE_ADDR, SZ_16K, MX50_INT_GPIO6_LOW, MX50_INT_GPIO6_HIGH); + /* i.mx50 has the i.mx35 type gpio */ + mxc_register_gpio("imx35-gpio", 0, MX50_GPIO1_BASE_ADDR, SZ_16K, MX50_INT_GPIO1_LOW, MX50_INT_GPIO1_HIGH); + mxc_register_gpio("imx35-gpio", 1, MX50_GPIO2_BASE_ADDR, SZ_16K, MX50_INT_GPIO2_LOW, MX50_INT_GPIO2_HIGH); + mxc_register_gpio("imx35-gpio", 2, MX50_GPIO3_BASE_ADDR, SZ_16K, MX50_INT_GPIO3_LOW, MX50_INT_GPIO3_HIGH); + mxc_register_gpio("imx35-gpio", 3, MX50_GPIO4_BASE_ADDR, SZ_16K, MX50_INT_GPIO4_LOW, MX50_INT_GPIO4_HIGH); + mxc_register_gpio("imx35-gpio", 4, MX50_GPIO5_BASE_ADDR, SZ_16K, MX50_INT_GPIO5_LOW, MX50_INT_GPIO5_HIGH); + mxc_register_gpio("imx35-gpio", 5, MX50_GPIO6_BASE_ADDR, SZ_16K, MX50_INT_GPIO6_LOW, MX50_INT_GPIO6_HIGH); /* i.mx50 has the i.mx31 type audmux */ platform_device_register_simple("imx31-audmux", 0, imx50_audmux_res, @@ -196,11 +196,11 @@ void __init imx50_soc_init(void) void __init imx51_soc_init(void) { - /* i.mx51 has the i.mx31 type gpio */ - mxc_register_gpio("imx31-gpio", 0, MX51_GPIO1_BASE_ADDR, SZ_16K, MX51_INT_GPIO1_LOW, MX51_INT_GPIO1_HIGH); - mxc_register_gpio("imx31-gpio", 1, MX51_GPIO2_BASE_ADDR, SZ_16K, MX51_INT_GPIO2_LOW, MX51_INT_GPIO2_HIGH); - mxc_register_gpio("imx31-gpio", 2, MX51_GPIO3_BASE_ADDR, SZ_16K, MX51_INT_GPIO3_LOW, MX51_INT_GPIO3_HIGH); - mxc_register_gpio("imx31-gpio", 3, MX51_GPIO4_BASE_ADDR, SZ_16K, MX51_INT_GPIO4_LOW, MX51_INT_GPIO4_HIGH); + /* i.mx51 has the i.mx35 type gpio */ + mxc_register_gpio("imx35-gpio", 0, MX51_GPIO1_BASE_ADDR, SZ_16K, MX51_INT_GPIO1_LOW, MX51_INT_GPIO1_HIGH); + mxc_register_gpio("imx35-gpio", 1, MX51_GPIO2_BASE_ADDR, SZ_16K, MX51_INT_GPIO2_LOW, MX51_INT_GPIO2_HIGH); + mxc_register_gpio("imx35-gpio", 2, MX51_GPIO3_BASE_ADDR, SZ_16K, MX51_INT_GPIO3_LOW, MX51_INT_GPIO3_HIGH); + mxc_register_gpio("imx35-gpio", 3, MX51_GPIO4_BASE_ADDR, SZ_16K, MX51_INT_GPIO4_LOW, MX51_INT_GPIO4_HIGH); pinctrl_provide_dummies(); @@ -218,14 +218,14 @@ void __init imx51_soc_init(void) void __init imx53_soc_init(void) { - /* i.mx53 has the i.mx31 type gpio */ - mxc_register_gpio("imx31-gpio", 0, MX53_GPIO1_BASE_ADDR, SZ_16K, MX53_INT_GPIO1_LOW, MX53_INT_GPIO1_HIGH); - mxc_register_gpio("imx31-gpio", 1, MX53_GPIO2_BASE_ADDR, SZ_16K, MX53_INT_GPIO2_LOW, MX53_INT_GPIO2_HIGH); - mxc_register_gpio("imx31-gpio", 2, MX53_GPIO3_BASE_ADDR, SZ_16K, MX53_INT_GPIO3_LOW, MX53_INT_GPIO3_HIGH); - mxc_register_gpio("imx31-gpio", 3, MX53_GPIO4_BASE_ADDR, SZ_16K, MX53_INT_GPIO4_LOW, MX53_INT_GPIO4_HIGH); - mxc_register_gpio("imx31-gpio", 4, MX53_GPIO5_BASE_ADDR, SZ_16K, MX53_INT_GPIO5_LOW, MX53_INT_GPIO5_HIGH); - mxc_register_gpio("imx31-gpio", 5, MX53_GPIO6_BASE_ADDR, SZ_16K, MX53_INT_GPIO6_LOW, MX53_INT_GPIO6_HIGH); - mxc_register_gpio("imx31-gpio", 6, MX53_GPIO7_BASE_ADDR, SZ_16K, MX53_INT_GPIO7_LOW, MX53_INT_GPIO7_HIGH); + /* i.mx53 has the i.mx35 type gpio */ + mxc_register_gpio("imx35-gpio", 0, MX53_GPIO1_BASE_ADDR, SZ_16K, MX53_INT_GPIO1_LOW, MX53_INT_GPIO1_HIGH); + mxc_register_gpio("imx35-gpio", 1, MX53_GPIO2_BASE_ADDR, SZ_16K, MX53_INT_GPIO2_LOW, MX53_INT_GPIO2_HIGH); + mxc_register_gpio("imx35-gpio", 2, MX53_GPIO3_BASE_ADDR, SZ_16K, MX53_INT_GPIO3_LOW, MX53_INT_GPIO3_HIGH); + mxc_register_gpio("imx35-gpio", 3, MX53_GPIO4_BASE_ADDR, SZ_16K, MX53_INT_GPIO4_LOW, MX53_INT_GPIO4_HIGH); + mxc_register_gpio("imx35-gpio", 4, MX53_GPIO5_BASE_ADDR, SZ_16K, MX53_INT_GPIO5_LOW, MX53_INT_GPIO5_HIGH); + mxc_register_gpio("imx35-gpio", 5, MX53_GPIO6_BASE_ADDR, SZ_16K, MX53_INT_GPIO6_LOW, MX53_INT_GPIO6_HIGH); + mxc_register_gpio("imx35-gpio", 6, MX53_GPIO7_BASE_ADDR, SZ_16K, MX53_INT_GPIO7_LOW, MX53_INT_GPIO7_HIGH); pinctrl_provide_dummies(); /* i.mx53 has the i.mx35 type sdma */ diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index c337143b18f..bb985e81553 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -38,7 +38,8 @@ enum mxc_gpio_hwtype { IMX1_GPIO, /* runs on i.mx1 */ IMX21_GPIO, /* runs on i.mx21 and i.mx27 */ - IMX31_GPIO, /* runs on all other i.mx */ + IMX31_GPIO, /* runs on i.mx31 */ + IMX35_GPIO, /* runs on all other i.mx */ }; /* device type dependent stuff */ @@ -50,6 +51,7 @@ struct mxc_gpio_hwdata { unsigned icr2_reg; unsigned imr_reg; unsigned isr_reg; + int edge_sel_reg; unsigned low_level; unsigned high_level; unsigned rise_edge; @@ -74,6 +76,7 @@ static struct mxc_gpio_hwdata imx1_imx21_gpio_hwdata = { .icr2_reg = 0x2c, .imr_reg = 0x30, .isr_reg = 0x34, + .edge_sel_reg = -EINVAL, .low_level = 0x03, .high_level = 0x02, .rise_edge = 0x00, @@ -88,6 +91,22 @@ static struct mxc_gpio_hwdata imx31_gpio_hwdata = { .icr2_reg = 0x10, .imr_reg = 0x14, .isr_reg = 0x18, + .edge_sel_reg = -EINVAL, + .low_level = 0x00, + .high_level = 0x01, + .rise_edge = 0x02, + .fall_edge = 0x03, +}; + +static struct mxc_gpio_hwdata imx35_gpio_hwdata = { + .dr_reg = 0x00, + .gdir_reg = 0x04, + .psr_reg = 0x08, + .icr1_reg = 0x0c, + .icr2_reg = 0x10, + .imr_reg = 0x14, + .isr_reg = 0x18, + .edge_sel_reg = 0x1c, .low_level = 0x00, .high_level = 0x01, .rise_edge = 0x02, @@ -104,12 +123,13 @@ static struct mxc_gpio_hwdata *mxc_gpio_hwdata; #define GPIO_ICR2 (mxc_gpio_hwdata->icr2_reg) #define GPIO_IMR (mxc_gpio_hwdata->imr_reg) #define GPIO_ISR (mxc_gpio_hwdata->isr_reg) +#define GPIO_EDGE_SEL (mxc_gpio_hwdata->edge_sel_reg) #define GPIO_INT_LOW_LEV (mxc_gpio_hwdata->low_level) #define GPIO_INT_HIGH_LEV (mxc_gpio_hwdata->high_level) #define GPIO_INT_RISE_EDGE (mxc_gpio_hwdata->rise_edge) #define GPIO_INT_FALL_EDGE (mxc_gpio_hwdata->fall_edge) -#define GPIO_INT_NONE 0x4 +#define GPIO_INT_BOTH_EDGES 0x4 static struct platform_device_id mxc_gpio_devtype[] = { { @@ -121,6 +141,9 @@ static struct platform_device_id mxc_gpio_devtype[] = { }, { .name = "imx31-gpio", .driver_data = IMX31_GPIO, + }, { + .name = "imx35-gpio", + .driver_data = IMX35_GPIO, }, { /* sentinel */ } @@ -130,6 +153,7 @@ static const struct of_device_id mxc_gpio_dt_ids[] = { { .compatible = "fsl,imx1-gpio", .data = &mxc_gpio_devtype[IMX1_GPIO], }, { .compatible = "fsl,imx21-gpio", .data = &mxc_gpio_devtype[IMX21_GPIO], }, { .compatible = "fsl,imx31-gpio", .data = &mxc_gpio_devtype[IMX31_GPIO], }, + { .compatible = "fsl,imx35-gpio", .data = &mxc_gpio_devtype[IMX35_GPIO], }, { /* sentinel */ } }; @@ -160,15 +184,19 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type) edge = GPIO_INT_FALL_EDGE; break; case IRQ_TYPE_EDGE_BOTH: - val = gpio_get_value(gpio); - if (val) { - edge = GPIO_INT_LOW_LEV; - pr_debug("mxc: set GPIO %d to low trigger\n", gpio); + if (GPIO_EDGE_SEL >= 0) { + edge = GPIO_INT_BOTH_EDGES; } else { - edge = GPIO_INT_HIGH_LEV; - pr_debug("mxc: set GPIO %d to high trigger\n", gpio); + val = gpio_get_value(gpio); + if (val) { + edge = GPIO_INT_LOW_LEV; + pr_debug("mxc: set GPIO %d to low trigger\n", gpio); + } else { + edge = GPIO_INT_HIGH_LEV; + pr_debug("mxc: set GPIO %d to high trigger\n", gpio); + } + port->both_edges |= 1 << (gpio & 31); } - port->both_edges |= 1 << (gpio & 31); break; case IRQ_TYPE_LEVEL_LOW: edge = GPIO_INT_LOW_LEV; @@ -180,10 +208,23 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type) return -EINVAL; } - reg += GPIO_ICR1 + ((gpio & 0x10) >> 2); /* lower or upper register */ - bit = gpio & 0xf; - val = readl(reg) & ~(0x3 << (bit << 1)); - writel(val | (edge << (bit << 1)), reg); + if (GPIO_EDGE_SEL >= 0) { + val = readl(port->base + GPIO_EDGE_SEL); + if (edge == GPIO_INT_BOTH_EDGES) + writel(val | (1 << (gpio & 0x1f)), + port->base + GPIO_EDGE_SEL); + else + writel(val & ~(1 << (gpio & 0x1f)), + port->base + GPIO_EDGE_SEL); + } + + if (edge != GPIO_INT_BOTH_EDGES) { + reg += GPIO_ICR1 + ((gpio & 0x10) >> 2); /* lower or upper register */ + bit = gpio & 0xf; + val = readl(reg) & ~(0x3 << (bit << 1)); + writel(val | (edge << (bit << 1)), reg); + } + writel(1 << (gpio & 0x1f), port->base + GPIO_ISR); return 0; @@ -338,7 +379,9 @@ static void __devinit mxc_gpio_get_hw(struct platform_device *pdev) return; } - if (hwtype == IMX31_GPIO) + if (hwtype == IMX35_GPIO) + mxc_gpio_hwdata = &imx35_gpio_hwdata; + else if (hwtype == IMX31_GPIO) mxc_gpio_hwdata = &imx31_gpio_hwdata; else mxc_gpio_hwdata = &imx1_imx21_gpio_hwdata; -- cgit v1.2.3-70-g09d2 From 13987435cc28eab6e562e878e71b521e7ef5c860 Mon Sep 17 00:00:00 2001 From: Sourav Poddar Date: Fri, 13 Jul 2012 00:10:47 -0700 Subject: Input: omap4-keypad - add device tree support Add device tree support for omap4 keypad driver and update the Documentation with omap4 keypad device tree binding information. Tested on omap4430 sdp. Signed-off-by: Sourav Poddar Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/omap-keypad.txt | 31 +++++ drivers/input/keyboard/omap4-keypad.c | 127 ++++++++++++++------- 2 files changed, 118 insertions(+), 40 deletions(-) create mode 100644 Documentation/devicetree/bindings/input/omap-keypad.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/input/omap-keypad.txt b/Documentation/devicetree/bindings/input/omap-keypad.txt new file mode 100644 index 00000000000..f2fa5e10493 --- /dev/null +++ b/Documentation/devicetree/bindings/input/omap-keypad.txt @@ -0,0 +1,31 @@ +* TI's Keypad Controller device tree bindings + +TI's Keypad controller is used to interface a SoC with a matrix-type +keypad device. The keypad controller supports multiple row and column lines. +A key can be placed at each intersection of a unique row and a unique column. +The keypad controller can sense a key-press and key-release and report the +event using a interrupt to the cpu. + +Required SoC Specific Properties: +- compatible: should be one of the following + - "ti,omap4-keypad": For controllers compatible with omap4 keypad + controller. + +Required Board Specific Properties, in addition to those specified by +the shared matrix-keyboard bindings: +- keypad,num-rows: Number of row lines connected to the keypad + controller. + +- keypad,num-columns: Number of column lines connected to the + keypad controller. + +Optional Properties specific to linux: +- linux,keypad-no-autorepeat: do no enable autorepeat feature. + +Example: + keypad@4ae1c000{ + compatible = "ti,omap4-keypad"; + keypad,num-rows = <2>; + keypad,num-columns = <8>; + linux,keypad-no-autorepeat; + }; diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c index aed5f6999ce..c05f98c4141 100644 --- a/drivers/input/keyboard/omap4-keypad.c +++ b/drivers/input/keyboard/omap4-keypad.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -84,8 +85,9 @@ struct omap4_keypad { u32 reg_offset; u32 irqreg_offset; unsigned int row_shift; + bool no_autorepeat; unsigned char key_state[8]; - unsigned short keymap[]; + unsigned short *keymap; }; static int kbd_readl(struct omap4_keypad *keypad_data, u32 offset) @@ -208,25 +210,51 @@ static void omap4_keypad_close(struct input_dev *input) pm_runtime_put_sync(input->dev.parent); } +#ifdef CONFIG_OF +static int __devinit omap4_keypad_parse_dt(struct device *dev, + struct omap4_keypad *keypad_data) +{ + struct device_node *np = dev->of_node; + + if (!np) { + dev_err(dev, "missing DT data"); + return -EINVAL; + } + + of_property_read_u32(np, "keypad,num-rows", &keypad_data->rows); + of_property_read_u32(np, "keypad,num-columns", &keypad_data->cols); + if (!keypad_data->rows || !keypad_data->cols) { + dev_err(dev, "number of keypad rows/columns not specified\n"); + return -EINVAL; + } + + if (of_get_property(np, "linux,input-no-autorepeat", NULL)) + keypad_data->no_autorepeat = true; + + return 0; +} +#else +static inline int omap4_keypad_parse_dt(struct device *dev, + struct omap4_keypad *keypad_data) +{ + return -ENOSYS; +} +#endif + static int __devinit omap4_keypad_probe(struct platform_device *pdev) { - const struct omap4_keypad_platform_data *pdata; + const struct omap4_keypad_platform_data *pdata = + dev_get_platdata(&pdev->dev); + const struct matrix_keymap_data *keymap_data = + pdata ? pdata->keymap_data : NULL; struct omap4_keypad *keypad_data; struct input_dev *input_dev; struct resource *res; - resource_size_t size; - unsigned int row_shift, max_keys; + unsigned int max_keys; int rev; int irq; int error; - /* platform data */ - pdata = pdev->dev.platform_data; - if (!pdata) { - dev_err(&pdev->dev, "no platform data defined\n"); - return -EINVAL; - } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "no base address specified\n"); @@ -239,25 +267,24 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev) return -EINVAL; } - if (!pdata->keymap_data) { - dev_err(&pdev->dev, "no keymap data defined\n"); - return -EINVAL; - } - - row_shift = get_count_order(pdata->cols); - max_keys = pdata->rows << row_shift; - - keypad_data = kzalloc(sizeof(struct omap4_keypad) + - max_keys * sizeof(keypad_data->keymap[0]), - GFP_KERNEL); + keypad_data = kzalloc(sizeof(struct omap4_keypad), GFP_KERNEL); if (!keypad_data) { dev_err(&pdev->dev, "keypad_data memory allocation failed\n"); return -ENOMEM; } - size = resource_size(res); + keypad_data->irq = irq; + + if (pdata) { + keypad_data->rows = pdata->rows; + keypad_data->cols = pdata->cols; + } else { + error = omap4_keypad_parse_dt(&pdev->dev, keypad_data); + if (error) + return error; + } - res = request_mem_region(res->start, size, pdev->name); + res = request_mem_region(res->start, resource_size(res), pdev->name); if (!res) { dev_err(&pdev->dev, "can't request mem region\n"); error = -EBUSY; @@ -271,15 +298,11 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev) goto err_release_mem; } - keypad_data->irq = irq; - keypad_data->row_shift = row_shift; - keypad_data->rows = pdata->rows; - keypad_data->cols = pdata->cols; /* - * Enable clocks for the keypad module so that we can read - * revision register. - */ + * Enable clocks for the keypad module so that we can read + * revision register. + */ pm_runtime_enable(&pdev->dev); error = pm_runtime_get_sync(&pdev->dev); if (error) { @@ -322,19 +345,30 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev) input_dev->open = omap4_keypad_open; input_dev->close = omap4_keypad_close; - error = matrix_keypad_build_keymap(pdata->keymap_data, NULL, - pdata->rows, pdata->cols, + input_set_capability(input_dev, EV_MSC, MSC_SCAN); + if (!keypad_data->no_autorepeat) + __set_bit(EV_REP, input_dev->evbit); + + input_set_drvdata(input_dev, keypad_data); + + keypad_data->row_shift = get_count_order(keypad_data->cols); + max_keys = keypad_data->rows << keypad_data->row_shift; + keypad_data->keymap = kzalloc(max_keys * sizeof(keypad_data->keymap[0]), + GFP_KERNEL); + if (!keypad_data->keymap) { + dev_err(&pdev->dev, "Not enough memory for keymap\n"); + error = -ENOMEM; + goto err_free_input; + } + + error = matrix_keypad_build_keymap(keymap_data, NULL, + keypad_data->rows, keypad_data->cols, keypad_data->keymap, input_dev); if (error) { dev_err(&pdev->dev, "failed to build keymap\n"); - goto err_free_input; + goto err_free_keymap; } - __set_bit(EV_REP, input_dev->evbit); - input_set_capability(input_dev, EV_MSC, MSC_SCAN); - - input_set_drvdata(input_dev, keypad_data); - error = request_irq(keypad_data->irq, omap4_keypad_interrupt, IRQF_TRIGGER_RISING, "omap4-keypad", keypad_data); @@ -357,6 +391,8 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev) err_pm_disable: pm_runtime_disable(&pdev->dev); free_irq(keypad_data->irq, keypad_data); +err_free_keymap: + kfree(keypad_data->keymap); err_free_input: input_free_device(input_dev); err_pm_put_sync: @@ -364,7 +400,7 @@ err_pm_put_sync: err_unmap: iounmap(keypad_data->base); err_release_mem: - release_mem_region(res->start, size); + release_mem_region(res->start, resource_size(res)); err_free_keypad: kfree(keypad_data); return error; @@ -386,18 +422,29 @@ static int __devexit omap4_keypad_remove(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(res->start, resource_size(res)); + kfree(keypad_data->keymap); kfree(keypad_data); + platform_set_drvdata(pdev, NULL); return 0; } +#ifdef CONFIG_OF +static const struct of_device_id omap_keypad_dt_match[] = { + { .compatible = "ti,omap4-keypad" }, + {}, +}; +MODULE_DEVICE_TABLE(of, omap_keypad_dt_match); +#endif + static struct platform_driver omap4_keypad_driver = { .probe = omap4_keypad_probe, .remove = __devexit_p(omap4_keypad_remove), .driver = { .name = "omap4-keypad", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(omap_keypad_dt_match), }, }; module_platform_driver(omap4_keypad_driver); -- cgit v1.2.3-70-g09d2 From 69690bec400e4c6cc89ef37376da1e633e14ad0f Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Fri, 13 Jul 2012 00:08:34 -0700 Subject: Input: add support for key scan interface of the LPC32xx SoC This is a driver for the key scan interface of the LPC32xx SoC Signed-off-by: Roland Stigge Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/lpc32xx-key.txt | 28 ++ drivers/input/keyboard/Kconfig | 10 + drivers/input/keyboard/Makefile | 1 + drivers/input/keyboard/lpc32xx-keys.c | 394 +++++++++++++++++++++ 4 files changed, 433 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/lpc32xx-key.txt create mode 100644 drivers/input/keyboard/lpc32xx-keys.c (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/input/lpc32xx-key.txt b/Documentation/devicetree/bindings/input/lpc32xx-key.txt new file mode 100644 index 00000000000..31afd5014c4 --- /dev/null +++ b/Documentation/devicetree/bindings/input/lpc32xx-key.txt @@ -0,0 +1,28 @@ +NXP LPC32xx Key Scan Interface + +Required Properties: +- compatible: Should be "nxp,lpc3220-key" +- reg: Physical base address of the controller and length of memory mapped + region. +- interrupts: The interrupt number to the cpu. +- keypad,num-rows: Number of rows and columns, e.g. 1: 1x1, 6: 6x6 +- keypad,num-columns: Must be equal to keypad,num-rows since LPC32xx only + supports square matrices +- nxp,debounce-delay-ms: Debounce delay in ms +- nxp,scan-delay-ms: Repeated scan period in ms +- linux,keymap: the key-code to be reported when the key is pressed + and released, see also + Documentation/devicetree/bindings/input/matrix-keymap.txt + +Example: + + key@40050000 { + compatible = "nxp,lpc3220-key"; + reg = <0x40050000 0x1000>; + interrupts = <54 0>; + keypad,num-rows = <1>; + keypad,num-columns = <1>; + nxp,debounce-delay-ms = <3>; + nxp,scan-delay-ms = <34>; + linux,keymap = <0x00000002>; + }; diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index c0e11ecc646..c50fa75416f 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -332,6 +332,16 @@ config KEYBOARD_LOCOMO To compile this driver as a module, choose M here: the module will be called locomokbd. +config KEYBOARD_LPC32XX + tristate "LPC32XX matrix key scanner support" + depends on ARCH_LPC32XX && OF + help + Say Y here if you want to use NXP LPC32XX SoC key scanner interface, + connected to a key matrix. + + To compile this driver as a module, choose M here: the + module will be called lpc32xx-keys. + config KEYBOARD_MAPLE tristate "Maple bus keyboard" depends on SH_DREAMCAST && MAPLE diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index b03b02456a8..44e76002f54 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_KEYBOARD_LKKBD) += lkkbd.o obj-$(CONFIG_KEYBOARD_LM8323) += lm8323.o obj-$(CONFIG_KEYBOARD_LM8333) += lm8333.o obj-$(CONFIG_KEYBOARD_LOCOMO) += locomokbd.o +obj-$(CONFIG_KEYBOARD_LPC32XX) += lpc32xx-keys.o obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o obj-$(CONFIG_KEYBOARD_MATRIX) += matrix_keypad.o obj-$(CONFIG_KEYBOARD_MAX7359) += max7359_keypad.o diff --git a/drivers/input/keyboard/lpc32xx-keys.c b/drivers/input/keyboard/lpc32xx-keys.c new file mode 100644 index 00000000000..dd786c8a758 --- /dev/null +++ b/drivers/input/keyboard/lpc32xx-keys.c @@ -0,0 +1,394 @@ +/* + * NXP LPC32xx SoC Key Scan Interface + * + * Authors: + * Kevin Wells + * Roland Stigge + * + * Copyright (C) 2010 NXP Semiconductors + * Copyright (C) 2012 Roland Stigge + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * This controller supports square key matrices from 1x1 up to 8x8 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "lpc32xx_keys" + +/* + * Key scanner register offsets + */ +#define LPC32XX_KS_DEB(x) ((x) + 0x00) +#define LPC32XX_KS_STATE_COND(x) ((x) + 0x04) +#define LPC32XX_KS_IRQ(x) ((x) + 0x08) +#define LPC32XX_KS_SCAN_CTL(x) ((x) + 0x0C) +#define LPC32XX_KS_FAST_TST(x) ((x) + 0x10) +#define LPC32XX_KS_MATRIX_DIM(x) ((x) + 0x14) /* 1..8 */ +#define LPC32XX_KS_DATA(x, y) ((x) + 0x40 + ((y) << 2)) + +#define LPC32XX_KSCAN_DEB_NUM_DEB_PASS(n) ((n) & 0xFF) + +#define LPC32XX_KSCAN_SCOND_IN_IDLE 0x0 +#define LPC32XX_KSCAN_SCOND_IN_SCANONCE 0x1 +#define LPC32XX_KSCAN_SCOND_IN_IRQGEN 0x2 +#define LPC32XX_KSCAN_SCOND_IN_SCAN_MATRIX 0x3 + +#define LPC32XX_KSCAN_IRQ_PENDING_CLR 0x1 + +#define LPC32XX_KSCAN_SCTRL_SCAN_DELAY(n) ((n) & 0xFF) + +#define LPC32XX_KSCAN_FTST_FORCESCANONCE 0x1 +#define LPC32XX_KSCAN_FTST_USE32K_CLK 0x2 + +#define LPC32XX_KSCAN_MSEL_SELECT(n) ((n) & 0xF) + +struct lpc32xx_kscan_drv { + struct input_dev *input; + struct clk *clk; + struct resource *iores; + void __iomem *kscan_base; + unsigned int irq; + + u32 matrix_sz; /* Size of matrix in XxY, ie. 3 = 3x3 */ + u32 deb_clks; /* Debounce clocks (based on 32KHz clock) */ + u32 scan_delay; /* Scan delay (based on 32KHz clock) */ + + unsigned short *keymap; /* Pointer to key map for the scan matrix */ + unsigned int row_shift; + + u8 lastkeystates[8]; +}; + +static void lpc32xx_mod_states(struct lpc32xx_kscan_drv *kscandat, int col) +{ + struct input_dev *input = kscandat->input; + unsigned row, changed, scancode, keycode; + u8 key; + + key = readl(LPC32XX_KS_DATA(kscandat->kscan_base, col)); + changed = key ^ kscandat->lastkeystates[col]; + kscandat->lastkeystates[col] = key; + + for (row = 0; changed; row++, changed >>= 1) { + if (changed & 1) { + /* Key state changed, signal an event */ + scancode = MATRIX_SCAN_CODE(row, col, + kscandat->row_shift); + keycode = kscandat->keymap[scancode]; + input_event(input, EV_MSC, MSC_SCAN, scancode); + input_report_key(input, keycode, key & (1 << row)); + } + } +} + +static irqreturn_t lpc32xx_kscan_irq(int irq, void *dev_id) +{ + struct lpc32xx_kscan_drv *kscandat = dev_id; + int i; + + for (i = 0; i < kscandat->matrix_sz; i++) + lpc32xx_mod_states(kscandat, i); + + writel(1, LPC32XX_KS_IRQ(kscandat->kscan_base)); + + input_sync(kscandat->input); + + return IRQ_HANDLED; +} + +static int lpc32xx_kscan_open(struct input_dev *dev) +{ + struct lpc32xx_kscan_drv *kscandat = input_get_drvdata(dev); + int error; + + error = clk_prepare_enable(kscandat->clk); + if (error) + return error; + + writel(1, LPC32XX_KS_IRQ(kscandat->kscan_base)); + + return 0; +} + +static void lpc32xx_kscan_close(struct input_dev *dev) +{ + struct lpc32xx_kscan_drv *kscandat = input_get_drvdata(dev); + + writel(1, LPC32XX_KS_IRQ(kscandat->kscan_base)); + clk_disable_unprepare(kscandat->clk); +} + +static int __devinit lpc32xx_parse_dt(struct device *dev, + struct lpc32xx_kscan_drv *kscandat) +{ + struct device_node *np = dev->of_node; + u32 rows = 0, columns = 0; + + of_property_read_u32(np, "keypad,num-rows", &rows); + of_property_read_u32(np, "keypad,num-columns", &columns); + if (!rows || rows != columns) { + dev_err(dev, + "rows and columns must be specified and be equal!\n"); + return -EINVAL; + } + + kscandat->matrix_sz = rows; + kscandat->row_shift = get_count_order(columns); + + of_property_read_u32(np, "nxp,debounce-delay-ms", &kscandat->deb_clks); + of_property_read_u32(np, "nxp,scan-delay-ms", &kscandat->scan_delay); + if (!kscandat->deb_clks || !kscandat->scan_delay) { + dev_err(dev, "debounce or scan delay not specified\n"); + return -EINVAL; + } + + return 0; +} + +static int __devinit lpc32xx_kscan_probe(struct platform_device *pdev) +{ + struct lpc32xx_kscan_drv *kscandat; + struct input_dev *input; + struct resource *res; + size_t keymap_size; + int error; + int irq; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "failed to get platform I/O memory\n"); + return -EINVAL; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0 || irq >= NR_IRQS) { + dev_err(&pdev->dev, "failed to get platform irq\n"); + return -EINVAL; + } + + kscandat = kzalloc(sizeof(struct lpc32xx_kscan_drv), GFP_KERNEL); + if (!kscandat) { + dev_err(&pdev->dev, "failed to allocate memory\n"); + return -ENOMEM; + } + + error = lpc32xx_parse_dt(&pdev->dev, kscandat); + if (error) { + dev_err(&pdev->dev, "failed to parse device tree\n"); + goto err_free_mem; + } + + keymap_size = sizeof(kscandat->keymap[0]) * + (kscandat->matrix_sz << kscandat->row_shift); + kscandat->keymap = kzalloc(keymap_size, GFP_KERNEL); + if (!kscandat->keymap) { + dev_err(&pdev->dev, "could not allocate memory for keymap\n"); + error = -ENOMEM; + goto err_free_mem; + } + + kscandat->input = input = input_allocate_device(); + if (!input) { + dev_err(&pdev->dev, "failed to allocate input device\n"); + error = -ENOMEM; + goto err_free_keymap; + } + + /* Setup key input */ + input->name = pdev->name; + input->phys = "lpc32xx/input0"; + input->id.vendor = 0x0001; + input->id.product = 0x0001; + input->id.version = 0x0100; + input->open = lpc32xx_kscan_open; + input->close = lpc32xx_kscan_close; + input->dev.parent = &pdev->dev; + + input_set_capability(input, EV_MSC, MSC_SCAN); + + error = matrix_keypad_build_keymap(NULL, NULL, + kscandat->matrix_sz, + kscandat->matrix_sz, + kscandat->keymap, kscandat->input); + if (error) { + dev_err(&pdev->dev, "failed to build keymap\n"); + goto err_free_input; + } + + input_set_drvdata(kscandat->input, kscandat); + + kscandat->iores = request_mem_region(res->start, resource_size(res), + pdev->name); + if (!kscandat->iores) { + dev_err(&pdev->dev, "failed to request I/O memory\n"); + error = -EBUSY; + goto err_free_input; + } + + kscandat->kscan_base = ioremap(kscandat->iores->start, + resource_size(kscandat->iores)); + if (!kscandat->kscan_base) { + dev_err(&pdev->dev, "failed to remap I/O memory\n"); + error = -EBUSY; + goto err_release_memregion; + } + + /* Get the key scanner clock */ + kscandat->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(kscandat->clk)) { + dev_err(&pdev->dev, "failed to get clock\n"); + error = PTR_ERR(kscandat->clk); + goto err_unmap; + } + + /* Configure the key scanner */ + error = clk_prepare_enable(kscandat->clk); + if (error) + goto err_clk_put; + + writel(kscandat->deb_clks, LPC32XX_KS_DEB(kscandat->kscan_base)); + writel(kscandat->scan_delay, LPC32XX_KS_SCAN_CTL(kscandat->kscan_base)); + writel(LPC32XX_KSCAN_FTST_USE32K_CLK, + LPC32XX_KS_FAST_TST(kscandat->kscan_base)); + writel(kscandat->matrix_sz, + LPC32XX_KS_MATRIX_DIM(kscandat->kscan_base)); + writel(1, LPC32XX_KS_IRQ(kscandat->kscan_base)); + clk_disable_unprepare(kscandat->clk); + + error = request_irq(irq, lpc32xx_kscan_irq, 0, pdev->name, kscandat); + if (error) { + dev_err(&pdev->dev, "failed to request irq\n"); + goto err_clk_put; + } + + error = input_register_device(kscandat->input); + if (error) { + dev_err(&pdev->dev, "failed to register input device\n"); + goto err_free_irq; + } + + platform_set_drvdata(pdev, kscandat); + return 0; + +err_free_irq: + free_irq(irq, kscandat); +err_clk_put: + clk_put(kscandat->clk); +err_unmap: + iounmap(kscandat->kscan_base); +err_release_memregion: + release_mem_region(kscandat->iores->start, + resource_size(kscandat->iores)); +err_free_input: + input_free_device(kscandat->input); +err_free_keymap: + kfree(kscandat->keymap); +err_free_mem: + kfree(kscandat); + + return error; +} + +static int __devexit lpc32xx_kscan_remove(struct platform_device *pdev) +{ + struct lpc32xx_kscan_drv *kscandat = platform_get_drvdata(pdev); + + free_irq(platform_get_irq(pdev, 0), kscandat); + clk_put(kscandat->clk); + iounmap(kscandat->kscan_base); + release_mem_region(kscandat->iores->start, + resource_size(kscandat->iores)); + input_unregister_device(kscandat->input); + kfree(kscandat->keymap); + kfree(kscandat); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int lpc32xx_kscan_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct lpc32xx_kscan_drv *kscandat = platform_get_drvdata(pdev); + struct input_dev *input = kscandat->input; + + mutex_lock(&input->mutex); + + if (input->users) { + /* Clear IRQ and disable clock */ + writel(1, LPC32XX_KS_IRQ(kscandat->kscan_base)); + clk_disable_unprepare(kscandat->clk); + } + + mutex_unlock(&input->mutex); + return 0; +} + +static int lpc32xx_kscan_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct lpc32xx_kscan_drv *kscandat = platform_get_drvdata(pdev); + struct input_dev *input = kscandat->input; + int retval = 0; + + mutex_lock(&input->mutex); + + if (input->users) { + /* Enable clock and clear IRQ */ + retval = clk_prepare_enable(kscandat->clk); + if (retval == 0) + writel(1, LPC32XX_KS_IRQ(kscandat->kscan_base)); + } + + mutex_unlock(&input->mutex); + return retval; +} +#endif + +static SIMPLE_DEV_PM_OPS(lpc32xx_kscan_pm_ops, lpc32xx_kscan_suspend, + lpc32xx_kscan_resume); + +static const struct of_device_id lpc32xx_kscan_match[] = { + { .compatible = "nxp,lpc3220-key" }, + {}, +}; +MODULE_DEVICE_TABLE(of, lpc32xx_kscan_match); + +static struct platform_driver lpc32xx_kscan_driver = { + .probe = lpc32xx_kscan_probe, + .remove = __devexit_p(lpc32xx_kscan_remove), + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .pm = &lpc32xx_kscan_pm_ops, + .of_match_table = of_match_ptr(lpc32xx_kscan_match), + } +}; + +module_platform_driver(lpc32xx_kscan_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kevin Wells "); +MODULE_AUTHOR("Roland Stigge "); +MODULE_DESCRIPTION("Key scanner driver for LPC32XX devices"); -- cgit v1.2.3-70-g09d2 From f814f9ac5a819542fdf6db97305db9da603c1eeb Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Mon, 23 Jul 2012 12:08:09 +0200 Subject: spi/orion: add device tree binding Signed-off-by: Michael Walle Signed-off-by: Andrew Lunn Acked-by: Jason Cooper Acked-by: Sebastian Hesselbarth Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi-orion.txt | 19 +++++++++++++++++++ drivers/spi/spi-orion.c | 17 +++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 Documentation/devicetree/bindings/spi/spi-orion.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/spi/spi-orion.txt b/Documentation/devicetree/bindings/spi/spi-orion.txt new file mode 100644 index 00000000000..a3ff50fc76f --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-orion.txt @@ -0,0 +1,19 @@ +Marvell Orion SPI device + +Required properties: +- compatible : should be "marvell,orion-spi". +- reg : offset and length of the register set for the device +- cell-index : Which of multiple SPI controllers is this. +Optional properties: +- interrupts : Is currently not used. + +Example: + spi@10600 { + compatible = "marvell,orion-spi"; + #address-cells = <1>; + #size-cells = <0>; + cell-index = <0>; + reg = <0x10600 0x28>; + interrupts = <23>; + status = "disabled"; + }; diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index dfd04e91fa6..74312a862ba 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -453,6 +454,8 @@ static int __init orion_spi_probe(struct platform_device *pdev) struct orion_spi_info *spi_info; unsigned long tclk_hz; int status = 0; + const u32 *iprop; + int size; spi_info = pdev->dev.platform_data; @@ -464,6 +467,12 @@ static int __init orion_spi_probe(struct platform_device *pdev) if (pdev->id != -1) master->bus_num = pdev->id; + if (pdev->dev.of_node) { + iprop = of_get_property(pdev->dev.of_node, "cell-index", + &size); + if (iprop && size == sizeof(*iprop)) + master->bus_num = *iprop; + } /* we support only mode 0, and no options */ master->mode_bits = 0; @@ -511,6 +520,7 @@ static int __init orion_spi_probe(struct platform_device *pdev) if (orion_spi_reset(spi) < 0) goto out_rel_mem; + master->dev.of_node = pdev->dev.of_node; status = spi_register_master(master); if (status < 0) goto out_rel_mem; @@ -552,10 +562,17 @@ static int __exit orion_spi_remove(struct platform_device *pdev) MODULE_ALIAS("platform:" DRIVER_NAME); +static const struct of_device_id orion_spi_of_match_table[] __devinitdata = { + { .compatible = "marvell,orion-spi", }, + {} +}; +MODULE_DEVICE_TABLE(of, orion_spi_of_match_table); + static struct platform_driver orion_spi_driver = { .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, + .of_match_table = of_match_ptr(orion_spi_of_match_table), }, .remove = __exit_p(orion_spi_remove), }; -- cgit v1.2.3-70-g09d2 From 3e3ed6cdc49d758719c148a78c8b04c243ef74d0 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 16 Dec 2011 21:25:29 +0100 Subject: pwm-backlight: Add rudimentary device tree support This commit adds very basic support for device tree probing. Currently, only a PWM and a list of distinct brightness levels can be specified. Enabling or disabling backlight power via GPIOs is not yet supported. Reviewed-by: Shawn Guo Reviewed-by: Mark Brown Signed-off-by: Thierry Reding --- .../bindings/video/backlight/pwm-backlight.txt | 28 ++++ drivers/video/backlight/Kconfig | 2 +- drivers/video/backlight/pwm_bl.c | 149 ++++++++++++++++++--- include/linux/pwm_backlight.h | 1 + 4 files changed, 159 insertions(+), 21 deletions(-) create mode 100644 Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt b/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt new file mode 100644 index 00000000000..1e4fc727f3b --- /dev/null +++ b/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt @@ -0,0 +1,28 @@ +pwm-backlight bindings + +Required properties: + - compatible: "pwm-backlight" + - pwms: OF device-tree PWM specification (see PWM binding[0]) + - brightness-levels: Array of distinct brightness levels. Typically these + are in the range from 0 to 255, but any range starting at 0 will do. + The actual brightness level (PWM duty cycle) will be interpolated + from these values. 0 means a 0% duty cycle (darkest/off), while the + last value in the array represents a 100% duty cycle (brightest). + - default-brightness-level: the default brightness level (index into the + array defined by the "brightness-levels" property) + +Optional properties: + - pwm-names: a list of names for the PWM devices specified in the + "pwms" property (see PWM binding[0]) + +[0]: Documentation/devicetree/bindings/pwm/pwm.txt + +Example: + + backlight { + compatible = "pwm-backlight"; + pwms = <&pwm 0 5000000>; + + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <6>; + }; diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index fa2b0375031..4c9c0221635 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -245,7 +245,7 @@ config BACKLIGHT_CARILLO_RANCH config BACKLIGHT_PWM tristate "Generic PWM based Backlight Driver" - depends on HAVE_PWM + depends on PWM help If you have a LCD backlight adjustable by PWM, say Y to enable this driver. diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index 342b7d7cbb6..057389d69a5 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -26,11 +26,13 @@ struct pwm_bl_data { struct device *dev; unsigned int period; unsigned int lth_brightness; + unsigned int *levels; int (*notify)(struct device *, int brightness); void (*notify_after)(struct device *, int brightness); int (*check_fb)(struct device *, struct fb_info *); + void (*exit)(struct device *); }; static int pwm_backlight_update_status(struct backlight_device *bl) @@ -52,6 +54,11 @@ static int pwm_backlight_update_status(struct backlight_device *bl) pwm_config(pb->pwm, 0, pb->period); pwm_disable(pb->pwm); } else { + if (pb->levels) { + brightness = pb->levels[brightness]; + max = pb->levels[max]; + } + brightness = pb->lth_brightness + (brightness * (pb->period - pb->lth_brightness) / max); pwm_config(pb->pwm, brightness, pb->period); @@ -83,17 +90,98 @@ static const struct backlight_ops pwm_backlight_ops = { .check_fb = pwm_backlight_check_fb, }; +#ifdef CONFIG_OF +static int pwm_backlight_parse_dt(struct device *dev, + struct platform_pwm_backlight_data *data) +{ + struct device_node *node = dev->of_node; + struct property *prop; + int length; + u32 value; + int ret; + + if (!node) + return -ENODEV; + + memset(data, 0, sizeof(*data)); + + /* determine the number of brightness levels */ + prop = of_find_property(node, "brightness-levels", &length); + if (!prop) + return -EINVAL; + + data->max_brightness = length / sizeof(u32); + + /* read brightness levels from DT property */ + if (data->max_brightness > 0) { + size_t size = sizeof(*data->levels) * data->max_brightness; + + data->levels = devm_kzalloc(dev, size, GFP_KERNEL); + if (!data->levels) + return -ENOMEM; + + ret = of_property_read_u32_array(node, "brightness-levels", + data->levels, + data->max_brightness); + if (ret < 0) + return ret; + + ret = of_property_read_u32(node, "default-brightness-level", + &value); + if (ret < 0) + return ret; + + if (value >= data->max_brightness) { + dev_warn(dev, "invalid default brightness level: %u, using %u\n", + value, data->max_brightness - 1); + value = data->max_brightness - 1; + } + + data->dft_brightness = value; + data->max_brightness--; + } + + /* + * TODO: Most users of this driver use a number of GPIOs to control + * backlight power. Support for specifying these needs to be + * added. + */ + + return 0; +} + +static struct of_device_id pwm_backlight_of_match[] = { + { .compatible = "pwm-backlight" }, + { } +}; + +MODULE_DEVICE_TABLE(of, pwm_backlight_of_match); +#else +static int pwm_backlight_parse_dt(struct device *dev, + struct platform_pwm_backlight_data *data) +{ + return -ENODEV; +} +#endif + static int pwm_backlight_probe(struct platform_device *pdev) { - struct backlight_properties props; struct platform_pwm_backlight_data *data = pdev->dev.platform_data; + struct platform_pwm_backlight_data defdata; + struct backlight_properties props; struct backlight_device *bl; struct pwm_bl_data *pb; + unsigned int max; int ret; if (!data) { - dev_err(&pdev->dev, "failed to find platform data\n"); - return -EINVAL; + ret = pwm_backlight_parse_dt(&pdev->dev, &defdata); + if (ret < 0) { + dev_err(&pdev->dev, "failed to find platform data\n"); + return ret; + } + + data = &defdata; } if (data->init) { @@ -109,21 +197,42 @@ static int pwm_backlight_probe(struct platform_device *pdev) goto err_alloc; } - pb->period = data->pwm_period_ns; + if (data->levels) { + max = data->levels[data->max_brightness]; + pb->levels = data->levels; + } else + max = data->max_brightness; + pb->notify = data->notify; pb->notify_after = data->notify_after; pb->check_fb = data->check_fb; - pb->lth_brightness = data->lth_brightness * - (data->pwm_period_ns / data->max_brightness); + pb->exit = data->exit; pb->dev = &pdev->dev; - pb->pwm = pwm_request(data->pwm_id, "backlight"); + pb->pwm = pwm_get(&pdev->dev, NULL); if (IS_ERR(pb->pwm)) { - dev_err(&pdev->dev, "unable to request PWM for backlight\n"); - ret = PTR_ERR(pb->pwm); - goto err_alloc; - } else - dev_dbg(&pdev->dev, "got pwm for backlight\n"); + dev_err(&pdev->dev, "unable to request PWM, trying legacy API\n"); + + pb->pwm = pwm_request(data->pwm_id, "pwm-backlight"); + if (IS_ERR(pb->pwm)) { + dev_err(&pdev->dev, "unable to request legacy PWM\n"); + ret = PTR_ERR(pb->pwm); + goto err_alloc; + } + } + + dev_dbg(&pdev->dev, "got pwm for backlight\n"); + + /* + * The DT case will set the pwm_period_ns field to 0 and store the + * period, parsed from the DT, in the PWM device. For the non-DT case, + * set the period from platform data. + */ + if (data->pwm_period_ns > 0) + pwm_set_period(pb->pwm, data->pwm_period_ns); + + pb->period = pwm_get_period(pb->pwm); + pb->lth_brightness = data->lth_brightness * (pb->period / max); memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; @@ -143,7 +252,7 @@ static int pwm_backlight_probe(struct platform_device *pdev) return 0; err_bl: - pwm_free(pb->pwm); + pwm_put(pb->pwm); err_alloc: if (data->exit) data->exit(&pdev->dev); @@ -152,16 +261,15 @@ err_alloc: static int pwm_backlight_remove(struct platform_device *pdev) { - struct platform_pwm_backlight_data *data = pdev->dev.platform_data; struct backlight_device *bl = platform_get_drvdata(pdev); struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev); backlight_device_unregister(bl); pwm_config(pb->pwm, 0, pb->period); pwm_disable(pb->pwm); - pwm_free(pb->pwm); - if (data->exit) - data->exit(&pdev->dev); + pwm_put(pb->pwm); + if (pb->exit) + pb->exit(&pdev->dev); return 0; } @@ -195,11 +303,12 @@ static SIMPLE_DEV_PM_OPS(pwm_backlight_pm_ops, pwm_backlight_suspend, static struct platform_driver pwm_backlight_driver = { .driver = { - .name = "pwm-backlight", - .owner = THIS_MODULE, + .name = "pwm-backlight", + .owner = THIS_MODULE, #ifdef CONFIG_PM - .pm = &pwm_backlight_pm_ops, + .pm = &pwm_backlight_pm_ops, #endif + .of_match_table = of_match_ptr(pwm_backlight_of_match), }, .probe = pwm_backlight_probe, .remove = pwm_backlight_remove, diff --git a/include/linux/pwm_backlight.h b/include/linux/pwm_backlight.h index 63d2df43e61..56f4a866539 100644 --- a/include/linux/pwm_backlight.h +++ b/include/linux/pwm_backlight.h @@ -12,6 +12,7 @@ struct platform_pwm_backlight_data { unsigned int dft_brightness; unsigned int lth_brightness; unsigned int pwm_period_ns; + unsigned int *levels; int (*init)(struct device *dev); int (*notify)(struct device *dev, int brightness); void (*notify_after)(struct device *dev, int brightness); -- cgit v1.2.3-70-g09d2 From 071407eefd708d7e273b67af150f8dff6c51eb58 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Tue, 26 Jun 2012 16:58:08 +0800 Subject: pwm: pwm-mxs: encode soc name in compatible string Encode soc name in the compatible string to know the specific version hardware block. This is the general approach adopted for most bindings. Change mxs-pwm binding to use the approach. Signed-off-by: Shawn Guo Signed-off-by: Thierry Reding --- Documentation/devicetree/bindings/pwm/mxs-pwm.txt | 4 ++-- drivers/pwm/pwm-mxs.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/pwm/mxs-pwm.txt b/Documentation/devicetree/bindings/pwm/mxs-pwm.txt index 48ead0db178..b16f4a57d11 100644 --- a/Documentation/devicetree/bindings/pwm/mxs-pwm.txt +++ b/Documentation/devicetree/bindings/pwm/mxs-pwm.txt @@ -1,7 +1,7 @@ Freescale MXS PWM controller Required properties: -- compatible: should be "fsl,mxs-pwm" +- compatible: should be "fsl,imx23-pwm" - reg: physical base address and length of the controller's registers - #pwm-cells: should be 2. The first cell specifies the per-chip index of the PWM to use and the second cell is the duty cycle in nanoseconds. @@ -10,7 +10,7 @@ Required properties: Example: pwm: pwm@80064000 { - compatible = "fsl,imx28-pwm", "fsl,mxs-pwm"; + compatible = "fsl,imx28-pwm", "fsl,imx23-pwm"; reg = <0x80064000 2000>; #pwm-cells = <2>; fsl,pwm-number = <8>; diff --git a/drivers/pwm/pwm-mxs.c b/drivers/pwm/pwm-mxs.c index 9602708372b..d9a38050a50 100644 --- a/drivers/pwm/pwm-mxs.c +++ b/drivers/pwm/pwm-mxs.c @@ -186,7 +186,7 @@ static int __devexit mxs_pwm_remove(struct platform_device *pdev) } static struct of_device_id mxs_pwm_dt_ids[] = { - { .compatible = "fsl,mxs-pwm", }, + { .compatible = "fsl,imx23-pwm", }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, mxs_pwm_dt_ids); -- cgit v1.2.3-70-g09d2 From 2132fa8d95bc13b8b0e307553b04ee3517762ebe Mon Sep 17 00:00:00 2001 From: Alexandre Pereira da Silva Date: Tue, 10 Jul 2012 11:38:10 -0300 Subject: pwm: add lpc32xx PWM support Add lpc32xx SOC PWM driver. Signed-off-by: Alexandre Pereira da Silva Acked-by: Roland Stigge Signed-off-by: Thierry Reding --- .../devicetree/bindings/pwm/lpc32xx-pwm.txt | 12 ++ drivers/pwm/Kconfig | 10 ++ drivers/pwm/Makefile | 1 + drivers/pwm/pwm-lpc32xx.c | 148 +++++++++++++++++++++ 4 files changed, 171 insertions(+) create mode 100644 Documentation/devicetree/bindings/pwm/lpc32xx-pwm.txt create mode 100644 drivers/pwm/pwm-lpc32xx.c (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/pwm/lpc32xx-pwm.txt b/Documentation/devicetree/bindings/pwm/lpc32xx-pwm.txt new file mode 100644 index 00000000000..cfe1db3bb6e --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/lpc32xx-pwm.txt @@ -0,0 +1,12 @@ +LPC32XX PWM controller + +Required properties: +- compatible: should be "nxp,lpc3220-pwm" +- reg: physical base address and length of the controller's registers + +Examples: + +pwm@0x4005C000 { + compatible = "nxp,lpc3220-pwm"; + reg = <0x4005C000 0x8>; +}; diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 0b2800fc1ca..94e176e26f4 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -28,6 +28,16 @@ config PWM_IMX To compile this driver as a module, choose M here: the module will be called pwm-imx. +config PWM_LPC32XX + tristate "LPC32XX PWM support" + depends on ARCH_LPC32XX + help + Generic PWM framework driver for LPC32XX. The LPC32XX SOC has two + PWM controllers. + + To compile this driver as a module, choose M here: the module + will be called pwm-lpc32xx. + config PWM_MXS tristate "Freescale MXS PWM support" depends on ARCH_MXS && OF diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index cec250091cf..54597020350 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_PWM) += core.o obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o obj-$(CONFIG_PWM_IMX) += pwm-imx.o +obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o obj-$(CONFIG_PWM_MXS) += pwm-mxs.o obj-$(CONFIG_PWM_PXA) += pwm-pxa.o obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o diff --git a/drivers/pwm/pwm-lpc32xx.c b/drivers/pwm/pwm-lpc32xx.c new file mode 100644 index 00000000000..adb87f0c163 --- /dev/null +++ b/drivers/pwm/pwm-lpc32xx.c @@ -0,0 +1,148 @@ +/* + * Copyright 2012 Alexandre Pereira da Silva + * + * 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 + * the Free Software Foundation; version 2. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct lpc32xx_pwm_chip { + struct pwm_chip chip; + struct clk *clk; + void __iomem *base; +}; + +#define PWM_ENABLE (1 << 31) +#define PWM_RELOADV(x) (((x) & 0xFF) << 8) +#define PWM_DUTY(x) ((x) & 0xFF) + +#define to_lpc32xx_pwm_chip(_chip) \ + container_of(_chip, struct lpc32xx_pwm_chip, chip) + +static int lpc32xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, + int duty_ns, int period_ns) +{ + struct lpc32xx_pwm_chip *lpc32xx = to_lpc32xx_pwm_chip(chip); + unsigned long long c; + int period_cycles, duty_cycles; + + c = clk_get_rate(lpc32xx->clk) / 256; + c = c * period_ns; + do_div(c, NSEC_PER_SEC); + + /* Handle high and low extremes */ + if (c == 0) + c = 1; + if (c > 255) + c = 0; /* 0 set division by 256 */ + period_cycles = c; + + c = 256 * duty_ns; + do_div(c, period_ns); + duty_cycles = c; + + writel(PWM_ENABLE | PWM_RELOADV(period_cycles) | PWM_DUTY(duty_cycles), + lpc32xx->base + (pwm->hwpwm << 2)); + + return 0; +} + +static int lpc32xx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct lpc32xx_pwm_chip *lpc32xx = to_lpc32xx_pwm_chip(chip); + + return clk_enable(lpc32xx->clk); +} + +static void lpc32xx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct lpc32xx_pwm_chip *lpc32xx = to_lpc32xx_pwm_chip(chip); + + writel(0, lpc32xx->base + (pwm->hwpwm << 2)); + clk_disable(lpc32xx->clk); +} + +static const struct pwm_ops lpc32xx_pwm_ops = { + .config = lpc32xx_pwm_config, + .enable = lpc32xx_pwm_enable, + .disable = lpc32xx_pwm_disable, + .owner = THIS_MODULE, +}; + +static int lpc32xx_pwm_probe(struct platform_device *pdev) +{ + struct lpc32xx_pwm_chip *lpc32xx; + struct resource *res; + int ret; + + lpc32xx = devm_kzalloc(&pdev->dev, sizeof(*lpc32xx), GFP_KERNEL); + if (!lpc32xx) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; + + lpc32xx->base = devm_request_and_ioremap(&pdev->dev, res); + if (!lpc32xx->base) + return -EADDRNOTAVAIL; + + lpc32xx->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(lpc32xx->clk)) + return PTR_ERR(lpc32xx->clk); + + lpc32xx->chip.dev = &pdev->dev; + lpc32xx->chip.ops = &lpc32xx_pwm_ops; + lpc32xx->chip.npwm = 2; + + ret = pwmchip_add(&lpc32xx->chip); + if (ret < 0) { + dev_err(&pdev->dev, "failed to add PWM chip, error %d\n", ret); + return ret; + } + + platform_set_drvdata(pdev, lpc32xx); + + return 0; +} + +static int __devexit lpc32xx_pwm_remove(struct platform_device *pdev) +{ + struct lpc32xx_pwm_chip *lpc32xx = platform_get_drvdata(pdev); + + clk_disable(lpc32xx->clk); + return pwmchip_remove(&lpc32xx->chip); +} + +static struct of_device_id lpc32xx_pwm_dt_ids[] = { + { .compatible = "nxp,lpc3220-pwm", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, lpc32xx_pwm_dt_ids); + +static struct platform_driver lpc32xx_pwm_driver = { + .driver = { + .name = "lpc32xx-pwm", + .of_match_table = of_match_ptr(lpc32xx_pwm_dt_ids), + }, + .probe = lpc32xx_pwm_probe, + .remove = __devexit_p(lpc32xx_pwm_remove), +}; +module_platform_driver(lpc32xx_pwm_driver); + +MODULE_ALIAS("platform:lpc32xx-pwm"); +MODULE_AUTHOR("Alexandre Pereira da Silva "); +MODULE_DESCRIPTION("LPC32XX PWM Driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-70-g09d2 From 736b1c9c957e38b80d2e36b2ed196fa1c07468bc Mon Sep 17 00:00:00 2001 From: David Daney Date: Thu, 5 Jul 2012 18:12:38 +0200 Subject: MIPS: Octeon: Add device tree source files. The two device tree files octeon_3xxx.dts and octeon_68xx.dts are trimmed by code in a subsequent patch to reflect the hardware actually present on the board. To this end several properties that are not part of the declared bindings are added to aid in trimming off unwanted nodes. Since the device tree and the code that trims it are bound into the kernel binary, these 'marker' properties never escape into the wild, and are purely an implementation detail of the kernel early boot process. This is done for backwards compatibility with existing boards (identified by a board type enumeration value by their bootloaders). New boards will always pass a device tree from the bootloader, the built-in trees are ignored in this case. Signed-off-by: David Daney Cc: linux-mips@linux-mips.org Cc: devicetree-discuss@lists.ozlabs.org Cc: Grant Likely Cc: Rob Herring Cc: linux-kernel@vger.kernel.org Cc: David Daney Patchwork: https://patchwork.linux-mips.org/patch/3937/ Signed-off-by: Ralf Baechle --- .../bindings/ata/cavium-compact-flash.txt | 30 + .../bindings/gpio/cavium-octeon-gpio.txt | 49 ++ .../devicetree/bindings/i2c/cavium-i2c.txt | 34 ++ .../devicetree/bindings/mips/cavium/bootbus.txt | 126 +++++ .../devicetree/bindings/mips/cavium/ciu.txt | 26 + .../devicetree/bindings/mips/cavium/ciu2.txt | 27 + .../devicetree/bindings/mips/cavium/dma-engine.txt | 21 + .../devicetree/bindings/mips/cavium/uctl.txt | 46 ++ .../devicetree/bindings/net/cavium-mdio.txt | 27 + .../devicetree/bindings/net/cavium-mix.txt | 39 ++ .../devicetree/bindings/net/cavium-pip.txt | 98 ++++ .../devicetree/bindings/serial/cavium-uart.txt | 19 + arch/mips/cavium-octeon/.gitignore | 2 + arch/mips/cavium-octeon/Makefile | 13 + arch/mips/cavium-octeon/octeon_3xxx.dts | 571 +++++++++++++++++++ arch/mips/cavium-octeon/octeon_68xx.dts | 625 +++++++++++++++++++++ 16 files changed, 1753 insertions(+) create mode 100644 Documentation/devicetree/bindings/ata/cavium-compact-flash.txt create mode 100644 Documentation/devicetree/bindings/gpio/cavium-octeon-gpio.txt create mode 100644 Documentation/devicetree/bindings/i2c/cavium-i2c.txt create mode 100644 Documentation/devicetree/bindings/mips/cavium/bootbus.txt create mode 100644 Documentation/devicetree/bindings/mips/cavium/ciu.txt create mode 100644 Documentation/devicetree/bindings/mips/cavium/ciu2.txt create mode 100644 Documentation/devicetree/bindings/mips/cavium/dma-engine.txt create mode 100644 Documentation/devicetree/bindings/mips/cavium/uctl.txt create mode 100644 Documentation/devicetree/bindings/net/cavium-mdio.txt create mode 100644 Documentation/devicetree/bindings/net/cavium-mix.txt create mode 100644 Documentation/devicetree/bindings/net/cavium-pip.txt create mode 100644 Documentation/devicetree/bindings/serial/cavium-uart.txt create mode 100644 arch/mips/cavium-octeon/.gitignore create mode 100644 arch/mips/cavium-octeon/octeon_3xxx.dts create mode 100644 arch/mips/cavium-octeon/octeon_68xx.dts (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/ata/cavium-compact-flash.txt b/Documentation/devicetree/bindings/ata/cavium-compact-flash.txt new file mode 100644 index 00000000000..93986a5a801 --- /dev/null +++ b/Documentation/devicetree/bindings/ata/cavium-compact-flash.txt @@ -0,0 +1,30 @@ +* Compact Flash + +The Cavium Compact Flash device is connected to the Octeon Boot Bus, +and is thus a child of the Boot Bus device. It can read and write +industry standard compact flash devices. + +Properties: +- compatible: "cavium,ebt3000-compact-flash"; + + Compatibility with many Cavium evaluation boards. + +- reg: The base address of the the CF chip select banks. Depending on + the device configuration, there may be one or two banks. + +- cavium,bus-width: The width of the connection to the CF devices. Valid + values are 8 and 16. + +- cavium,true-ide: Optional, if present the CF connection is in True IDE mode. + +- cavium,dma-engine-handle: Optional, a phandle for the DMA Engine connected + to this device. + +Example: + compact-flash@5,0 { + compatible = "cavium,ebt3000-compact-flash"; + reg = <5 0 0x10000>, <6 0 0x10000>; + cavium,bus-width = <16>; + cavium,true-ide; + cavium,dma-engine-handle = <&dma0>; + }; diff --git a/Documentation/devicetree/bindings/gpio/cavium-octeon-gpio.txt b/Documentation/devicetree/bindings/gpio/cavium-octeon-gpio.txt new file mode 100644 index 00000000000..9d6dcd3fe7f --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/cavium-octeon-gpio.txt @@ -0,0 +1,49 @@ +* General Purpose Input Output (GPIO) bus. + +Properties: +- compatible: "cavium,octeon-3860-gpio" + + Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs. + +- reg: The base address of the GPIO unit's register bank. + +- gpio-controller: This is a GPIO controller. + +- #gpio-cells: Must be <2>. The first cell is the GPIO pin. + +- interrupt-controller: The GPIO controller is also an interrupt + controller, many of its pins may be configured as an interrupt + source. + +- #interrupt-cells: Must be <2>. The first cell is the GPIO pin + connected to the interrupt source. The second cell is the interrupt + triggering protocol and may have one of four values: + 1 - edge triggered on the rising edge. + 2 - edge triggered on the falling edge + 4 - level triggered active high. + 8 - level triggered active low. + +- interrupts: Interrupt routing for each pin. + +Example: + + gpio-controller@1070000000800 { + #gpio-cells = <2>; + compatible = "cavium,octeon-3860-gpio"; + reg = <0x10700 0x00000800 0x0 0x100>; + gpio-controller; + /* Interrupts are specified by two parts: + * 1) GPIO pin number (0..15) + * 2) Triggering (1 - edge rising + * 2 - edge falling + * 4 - level active high + * 8 - level active low) + */ + interrupt-controller; + #interrupt-cells = <2>; + /* The GPIO pin connect to 16 consecutive CUI bits */ + interrupts = <0 16>, <0 17>, <0 18>, <0 19>, + <0 20>, <0 21>, <0 22>, <0 23>, + <0 24>, <0 25>, <0 26>, <0 27>, + <0 28>, <0 29>, <0 30>, <0 31>; + }; diff --git a/Documentation/devicetree/bindings/i2c/cavium-i2c.txt b/Documentation/devicetree/bindings/i2c/cavium-i2c.txt new file mode 100644 index 00000000000..dced82ebe31 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/cavium-i2c.txt @@ -0,0 +1,34 @@ +* Two Wire Serial Interface (TWSI) / I2C + +- compatible: "cavium,octeon-3860-twsi" + + Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs. + +- reg: The base address of the TWSI/I2C bus controller register bank. + +- #address-cells: Must be <1>. + +- #size-cells: Must be <0>. I2C addresses have no size component. + +- interrupts: A single interrupt specifier. + +- clock-frequency: The I2C bus clock rate in Hz. + +Example: + twsi0: i2c@1180000001000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "cavium,octeon-3860-twsi"; + reg = <0x11800 0x00001000 0x0 0x200>; + interrupts = <0 45>; + clock-frequency = <100000>; + + rtc@68 { + compatible = "dallas,ds1337"; + reg = <0x68>; + }; + tmp@4c { + compatible = "ti,tmp421"; + reg = <0x4c>; + }; + }; diff --git a/Documentation/devicetree/bindings/mips/cavium/bootbus.txt b/Documentation/devicetree/bindings/mips/cavium/bootbus.txt new file mode 100644 index 00000000000..6581478225a --- /dev/null +++ b/Documentation/devicetree/bindings/mips/cavium/bootbus.txt @@ -0,0 +1,126 @@ +* Boot Bus + +The Octeon Boot Bus is a configurable parallel bus with 8 chip +selects. Each chip select is independently configurable. + +Properties: +- compatible: "cavium,octeon-3860-bootbus" + + Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs. + +- reg: The base address of the Boot Bus' register bank. + +- #address-cells: Must be <2>. The first cell is the chip select + within the bootbus. The second cell is the offset from the chip select. + +- #size-cells: Must be <1>. + +- ranges: There must be one one triplet of (child-bus-address, + parent-bus-address, length) for each active chip select. If the + length element for any triplet is zero, the chip select is disabled, + making it inactive. + +The configuration parameters for each chip select are stored in child +nodes. + +Configuration Properties: +- compatible: "cavium,octeon-3860-bootbus-config" + +- cavium,cs-index: A single cell indicating the chip select that + corresponds to this configuration. + +- cavium,t-adr: A cell specifying the ADR timing (in nS). + +- cavium,t-ce: A cell specifying the CE timing (in nS). + +- cavium,t-oe: A cell specifying the OE timing (in nS). + +- cavium,t-we: A cell specifying the WE timing (in nS). + +- cavium,t-rd-hld: A cell specifying the RD_HLD timing (in nS). + +- cavium,t-wr-hld: A cell specifying the WR_HLD timing (in nS). + +- cavium,t-pause: A cell specifying the PAUSE timing (in nS). + +- cavium,t-wait: A cell specifying the WAIT timing (in nS). + +- cavium,t-page: A cell specifying the PAGE timing (in nS). + +- cavium,t-rd-dly: A cell specifying the RD_DLY timing (in nS). + +- cavium,pages: A cell specifying the PAGES parameter (0 = 8 bytes, 1 + = 2 bytes, 2 = 4 bytes, 3 = 8 bytes). + +- cavium,wait-mode: Optional. If present, wait mode (WAITM) is selected. + +- cavium,page-mode: Optional. If present, page mode (PAGEM) is selected. + +- cavium,bus-width: A cell specifying the WIDTH parameter (in bits) of + the bus for this chip select. + +- cavium,ale-mode: Optional. If present, ALE mode is selected. + +- cavium,sam-mode: Optional. If present, SAM mode is selected. + +- cavium,or-mode: Optional. If present, OR mode is selected. + +Example: + bootbus: bootbus@1180000000000 { + compatible = "cavium,octeon-3860-bootbus"; + reg = <0x11800 0x00000000 0x0 0x200>; + /* The chip select number and offset */ + #address-cells = <2>; + /* The size of the chip select region */ + #size-cells = <1>; + ranges = <0 0 0x0 0x1f400000 0xc00000>, + <1 0 0x10000 0x30000000 0>, + <2 0 0x10000 0x40000000 0>, + <3 0 0x10000 0x50000000 0>, + <4 0 0x0 0x1d020000 0x10000>, + <5 0 0x0 0x1d040000 0x10000>, + <6 0 0x0 0x1d050000 0x10000>, + <7 0 0x10000 0x90000000 0>; + + cavium,cs-config@0 { + compatible = "cavium,octeon-3860-bootbus-config"; + cavium,cs-index = <0>; + cavium,t-adr = <20>; + cavium,t-ce = <60>; + cavium,t-oe = <60>; + cavium,t-we = <45>; + cavium,t-rd-hld = <35>; + cavium,t-wr-hld = <45>; + cavium,t-pause = <0>; + cavium,t-wait = <0>; + cavium,t-page = <35>; + cavium,t-rd-dly = <0>; + + cavium,pages = <0>; + cavium,bus-width = <8>; + }; + . + . + . + cavium,cs-config@6 { + compatible = "cavium,octeon-3860-bootbus-config"; + cavium,cs-index = <6>; + cavium,t-adr = <5>; + cavium,t-ce = <300>; + cavium,t-oe = <270>; + cavium,t-we = <150>; + cavium,t-rd-hld = <100>; + cavium,t-wr-hld = <70>; + cavium,t-pause = <0>; + cavium,t-wait = <0>; + cavium,t-page = <320>; + cavium,t-rd-dly = <0>; + + cavium,pages = <0>; + cavium,wait-mode; + cavium,bus-width = <16>; + }; + . + . + . + }; diff --git a/Documentation/devicetree/bindings/mips/cavium/ciu.txt b/Documentation/devicetree/bindings/mips/cavium/ciu.txt new file mode 100644 index 00000000000..2c2d0746b43 --- /dev/null +++ b/Documentation/devicetree/bindings/mips/cavium/ciu.txt @@ -0,0 +1,26 @@ +* Central Interrupt Unit + +Properties: +- compatible: "cavium,octeon-3860-ciu" + + Compatibility with all cn3XXX, cn5XXX and cn63XX SOCs. + +- interrupt-controller: This is an interrupt controller. + +- reg: The base address of the CIU's register bank. + +- #interrupt-cells: Must be <2>. The first cell is the bank within + the CIU and may have a value of 0 or 1. The second cell is the bit + within the bank and may have a value between 0 and 63. + +Example: + interrupt-controller@1070000000000 { + compatible = "cavium,octeon-3860-ciu"; + interrupt-controller; + /* Interrupts are specified by two parts: + * 1) Controller register (0 or 1) + * 2) Bit within the register (0..63) + */ + #interrupt-cells = <2>; + reg = <0x10700 0x00000000 0x0 0x7000>; + }; diff --git a/Documentation/devicetree/bindings/mips/cavium/ciu2.txt b/Documentation/devicetree/bindings/mips/cavium/ciu2.txt new file mode 100644 index 00000000000..0ec7ba8bbbc --- /dev/null +++ b/Documentation/devicetree/bindings/mips/cavium/ciu2.txt @@ -0,0 +1,27 @@ +* Central Interrupt Unit + +Properties: +- compatible: "cavium,octeon-6880-ciu2" + + Compatibility with 68XX SOCs. + +- interrupt-controller: This is an interrupt controller. + +- reg: The base address of the CIU's register bank. + +- #interrupt-cells: Must be <2>. The first cell is the bank within + the CIU and may have a value between 0 and 63. The second cell is + the bit within the bank and may also have a value between 0 and 63. + +Example: + interrupt-controller@1070100000000 { + compatible = "cavium,octeon-6880-ciu2"; + interrupt-controller; + /* Interrupts are specified by two parts: + * 1) Controller register (0..63) + * 2) Bit within the register (0..63) + */ + #address-cells = <0>; + #interrupt-cells = <2>; + reg = <0x10701 0x00000000 0x0 0x4000000>; + }; diff --git a/Documentation/devicetree/bindings/mips/cavium/dma-engine.txt b/Documentation/devicetree/bindings/mips/cavium/dma-engine.txt new file mode 100644 index 00000000000..cb4291e3b1d --- /dev/null +++ b/Documentation/devicetree/bindings/mips/cavium/dma-engine.txt @@ -0,0 +1,21 @@ +* DMA Engine. + +The Octeon DMA Engine transfers between the Boot Bus and main memory. +The DMA Engine will be refered to by phandle by any device that is +connected to it. + +Properties: +- compatible: "cavium,octeon-5750-bootbus-dma" + + Compatibility with all cn52XX, cn56XX and cn6XXX SOCs. + +- reg: The base address of the DMA Engine's register bank. + +- interrupts: A single interrupt specifier. + +Example: + dma0: dma-engine@1180000000100 { + compatible = "cavium,octeon-5750-bootbus-dma"; + reg = <0x11800 0x00000100 0x0 0x8>; + interrupts = <0 63>; + }; diff --git a/Documentation/devicetree/bindings/mips/cavium/uctl.txt b/Documentation/devicetree/bindings/mips/cavium/uctl.txt new file mode 100644 index 00000000000..aa66b9b8d80 --- /dev/null +++ b/Documentation/devicetree/bindings/mips/cavium/uctl.txt @@ -0,0 +1,46 @@ +* UCTL USB controller glue + +Properties: +- compatible: "cavium,octeon-6335-uctl" + + Compatibility with all cn6XXX SOCs. + +- reg: The base address of the UCTL register bank. + +- #address-cells: Must be <2>. + +- #size-cells: Must be <2>. + +- ranges: Empty to signify direct mapping of the children. + +- refclk-frequency: A single cell containing the reference clock + frequency in Hz. + +- refclk-type: A string describing the reference clock connection + either "crystal" or "external". + +Example: + uctl@118006f000000 { + compatible = "cavium,octeon-6335-uctl"; + reg = <0x11800 0x6f000000 0x0 0x100>; + ranges; /* Direct mapping */ + #address-cells = <2>; + #size-cells = <2>; + /* 12MHz, 24MHz and 48MHz allowed */ + refclk-frequency = <24000000>; + /* Either "crystal" or "external" */ + refclk-type = "crystal"; + + ehci@16f0000000000 { + compatible = "cavium,octeon-6335-ehci","usb-ehci"; + reg = <0x16f00 0x00000000 0x0 0x100>; + interrupts = <0 56>; + big-endian-regs; + }; + ohci@16f0000000400 { + compatible = "cavium,octeon-6335-ohci","usb-ohci"; + reg = <0x16f00 0x00000400 0x0 0x100>; + interrupts = <0 56>; + big-endian-regs; + }; + }; diff --git a/Documentation/devicetree/bindings/net/cavium-mdio.txt b/Documentation/devicetree/bindings/net/cavium-mdio.txt new file mode 100644 index 00000000000..04cb7491d23 --- /dev/null +++ b/Documentation/devicetree/bindings/net/cavium-mdio.txt @@ -0,0 +1,27 @@ +* System Management Interface (SMI) / MDIO + +Properties: +- compatible: "cavium,octeon-3860-mdio" + + Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs. + +- reg: The base address of the MDIO bus controller register bank. + +- #address-cells: Must be <1>. + +- #size-cells: Must be <0>. MDIO addresses have no size component. + +Typically an MDIO bus might have several children. + +Example: + mdio@1180000001800 { + compatible = "cavium,octeon-3860-mdio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x11800 0x00001800 0x0 0x40>; + + ethernet-phy@0 { + ... + reg = <0>; + }; + }; diff --git a/Documentation/devicetree/bindings/net/cavium-mix.txt b/Documentation/devicetree/bindings/net/cavium-mix.txt new file mode 100644 index 00000000000..5da628db68b --- /dev/null +++ b/Documentation/devicetree/bindings/net/cavium-mix.txt @@ -0,0 +1,39 @@ +* MIX Ethernet controller. + +Properties: +- compatible: "cavium,octeon-5750-mix" + + Compatibility with all cn5XXX and cn6XXX SOCs populated with MIX + devices. + +- reg: The base addresses of four separate register banks. The first + bank contains the MIX registers. The second bank the corresponding + AGL registers. The third bank are the AGL registers shared by all + MIX devices present. The fourth bank is the AGL_PRT_CTL shared by + all MIX devices present. + +- cell-index: A single cell specifying which portion of the shared + register banks corresponds to this MIX device. + +- interrupts: Two interrupt specifiers. The first is the MIX + interrupt routing and the second the routing for the AGL interrupts. + +- mac-address: Optional, the MAC address to assign to the device. + +- local-mac-address: Optional, the MAC address to assign to the device + if mac-address is not specified. + +- phy-handle: Optional, a phandle for the PHY device connected to this device. + +Example: + ethernet@1070000100800 { + compatible = "cavium,octeon-5750-mix"; + reg = <0x10700 0x00100800 0x0 0x100>, /* MIX */ + <0x11800 0xE0000800 0x0 0x300>, /* AGL */ + <0x11800 0xE0000400 0x0 0x400>, /* AGL_SHARED */ + <0x11800 0xE0002008 0x0 0x8>; /* AGL_PRT_CTL */ + cell-index = <1>; + interrupts = <1 18>, < 1 46>; + local-mac-address = [ 00 0f b7 10 63 54 ]; + phy-handle = <&phy1>; + }; diff --git a/Documentation/devicetree/bindings/net/cavium-pip.txt b/Documentation/devicetree/bindings/net/cavium-pip.txt new file mode 100644 index 00000000000..d4c53ba04b3 --- /dev/null +++ b/Documentation/devicetree/bindings/net/cavium-pip.txt @@ -0,0 +1,98 @@ +* PIP Ethernet nexus. + +The PIP Ethernet nexus can control several data packet input/output +devices. The devices have a two level grouping scheme. There may be +several interfaces, and each interface may have several ports. These +ports might be an individual Ethernet PHY. + + +Properties for the PIP nexus: +- compatible: "cavium,octeon-3860-pip" + + Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs. + +- reg: The base address of the PIP's register bank. + +- #address-cells: Must be <1>. + +- #size-cells: Must be <0>. + +Properties for PIP interfaces which is a child the PIP nexus: +- compatible: "cavium,octeon-3860-pip-interface" + + Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs. + +- reg: The interface number. + +- #address-cells: Must be <1>. + +- #size-cells: Must be <0>. + +Properties for PIP port which is a child the PIP interface: +- compatible: "cavium,octeon-3860-pip-port" + + Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs. + +- reg: The port number within the interface group. + +- mac-address: Optional, the MAC address to assign to the device. + +- local-mac-address: Optional, the MAC address to assign to the device + if mac-address is not specified. + +- phy-handle: Optional, a phandle for the PHY device connected to this device. + +Example: + + pip@11800a0000000 { + compatible = "cavium,octeon-3860-pip"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x11800 0xa0000000 0x0 0x2000>; + + interface@0 { + compatible = "cavium,octeon-3860-pip-interface"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; /* interface */ + + ethernet@0 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x0>; /* Port */ + local-mac-address = [ 00 0f b7 10 63 60 ]; + phy-handle = <&phy2>; + }; + ethernet@1 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x1>; /* Port */ + local-mac-address = [ 00 0f b7 10 63 61 ]; + phy-handle = <&phy3>; + }; + ethernet@2 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x2>; /* Port */ + local-mac-address = [ 00 0f b7 10 63 62 ]; + phy-handle = <&phy4>; + }; + ethernet@3 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x3>; /* Port */ + local-mac-address = [ 00 0f b7 10 63 63 ]; + phy-handle = <&phy5>; + }; + }; + + interface@1 { + compatible = "cavium,octeon-3860-pip-interface"; + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; /* interface */ + + ethernet@0 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x0>; /* Port */ + local-mac-address = [ 00 0f b7 10 63 64 ]; + phy-handle = <&phy6>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/serial/cavium-uart.txt b/Documentation/devicetree/bindings/serial/cavium-uart.txt new file mode 100644 index 00000000000..87a6c375cd4 --- /dev/null +++ b/Documentation/devicetree/bindings/serial/cavium-uart.txt @@ -0,0 +1,19 @@ +* Universal Asynchronous Receiver/Transmitter (UART) + +- compatible: "cavium,octeon-3860-uart" + + Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs. + +- reg: The base address of the UART register bank. + +- interrupts: A single interrupt specifier. + +- current-speed: Optional, the current bit rate in bits per second. + +Example: + uart1: serial@1180000000c00 { + compatible = "cavium,octeon-3860-uart","ns16550"; + reg = <0x11800 0x00000c00 0x0 0x400>; + current-speed = <115200>; + interrupts = <0 35>; + }; diff --git a/arch/mips/cavium-octeon/.gitignore b/arch/mips/cavium-octeon/.gitignore new file mode 100644 index 00000000000..39c968605ff --- /dev/null +++ b/arch/mips/cavium-octeon/.gitignore @@ -0,0 +1,2 @@ +*.dtb.S +*.dtb diff --git a/arch/mips/cavium-octeon/Makefile b/arch/mips/cavium-octeon/Makefile index 19eb0434269..1e37522cc21 100644 --- a/arch/mips/cavium-octeon/Makefile +++ b/arch/mips/cavium-octeon/Makefile @@ -15,3 +15,16 @@ obj-y += octeon-memcpy.o obj-y += executive/ obj-$(CONFIG_SMP) += smp.o + +DTS_FILES = octeon_3xxx.dts octeon_68xx.dts +DTB_FILES = $(patsubst %.dts, %.dtb, $(DTS_FILES)) + +obj-y += $(patsubst %.dts, %.dtb.o, $(DTS_FILES)) + +$(obj)/%.dtb: $(src)/%.dts FORCE + $(call if_changed_dep,dtc) + +# Let's keep the .dtb files around in case we want to look at them. +.SECONDARY: $(addprefix $(obj)/, $(DTB_FILES)) + +clean-files += $(DTB_FILES) $(patsubst %.dtb, %.dtb.S, $(DTB_FILES)) diff --git a/arch/mips/cavium-octeon/octeon_3xxx.dts b/arch/mips/cavium-octeon/octeon_3xxx.dts new file mode 100644 index 00000000000..f28b2d0fde2 --- /dev/null +++ b/arch/mips/cavium-octeon/octeon_3xxx.dts @@ -0,0 +1,571 @@ +/dts-v1/; +/* + * OCTEON 3XXX, 5XXX, 63XX device tree skeleton. + * + * This device tree is pruned and patched by early boot code before + * use. Because of this, it contains a super-set of the available + * devices and properties. + */ +/ { + compatible = "cavium,octeon-3860"; + #address-cells = <2>; + #size-cells = <2>; + interrupt-parent = <&ciu>; + + soc@0 { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; /* Direct mapping */ + + ciu: interrupt-controller@1070000000000 { + compatible = "cavium,octeon-3860-ciu"; + interrupt-controller; + /* Interrupts are specified by two parts: + * 1) Controller register (0 or 1) + * 2) Bit within the register (0..63) + */ + #interrupt-cells = <2>; + reg = <0x10700 0x00000000 0x0 0x7000>; + }; + + gpio: gpio-controller@1070000000800 { + #gpio-cells = <2>; + compatible = "cavium,octeon-3860-gpio"; + reg = <0x10700 0x00000800 0x0 0x100>; + gpio-controller; + /* Interrupts are specified by two parts: + * 1) GPIO pin number (0..15) + * 2) Triggering (1 - edge rising + * 2 - edge falling + * 4 - level active high + * 8 - level active low) + */ + interrupt-controller; + #interrupt-cells = <2>; + /* The GPIO pin connect to 16 consecutive CUI bits */ + interrupts = <0 16>, <0 17>, <0 18>, <0 19>, + <0 20>, <0 21>, <0 22>, <0 23>, + <0 24>, <0 25>, <0 26>, <0 27>, + <0 28>, <0 29>, <0 30>, <0 31>; + }; + + smi0: mdio@1180000001800 { + compatible = "cavium,octeon-3860-mdio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x11800 0x00001800 0x0 0x40>; + + phy0: ethernet-phy@0 { + compatible = "marvell,88e1118"; + marvell,reg-init = + /* Fix rx and tx clock transition timing */ + <2 0x15 0xffcf 0>, /* Reg 2,21 Clear bits 4, 5 */ + /* Adjust LED drive. */ + <3 0x11 0 0x442a>, /* Reg 3,17 <- 0442a */ + /* irq, blink-activity, blink-link */ + <3 0x10 0 0x0242>; /* Reg 3,16 <- 0x0242 */ + reg = <0>; + }; + + phy1: ethernet-phy@1 { + compatible = "marvell,88e1118"; + marvell,reg-init = + /* Fix rx and tx clock transition timing */ + <2 0x15 0xffcf 0>, /* Reg 2,21 Clear bits 4, 5 */ + /* Adjust LED drive. */ + <3 0x11 0 0x442a>, /* Reg 3,17 <- 0442a */ + /* irq, blink-activity, blink-link */ + <3 0x10 0 0x0242>; /* Reg 3,16 <- 0x0242 */ + reg = <1>; + }; + + phy2: ethernet-phy@2 { + reg = <2>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy3: ethernet-phy@3 { + reg = <3>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy4: ethernet-phy@4 { + reg = <4>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy5: ethernet-phy@5 { + reg = <5>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + + phy6: ethernet-phy@6 { + reg = <6>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy7: ethernet-phy@7 { + reg = <7>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy8: ethernet-phy@8 { + reg = <8>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy9: ethernet-phy@9 { + reg = <9>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + }; + + smi1: mdio@1180000001900 { + compatible = "cavium,octeon-3860-mdio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x11800 0x00001900 0x0 0x40>; + + phy100: ethernet-phy@1 { + reg = <1>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <12 8>; /* Pin 12, active low */ + }; + phy101: ethernet-phy@2 { + reg = <2>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <12 8>; /* Pin 12, active low */ + }; + phy102: ethernet-phy@3 { + reg = <3>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <12 8>; /* Pin 12, active low */ + }; + phy103: ethernet-phy@4 { + reg = <4>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <12 8>; /* Pin 12, active low */ + }; + }; + + mix0: ethernet@1070000100000 { + compatible = "cavium,octeon-5750-mix"; + reg = <0x10700 0x00100000 0x0 0x100>, /* MIX */ + <0x11800 0xE0000000 0x0 0x300>, /* AGL */ + <0x11800 0xE0000400 0x0 0x400>, /* AGL_SHARED */ + <0x11800 0xE0002000 0x0 0x8>; /* AGL_PRT_CTL */ + cell-index = <0>; + interrupts = <0 62>, <1 46>; + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy0>; + }; + + mix1: ethernet@1070000100800 { + compatible = "cavium,octeon-5750-mix"; + reg = <0x10700 0x00100800 0x0 0x100>, /* MIX */ + <0x11800 0xE0000800 0x0 0x300>, /* AGL */ + <0x11800 0xE0000400 0x0 0x400>, /* AGL_SHARED */ + <0x11800 0xE0002008 0x0 0x8>; /* AGL_PRT_CTL */ + cell-index = <1>; + interrupts = <1 18>, < 1 46>; + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy1>; + }; + + pip: pip@11800a0000000 { + compatible = "cavium,octeon-3860-pip"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x11800 0xa0000000 0x0 0x2000>; + + interface@0 { + compatible = "cavium,octeon-3860-pip-interface"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; /* interface */ + + ethernet@0 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x0>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy2>; + cavium,alt-phy-handle = <&phy100>; + }; + ethernet@1 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x1>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy3>; + cavium,alt-phy-handle = <&phy101>; + }; + ethernet@2 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x2>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy4>; + cavium,alt-phy-handle = <&phy102>; + }; + ethernet@3 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x3>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy5>; + cavium,alt-phy-handle = <&phy103>; + }; + ethernet@4 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x4>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + }; + ethernet@5 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x5>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + }; + ethernet@6 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x6>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + }; + ethernet@7 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x7>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + }; + ethernet@8 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x8>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + }; + ethernet@9 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x9>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + }; + ethernet@a { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0xa>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + }; + ethernet@b { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0xb>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + }; + ethernet@c { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0xc>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + }; + ethernet@d { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0xd>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + }; + ethernet@e { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0xe>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + }; + ethernet@f { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0xf>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + }; + }; + + interface@1 { + compatible = "cavium,octeon-3860-pip-interface"; + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; /* interface */ + + ethernet@0 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x0>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy6>; + }; + ethernet@1 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x1>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy7>; + }; + ethernet@2 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x2>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy8>; + }; + ethernet@3 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x3>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy9>; + }; + }; + }; + + twsi0: i2c@1180000001000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "cavium,octeon-3860-twsi"; + reg = <0x11800 0x00001000 0x0 0x200>; + interrupts = <0 45>; + clock-frequency = <100000>; + + rtc@68 { + compatible = "dallas,ds1337"; + reg = <0x68>; + }; + tmp@4c { + compatible = "ti,tmp421"; + reg = <0x4c>; + }; + }; + + twsi1: i2c@1180000001200 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "cavium,octeon-3860-twsi"; + reg = <0x11800 0x00001200 0x0 0x200>; + interrupts = <0 59>; + clock-frequency = <100000>; + }; + + uart0: serial@1180000000800 { + compatible = "cavium,octeon-3860-uart","ns16550"; + reg = <0x11800 0x00000800 0x0 0x400>; + clock-frequency = <0>; + current-speed = <115200>; + reg-shift = <3>; + interrupts = <0 34>; + }; + + uart1: serial@1180000000c00 { + compatible = "cavium,octeon-3860-uart","ns16550"; + reg = <0x11800 0x00000c00 0x0 0x400>; + clock-frequency = <0>; + current-speed = <115200>; + reg-shift = <3>; + interrupts = <0 35>; + }; + + uart2: serial@1180000000400 { + compatible = "cavium,octeon-3860-uart","ns16550"; + reg = <0x11800 0x00000400 0x0 0x400>; + clock-frequency = <0>; + current-speed = <115200>; + reg-shift = <3>; + interrupts = <1 16>; + }; + + bootbus: bootbus@1180000000000 { + compatible = "cavium,octeon-3860-bootbus"; + reg = <0x11800 0x00000000 0x0 0x200>; + /* The chip select number and offset */ + #address-cells = <2>; + /* The size of the chip select region */ + #size-cells = <1>; + ranges = <0 0 0x0 0x1f400000 0xc00000>, + <1 0 0x10000 0x30000000 0>, + <2 0 0x10000 0x40000000 0>, + <3 0 0x10000 0x50000000 0>, + <4 0 0x0 0x1d020000 0x10000>, + <5 0 0x0 0x1d040000 0x10000>, + <6 0 0x0 0x1d050000 0x10000>, + <7 0 0x10000 0x90000000 0>; + + cavium,cs-config@0 { + compatible = "cavium,octeon-3860-bootbus-config"; + cavium,cs-index = <0>; + cavium,t-adr = <20>; + cavium,t-ce = <60>; + cavium,t-oe = <60>; + cavium,t-we = <45>; + cavium,t-rd-hld = <35>; + cavium,t-wr-hld = <45>; + cavium,t-pause = <0>; + cavium,t-wait = <0>; + cavium,t-page = <35>; + cavium,t-rd-dly = <0>; + + cavium,pages = <0>; + cavium,bus-width = <8>; + }; + cavium,cs-config@4 { + compatible = "cavium,octeon-3860-bootbus-config"; + cavium,cs-index = <4>; + cavium,t-adr = <320>; + cavium,t-ce = <320>; + cavium,t-oe = <320>; + cavium,t-we = <320>; + cavium,t-rd-hld = <320>; + cavium,t-wr-hld = <320>; + cavium,t-pause = <320>; + cavium,t-wait = <320>; + cavium,t-page = <320>; + cavium,t-rd-dly = <0>; + + cavium,pages = <0>; + cavium,bus-width = <8>; + }; + cavium,cs-config@5 { + compatible = "cavium,octeon-3860-bootbus-config"; + cavium,cs-index = <5>; + cavium,t-adr = <5>; + cavium,t-ce = <300>; + cavium,t-oe = <125>; + cavium,t-we = <150>; + cavium,t-rd-hld = <100>; + cavium,t-wr-hld = <30>; + cavium,t-pause = <0>; + cavium,t-wait = <30>; + cavium,t-page = <320>; + cavium,t-rd-dly = <0>; + + cavium,pages = <0>; + cavium,bus-width = <16>; + }; + cavium,cs-config@6 { + compatible = "cavium,octeon-3860-bootbus-config"; + cavium,cs-index = <6>; + cavium,t-adr = <5>; + cavium,t-ce = <300>; + cavium,t-oe = <270>; + cavium,t-we = <150>; + cavium,t-rd-hld = <100>; + cavium,t-wr-hld = <70>; + cavium,t-pause = <0>; + cavium,t-wait = <0>; + cavium,t-page = <320>; + cavium,t-rd-dly = <0>; + + cavium,pages = <0>; + cavium,wait-mode; + cavium,bus-width = <16>; + }; + + flash0: nor@0,0 { + compatible = "cfi-flash"; + reg = <0 0 0x800000>; + #address-cells = <1>; + #size-cells = <1>; + }; + + led0: led-display@4,0 { + compatible = "avago,hdsp-253x"; + reg = <4 0x20 0x20>, <4 0 0x20>; + }; + + cf0: compact-flash@5,0 { + compatible = "cavium,ebt3000-compact-flash"; + reg = <5 0 0x10000>, <6 0 0x10000>; + cavium,bus-width = <16>; + cavium,true-ide; + cavium,dma-engine-handle = <&dma0>; + }; + }; + + dma0: dma-engine@1180000000100 { + compatible = "cavium,octeon-5750-bootbus-dma"; + reg = <0x11800 0x00000100 0x0 0x8>; + interrupts = <0 63>; + }; + dma1: dma-engine@1180000000108 { + compatible = "cavium,octeon-5750-bootbus-dma"; + reg = <0x11800 0x00000108 0x0 0x8>; + interrupts = <0 63>; + }; + + uctl: uctl@118006f000000 { + compatible = "cavium,octeon-6335-uctl"; + reg = <0x11800 0x6f000000 0x0 0x100>; + ranges; /* Direct mapping */ + #address-cells = <2>; + #size-cells = <2>; + /* 12MHz, 24MHz and 48MHz allowed */ + refclk-frequency = <12000000>; + /* Either "crystal" or "external" */ + refclk-type = "crystal"; + + ehci@16f0000000000 { + compatible = "cavium,octeon-6335-ehci","usb-ehci"; + reg = <0x16f00 0x00000000 0x0 0x100>; + interrupts = <0 56>; + big-endian-regs; + }; + ohci@16f0000000400 { + compatible = "cavium,octeon-6335-ohci","usb-ohci"; + reg = <0x16f00 0x00000400 0x0 0x100>; + interrupts = <0 56>; + big-endian-regs; + }; + }; + }; + + aliases { + mix0 = &mix0; + mix1 = &mix1; + pip = &pip; + smi0 = &smi0; + smi1 = &smi1; + twsi0 = &twsi0; + twsi1 = &twsi1; + uart0 = &uart0; + uart1 = &uart1; + uart2 = &uart2; + flash0 = &flash0; + cf0 = &cf0; + uctl = &uctl; + led0 = &led0; + }; + }; diff --git a/arch/mips/cavium-octeon/octeon_68xx.dts b/arch/mips/cavium-octeon/octeon_68xx.dts new file mode 100644 index 00000000000..1839468932b --- /dev/null +++ b/arch/mips/cavium-octeon/octeon_68xx.dts @@ -0,0 +1,625 @@ +/dts-v1/; +/* + * OCTEON 68XX device tree skeleton. + * + * This device tree is pruned and patched by early boot code before + * use. Because of this, it contains a super-set of the available + * devices and properties. + */ +/ { + compatible = "cavium,octeon-6880"; + #address-cells = <2>; + #size-cells = <2>; + interrupt-parent = <&ciu2>; + + soc@0 { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; /* Direct mapping */ + + ciu2: interrupt-controller@1070100000000 { + compatible = "cavium,octeon-6880-ciu2"; + interrupt-controller; + /* Interrupts are specified by two parts: + * 1) Controller register (0 or 7) + * 2) Bit within the register (0..63) + */ + #address-cells = <0>; + #interrupt-cells = <2>; + reg = <0x10701 0x00000000 0x0 0x4000000>; + }; + + gpio: gpio-controller@1070000000800 { + #gpio-cells = <2>; + compatible = "cavium,octeon-3860-gpio"; + reg = <0x10700 0x00000800 0x0 0x100>; + gpio-controller; + /* Interrupts are specified by two parts: + * 1) GPIO pin number (0..15) + * 2) Triggering (1 - edge rising + * 2 - edge falling + * 4 - level active high + * 8 - level active low) + */ + interrupt-controller; + #interrupt-cells = <2>; + /* The GPIO pins connect to 16 consecutive CUI bits */ + interrupts = <7 0>, <7 1>, <7 2>, <7 3>, + <7 4>, <7 5>, <7 6>, <7 7>, + <7 8>, <7 9>, <7 10>, <7 11>, + <7 12>, <7 13>, <7 14>, <7 15>; + }; + + smi0: mdio@1180000003800 { + compatible = "cavium,octeon-3860-mdio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x11800 0x00003800 0x0 0x40>; + + phy0: ethernet-phy@6 { + compatible = "marvell,88e1118"; + marvell,reg-init = + /* Fix rx and tx clock transition timing */ + <2 0x15 0xffcf 0>, /* Reg 2,21 Clear bits 4, 5 */ + /* Adjust LED drive. */ + <3 0x11 0 0x442a>, /* Reg 3,17 <- 0442a */ + /* irq, blink-activity, blink-link */ + <3 0x10 0 0x0242>; /* Reg 3,16 <- 0x0242 */ + reg = <6>; + }; + + phy1: ethernet-phy@1 { + cavium,qlm-trim = "4,sgmii"; + reg = <1>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy2: ethernet-phy@2 { + cavium,qlm-trim = "4,sgmii"; + reg = <2>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy3: ethernet-phy@3 { + cavium,qlm-trim = "4,sgmii"; + reg = <3>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy4: ethernet-phy@4 { + cavium,qlm-trim = "4,sgmii"; + reg = <4>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + }; + + smi1: mdio@1180000003880 { + compatible = "cavium,octeon-3860-mdio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x11800 0x00003880 0x0 0x40>; + + phy41: ethernet-phy@1 { + cavium,qlm-trim = "0,sgmii"; + reg = <1>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy42: ethernet-phy@2 { + cavium,qlm-trim = "0,sgmii"; + reg = <2>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy43: ethernet-phy@3 { + cavium,qlm-trim = "0,sgmii"; + reg = <3>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy44: ethernet-phy@4 { + cavium,qlm-trim = "0,sgmii"; + reg = <4>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + }; + + smi2: mdio@1180000003900 { + compatible = "cavium,octeon-3860-mdio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x11800 0x00003900 0x0 0x40>; + + phy21: ethernet-phy@1 { + cavium,qlm-trim = "2,sgmii"; + reg = <1>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy22: ethernet-phy@2 { + cavium,qlm-trim = "2,sgmii"; + reg = <2>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy23: ethernet-phy@3 { + cavium,qlm-trim = "2,sgmii"; + reg = <3>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy24: ethernet-phy@4 { + cavium,qlm-trim = "2,sgmii"; + reg = <4>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + }; + + smi3: mdio@1180000003980 { + compatible = "cavium,octeon-3860-mdio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x11800 0x00003980 0x0 0x40>; + + phy11: ethernet-phy@1 { + cavium,qlm-trim = "3,sgmii"; + reg = <1>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy12: ethernet-phy@2 { + cavium,qlm-trim = "3,sgmii"; + reg = <2>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy13: ethernet-phy@3 { + cavium,qlm-trim = "3,sgmii"; + reg = <3>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy14: ethernet-phy@4 { + cavium,qlm-trim = "3,sgmii"; + reg = <4>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + }; + + mix0: ethernet@1070000100000 { + compatible = "cavium,octeon-5750-mix"; + reg = <0x10700 0x00100000 0x0 0x100>, /* MIX */ + <0x11800 0xE0000000 0x0 0x300>, /* AGL */ + <0x11800 0xE0000400 0x0 0x400>, /* AGL_SHARED */ + <0x11800 0xE0002000 0x0 0x8>; /* AGL_PRT_CTL */ + cell-index = <0>; + interrupts = <6 40>, <6 32>; + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy0>; + }; + + pip: pip@11800a0000000 { + compatible = "cavium,octeon-3860-pip"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x11800 0xa0000000 0x0 0x2000>; + + interface@4 { + compatible = "cavium,octeon-3860-pip-interface"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x4>; /* interface */ + + ethernet@0 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x0>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy1>; + }; + ethernet@1 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x1>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy2>; + }; + ethernet@2 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x2>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy3>; + }; + ethernet@3 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x3>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy4>; + }; + }; + + interface@3 { + compatible = "cavium,octeon-3860-pip-interface"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x3>; /* interface */ + + ethernet@0 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x0>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy11>; + }; + ethernet@1 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x1>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy12>; + }; + ethernet@2 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x2>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy13>; + }; + ethernet@3 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x3>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy14>; + }; + }; + + interface@2 { + compatible = "cavium,octeon-3860-pip-interface"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x2>; /* interface */ + + ethernet@0 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x0>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy21>; + }; + ethernet@1 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x1>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy22>; + }; + ethernet@2 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x2>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy23>; + }; + ethernet@3 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x3>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy24>; + }; + }; + + interface@1 { + compatible = "cavium,octeon-3860-pip-interface"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x1>; /* interface */ + + ethernet@0 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x0>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + }; + }; + + interface@0 { + compatible = "cavium,octeon-3860-pip-interface"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0>; /* interface */ + + ethernet@0 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x0>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy41>; + }; + ethernet@1 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x1>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy42>; + }; + ethernet@2 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x2>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy43>; + }; + ethernet@3 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x3>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy44>; + }; + }; + }; + + twsi0: i2c@1180000001000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "cavium,octeon-3860-twsi"; + reg = <0x11800 0x00001000 0x0 0x200>; + interrupts = <3 32>; + clock-frequency = <100000>; + + rtc@68 { + compatible = "dallas,ds1337"; + reg = <0x68>; + }; + tmp@4c { + compatible = "ti,tmp421"; + reg = <0x4c>; + }; + }; + + twsi1: i2c@1180000001200 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "cavium,octeon-3860-twsi"; + reg = <0x11800 0x00001200 0x0 0x200>; + interrupts = <3 33>; + clock-frequency = <100000>; + }; + + uart0: serial@1180000000800 { + compatible = "cavium,octeon-3860-uart","ns16550"; + reg = <0x11800 0x00000800 0x0 0x400>; + clock-frequency = <0>; + current-speed = <115200>; + reg-shift = <3>; + interrupts = <3 36>; + }; + + uart1: serial@1180000000c00 { + compatible = "cavium,octeon-3860-uart","ns16550"; + reg = <0x11800 0x00000c00 0x0 0x400>; + clock-frequency = <0>; + current-speed = <115200>; + reg-shift = <3>; + interrupts = <3 37>; + }; + + bootbus: bootbus@1180000000000 { + compatible = "cavium,octeon-3860-bootbus"; + reg = <0x11800 0x00000000 0x0 0x200>; + /* The chip select number and offset */ + #address-cells = <2>; + /* The size of the chip select region */ + #size-cells = <1>; + ranges = <0 0 0 0x1f400000 0xc00000>, + <1 0 0x10000 0x30000000 0>, + <2 0 0x10000 0x40000000 0>, + <3 0 0x10000 0x50000000 0>, + <4 0 0 0x1d020000 0x10000>, + <5 0 0 0x1d040000 0x10000>, + <6 0 0 0x1d050000 0x10000>, + <7 0 0x10000 0x90000000 0>; + + cavium,cs-config@0 { + compatible = "cavium,octeon-3860-bootbus-config"; + cavium,cs-index = <0>; + cavium,t-adr = <10>; + cavium,t-ce = <50>; + cavium,t-oe = <50>; + cavium,t-we = <35>; + cavium,t-rd-hld = <25>; + cavium,t-wr-hld = <35>; + cavium,t-pause = <0>; + cavium,t-wait = <300>; + cavium,t-page = <25>; + cavium,t-rd-dly = <0>; + + cavium,pages = <0>; + cavium,bus-width = <8>; + }; + cavium,cs-config@4 { + compatible = "cavium,octeon-3860-bootbus-config"; + cavium,cs-index = <4>; + cavium,t-adr = <320>; + cavium,t-ce = <320>; + cavium,t-oe = <320>; + cavium,t-we = <320>; + cavium,t-rd-hld = <320>; + cavium,t-wr-hld = <320>; + cavium,t-pause = <320>; + cavium,t-wait = <320>; + cavium,t-page = <320>; + cavium,t-rd-dly = <0>; + + cavium,pages = <0>; + cavium,bus-width = <8>; + }; + cavium,cs-config@5 { + compatible = "cavium,octeon-3860-bootbus-config"; + cavium,cs-index = <5>; + cavium,t-adr = <0>; + cavium,t-ce = <300>; + cavium,t-oe = <125>; + cavium,t-we = <150>; + cavium,t-rd-hld = <100>; + cavium,t-wr-hld = <300>; + cavium,t-pause = <0>; + cavium,t-wait = <300>; + cavium,t-page = <310>; + cavium,t-rd-dly = <0>; + + cavium,pages = <0>; + cavium,bus-width = <16>; + }; + cavium,cs-config@6 { + compatible = "cavium,octeon-3860-bootbus-config"; + cavium,cs-index = <6>; + cavium,t-adr = <0>; + cavium,t-ce = <30>; + cavium,t-oe = <125>; + cavium,t-we = <150>; + cavium,t-rd-hld = <100>; + cavium,t-wr-hld = <30>; + cavium,t-pause = <0>; + cavium,t-wait = <30>; + cavium,t-page = <310>; + cavium,t-rd-dly = <0>; + + cavium,pages = <0>; + cavium,wait-mode; + cavium,bus-width = <16>; + }; + + flash0: nor@0,0 { + compatible = "cfi-flash"; + reg = <0 0 0x800000>; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "bootloader"; + reg = <0 0x200000>; + read-only; + }; + partition@200000 { + label = "kernel"; + reg = <0x200000 0x200000>; + }; + partition@400000 { + label = "cramfs"; + reg = <0x400000 0x3fe000>; + }; + partition@7fe000 { + label = "environment"; + reg = <0x7fe000 0x2000>; + read-only; + }; + }; + + led0: led-display@4,0 { + compatible = "avago,hdsp-253x"; + reg = <4 0x20 0x20>, <4 0 0x20>; + }; + + compact-flash@5,0 { + compatible = "cavium,ebt3000-compact-flash"; + reg = <5 0 0x10000>, <6 0 0x10000>; + cavium,bus-width = <16>; + cavium,true-ide; + cavium,dma-engine-handle = <&dma0>; + }; + }; + + dma0: dma-engine@1180000000100 { + compatible = "cavium,octeon-5750-bootbus-dma"; + reg = <0x11800 0x00000100 0x0 0x8>; + interrupts = <0 63>; + }; + dma1: dma-engine@1180000000108 { + compatible = "cavium,octeon-5750-bootbus-dma"; + reg = <0x11800 0x00000108 0x0 0x8>; + interrupts = <0 63>; + }; + + uctl: uctl@118006f000000 { + compatible = "cavium,octeon-6335-uctl"; + reg = <0x11800 0x6f000000 0x0 0x100>; + ranges; /* Direct mapping */ + #address-cells = <2>; + #size-cells = <2>; + /* 12MHz, 24MHz and 48MHz allowed */ + refclk-frequency = <12000000>; + /* Either "crystal" or "external" */ + refclk-type = "crystal"; + + ehci@16f0000000000 { + compatible = "cavium,octeon-6335-ehci","usb-ehci"; + reg = <0x16f00 0x00000000 0x0 0x100>; + interrupts = <3 44>; + big-endian-regs; + }; + ohci@16f0000000400 { + compatible = "cavium,octeon-6335-ohci","usb-ohci"; + reg = <0x16f00 0x00000400 0x0 0x100>; + interrupts = <3 44>; + big-endian-regs; + }; + }; + }; + + aliases { + mix0 = &mix0; + pip = &pip; + smi0 = &smi0; + smi1 = &smi1; + smi2 = &smi2; + smi3 = &smi3; + twsi0 = &twsi0; + twsi1 = &twsi1; + uart0 = &uart0; + uart1 = &uart1; + uctl = &uctl; + led0 = &led0; + flash0 = &flash0; + }; + }; -- cgit v1.2.3-70-g09d2 From b61d15758941166b9cac41b87751dea21978bebc Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sun, 22 Jul 2012 12:51:35 +0200 Subject: I2C: MV64XYZ: Add Device Tree support Extends the driver to get properties from device tree. Rather than pass the N & M factors in DT, use the more standard clock-frequency property. Calculate N & M at run time. In order to do this, we need to know tclk. So the driver uses clk_get() etc in order to get the clock and clk_get_rate() to determine the tclk rate. Not all platforms however have CLK, so some #ifdefery is needed to ensure the driver still compiles when CLK is not available. Signed-off-by: Andrew Lunn [wsa: converted some ints to u32 to match signedness] Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/mrvl-i2c.txt | 19 ++- drivers/i2c/busses/i2c-mv64xxx.c | 133 ++++++++++++++++++++- 2 files changed, 146 insertions(+), 6 deletions(-) (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/i2c/mrvl-i2c.txt b/Documentation/devicetree/bindings/i2c/mrvl-i2c.txt index b891ee21835..0f7945019f6 100644 --- a/Documentation/devicetree/bindings/i2c/mrvl-i2c.txt +++ b/Documentation/devicetree/bindings/i2c/mrvl-i2c.txt @@ -1,4 +1,4 @@ -* I2C +* Marvell MMP I2C controller Required properties : @@ -32,3 +32,20 @@ Examples: interrupts = <58>; }; +* Marvell MV64XXX I2C controller + +Required properties : + + - reg : Offset and length of the register set for the device + - compatible : Should be "marvell,mv64xxx-i2c" + - interrupts : The interrupt number + - clock-frequency : Desired I2C bus clock frequency in Hz. + +Examples: + + i2c@11000 { + compatible = "marvell,mv64xxx-i2c"; + reg = <0x11000 0x20>; + interrupts = <29>; + clock-frequency = <100000>; + }; diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 6e70eea0cd2..2e9d56719e9 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -18,6 +18,11 @@ #include #include #include +#include +#include +#include +#include +#include /* Register defines */ #define MV64XXX_I2C_REG_SLAVE_ADDR 0x00 @@ -98,6 +103,9 @@ struct mv64xxx_i2c_data { int rc; u32 freq_m; u32 freq_n; +#if defined(CONFIG_HAVE_CLK) + struct clk *clk; +#endif wait_queue_head_t waitq; spinlock_t lock; struct i2c_msg *msg; @@ -521,6 +529,82 @@ mv64xxx_i2c_unmap_regs(struct mv64xxx_i2c_data *drv_data) drv_data->reg_base_p = 0; } +#ifdef CONFIG_OF +static int __devinit +mv64xxx_calc_freq(const int tclk, const int n, const int m) +{ + return tclk / (10 * (m + 1) * (2 << n)); +} + +static bool __devinit +mv64xxx_find_baud_factors(const u32 req_freq, const u32 tclk, u32 *best_n, + u32 *best_m) +{ + int freq, delta, best_delta = INT_MAX; + int m, n; + + for (n = 0; n <= 7; n++) + for (m = 0; m <= 15; m++) { + freq = mv64xxx_calc_freq(tclk, n, m); + delta = req_freq - freq; + if (delta >= 0 && delta < best_delta) { + *best_m = m; + *best_n = n; + best_delta = delta; + } + if (best_delta == 0) + return true; + } + if (best_delta == INT_MAX) + return false; + return true; +} + +static int __devinit +mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data, + struct device_node *np) +{ + u32 bus_freq, tclk; + int rc = 0; + + /* CLK is mandatory when using DT to describe the i2c bus. We + * need to know tclk in order to calculate bus clock + * factors. + */ +#if !defined(CONFIG_HAVE_CLK) + /* Have OF but no CLK */ + return -ENODEV; +#else + if (IS_ERR(drv_data->clk)) { + rc = -ENODEV; + goto out; + } + tclk = clk_get_rate(drv_data->clk); + of_property_read_u32(np, "clock-frequency", &bus_freq); + if (!mv64xxx_find_baud_factors(bus_freq, tclk, + &drv_data->freq_n, &drv_data->freq_m)) { + rc = -EINVAL; + goto out; + } + drv_data->irq = irq_of_parse_and_map(np, 0); + + /* Its not yet defined how timeouts will be specified in device tree. + * So hard code the value to 1 second. + */ + drv_data->adapter.timeout = HZ; +out: + return rc; +#endif +} +#else /* CONFIG_OF */ +static int __devinit +mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data, + struct device_node *np) +{ + return -ENODEV; +} +#endif /* CONFIG_OF */ + static int __devinit mv64xxx_i2c_probe(struct platform_device *pd) { @@ -528,7 +612,7 @@ mv64xxx_i2c_probe(struct platform_device *pd) struct mv64xxx_i2c_pdata *pdata = pd->dev.platform_data; int rc; - if (!pdata) + if ((!pdata && !pd->dev.of_node)) return -ENODEV; drv_data = kzalloc(sizeof(struct mv64xxx_i2c_data), GFP_KERNEL); @@ -546,19 +630,35 @@ mv64xxx_i2c_probe(struct platform_device *pd) init_waitqueue_head(&drv_data->waitq); spin_lock_init(&drv_data->lock); - drv_data->freq_m = pdata->freq_m; - drv_data->freq_n = pdata->freq_n; - drv_data->irq = platform_get_irq(pd, 0); +#if defined(CONFIG_HAVE_CLK) + /* Not all platforms have a clk */ + drv_data->clk = clk_get(&pd->dev, NULL); + if (!IS_ERR(drv_data->clk)) { + clk_prepare(drv_data->clk); + clk_enable(drv_data->clk); + } +#endif + if (pdata) { + drv_data->freq_m = pdata->freq_m; + drv_data->freq_n = pdata->freq_n; + drv_data->irq = platform_get_irq(pd, 0); + drv_data->adapter.timeout = msecs_to_jiffies(pdata->timeout); + } else if (pd->dev.of_node) { + rc = mv64xxx_of_config(drv_data, pd->dev.of_node); + if (rc) + goto exit_unmap_regs; + } if (drv_data->irq < 0) { rc = -ENXIO; goto exit_unmap_regs; } + drv_data->adapter.dev.parent = &pd->dev; drv_data->adapter.algo = &mv64xxx_i2c_algo; drv_data->adapter.owner = THIS_MODULE; drv_data->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; - drv_data->adapter.timeout = msecs_to_jiffies(pdata->timeout); drv_data->adapter.nr = pd->id; + drv_data->adapter.dev.of_node = pd->dev.of_node; platform_set_drvdata(pd, drv_data); i2c_set_adapdata(&drv_data->adapter, drv_data); @@ -577,11 +677,20 @@ mv64xxx_i2c_probe(struct platform_device *pd) goto exit_free_irq; } + of_i2c_register_devices(&drv_data->adapter); + return 0; exit_free_irq: free_irq(drv_data->irq, drv_data); exit_unmap_regs: +#if defined(CONFIG_HAVE_CLK) + /* Not all platforms have a clk */ + if (!IS_ERR(drv_data->clk)) { + clk_disable(drv_data->clk); + clk_unprepare(drv_data->clk); + } +#endif mv64xxx_i2c_unmap_regs(drv_data); exit_kfree: kfree(drv_data); @@ -597,17 +706,31 @@ mv64xxx_i2c_remove(struct platform_device *dev) rc = i2c_del_adapter(&drv_data->adapter); free_irq(drv_data->irq, drv_data); mv64xxx_i2c_unmap_regs(drv_data); +#if defined(CONFIG_HAVE_CLK) + /* Not all platforms have a clk */ + if (!IS_ERR(drv_data->clk)) { + clk_disable(drv_data->clk); + clk_unprepare(drv_data->clk); + } +#endif kfree(drv_data); return rc; } +static const struct of_device_id mv64xxx_i2c_of_match_table[] __devinitdata = { + { .compatible = "marvell,mv64xxx-i2c", }, + {} +}; +MODULE_DEVICE_TABLE(of, mv64xxx_i2c_of_match_table); + static struct platform_driver mv64xxx_i2c_driver = { .probe = mv64xxx_i2c_probe, .remove = __devexit_p(mv64xxx_i2c_remove), .driver = { .owner = THIS_MODULE, .name = MV64XXX_I2C_CTLR_NAME, + .of_match_table = of_match_ptr(mv64xxx_i2c_of_match_table), }, }; -- cgit v1.2.3-70-g09d2 From 1fc74aef0420f6bad7b632cbc961edac40a3eeae Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 16 Jul 2012 11:49:44 +0200 Subject: mfd: Add support for twl6041 The delta between twl6040 and twl6041 is small, the main difference is in the number of GPOs (3 on twl6040, 1 on twl6041). Signed-off-by: Peter Ujfalusi Signed-off-by: Samuel Ortiz --- Documentation/devicetree/bindings/mfd/twl6040.txt | 2 +- drivers/mfd/twl6040-core.c | 1 + include/linux/mfd/twl6040.h | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/mfd/twl6040.txt b/Documentation/devicetree/bindings/mfd/twl6040.txt index bc67c6f424a..c855240f3a0 100644 --- a/Documentation/devicetree/bindings/mfd/twl6040.txt +++ b/Documentation/devicetree/bindings/mfd/twl6040.txt @@ -6,7 +6,7 @@ They are connected ot the host processor via i2c for commands, McPDM for audio data and commands. Required properties: -- compatible : Must be "ti,twl6040"; +- compatible : "ti,twl6040" for twl6040, "ti,twl6041" for twl6041 - reg: must be 0x4b for i2c address - interrupts: twl6040 has one interrupt line connecteded to the main SoC - interrupt-parent: The parent interrupt controller diff --git a/drivers/mfd/twl6040-core.c b/drivers/mfd/twl6040-core.c index 5f620ae3b1f..b0fad0ffca5 100644 --- a/drivers/mfd/twl6040-core.c +++ b/drivers/mfd/twl6040-core.c @@ -679,6 +679,7 @@ static int __devexit twl6040_remove(struct i2c_client *client) static const struct i2c_device_id twl6040_i2c_id[] = { { "twl6040", 0, }, + { "twl6041", 0, }, { }, }; MODULE_DEVICE_TABLE(i2c, twl6040_i2c_id); diff --git a/include/linux/mfd/twl6040.h b/include/linux/mfd/twl6040.h index 00b330e578b..eaad49f7c13 100644 --- a/include/linux/mfd/twl6040.h +++ b/include/linux/mfd/twl6040.h @@ -163,6 +163,7 @@ #define TWL6040_REV_ES1_0 0x00 #define TWL6040_REV_ES1_1 0x01 /* Rev ES1.1 and ES1.2 */ #define TWL6040_REV_ES1_3 0x02 +#define TWL6041_REV_ES2_0 0x10 #define TWL6040_IRQ_TH 0 #define TWL6040_IRQ_PLUG 1 -- cgit v1.2.3-70-g09d2 From 778435045a416da71f1757a80e37200a5ea5af70 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Wed, 18 Jul 2012 19:22:54 +0200 Subject: ARM: Kirkwood: Replace mrvl with marvell It has been decided to use marvell, not mrvl, in the compatibility property. Search & replace. Signed-off-by: Andrew Lunn --- Documentation/devicetree/bindings/mtd/orion-nand.txt | 4 ++-- arch/arm/boot/dts/kirkwood-dns320.dts | 2 +- arch/arm/boot/dts/kirkwood-dns325.dts | 2 +- arch/arm/boot/dts/kirkwood-dreamplug.dts | 2 +- arch/arm/boot/dts/kirkwood-ib62x0.dts | 2 +- arch/arm/boot/dts/kirkwood-iconnect.dts | 2 +- arch/arm/boot/dts/kirkwood.dtsi | 6 +++--- drivers/mtd/nand/orion_nand.c | 2 +- drivers/rtc/rtc-mv.c | 2 +- 9 files changed, 12 insertions(+), 12 deletions(-) (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/mtd/orion-nand.txt b/Documentation/devicetree/bindings/mtd/orion-nand.txt index b2356b7d2fa..2d6ab660e60 100644 --- a/Documentation/devicetree/bindings/mtd/orion-nand.txt +++ b/Documentation/devicetree/bindings/mtd/orion-nand.txt @@ -1,7 +1,7 @@ NAND support for Marvell Orion SoC platforms Required properties: -- compatible : "mrvl,orion-nand". +- compatible : "marvell,orion-nand". - reg : Base physical address of the NAND and length of memory mapped region @@ -24,7 +24,7 @@ nand@f4000000 { ale = <1>; bank-width = <1>; chip-delay = <25>; - compatible = "mrvl,orion-nand"; + compatible = "marvell,orion-nand"; reg = <0xf4000000 0x400>; partition@0 { diff --git a/arch/arm/boot/dts/kirkwood-dns320.dts b/arch/arm/boot/dts/kirkwood-dns320.dts index dc09a735b04..9a33077130e 100644 --- a/arch/arm/boot/dts/kirkwood-dns320.dts +++ b/arch/arm/boot/dts/kirkwood-dns320.dts @@ -4,7 +4,7 @@ / { model = "D-Link DNS-320 NAS (Rev A1)"; - compatible = "dlink,dns-320-a1", "dlink,dns-320", "dlink,dns-kirkwood", "mrvl,kirkwood-88f6281", "mrvl,kirkwood"; + compatible = "dlink,dns-320-a1", "dlink,dns-320", "dlink,dns-kirkwood", "marvell,kirkwood-88f6281", "marvell,kirkwood"; memory { device_type = "memory"; diff --git a/arch/arm/boot/dts/kirkwood-dns325.dts b/arch/arm/boot/dts/kirkwood-dns325.dts index c2a5562525d..16734c1b5df 100644 --- a/arch/arm/boot/dts/kirkwood-dns325.dts +++ b/arch/arm/boot/dts/kirkwood-dns325.dts @@ -4,7 +4,7 @@ / { model = "D-Link DNS-325 NAS (Rev A1)"; - compatible = "dlink,dns-325-a1", "dlink,dns-325", "dlink,dns-kirkwood", "mrvl,kirkwood-88f6281", "mrvl,kirkwood"; + compatible = "dlink,dns-325-a1", "dlink,dns-325", "dlink,dns-kirkwood", "marvell,kirkwood-88f6281", "marvell,kirkwood"; memory { device_type = "memory"; diff --git a/arch/arm/boot/dts/kirkwood-dreamplug.dts b/arch/arm/boot/dts/kirkwood-dreamplug.dts index a5376b84227..78b0f06a09a 100644 --- a/arch/arm/boot/dts/kirkwood-dreamplug.dts +++ b/arch/arm/boot/dts/kirkwood-dreamplug.dts @@ -4,7 +4,7 @@ / { model = "Globalscale Technologies Dreamplug"; - compatible = "globalscale,dreamplug-003-ds2001", "globalscale,dreamplug", "mrvl,kirkwood-88f6281", "mrvl,kirkwood"; + compatible = "globalscale,dreamplug-003-ds2001", "globalscale,dreamplug", "marvell,kirkwood-88f6281", "marvell,kirkwood"; memory { device_type = "memory"; diff --git a/arch/arm/boot/dts/kirkwood-ib62x0.dts b/arch/arm/boot/dts/kirkwood-ib62x0.dts index ada0f0c2308..f59dcf6dc45 100644 --- a/arch/arm/boot/dts/kirkwood-ib62x0.dts +++ b/arch/arm/boot/dts/kirkwood-ib62x0.dts @@ -4,7 +4,7 @@ / { model = "RaidSonic ICY BOX IB-NAS62x0 (Rev B)"; - compatible = "raidsonic,ib-nas6210-b", "raidsonic,ib-nas6220-b", "raidsonic,ib-nas6210", "raidsonic,ib-nas6220", "raidsonic,ib-nas62x0", "mrvl,kirkwood-88f6281", "mrvl,kirkwood"; + compatible = "raidsonic,ib-nas6210-b", "raidsonic,ib-nas6220-b", "raidsonic,ib-nas6210", "raidsonic,ib-nas6220", "raidsonic,ib-nas62x0", "marvell,kirkwood-88f6281", "marvell,kirkwood"; memory { device_type = "memory"; diff --git a/arch/arm/boot/dts/kirkwood-iconnect.dts b/arch/arm/boot/dts/kirkwood-iconnect.dts index 1ba75d4adec..026a1f82d81 100644 --- a/arch/arm/boot/dts/kirkwood-iconnect.dts +++ b/arch/arm/boot/dts/kirkwood-iconnect.dts @@ -4,7 +4,7 @@ / { model = "Iomega Iconnect"; - compatible = "iom,iconnect-1.1", "iom,iconnect", "mrvl,kirkwood-88f6281", "mrvl,kirkwood"; + compatible = "iom,iconnect-1.1", "iom,iconnect", "marvell,kirkwood-88f6281", "marvell,kirkwood"; memory { device_type = "memory"; diff --git a/arch/arm/boot/dts/kirkwood.dtsi b/arch/arm/boot/dts/kirkwood.dtsi index 926528b81ba..f95dbc190ab 100644 --- a/arch/arm/boot/dts/kirkwood.dtsi +++ b/arch/arm/boot/dts/kirkwood.dtsi @@ -1,7 +1,7 @@ /include/ "skeleton.dtsi" / { - compatible = "mrvl,kirkwood"; + compatible = "marvell,kirkwood"; ocp@f1000000 { compatible = "simple-bus"; @@ -28,7 +28,7 @@ }; rtc@10300 { - compatible = "mrvl,kirkwood-rtc", "mrvl,orion-rtc"; + compatible = "marvell,kirkwood-rtc", "marvell,orion-rtc"; reg = <0x10300 0x20>; interrupts = <53>; }; @@ -39,7 +39,7 @@ cle = <0>; ale = <1>; bank-width = <1>; - compatible = "mrvl,orion-nand"; + compatible = "marvell,orion-nand"; reg = <0x3000000 0x400>; chip-delay = <25>; /* set partition map and/or chip-delay in board dts */ diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c index 9b8fd3d7716..fc5a868c436 100644 --- a/drivers/mtd/nand/orion_nand.c +++ b/drivers/mtd/nand/orion_nand.c @@ -218,7 +218,7 @@ static int __devexit orion_nand_remove(struct platform_device *pdev) #ifdef CONFIG_OF static struct of_device_id orion_nand_of_match_table[] = { - { .compatible = "mrvl,orion-nand", }, + { .compatible = "marvell,orion-nand", }, {}, }; #endif diff --git a/drivers/rtc/rtc-mv.c b/drivers/rtc/rtc-mv.c index b2185f4255a..ebc1649d45d 100644 --- a/drivers/rtc/rtc-mv.c +++ b/drivers/rtc/rtc-mv.c @@ -297,7 +297,7 @@ static int __exit mv_rtc_remove(struct platform_device *pdev) #ifdef CONFIG_OF static struct of_device_id rtc_mv_of_match_table[] = { - { .compatible = "mrvl,orion-rtc", }, + { .compatible = "marvell,orion-rtc", }, {} }; #endif -- cgit v1.2.3-70-g09d2 From ed85c60457a8e6bfe4604f8d3d343e70e30aaa3e Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Mon, 11 Jun 2012 21:57:14 +0200 Subject: serial/of-serial: Add LPC3220 standard UART compatible string This patch adds a "compatible" string for the new 8250 UART type PORT_LPC3220. This is necessary for initializing LPC32xx UARTs via DT. Signed-off-by: Roland Stigge Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/tty/serial/of-serial.txt | 1 + drivers/tty/serial/of_serial.c | 1 + 2 files changed, 2 insertions(+) (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/tty/serial/of-serial.txt b/Documentation/devicetree/bindings/tty/serial/of-serial.txt index b8b27b0aca1..0847fdeee11 100644 --- a/Documentation/devicetree/bindings/tty/serial/of-serial.txt +++ b/Documentation/devicetree/bindings/tty/serial/of-serial.txt @@ -9,6 +9,7 @@ Required properties: - "ns16750" - "ns16850" - "nvidia,tegra20-uart" + - "nxp,lpc3220-uart" - "ibm,qpace-nwp-serial" - "serial" if the port type is unknown. - reg : offset and length of the register set for the device. diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c index 5410c063726..34e71874a89 100644 --- a/drivers/tty/serial/of_serial.c +++ b/drivers/tty/serial/of_serial.c @@ -208,6 +208,7 @@ static struct of_device_id __devinitdata of_platform_serial_table[] = { { .compatible = "ns16750", .data = (void *)PORT_16750, }, { .compatible = "ns16850", .data = (void *)PORT_16850, }, { .compatible = "nvidia,tegra20-uart", .data = (void *)PORT_TEGRA, }, + { .compatible = "nxp,lpc3220-uart", .data = (void *)PORT_LPC3220, }, #ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL { .compatible = "ibm,qpace-nwp-serial", .data = (void *)PORT_NWPSERIAL, }, -- cgit v1.2.3-70-g09d2