From c3503fd02558245ebbb0b48f3ae1d62416e3fd2a Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Wed, 10 Aug 2011 21:45:36 +0100 Subject: olpc_battery: Bind to device tree This is cleaner, and allows suspend/resume (wakeup) handlers to be added in an upcoming patch. Signed-off-by: Daniel Drake Acked-by: Andres Salomon Signed-off-by: Anton Vorontsov --- Documentation/devicetree/bindings/power_supply/olpc_battery.txt | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 Documentation/devicetree/bindings/power_supply/olpc_battery.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/power_supply/olpc_battery.txt b/Documentation/devicetree/bindings/power_supply/olpc_battery.txt new file mode 100644 index 00000000000..c8901b3992d --- /dev/null +++ b/Documentation/devicetree/bindings/power_supply/olpc_battery.txt @@ -0,0 +1,5 @@ +OLPC battery +~~~~~~~~~~~~ + +Required properties: + - compatible : "olpc,xo1-battery" -- cgit v1.2.3-70-g09d2 From 041cadca7008f08fb4785f2288c8127c16faa529 Mon Sep 17 00:00:00 2001 From: Mark Salter Date: Tue, 4 Oct 2011 12:12:20 -0400 Subject: C6X: devicetree support This is the basic devicetree support for C6X. Currently, four boards are supported. Each one uses a different SoC part. Two of the four supported SoCs are multicore. One with 3 cores and the other with 6 cores. There is no coherency between the core-level caches, so SMP is not an option. It is possible to run separate kernel instances on the various cores. There is currently no C6X bootloader support for device trees so we build in the DTB for now. There are some interesting twists to the hardware which are of note for device tree support. Each core has its own interrupt controller which is controlled by special purpose core registers. This core controller provides 12 general purpose prioritized interrupt sources. Each core is contained within a hardware "module" which provides L1 and L2 caches, power control, and another interrupt controller which cascades into the core interrupt controller. These core module functions are controlled by memory mapped registers. The addresses for these registers are the same for each core. That is, when coreN accesses a module-level MMIO register at a given address, it accesses the register for coreN even though other cores would use the same address to access the register in the module containing those cores. Other hardware modules (timers, enet, etc) which are memory mapped can be accessed by all cores. The timers need some further explanation for multicore SoCs. Even though all timer control registers are visible to all cores, interrupt routing or other considerations may make a given timer more suitable for use by a core than some other timer. Because of this and the desire to have the same image run on more than one core, the timer nodes have a "ti,core-mask" property which is used by the driver to scan for a suitable timer to use. Signed-off-by: Mark Salter Signed-off-by: Aurelien Jacquiot Acked-by: Arnd Bergmann --- Documentation/devicetree/bindings/c6x/clocks.txt | 40 ++++++ Documentation/devicetree/bindings/c6x/dscr.txt | 127 +++++++++++++++++++ Documentation/devicetree/bindings/c6x/emifa.txt | 62 ++++++++++ .../devicetree/bindings/c6x/interrupt.txt | 104 ++++++++++++++++ Documentation/devicetree/bindings/c6x/soc.txt | 28 +++++ Documentation/devicetree/bindings/c6x/timer64.txt | 26 ++++ arch/c6x/boot/dts/dsk6455.dts | 62 ++++++++++ arch/c6x/boot/dts/evmc6457.dts | 48 ++++++++ arch/c6x/boot/dts/evmc6472.dts | 73 +++++++++++ arch/c6x/boot/dts/evmc6474.dts | 58 +++++++++ arch/c6x/boot/dts/tms320c6455.dtsi | 96 +++++++++++++++ arch/c6x/boot/dts/tms320c6457.dtsi | 68 +++++++++++ arch/c6x/boot/dts/tms320c6472.dtsi | 134 +++++++++++++++++++++ arch/c6x/boot/dts/tms320c6474.dtsi | 89 ++++++++++++++ arch/c6x/boot/linked_dtb.S | 2 + arch/c6x/kernel/devicetree.c | 53 ++++++++ arch/c6x/platforms/platform.c | 17 +++ 17 files changed, 1087 insertions(+) create mode 100644 Documentation/devicetree/bindings/c6x/clocks.txt create mode 100644 Documentation/devicetree/bindings/c6x/dscr.txt create mode 100644 Documentation/devicetree/bindings/c6x/emifa.txt create mode 100644 Documentation/devicetree/bindings/c6x/interrupt.txt create mode 100644 Documentation/devicetree/bindings/c6x/soc.txt create mode 100644 Documentation/devicetree/bindings/c6x/timer64.txt create mode 100644 arch/c6x/boot/dts/dsk6455.dts create mode 100644 arch/c6x/boot/dts/evmc6457.dts create mode 100644 arch/c6x/boot/dts/evmc6472.dts create mode 100644 arch/c6x/boot/dts/evmc6474.dts create mode 100644 arch/c6x/boot/dts/tms320c6455.dtsi create mode 100644 arch/c6x/boot/dts/tms320c6457.dtsi create mode 100644 arch/c6x/boot/dts/tms320c6472.dtsi create mode 100644 arch/c6x/boot/dts/tms320c6474.dtsi create mode 100644 arch/c6x/boot/linked_dtb.S create mode 100644 arch/c6x/kernel/devicetree.c create mode 100644 arch/c6x/platforms/platform.c (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/c6x/clocks.txt b/Documentation/devicetree/bindings/c6x/clocks.txt new file mode 100644 index 00000000000..a04f5fd3012 --- /dev/null +++ b/Documentation/devicetree/bindings/c6x/clocks.txt @@ -0,0 +1,40 @@ +C6X PLL Clock Controllers +------------------------- + +This is a first-cut support for the SoC clock controllers. This is still +under development and will probably change as the common device tree +clock support is added to the kernel. + +Required properties: + +- compatible: "ti,c64x+pll" + May also have SoC-specific value to support SoC-specific initialization + in the driver. One of: + "ti,c6455-pll" + "ti,c6457-pll" + "ti,c6472-pll" + "ti,c6474-pll" + +- reg: base address and size of register area +- clock-frequency: input clock frequency in hz + + +Optional properties: + +- ti,c64x+pll-bypass-delay: CPU cycles to delay when entering bypass mode + +- ti,c64x+pll-reset-delay: CPU cycles to delay after PLL reset + +- ti,c64x+pll-lock-delay: CPU cycles to delay after PLL frequency change + +Example: + + clock-controller@29a0000 { + compatible = "ti,c6472-pll", "ti,c64x+pll"; + reg = <0x029a0000 0x200>; + clock-frequency = <25000000>; + + ti,c64x+pll-bypass-delay = <200>; + ti,c64x+pll-reset-delay = <12000>; + ti,c64x+pll-lock-delay = <80000>; + }; diff --git a/Documentation/devicetree/bindings/c6x/dscr.txt b/Documentation/devicetree/bindings/c6x/dscr.txt new file mode 100644 index 00000000000..d847758f2b2 --- /dev/null +++ b/Documentation/devicetree/bindings/c6x/dscr.txt @@ -0,0 +1,127 @@ +Device State Configuration Registers +------------------------------------ + +TI C6X SoCs contain a region of miscellaneous registers which provide various +function for SoC control or status. Details vary considerably among from SoC +to SoC with no two being alike. + +In general, the Device State Configuraion Registers (DSCR) will provide one or +more configuration registers often protected by a lock register where one or +more key values must be written to a lock register in order to unlock the +configuration register for writes. These configuration register may be used to +enable (and disable in some cases) SoC pin drivers, select peripheral clock +sources (internal or pin), etc. In some cases, a configuration register is +write once or the individual bits are write once. In addition to device config, +the DSCR block may provide registers which which are used to reset peripherals, +provide device ID information, provide ethernet MAC addresses, as well as other +miscellaneous functions. + +For device state control (enable/disable), each device control is assigned an +id which is used by individual device drivers to control the state as needed. + +Required properties: + +- compatible: must be "ti,c64x+dscr" +- reg: register area base and size + +Optional properties: + + NOTE: These are optional in that not all SoCs will have all properties. For + SoCs which do support a given property, leaving the property out of the + device tree will result in reduced functionality or possibly driver + failure. + +- ti,dscr-devstat + offset of the devstat register + +- ti,dscr-silicon-rev + offset, start bit, and bitsize of silicon revision field + +- ti,dscr-rmii-resets + offset and bitmask of RMII reset field. May have multiple tuples if more + than one ethernet port is available. + +- ti,dscr-locked-regs + possibly multiple tuples describing registers which are write protected by + a lock register. Each tuple consists of the register offset, lock register + offsset, and the key value used to unlock the register. + +- ti,dscr-kick-regs + offset and key values of two "kick" registers used to write protect other + registers in DSCR. On SoCs using kick registers, the first key must be + written to the first kick register and the second key must be written to + the second register before other registers in the area are write-enabled. + +- ti,dscr-mac-fuse-regs + MAC addresses are contained in two registers. Each element of a MAC address + is contained in a single byte. This property has two tuples. Each tuple has + a register offset and four cells representing bytes in the register from + most significant to least. The value of these four cells is the MAC byte + index (1-6) of the byte within the register. A value of 0 means the byte + is unused in the MAC address. + +- ti,dscr-devstate-ctl-regs + This property describes the bitfields used to control the state of devices. + Each tuple describes a range of identical bitfields used to control one or + more devices (one bitfield per device). The layout of each tuple is: + + start_id num_ids reg enable disable start_bit nbits + + Where: + start_id is device id for the first device control in the range + num_ids is the number of device controls in the range + reg is the offset of the register holding the control bits + enable is the value to enable a device + disable is the value to disable a device (0xffffffff if cannot disable) + start_bit is the bit number of the first bit in the range + nbits is the number of bits per device control + +- ti,dscr-devstate-stat-regs + This property describes the bitfields used to provide device state status + for device states controlled by the DSCR. Each tuple describes a range of + identical bitfields used to provide status for one or more devices (one + bitfield per device). The layout of each tuple is: + + start_id num_ids reg enable disable start_bit nbits + + Where: + start_id is device id for the first device status in the range + num_ids is the number of devices covered by the range + reg is the offset of the register holding the status bits + enable is the value indicating device is enabled + disable is the value indicating device is disabled + start_bit is the bit number of the first bit in the range + nbits is the number of bits per device status + +- ti,dscr-privperm + Offset and default value for register used to set access privilege for + some SoC devices. + + +Example: + + device-state-config-regs@2a80000 { + compatible = "ti,c64x+dscr"; + reg = <0x02a80000 0x41000>; + + ti,dscr-devstat = <0>; + ti,dscr-silicon-rev = <8 28 0xf>; + ti,dscr-rmii-resets = <0x40020 0x00040000>; + + ti,dscr-locked-regs = <0x40008 0x40004 0x0f0a0b00>; + ti,dscr-devstate-ctl-regs = + <0 12 0x40008 1 0 0 2 + 12 1 0x40008 3 0 30 2 + 13 2 0x4002c 1 0xffffffff 0 1>; + ti,dscr-devstate-stat-regs = + <0 10 0x40014 1 0 0 3 + 10 2 0x40018 1 0 0 3>; + + ti,dscr-mac-fuse-regs = <0x700 1 2 3 4 + 0x704 5 6 0 0>; + + ti,dscr-privperm = <0x41c 0xaaaaaaaa>; + + ti,dscr-kick-regs = <0x38 0x83E70B13 + 0x3c 0x95A4F1E0>; + }; diff --git a/Documentation/devicetree/bindings/c6x/emifa.txt b/Documentation/devicetree/bindings/c6x/emifa.txt new file mode 100644 index 00000000000..0ff6e9b9a13 --- /dev/null +++ b/Documentation/devicetree/bindings/c6x/emifa.txt @@ -0,0 +1,62 @@ +External Memory Interface +------------------------- + +The emifa node describes a simple external bus controller found on some C6X +SoCs. This interface provides external busses with a number of chip selects. + +Required properties: + +- compatible: must be "ti,c64x+emifa", "simple-bus" +- reg: register area base and size +- #address-cells: must be 2 (chip-select + offset) +- #size-cells: must be 1 +- ranges: mapping from EMIFA space to parent space + + +Optional properties: + +- ti,dscr-dev-enable: Device ID if EMIF is enabled/disabled from DSCR + +- ti,emifa-burst-priority: + Number of memory transfers after which the EMIF will elevate the priority + of the oldest command in the command FIFO. Setting this field to 255 + disables this feature, thereby allowing old commands to stay in the FIFO + indefinitely. + +- ti,emifa-ce-config: + Configuration values for each of the supported chip selects. + +Example: + + emifa@70000000 { + compatible = "ti,c64x+emifa", "simple-bus"; + #address-cells = <2>; + #size-cells = <1>; + reg = <0x70000000 0x100>; + ranges = <0x2 0x0 0xa0000000 0x00000008 + 0x3 0x0 0xb0000000 0x00400000 + 0x4 0x0 0xc0000000 0x10000000 + 0x5 0x0 0xD0000000 0x10000000>; + + ti,dscr-dev-enable = <13>; + ti,emifa-burst-priority = <255>; + ti,emifa-ce-config = <0x00240120 + 0x00240120 + 0x00240122 + 0x00240122>; + + flash@3,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "cfi-flash"; + reg = <0x3 0x0 0x400000>; + bank-width = <1>; + device-width = <1>; + partition@0 { + reg = <0x0 0x400000>; + label = "NOR"; + }; + }; + }; + +This shows a flash chip attached to chip select 3. diff --git a/Documentation/devicetree/bindings/c6x/interrupt.txt b/Documentation/devicetree/bindings/c6x/interrupt.txt new file mode 100644 index 00000000000..42bb796cc4a --- /dev/null +++ b/Documentation/devicetree/bindings/c6x/interrupt.txt @@ -0,0 +1,104 @@ +C6X Interrupt Chips +------------------- + +* C64X+ Core Interrupt Controller + + The core interrupt controller provides 16 prioritized interrupts to the + C64X+ core. Priority 0 and 1 are used for reset and NMI respectively. + Priority 2 and 3 are reserved. Priority 4-15 are used for interrupt + sources coming from outside the core. + + Required properties: + -------------------- + - compatible: Should be "ti,c64x+core-pic"; + - #interrupt-cells: <1> + + Interrupt Specifier Definition + ------------------------------ + Single cell specifying the core interrupt priority level (4-15) where + 4 is highest priority and 15 is lowest priority. + + Example + ------- + core_pic: interrupt-controller@0 { + interrupt-controller; + #interrupt-cells = <1>; + compatible = "ti,c64x+core-pic"; + }; + + + +* C64x+ Megamodule Interrupt Controller + + The megamodule PIC consists of four interrupt mupliplexers each of which + combine up to 32 interrupt inputs into a single interrupt output which + may be cascaded into the core interrupt controller. The megamodule PIC + has a total of 12 outputs cascading into the core interrupt controller. + One for each core interrupt priority level. In addition to the combined + interrupt sources, individual megamodule interrupts may be cascaded to + the core interrupt controller. When an individual interrupt is cascaded, + it is no longer handled through a megamodule interrupt combiner and is + considered to have the core interrupt controller as the parent. + + Required properties: + -------------------- + - compatible: "ti,c64x+megamod-pic" + - interrupt-controller + - #interrupt-cells: <1> + - reg: base address and size of register area + - interrupt-parent: must be core interrupt controller + - interrupts: This should have four cells; one for each interrupt combiner. + The cells contain the core priority interrupt to which the + corresponding combiner output is wired. + + Optional properties: + -------------------- + - ti,c64x+megamod-pic-mux: Array of 12 cells correspnding to the 12 core + priority interrupts. The first cell corresponds to + core priority 4 and the last cell corresponds to + core priority 15. The value of each cell is the + megamodule interrupt source which is MUXed to + the core interrupt corresponding to the cell + position. Allowed values are 4 - 127. Mapping for + interrupts 0 - 3 (combined interrupt sources) are + ignored. + + Interrupt Specifier Definition + ------------------------------ + Single cell specifying the megamodule interrupt source (4-127). Note that + interrupts mapped directly to the core with "ti,c64x+megamod-pic-mux" will + use the core interrupt controller as their parent and the specifier will + be the core priority level, not the megamodule interrupt number. + + Examples + -------- + megamod_pic: interrupt-controller@1800000 { + compatible = "ti,c64x+megamod-pic"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x1800000 0x1000>; + interrupt-parent = <&core_pic>; + interrupts = < 12 13 14 15 >; + }; + + This is a minimal example where all individual interrupts go through a + combiner. Combiner-0 is mapped to core interrupt 12, combiner-1 is mapped + to interrupt 13, etc. + + + megamod_pic: interrupt-controller@1800000 { + compatible = "ti,c64x+megamod-pic"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x1800000 0x1000>; + interrupt-parent = <&core_pic>; + interrupts = < 12 13 14 15 >; + ti,c64x+megamod-pic-mux = < 0 0 0 0 + 32 0 0 0 + 0 0 0 0 >; + }; + + This the same as the first example except that megamodule interrupt 32 is + mapped directly to core priority interrupt 8. The node using this interrupt + must set the core controller as its interrupt parent and use 8 in the + interrupt specifier value. diff --git a/Documentation/devicetree/bindings/c6x/soc.txt b/Documentation/devicetree/bindings/c6x/soc.txt new file mode 100644 index 00000000000..b1e4973b576 --- /dev/null +++ b/Documentation/devicetree/bindings/c6x/soc.txt @@ -0,0 +1,28 @@ +C6X System-on-Chip +------------------ + +Required properties: + +- compatible: "simple-bus" +- #address-cells: must be 1 +- #size-cells: must be 1 +- ranges + +Optional properties: + +- model: specific SoC model + +- nodes for IP blocks within SoC + + +Example: + + soc { + compatible = "simple-bus"; + model = "tms320c6455"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + ... + }; diff --git a/Documentation/devicetree/bindings/c6x/timer64.txt b/Documentation/devicetree/bindings/c6x/timer64.txt new file mode 100644 index 00000000000..95911fe7022 --- /dev/null +++ b/Documentation/devicetree/bindings/c6x/timer64.txt @@ -0,0 +1,26 @@ +Timer64 +------- + +The timer64 node describes C6X event timers. + +Required properties: + +- compatible: must be "ti,c64x+timer64" +- reg: base address and size of register region +- interrupt-parent: interrupt controller +- interrupts: interrupt id + +Optional properties: + +- ti,dscr-dev-enable: Device ID used to enable timer IP through DSCR interface. + +- ti,core-mask: on multi-core SoCs, bitmask of cores allowed to use this timer. + +Example: + timer0: timer@25e0000 { + compatible = "ti,c64x+timer64"; + ti,core-mask = < 0x01 >; + reg = <0x25e0000 0x40>; + interrupt-parent = <&megamod_pic>; + interrupts = < 16 >; + }; diff --git a/arch/c6x/boot/dts/dsk6455.dts b/arch/c6x/boot/dts/dsk6455.dts new file mode 100644 index 00000000000..2b71f800618 --- /dev/null +++ b/arch/c6x/boot/dts/dsk6455.dts @@ -0,0 +1,62 @@ +/* + * arch/c6x/boot/dts/dsk6455.dts + * + * DSK6455 Evaluation Platform For TMS320C6455 + * Copyright (C) 2011 Texas Instruments Incorporated + * + * Author: Mark Salter + * + * 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. + * + */ + +/dts-v1/; + +/include/ "tms320c6455.dtsi" + +/ { + model = "Spectrum Digital DSK6455"; + compatible = "spectrum-digital,dsk6455"; + + chosen { + bootargs = "root=/dev/nfs ip=dhcp rw"; + }; + + memory { + device_type = "memory"; + reg = <0xE0000000 0x08000000>; + }; + + soc { + megamod_pic: interrupt-controller@1800000 { + interrupts = < 12 13 14 15 >; + }; + + emifa@70000000 { + flash@3,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "cfi-flash"; + reg = <0x3 0x0 0x400000>; + bank-width = <1>; + device-width = <1>; + partition@0 { + reg = <0x0 0x400000>; + label = "NOR"; + }; + }; + }; + + timer1: timer@2980000 { + interrupt-parent = <&megamod_pic>; + interrupts = < 69 >; + }; + + clock-controller@029a0000 { + clock-frequency = <50000000>; + }; + }; +}; diff --git a/arch/c6x/boot/dts/evmc6457.dts b/arch/c6x/boot/dts/evmc6457.dts new file mode 100644 index 00000000000..0301eb9a8ff --- /dev/null +++ b/arch/c6x/boot/dts/evmc6457.dts @@ -0,0 +1,48 @@ +/* + * arch/c6x/boot/dts/evmc6457.dts + * + * EVMC6457 Evaluation Platform For TMS320C6457 + * + * Copyright (C) 2011 Texas Instruments Incorporated + * + * Author: Mark Salter + * + * 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. + * + */ + +/dts-v1/; + +/include/ "tms320c6457.dtsi" + +/ { + model = "eInfochips EVMC6457"; + compatible = "einfochips,evmc6457"; + + chosen { + bootargs = "console=hvc root=/dev/nfs ip=dhcp rw"; + }; + + memory { + device_type = "memory"; + reg = <0xE0000000 0x10000000>; + }; + + soc { + megamod_pic: interrupt-controller@1800000 { + interrupts = < 12 13 14 15 >; + }; + + timer0: timer@2940000 { + interrupt-parent = <&megamod_pic>; + interrupts = < 67 >; + }; + + clock-controller@29a0000 { + clock-frequency = <60000000>; + }; + }; +}; diff --git a/arch/c6x/boot/dts/evmc6472.dts b/arch/c6x/boot/dts/evmc6472.dts new file mode 100644 index 00000000000..3e207b449a9 --- /dev/null +++ b/arch/c6x/boot/dts/evmc6472.dts @@ -0,0 +1,73 @@ +/* + * arch/c6x/boot/dts/evmc6472.dts + * + * EVMC6472 Evaluation Platform For TMS320C6472 + * + * Copyright (C) 2011 Texas Instruments Incorporated + * + * Author: Mark Salter + * + * 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. + * + */ + +/dts-v1/; + +/include/ "tms320c6472.dtsi" + +/ { + model = "eInfochips EVMC6472"; + compatible = "einfochips,evmc6472"; + + chosen { + bootargs = "console=hvc root=/dev/nfs ip=dhcp rw"; + }; + + memory { + device_type = "memory"; + reg = <0xE0000000 0x10000000>; + }; + + soc { + megamod_pic: interrupt-controller@1800000 { + interrupts = < 12 13 14 15 >; + }; + + timer0: timer@25e0000 { + interrupt-parent = <&megamod_pic>; + interrupts = < 16 >; + }; + + timer1: timer@25f0000 { + interrupt-parent = <&megamod_pic>; + interrupts = < 16 >; + }; + + timer2: timer@2600000 { + interrupt-parent = <&megamod_pic>; + interrupts = < 16 >; + }; + + timer3: timer@2610000 { + interrupt-parent = <&megamod_pic>; + interrupts = < 16 >; + }; + + timer4: timer@2620000 { + interrupt-parent = <&megamod_pic>; + interrupts = < 16 >; + }; + + timer5: timer@2630000 { + interrupt-parent = <&megamod_pic>; + interrupts = < 16 >; + }; + + clock-controller@29a0000 { + clock-frequency = <25000000>; + }; + }; +}; diff --git a/arch/c6x/boot/dts/evmc6474.dts b/arch/c6x/boot/dts/evmc6474.dts new file mode 100644 index 00000000000..4dc291292bc --- /dev/null +++ b/arch/c6x/boot/dts/evmc6474.dts @@ -0,0 +1,58 @@ +/* + * arch/c6x/boot/dts/evmc6474.dts + * + * EVMC6474 Evaluation Platform For TMS320C6474 + * + * Copyright (C) 2011 Texas Instruments Incorporated + * + * Author: Mark Salter + * + * 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. + * + */ + +/dts-v1/; + +/include/ "tms320c6474.dtsi" + +/ { + model = "Spectrum Digital EVMC6474"; + compatible = "spectrum-digital,evmc6474"; + + chosen { + bootargs = "console=hvc root=/dev/nfs ip=dhcp rw"; + }; + + memory { + device_type = "memory"; + reg = <0x80000000 0x08000000>; + }; + + soc { + megamod_pic: interrupt-controller@1800000 { + interrupts = < 12 13 14 15 >; + }; + + timer3: timer@2940000 { + interrupt-parent = <&megamod_pic>; + interrupts = < 39 >; + }; + + timer4: timer@2950000 { + interrupt-parent = <&megamod_pic>; + interrupts = < 41 >; + }; + + timer5: timer@2960000 { + interrupt-parent = <&megamod_pic>; + interrupts = < 43 >; + }; + + clock-controller@29a0000 { + clock-frequency = <50000000>; + }; + }; +}; diff --git a/arch/c6x/boot/dts/tms320c6455.dtsi b/arch/c6x/boot/dts/tms320c6455.dtsi new file mode 100644 index 00000000000..a804ec1e018 --- /dev/null +++ b/arch/c6x/boot/dts/tms320c6455.dtsi @@ -0,0 +1,96 @@ + +/ { + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + model = "ti,c64x+"; + reg = <0>; + }; + }; + + soc { + compatible = "simple-bus"; + model = "tms320c6455"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + core_pic: interrupt-controller { + interrupt-controller; + #interrupt-cells = <1>; + compatible = "ti,c64x+core-pic"; + }; + + /* + * Megamodule interrupt controller + */ + megamod_pic: interrupt-controller@1800000 { + compatible = "ti,c64x+megamod-pic"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x1800000 0x1000>; + interrupt-parent = <&core_pic>; + }; + + cache-controller@1840000 { + compatible = "ti,c64x+cache"; + reg = <0x01840000 0x8400>; + }; + + emifa@70000000 { + compatible = "ti,c64x+emifa", "simple-bus"; + #address-cells = <2>; + #size-cells = <1>; + reg = <0x70000000 0x100>; + ranges = <0x2 0x0 0xa0000000 0x00000008 + 0x3 0x0 0xb0000000 0x00400000 + 0x4 0x0 0xc0000000 0x10000000 + 0x5 0x0 0xD0000000 0x10000000>; + + ti,dscr-dev-enable = <13>; + ti,emifa-burst-priority = <255>; + ti,emifa-ce-config = <0x00240120 + 0x00240120 + 0x00240122 + 0x00240122>; + }; + + timer1: timer@2980000 { + compatible = "ti,c64x+timer64"; + reg = <0x2980000 0x40>; + ti,dscr-dev-enable = <4>; + }; + + clock-controller@029a0000 { + compatible = "ti,c6455-pll", "ti,c64x+pll"; + reg = <0x029a0000 0x200>; + ti,c64x+pll-bypass-delay = <1440>; + ti,c64x+pll-reset-delay = <15360>; + ti,c64x+pll-lock-delay = <24000>; + }; + + device-state-config-regs@2a80000 { + compatible = "ti,c64x+dscr"; + reg = <0x02a80000 0x41000>; + + ti,dscr-devstat = <0>; + ti,dscr-silicon-rev = <8 28 0xf>; + ti,dscr-rmii-resets = <0 0x40020 0x00040000>; + + ti,dscr-locked-regs = <0x40008 0x40004 0x0f0a0b00>; + ti,dscr-devstate-ctl-regs = + <0 12 0x40008 1 0 0 2 + 12 1 0x40008 3 0 30 2 + 13 2 0x4002c 1 0xffffffff 0 1>; + ti,dscr-devstate-stat-regs = + <0 10 0x40014 1 0 0 3 + 10 2 0x40018 1 0 0 3>; + }; + }; +}; diff --git a/arch/c6x/boot/dts/tms320c6457.dtsi b/arch/c6x/boot/dts/tms320c6457.dtsi new file mode 100644 index 00000000000..35f40709a71 --- /dev/null +++ b/arch/c6x/boot/dts/tms320c6457.dtsi @@ -0,0 +1,68 @@ + +/ { + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + model = "ti,c64x+"; + reg = <0>; + }; + }; + + soc { + compatible = "simple-bus"; + model = "tms320c6457"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + core_pic: interrupt-controller { + interrupt-controller; + #interrupt-cells = <1>; + compatible = "ti,c64x+core-pic"; + }; + + megamod_pic: interrupt-controller@1800000 { + compatible = "ti,c64x+megamod-pic"; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&core_pic>; + reg = <0x1800000 0x1000>; + }; + + cache-controller@1840000 { + compatible = "ti,c64x+cache"; + reg = <0x01840000 0x8400>; + }; + + device-state-controller@2880800 { + compatible = "ti,c64x+dscr"; + reg = <0x02880800 0x400>; + + ti,dscr-devstat = <0x20>; + ti,dscr-silicon-rev = <0x18 28 0xf>; + ti,dscr-mac-fuse-regs = <0x114 3 4 5 6 + 0x118 0 0 1 2>; + ti,dscr-kick-regs = <0x38 0x83E70B13 + 0x3c 0x95A4F1E0>; + }; + + timer0: timer@2940000 { + compatible = "ti,c64x+timer64"; + reg = <0x2940000 0x40>; + }; + + clock-controller@29a0000 { + compatible = "ti,c6457-pll", "ti,c64x+pll"; + reg = <0x029a0000 0x200>; + ti,c64x+pll-bypass-delay = <300>; + ti,c64x+pll-reset-delay = <24000>; + ti,c64x+pll-lock-delay = <50000>; + }; + }; +}; diff --git a/arch/c6x/boot/dts/tms320c6472.dtsi b/arch/c6x/boot/dts/tms320c6472.dtsi new file mode 100644 index 00000000000..b488aaec65c --- /dev/null +++ b/arch/c6x/boot/dts/tms320c6472.dtsi @@ -0,0 +1,134 @@ + +/ { + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + reg = <0>; + model = "ti,c64x+"; + }; + cpu@1 { + device_type = "cpu"; + reg = <1>; + model = "ti,c64x+"; + }; + cpu@2 { + device_type = "cpu"; + reg = <2>; + model = "ti,c64x+"; + }; + cpu@3 { + device_type = "cpu"; + reg = <3>; + model = "ti,c64x+"; + }; + cpu@4 { + device_type = "cpu"; + reg = <4>; + model = "ti,c64x+"; + }; + cpu@5 { + device_type = "cpu"; + reg = <5>; + model = "ti,c64x+"; + }; + }; + + soc { + compatible = "simple-bus"; + model = "tms320c6472"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + core_pic: interrupt-controller { + compatible = "ti,c64x+core-pic"; + interrupt-controller; + #interrupt-cells = <1>; + }; + + megamod_pic: interrupt-controller@1800000 { + compatible = "ti,c64x+megamod-pic"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x1800000 0x1000>; + interrupt-parent = <&core_pic>; + }; + + cache-controller@1840000 { + compatible = "ti,c64x+cache"; + reg = <0x01840000 0x8400>; + }; + + timer0: timer@25e0000 { + compatible = "ti,c64x+timer64"; + ti,core-mask = < 0x01 >; + reg = <0x25e0000 0x40>; + }; + + timer1: timer@25f0000 { + compatible = "ti,c64x+timer64"; + ti,core-mask = < 0x02 >; + reg = <0x25f0000 0x40>; + }; + + timer2: timer@2600000 { + compatible = "ti,c64x+timer64"; + ti,core-mask = < 0x04 >; + reg = <0x2600000 0x40>; + }; + + timer3: timer@2610000 { + compatible = "ti,c64x+timer64"; + ti,core-mask = < 0x08 >; + reg = <0x2610000 0x40>; + }; + + timer4: timer@2620000 { + compatible = "ti,c64x+timer64"; + ti,core-mask = < 0x10 >; + reg = <0x2620000 0x40>; + }; + + timer5: timer@2630000 { + compatible = "ti,c64x+timer64"; + ti,core-mask = < 0x20 >; + reg = <0x2630000 0x40>; + }; + + clock-controller@29a0000 { + compatible = "ti,c6472-pll", "ti,c64x+pll"; + reg = <0x029a0000 0x200>; + ti,c64x+pll-bypass-delay = <200>; + ti,c64x+pll-reset-delay = <12000>; + ti,c64x+pll-lock-delay = <80000>; + }; + + device-state-controller@2a80000 { + compatible = "ti,c64x+dscr"; + reg = <0x02a80000 0x1000>; + + ti,dscr-devstat = <0>; + ti,dscr-silicon-rev = <0x70c 16 0xff>; + + ti,dscr-mac-fuse-regs = <0x700 1 2 3 4 + 0x704 5 6 0 0>; + + ti,dscr-rmii-resets = <0x208 1 + 0x20c 1>; + + ti,dscr-locked-regs = <0x200 0x204 0x0a1e183a + 0x40c 0x420 0xbea7 + 0x41c 0x420 0xbea7>; + + ti,dscr-privperm = <0x41c 0xaaaaaaaa>; + + ti,dscr-devstate-ctl-regs = <0 13 0x200 1 0 0 1>; + }; + }; +}; diff --git a/arch/c6x/boot/dts/tms320c6474.dtsi b/arch/c6x/boot/dts/tms320c6474.dtsi new file mode 100644 index 00000000000..cc601bf348a --- /dev/null +++ b/arch/c6x/boot/dts/tms320c6474.dtsi @@ -0,0 +1,89 @@ + +/ { + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + reg = <0>; + model = "ti,c64x+"; + }; + cpu@1 { + device_type = "cpu"; + reg = <1>; + model = "ti,c64x+"; + }; + cpu@2 { + device_type = "cpu"; + reg = <2>; + model = "ti,c64x+"; + }; + }; + + soc { + compatible = "simple-bus"; + model = "tms320c6474"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + core_pic: interrupt-controller { + interrupt-controller; + #interrupt-cells = <1>; + compatible = "ti,c64x+core-pic"; + }; + + megamod_pic: interrupt-controller@1800000 { + compatible = "ti,c64x+megamod-pic"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x1800000 0x1000>; + interrupt-parent = <&core_pic>; + }; + + cache-controller@1840000 { + compatible = "ti,c64x+cache"; + reg = <0x01840000 0x8400>; + }; + + timer3: timer@2940000 { + compatible = "ti,c64x+timer64"; + ti,core-mask = < 0x04 >; + reg = <0x2940000 0x40>; + }; + + timer4: timer@2950000 { + compatible = "ti,c64x+timer64"; + ti,core-mask = < 0x02 >; + reg = <0x2950000 0x40>; + }; + + timer5: timer@2960000 { + compatible = "ti,c64x+timer64"; + ti,core-mask = < 0x01 >; + reg = <0x2960000 0x40>; + }; + + device-state-controller@2880800 { + compatible = "ti,c64x+dscr"; + reg = <0x02880800 0x400>; + + ti,dscr-devstat = <0x004>; + ti,dscr-silicon-rev = <0x014 28 0xf>; + ti,dscr-mac-fuse-regs = <0x34 3 4 5 6 + 0x38 0 0 1 2>; + }; + + clock-controller@29a0000 { + compatible = "ti,c6474-pll", "ti,c64x+pll"; + reg = <0x029a0000 0x200>; + ti,c64x+pll-bypass-delay = <120>; + ti,c64x+pll-reset-delay = <30000>; + ti,c64x+pll-lock-delay = <60000>; + }; + }; +}; diff --git a/arch/c6x/boot/linked_dtb.S b/arch/c6x/boot/linked_dtb.S new file mode 100644 index 00000000000..57a4454eaec --- /dev/null +++ b/arch/c6x/boot/linked_dtb.S @@ -0,0 +1,2 @@ +.section __fdt_blob,"a" +.incbin "arch/c6x/boot/builtin.dtb" diff --git a/arch/c6x/kernel/devicetree.c b/arch/c6x/kernel/devicetree.c new file mode 100644 index 00000000000..bdb56f09d0a --- /dev/null +++ b/arch/c6x/kernel/devicetree.c @@ -0,0 +1,53 @@ +/* + * Architecture specific OF callbacks. + * + * Copyright (C) 2011 Texas Instruments Incorporated + * Author: Mark Salter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#include +#include +#include +#include +#include + +void __init early_init_devtree(void *params) +{ + /* Setup flat device-tree pointer */ + initial_boot_params = params; + + /* Retrieve various informations from the /chosen node of the + * device-tree, including the platform type, initrd location and + * size and more ... + */ + of_scan_flat_dt(early_init_dt_scan_chosen, c6x_command_line); + + /* Scan memory nodes and rebuild MEMBLOCKs */ + of_scan_flat_dt(early_init_dt_scan_root, NULL); + of_scan_flat_dt(early_init_dt_scan_memory, NULL); +} + + +#ifdef CONFIG_BLK_DEV_INITRD +void __init early_init_dt_setup_initrd_arch(unsigned long start, + unsigned long end) +{ + initrd_start = (unsigned long)__va(start); + initrd_end = (unsigned long)__va(end); + initrd_below_start_ok = 1; +} +#endif + +void __init early_init_dt_add_memory_arch(u64 base, u64 size) +{ + c6x_add_memory(base, size); +} + +void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) +{ + return __va(memblock_alloc(size, align)); +} diff --git a/arch/c6x/platforms/platform.c b/arch/c6x/platforms/platform.c new file mode 100644 index 00000000000..26c1a355d60 --- /dev/null +++ b/arch/c6x/platforms/platform.c @@ -0,0 +1,17 @@ +/* + * Copyright 2011 Texas Instruments Incorporated + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include + +static int __init c6x_device_probe(void) +{ + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + return 0; +} +core_initcall(c6x_device_probe); -- cgit v1.2.3-70-g09d2 From c511595390a373e19a774246c659b4f563a4c3f3 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Mon, 17 Oct 2011 14:56:41 +0200 Subject: dmaengine: at_hdmac: add device tree support Add device tree probe support for atmel at_hdmac DMA driver. Bindings are added to specify DMA controller configuration. Signed-off-by: Nicolas Ferre Acked-by: Grant Likely Signed-off-by: Vinod Koul --- .../devicetree/bindings/dma/atmel-dma.txt | 14 ++++++++++ drivers/dma/at_hdmac.c | 32 +++++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/dma/atmel-dma.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/dma/atmel-dma.txt b/Documentation/devicetree/bindings/dma/atmel-dma.txt new file mode 100644 index 00000000000..3c046ee6e8b --- /dev/null +++ b/Documentation/devicetree/bindings/dma/atmel-dma.txt @@ -0,0 +1,14 @@ +* Atmel Direct Memory Access Controller (DMA) + +Required properties: +- compatible: Should be "atmel,-dma" +- reg: Should contain DMA registers location and length +- interrupts: Should contain DMA interrupt + +Examples: + +dma@ffffec00 { + compatible = "atmel,at91sam9g45-dma"; + reg = <0xffffec00 0x200>; + interrupts = <21>; +}; diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index d1869c597e4..f3cb4a009e7 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include "at_hdmac_regs.h" @@ -1175,6 +1177,20 @@ static void atc_free_chan_resources(struct dma_chan *chan) /*-- Module Management -----------------------------------------------*/ +#if defined(CONFIG_OF) +static const struct of_device_id atmel_dma_dt_ids[] = { + { + .compatible = "atmel,at91sam9rl-dma", + .data = (void *)ATDMA_DEVTYPE_SAM9RL + }, { + .compatible = "atmel,at91sam9g45-dma", + .data = (void *)ATDMA_DEVTYPE_SAM9G45 + }, { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, atmel_dma_dt_ids); +#endif + static struct platform_device_id atdma_devtypes[] = { { .name = "at91sam9rl_dma", @@ -1187,6 +1203,19 @@ static struct platform_device_id atdma_devtypes[] = { } }; +static inline enum atdma_devtype __init at_dma_get_driver_data( + struct platform_device *pdev) +{ + if (pdev->dev.of_node) { + const struct of_device_id *match; + match = of_match_node(atmel_dma_dt_ids, pdev->dev.of_node); + if (match == NULL) + return ATDMA_DEVTYPE_UNDEFINED; + return (enum atdma_devtype)match->data; + } + return platform_get_device_id(pdev)->driver_data; +} + /** * at_dma_off - disable DMA controller * @atdma: the Atmel HDAMC device @@ -1218,7 +1247,7 @@ static int __init at_dma_probe(struct platform_device *pdev) dma_cap_set(DMA_MEMCPY, cap_mask); /* get DMA parameters from controller type */ - atdmatype = platform_get_device_id(pdev)->driver_data; + atdmatype = at_dma_get_driver_data(pdev); switch (atdmatype) { case ATDMA_DEVTYPE_SAM9RL: @@ -1526,6 +1555,7 @@ static struct platform_driver at_dma_driver = { .driver = { .name = "at_hdmac", .pm = &at_dma_dev_pm_ops, + .of_match_table = of_match_ptr(atmel_dma_dt_ids), }, }; -- cgit v1.2.3-70-g09d2 From db0d4db22a78d31c59087f7057b8f1612fecc35d Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sat, 12 Nov 2011 16:09:49 +0000 Subject: ARM: gic: allow GIC to support non-banked setups The GIC support code is heavily using the fact that hardware implementations are exposing banked registers. Unfortunately, it looks like at least one GIC implementation (EXYNOS) offers both the distributor and the CPU interfaces at different addresses, depending on the CPU. This problem is solved by allowing the distributor and CPU interface addresses to be per-cpu variables for the platforms that require it. The EXYNOS code is updated not to mess with the GIC internals while handling interrupts, and struct gic_chip_data is back to being private. The DT binding for the gic is updated to allow an optional "cpu-offset" value, which is used to compute the various base addresses. Finally, a new config option (GIC_NON_BANKED) is used to control this feature, so the overhead is only present on kernels compiled with support for EXYNOS. Tested on Origen (EXYNOS4) and Panda (OMAP4). Cc: Kukjin Kim Cc: Will Deacon Cc: Thomas Abraham Acked-by: Rob Herring Signed-off-by: Marc Zyngier --- Documentation/devicetree/bindings/arm/gic.txt | 4 + arch/arm/common/Kconfig | 3 + arch/arm/common/gic.c | 133 ++++++++++++++++++++++---- arch/arm/include/asm/hardware/gic.h | 24 ++--- arch/arm/mach-exynos/cpu.c | 16 +--- arch/arm/mach-exynos/platsmp.c | 28 +----- arch/arm/plat-s5p/Kconfig | 1 + 7 files changed, 132 insertions(+), 77 deletions(-) (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/arm/gic.txt b/Documentation/devicetree/bindings/arm/gic.txt index 52916b4aa1f..9b4b82a721b 100644 --- a/Documentation/devicetree/bindings/arm/gic.txt +++ b/Documentation/devicetree/bindings/arm/gic.txt @@ -42,6 +42,10 @@ Optional - interrupts : Interrupt source of the parent interrupt controller. Only present on secondary GICs. +- cpu-offset : per-cpu offset within the distributor and cpu interface + regions, used when the GIC doesn't have banked registers. The offset is + cpu-offset * cpu-nr. + Example: intc: interrupt-controller@fff11000 { diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig index 74df9ca2be3..a3beda1213d 100644 --- a/arch/arm/common/Kconfig +++ b/arch/arm/common/Kconfig @@ -2,6 +2,9 @@ config ARM_GIC select IRQ_DOMAIN bool +config GIC_NON_BANKED + bool + config ARM_VIC bool diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c index 0e6ae470c94..43cb6f1a7cf 100644 --- a/arch/arm/common/gic.c +++ b/arch/arm/common/gic.c @@ -43,6 +43,31 @@ #include #include +union gic_base { + void __iomem *common_base; + void __percpu __iomem **percpu_base; +}; + +struct gic_chip_data { + unsigned int irq_offset; + union gic_base dist_base; + union gic_base cpu_base; +#ifdef CONFIG_CPU_PM + u32 saved_spi_enable[DIV_ROUND_UP(1020, 32)]; + u32 saved_spi_conf[DIV_ROUND_UP(1020, 16)]; + u32 saved_spi_target[DIV_ROUND_UP(1020, 4)]; + u32 __percpu *saved_ppi_enable; + u32 __percpu *saved_ppi_conf; +#endif +#ifdef CONFIG_IRQ_DOMAIN + struct irq_domain domain; +#endif + unsigned int gic_irqs; +#ifdef CONFIG_GIC_NON_BANKED + void __iomem *(*get_base)(union gic_base *); +#endif +}; + static DEFINE_RAW_SPINLOCK(irq_controller_lock); /* Address of GIC 0 CPU interface */ @@ -67,16 +92,48 @@ struct irq_chip gic_arch_extn = { static struct gic_chip_data gic_data[MAX_GIC_NR] __read_mostly; +#ifdef CONFIG_GIC_NON_BANKED +static void __iomem *gic_get_percpu_base(union gic_base *base) +{ + return *__this_cpu_ptr(base->percpu_base); +} + +static void __iomem *gic_get_common_base(union gic_base *base) +{ + return base->common_base; +} + +static inline void __iomem *gic_data_dist_base(struct gic_chip_data *data) +{ + return data->get_base(&data->dist_base); +} + +static inline void __iomem *gic_data_cpu_base(struct gic_chip_data *data) +{ + return data->get_base(&data->cpu_base); +} + +static inline void gic_set_base_accessor(struct gic_chip_data *data, + void __iomem *(*f)(union gic_base *)) +{ + data->get_base = f; +} +#else +#define gic_data_dist_base(d) ((d)->dist_base.common_base) +#define gic_data_cpu_base(d) ((d)->cpu_base.common_base) +#define gic_set_base_accessor(d,f) +#endif + static inline void __iomem *gic_dist_base(struct irq_data *d) { struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d); - return gic_data->dist_base; + return gic_data_dist_base(gic_data); } static inline void __iomem *gic_cpu_base(struct irq_data *d) { struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d); - return gic_data->cpu_base; + return gic_data_cpu_base(gic_data); } static inline unsigned int gic_irq(struct irq_data *d) @@ -225,7 +282,7 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc) chained_irq_enter(chip, desc); raw_spin_lock(&irq_controller_lock); - status = readl_relaxed(chip_data->cpu_base + GIC_CPU_INTACK); + status = readl_relaxed(gic_data_cpu_base(chip_data) + GIC_CPU_INTACK); raw_spin_unlock(&irq_controller_lock); gic_irq = (status & 0x3ff); @@ -270,7 +327,7 @@ static void __init gic_dist_init(struct gic_chip_data *gic) u32 cpumask; unsigned int gic_irqs = gic->gic_irqs; struct irq_domain *domain = &gic->domain; - void __iomem *base = gic->dist_base; + void __iomem *base = gic_data_dist_base(gic); u32 cpu = 0; #ifdef CONFIG_SMP @@ -330,8 +387,8 @@ static void __init gic_dist_init(struct gic_chip_data *gic) static void __cpuinit gic_cpu_init(struct gic_chip_data *gic) { - void __iomem *dist_base = gic->dist_base; - void __iomem *base = gic->cpu_base; + void __iomem *dist_base = gic_data_dist_base(gic); + void __iomem *base = gic_data_cpu_base(gic); int i; /* @@ -368,7 +425,7 @@ static void gic_dist_save(unsigned int gic_nr) BUG(); gic_irqs = gic_data[gic_nr].gic_irqs; - dist_base = gic_data[gic_nr].dist_base; + dist_base = gic_data_dist_base(&gic_data[gic_nr]); if (!dist_base) return; @@ -403,7 +460,7 @@ static void gic_dist_restore(unsigned int gic_nr) BUG(); gic_irqs = gic_data[gic_nr].gic_irqs; - dist_base = gic_data[gic_nr].dist_base; + dist_base = gic_data_dist_base(&gic_data[gic_nr]); if (!dist_base) return; @@ -439,8 +496,8 @@ static void gic_cpu_save(unsigned int gic_nr) if (gic_nr >= MAX_GIC_NR) BUG(); - dist_base = gic_data[gic_nr].dist_base; - cpu_base = gic_data[gic_nr].cpu_base; + dist_base = gic_data_dist_base(&gic_data[gic_nr]); + cpu_base = gic_data_cpu_base(&gic_data[gic_nr]); if (!dist_base || !cpu_base) return; @@ -465,8 +522,8 @@ static void gic_cpu_restore(unsigned int gic_nr) if (gic_nr >= MAX_GIC_NR) BUG(); - dist_base = gic_data[gic_nr].dist_base; - cpu_base = gic_data[gic_nr].cpu_base; + dist_base = gic_data_dist_base(&gic_data[gic_nr]); + cpu_base = gic_data_cpu_base(&gic_data[gic_nr]); if (!dist_base || !cpu_base) return; @@ -491,6 +548,11 @@ static int gic_notifier(struct notifier_block *self, unsigned long cmd, void *v) int i; for (i = 0; i < MAX_GIC_NR; i++) { +#ifdef CONFIG_GIC_NON_BANKED + /* Skip over unused GICs */ + if (!gic_data[i].get_base) + continue; +#endif switch (cmd) { case CPU_PM_ENTER: gic_cpu_save(i); @@ -563,8 +625,9 @@ const struct irq_domain_ops gic_irq_domain_ops = { #endif }; -void __init gic_init(unsigned int gic_nr, int irq_start, - void __iomem *dist_base, void __iomem *cpu_base) +void __init gic_init_bases(unsigned int gic_nr, int irq_start, + void __iomem *dist_base, void __iomem *cpu_base, + u32 percpu_offset) { struct gic_chip_data *gic; struct irq_domain *domain; @@ -574,8 +637,36 @@ void __init gic_init(unsigned int gic_nr, int irq_start, gic = &gic_data[gic_nr]; domain = &gic->domain; - gic->dist_base = dist_base; - gic->cpu_base = cpu_base; +#ifdef CONFIG_GIC_NON_BANKED + if (percpu_offset) { /* Frankein-GIC without banked registers... */ + unsigned int cpu; + + gic->dist_base.percpu_base = alloc_percpu(void __iomem *); + gic->cpu_base.percpu_base = alloc_percpu(void __iomem *); + if (WARN_ON(!gic->dist_base.percpu_base || + !gic->cpu_base.percpu_base)) { + free_percpu(gic->dist_base.percpu_base); + free_percpu(gic->cpu_base.percpu_base); + return; + } + + for_each_possible_cpu(cpu) { + unsigned long offset = percpu_offset * cpu_logical_map(cpu); + *per_cpu_ptr(gic->dist_base.percpu_base, cpu) = dist_base + offset; + *per_cpu_ptr(gic->cpu_base.percpu_base, cpu) = cpu_base + offset; + } + + gic_set_base_accessor(gic, gic_get_percpu_base); + } else +#endif + { /* Normal, sane GIC... */ + WARN(percpu_offset, + "GIC_NON_BANKED not enabled, ignoring %08x offset!", + percpu_offset); + gic->dist_base.common_base = dist_base; + gic->cpu_base.common_base = cpu_base; + gic_set_base_accessor(gic, gic_get_common_base); + } /* * For primary GICs, skip over SGIs. @@ -593,7 +684,7 @@ void __init gic_init(unsigned int gic_nr, int irq_start, * Find out how many interrupts are supported. * The GIC only supports up to 1020 interrupt sources. */ - gic_irqs = readl_relaxed(dist_base + GIC_DIST_CTR) & 0x1f; + gic_irqs = readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_CTR) & 0x1f; gic_irqs = (gic_irqs + 1) * 32; if (gic_irqs > 1020) gic_irqs = 1020; @@ -641,7 +732,7 @@ void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) dsb(); /* this always happens on GIC0 */ - writel_relaxed(map << 16 | irq, gic_data[0].dist_base + GIC_DIST_SOFTINT); + writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT); } #endif @@ -652,6 +743,7 @@ int __init gic_of_init(struct device_node *node, struct device_node *parent) { void __iomem *cpu_base; void __iomem *dist_base; + u32 percpu_offset; int irq; struct irq_domain *domain = &gic_data[gic_cnt].domain; @@ -664,9 +756,12 @@ int __init gic_of_init(struct device_node *node, struct device_node *parent) cpu_base = of_iomap(node, 1); WARN(!cpu_base, "unable to map gic cpu registers\n"); + if (of_property_read_u32(node, "cpu-offset", &percpu_offset)) + percpu_offset = 0; + domain->of_node = of_node_get(node); - gic_init(gic_cnt, -1, dist_base, cpu_base); + gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset); if (parent) { irq = irq_of_parse_and_map(node, 0); diff --git a/arch/arm/include/asm/hardware/gic.h b/arch/arm/include/asm/hardware/gic.h index 3e91f22046f..2721d90625e 100644 --- a/arch/arm/include/asm/hardware/gic.h +++ b/arch/arm/include/asm/hardware/gic.h @@ -39,27 +39,19 @@ struct device_node; extern void __iomem *gic_cpu_base_addr; extern struct irq_chip gic_arch_extn; -void gic_init(unsigned int, int, void __iomem *, void __iomem *); +void gic_init_bases(unsigned int, int, void __iomem *, void __iomem *, + u32 offset); int gic_of_init(struct device_node *node, struct device_node *parent); void gic_secondary_init(unsigned int); void gic_cascade_irq(unsigned int gic_nr, unsigned int irq); void gic_raise_softirq(const struct cpumask *mask, unsigned int irq); -struct gic_chip_data { - void __iomem *dist_base; - void __iomem *cpu_base; -#ifdef CONFIG_CPU_PM - u32 saved_spi_enable[DIV_ROUND_UP(1020, 32)]; - u32 saved_spi_conf[DIV_ROUND_UP(1020, 16)]; - u32 saved_spi_target[DIV_ROUND_UP(1020, 4)]; - u32 __percpu *saved_ppi_enable; - u32 __percpu *saved_ppi_conf; -#endif -#ifdef CONFIG_IRQ_DOMAIN - struct irq_domain domain; -#endif - unsigned int gic_irqs; -}; +static inline void gic_init(unsigned int nr, int start, + void __iomem *dist , void __iomem *cpu) +{ + gic_init_bases(nr, start, dist, cpu, 0); +} + #endif #endif diff --git a/arch/arm/mach-exynos/cpu.c b/arch/arm/mach-exynos/cpu.c index 90ec247f3b3..e92e464bdbb 100644 --- a/arch/arm/mach-exynos/cpu.c +++ b/arch/arm/mach-exynos/cpu.c @@ -207,27 +207,13 @@ void __init exynos4_init_clocks(int xtal) exynos4_setup_clocks(); } -static void exynos4_gic_irq_fix_base(struct irq_data *d) -{ - struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d); - - gic_data->cpu_base = S5P_VA_GIC_CPU + - (gic_bank_offset * smp_processor_id()); - - gic_data->dist_base = S5P_VA_GIC_DIST + - (gic_bank_offset * smp_processor_id()); -} - void __init exynos4_init_irq(void) { int irq; gic_bank_offset = soc_is_exynos4412() ? 0x4000 : 0x8000; - gic_init(0, IRQ_PPI(0), S5P_VA_GIC_DIST, S5P_VA_GIC_CPU); - gic_arch_extn.irq_eoi = exynos4_gic_irq_fix_base; - gic_arch_extn.irq_unmask = exynos4_gic_irq_fix_base; - gic_arch_extn.irq_mask = exynos4_gic_irq_fix_base; + gic_init_bases(0, IRQ_PPI(0), S5P_VA_GIC_DIST, S5P_VA_GIC_CPU, gic_bank_offset); for (irq = 0; irq < MAX_COMBINER_NR; irq++) { diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c index 69ffb2fb387..60bc45e3e70 100644 --- a/arch/arm/mach-exynos/platsmp.c +++ b/arch/arm/mach-exynos/platsmp.c @@ -32,7 +32,6 @@ #include -extern unsigned int gic_bank_offset; extern void exynos4_secondary_startup(void); #define CPU1_BOOT_REG (samsung_rev() == EXYNOS4210_REV_1_1 ? \ @@ -65,31 +64,6 @@ static void __iomem *scu_base_addr(void) static DEFINE_SPINLOCK(boot_lock); -static void __cpuinit exynos4_gic_secondary_init(void) -{ - void __iomem *dist_base = S5P_VA_GIC_DIST + - (gic_bank_offset * smp_processor_id()); - void __iomem *cpu_base = S5P_VA_GIC_CPU + - (gic_bank_offset * smp_processor_id()); - int i; - - /* - * Deal with the banked PPI and SGI interrupts - disable all - * PPI interrupts, ensure all SGI interrupts are enabled. - */ - __raw_writel(0xffff0000, dist_base + GIC_DIST_ENABLE_CLEAR); - __raw_writel(0x0000ffff, dist_base + GIC_DIST_ENABLE_SET); - - /* - * Set priority on PPI and SGI interrupts - */ - for (i = 0; i < 32; i += 4) - __raw_writel(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4); - - __raw_writel(0xf0, cpu_base + GIC_CPU_PRIMASK); - __raw_writel(1, cpu_base + GIC_CPU_CTRL); -} - void __cpuinit platform_secondary_init(unsigned int cpu) { /* @@ -97,7 +71,7 @@ void __cpuinit platform_secondary_init(unsigned int cpu) * core (e.g. timer irq), then they will not have been enabled * for us: do so */ - exynos4_gic_secondary_init(); + gic_secondary_init(0); /* * let the primary processor know we're out of the diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig index 9b9968fa869..8167ce66188 100644 --- a/arch/arm/plat-s5p/Kconfig +++ b/arch/arm/plat-s5p/Kconfig @@ -11,6 +11,7 @@ config PLAT_S5P default y select ARM_VIC if !ARCH_EXYNOS4 select ARM_GIC if ARCH_EXYNOS4 + select GIC_NON_BANKED if ARCH_EXYNOS4 select NO_IOPORT select ARCH_REQUIRE_GPIOLIB select S3C_GPIO_TRACK -- cgit v1.2.3-70-g09d2 From f9b28ccbc7139af656147dcbba9c5425d5706b7d Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Tue, 27 Sep 2011 11:00:46 +0100 Subject: ARM: vic: device tree binding This adds a device tree binding for the VIC based on the of_irq_init() support. This adds an irqdomain to the vic and always registers all vics in the static vic array rather than for pm only to keep track of the irq domain. struct irq_data::hwirq is used where appropriate rather than runtime masking. v3: - include linux/export.h for THIS_MODULE v2: - use irq_domain_simple_ops - remove stub implementation of vic_of_init for !CONFIG_OF - Make VIC select IRQ_DOMAIN Reviewed-by: Rob Herring Reviewed-by: Grant Likely Tested-by: Thomas Abraham Signed-off-by: Jamie Iles --- Documentation/devicetree/bindings/arm/vic.txt | 29 +++++++ arch/arm/common/Kconfig | 1 + arch/arm/common/vic.c | 107 +++++++++++++++++++------- arch/arm/include/asm/hardware/vic.h | 7 +- 4 files changed, 115 insertions(+), 29 deletions(-) create mode 100644 Documentation/devicetree/bindings/arm/vic.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/arm/vic.txt b/Documentation/devicetree/bindings/arm/vic.txt new file mode 100644 index 00000000000..266716b2343 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/vic.txt @@ -0,0 +1,29 @@ +* ARM Vectored Interrupt Controller + +One or more Vectored Interrupt Controllers (VIC's) can be connected in an ARM +system for interrupt routing. For multiple controllers they can either be +nested or have the outputs wire-OR'd together. + +Required properties: + +- compatible : should be one of + "arm,pl190-vic" + "arm,pl192-vic" +- interrupt-controller : Identifies the node as an interrupt controller +- #interrupt-cells : The number of cells to define the interrupts. Must be 1 as + the VIC has no configuration options for interrupt sources. The cell is a u32 + and defines the interrupt number. +- reg : The register bank for the VIC. + +Optional properties: + +- interrupts : Interrupt source for parent controllers if the VIC is nested. + +Example: + + vic0: interrupt-controller@60000 { + compatible = "arm,pl192-vic"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x60000 0x1000>; + }; diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig index a11cee523cd..10ca9749e94 100644 --- a/arch/arm/common/Kconfig +++ b/arch/arm/common/Kconfig @@ -7,6 +7,7 @@ config GIC_NON_BANKED bool config ARM_VIC + select IRQ_DOMAIN bool config ARM_VIC_NR diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c index 01f18a421b1..a227a7d5370 100644 --- a/arch/arm/common/vic.c +++ b/arch/arm/common/vic.c @@ -19,9 +19,14 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include #include #include #include +#include +#include +#include +#include #include #include #include @@ -29,7 +34,6 @@ #include #include -#ifdef CONFIG_PM /** * struct vic_device - VIC PM device * @irq: The IRQ number for the base of the VIC. @@ -40,6 +44,7 @@ * @int_enable: Save for VIC_INT_ENABLE. * @soft_int: Save for VIC_INT_SOFT. * @protect: Save for VIC_PROTECT. + * @domain: The IRQ domain for the VIC. */ struct vic_device { void __iomem *base; @@ -50,13 +55,13 @@ struct vic_device { u32 int_enable; u32 soft_int; u32 protect; + struct irq_domain domain; }; /* we cannot allocate memory when VICs are initially registered */ static struct vic_device vic_devices[CONFIG_ARM_VIC_NR]; static int vic_id; -#endif /* CONFIG_PM */ /** * vic_init2 - common initialisation code @@ -156,39 +161,50 @@ static int __init vic_pm_init(void) return 0; } late_initcall(vic_pm_init); +#endif /* CONFIG_PM */ /** - * vic_pm_register - Register a VIC for later power management control + * vic_register() - Register a VIC. * @base: The base address of the VIC. * @irq: The base IRQ for the VIC. * @resume_sources: bitmask of interrupts allowed for resume sources. + * @node: The device tree node associated with the VIC. * * Register the VIC with the system device tree so that it can be notified * of suspend and resume requests and ensure that the correct actions are * taken to re-instate the settings on resume. + * + * This also configures the IRQ domain for the VIC. */ -static void __init vic_pm_register(void __iomem *base, unsigned int irq, u32 resume_sources) +static void __init vic_register(void __iomem *base, unsigned int irq, + u32 resume_sources, struct device_node *node) { struct vic_device *v; - if (vic_id >= ARRAY_SIZE(vic_devices)) + if (vic_id >= ARRAY_SIZE(vic_devices)) { printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__); - else { - v = &vic_devices[vic_id]; - v->base = base; - v->resume_sources = resume_sources; - v->irq = irq; - vic_id++; + return; } + + v = &vic_devices[vic_id]; + v->base = base; + v->resume_sources = resume_sources; + v->irq = irq; + vic_id++; + + v->domain.irq_base = irq; + v->domain.nr_irq = 32; +#ifdef CONFIG_OF_IRQ + v->domain.of_node = of_node_get(node); + v->domain.ops = &irq_domain_simple_ops; +#endif /* CONFIG_OF */ + irq_domain_add(&v->domain); } -#else -static inline void vic_pm_register(void __iomem *base, unsigned int irq, u32 arg1) { } -#endif /* CONFIG_PM */ static void vic_ack_irq(struct irq_data *d) { void __iomem *base = irq_data_get_irq_chip_data(d); - unsigned int irq = d->irq & 31; + unsigned int irq = d->hwirq; writel(1 << irq, base + VIC_INT_ENABLE_CLEAR); /* moreover, clear the soft-triggered, in case it was the reason */ writel(1 << irq, base + VIC_INT_SOFT_CLEAR); @@ -197,14 +213,14 @@ static void vic_ack_irq(struct irq_data *d) static void vic_mask_irq(struct irq_data *d) { void __iomem *base = irq_data_get_irq_chip_data(d); - unsigned int irq = d->irq & 31; + unsigned int irq = d->hwirq; writel(1 << irq, base + VIC_INT_ENABLE_CLEAR); } static void vic_unmask_irq(struct irq_data *d) { void __iomem *base = irq_data_get_irq_chip_data(d); - unsigned int irq = d->irq & 31; + unsigned int irq = d->hwirq; writel(1 << irq, base + VIC_INT_ENABLE); } @@ -226,7 +242,7 @@ static struct vic_device *vic_from_irq(unsigned int irq) static int vic_set_wake(struct irq_data *d, unsigned int on) { struct vic_device *v = vic_from_irq(d->irq); - unsigned int off = d->irq & 31; + unsigned int off = d->hwirq; u32 bit = 1 << off; if (!v) @@ -330,15 +346,9 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start, vic_set_irq_sources(base, irq_start, vic_sources); } -/** - * vic_init - initialise a vectored interrupt controller - * @base: iomem base address - * @irq_start: starting interrupt number, must be muliple of 32 - * @vic_sources: bitmask of interrupt sources to allow - * @resume_sources: bitmask of interrupt sources to allow for resume - */ -void __init vic_init(void __iomem *base, unsigned int irq_start, - u32 vic_sources, u32 resume_sources) +static void __init __vic_init(void __iomem *base, unsigned int irq_start, + u32 vic_sources, u32 resume_sources, + struct device_node *node) { unsigned int i; u32 cellid = 0; @@ -375,5 +385,46 @@ void __init vic_init(void __iomem *base, unsigned int irq_start, vic_set_irq_sources(base, irq_start, vic_sources); - vic_pm_register(base, irq_start, resume_sources); + vic_register(base, irq_start, resume_sources, node); +} + +/** + * vic_init() - initialise a vectored interrupt controller + * @base: iomem base address + * @irq_start: starting interrupt number, must be muliple of 32 + * @vic_sources: bitmask of interrupt sources to allow + * @resume_sources: bitmask of interrupt sources to allow for resume + */ +void __init vic_init(void __iomem *base, unsigned int irq_start, + u32 vic_sources, u32 resume_sources) +{ + __vic_init(base, irq_start, vic_sources, resume_sources, NULL); +} + +#ifdef CONFIG_OF +int __init vic_of_init(struct device_node *node, struct device_node *parent) +{ + void __iomem *regs; + int irq_base; + + if (WARN(parent, "non-root VICs are not supported")) + return -EINVAL; + + regs = of_iomap(node, 0); + if (WARN_ON(!regs)) + return -EIO; + + irq_base = irq_alloc_descs(-1, 0, 32, numa_node_id()); + if (WARN_ON(irq_base < 0)) + goto out_unmap; + + __vic_init(regs, irq_base, ~0, ~0, node); + + return 0; + + out_unmap: + iounmap(regs); + + return -EIO; } +#endif /* CONFIG OF */ diff --git a/arch/arm/include/asm/hardware/vic.h b/arch/arm/include/asm/hardware/vic.h index 5d72550a809..b348a545de2 100644 --- a/arch/arm/include/asm/hardware/vic.h +++ b/arch/arm/include/asm/hardware/vic.h @@ -41,7 +41,12 @@ #define VIC_PL192_VECT_ADDR 0xF00 #ifndef __ASSEMBLY__ +#include +#include + +struct device_node; void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources); -#endif +int vic_of_init(struct device_node *node, struct device_node *parent); +#endif /* __ASSEMBLY__ */ #endif -- cgit v1.2.3-70-g09d2 From 5786b6622112ab582c0bf05d6e722ed12a07642f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 17 Oct 2011 22:59:05 +0100 Subject: devicetree: Document Wolfson prefix Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index e8552782b44..2c1b2cb8539 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -37,4 +37,5 @@ simtek sirf SiRF Technology, Inc. stericsson ST-Ericsson ti Texas Instruments +wlf Wolfson Microelectronics xlnx Xilinx -- cgit v1.2.3-70-g09d2 From 186bcda6f6217dc4b5353c3474121bc1194847f6 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 22 Nov 2011 18:21:18 -0700 Subject: ASoC: Tegra DAS: Add device tree binding Signed-off-by: Stephen Warren Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/tegra20-das.txt | 12 ++++++++++++ sound/soc/tegra/tegra_das.c | 8 ++++++++ 2 files changed, 20 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/tegra20-das.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/sound/tegra20-das.txt b/Documentation/devicetree/bindings/sound/tegra20-das.txt new file mode 100644 index 00000000000..6de3a7ee4ef --- /dev/null +++ b/Documentation/devicetree/bindings/sound/tegra20-das.txt @@ -0,0 +1,12 @@ +NVIDIA Tegra 20 DAS (Digital Audio Switch) controller + +Required properties: +- compatible : "nvidia,tegra20-das" +- reg : Should contain DAS registers location and length + +Example: + +das@70000c00 { + compatible = "nvidia,tegra20-das"; + reg = <0x70000c00 0x80>; +}; diff --git a/sound/soc/tegra/tegra_das.c b/sound/soc/tegra/tegra_das.c index fa3a4426cbd..5b82b4e7923 100644 --- a/sound/soc/tegra/tegra_das.c +++ b/sound/soc/tegra/tegra_das.c @@ -225,11 +225,18 @@ static int __devexit tegra_das_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id tegra_das_of_match[] __devinitconst = { + { .compatible = "nvidia,tegra20-das", }, + {}, +}; + static struct platform_driver tegra_das_driver = { .probe = tegra_das_probe, .remove = __devexit_p(tegra_das_remove), .driver = { .name = DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = tegra_das_of_match, }, }; module_platform_driver(tegra_das_driver); @@ -238,3 +245,4 @@ MODULE_AUTHOR("Stephen Warren "); MODULE_DESCRIPTION("Tegra DAS driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" DRV_NAME); +MODULE_DEVICE_TABLE(of, tegra_das_of_match); -- cgit v1.2.3-70-g09d2 From 8f446e6fa1d506be2cb80f91c214f1705327c7f9 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Fri, 18 Nov 2011 16:47:17 +0530 Subject: regulator: helper routine to extract regulator_init_data The helper routine is meant to be used by the regulator drivers to extract the regulator_init_data structure from the data that is passed from device tree. 'consumer_supplies' which is part of regulator_init_data is not extracted as the regulator consumer mappings are passed through DT differently, implemented in subsequent patches. Similarly the regulator<-->parent/supply mapping is handled in subsequent patches. Also add documentation for regulator bindings to be used to pass regulator_init_data struct information from device tree. Some of the regulator properties which are linux and board specific, are left out since its not clear if they can be in someway embedded into the kernel or passed in from DT. They will be revisited later. Signed-off-by: Rajendra Nayak Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/regulator.txt | 54 +++++++++++++++ drivers/regulator/Makefile | 1 + drivers/regulator/of_regulator.c | 81 ++++++++++++++++++++++ include/linux/regulator/of_regulator.h | 20 ++++++ 4 files changed, 156 insertions(+) create mode 100644 Documentation/devicetree/bindings/regulator/regulator.txt create mode 100644 drivers/regulator/of_regulator.c create mode 100644 include/linux/regulator/of_regulator.h (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt new file mode 100644 index 00000000000..82bef20d4c4 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/regulator.txt @@ -0,0 +1,54 @@ +Voltage/Current Regulators + +Optional properties: +- regulator-name: A string used as a descriptive name for regulator outputs +- regulator-min-microvolt: smallest voltage consumers may set +- regulator-max-microvolt: largest voltage consumers may set +- regulator-microvolt-offset: Offset applied to voltages to compensate for voltage drops +- regulator-min-microamp: smallest current consumers may set +- regulator-max-microamp: largest current consumers may set +- regulator-always-on: boolean, regulator should never be disabled +- regulator-boot-on: bootloader/firmware enabled regulator +- -supply: phandle to the parent supply/regulator node + +Example: + + xyzreg: regulator@0 { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <2500000>; + regulator-always-on; + vin-supply = <&vin>; + }; + +Regulator Consumers: +Consumer nodes can reference one or more of its supplies/ +regulators using the below bindings. + +- -supply: phandle to the regulator node + +These are the same bindings that a regulator in the above +example used to reference its own supply, in which case +its just seen as a special case of a regulator being a +consumer itself. + +Example of a consumer device node (mmc) referencing two +regulators (twl-reg1 and twl-reg2), + + twl-reg1: regulator@0 { + ... + ... + ... + }; + + twl-reg2: regulator@1 { + ... + ... + ... + }; + + mmc: mmc@0x0 { + ... + ... + vmmc-supply = <&twl-reg1>; + vmmcaux-supply = <&twl-reg2>; + }; diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 93a6318f532..c75a5229cb2 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_REGULATOR) += core.o dummy.o +obj-$(CONFIG_OF) += of_regulator.o obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c new file mode 100644 index 00000000000..76673c784ab --- /dev/null +++ b/drivers/regulator/of_regulator.c @@ -0,0 +1,81 @@ +/* + * OF helpers for regulator framework + * + * Copyright (C) 2011 Texas Instruments, Inc. + * Rajendra Nayak + * + * 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. + */ + +#include +#include +#include + +static void of_get_regulation_constraints(struct device_node *np, + struct regulator_init_data **init_data) +{ + const __be32 *min_uV, *max_uV, *uV_offset; + const __be32 *min_uA, *max_uA; + struct regulation_constraints *constraints = &(*init_data)->constraints; + + constraints->name = of_get_property(np, "regulator-name", NULL); + + min_uV = of_get_property(np, "regulator-min-microvolt", NULL); + if (min_uV) + constraints->min_uV = be32_to_cpu(*min_uV); + max_uV = of_get_property(np, "regulator-max-microvolt", NULL); + if (max_uV) + constraints->max_uV = be32_to_cpu(*max_uV); + + /* Voltage change possible? */ + if (constraints->min_uV != constraints->max_uV) + constraints->valid_ops_mask |= REGULATOR_CHANGE_VOLTAGE; + + uV_offset = of_get_property(np, "regulator-microvolt-offset", NULL); + if (uV_offset) + constraints->uV_offset = be32_to_cpu(*uV_offset); + min_uA = of_get_property(np, "regulator-min-microamp", NULL); + if (min_uA) + constraints->min_uA = be32_to_cpu(*min_uA); + max_uA = of_get_property(np, "regulator-max-microamp", NULL); + if (max_uA) + constraints->max_uA = be32_to_cpu(*max_uA); + + /* Current change possible? */ + if (constraints->min_uA != constraints->max_uA) + constraints->valid_ops_mask |= REGULATOR_CHANGE_CURRENT; + + if (of_find_property(np, "regulator-boot-on", NULL)) + constraints->boot_on = true; + + if (of_find_property(np, "regulator-always-on", NULL)) + constraints->always_on = true; + else /* status change should be possible if not always on. */ + constraints->valid_ops_mask |= REGULATOR_CHANGE_STATUS; +} + +/** + * of_get_regulator_init_data - extract regulator_init_data structure info + * @dev: device requesting for regulator_init_data + * + * Populates regulator_init_data structure by extracting data from device + * tree node, returns a pointer to the populated struture or NULL if memory + * alloc fails. + */ +struct regulator_init_data *of_get_regulator_init_data(struct device *dev) +{ + struct regulator_init_data *init_data; + + if (!dev->of_node) + return NULL; + + init_data = devm_kzalloc(dev, sizeof(*init_data), GFP_KERNEL); + if (!init_data) + return NULL; /* Out of memory? */ + + of_get_regulation_constraints(dev->of_node, &init_data); + return init_data; +} diff --git a/include/linux/regulator/of_regulator.h b/include/linux/regulator/of_regulator.h new file mode 100644 index 00000000000..d83a98d3e3f --- /dev/null +++ b/include/linux/regulator/of_regulator.h @@ -0,0 +1,20 @@ +/* + * OpenFirmware regulator support routines + * + */ + +#ifndef __LINUX_OF_REG_H +#define __LINUX_OF_REG_H + +#if defined(CONFIG_OF) +extern struct regulator_init_data + *of_get_regulator_init_data(struct device *dev); +#else +static inline struct regulator_init_data + *of_get_regulator_init_data(struct device *dev) +{ + return NULL; +} +#endif /* CONFIG_OF */ + +#endif /* __LINUX_OF_REG_H */ -- cgit v1.2.3-70-g09d2 From cef49102c1d6b1e7adcb3f8b706757e0731e955c Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Fri, 18 Nov 2011 16:47:18 +0530 Subject: regulator: adapt fixed regulator driver to dt The fixed regulator driver uses of_get_fixed_voltage_config() to extract fixed_voltage_config structure contents from device tree. Also add documenation for additional bindings for fixed regulators that can be passed through dt. Signed-off-by: Rajendra Nayak Signed-off-by: Mark Brown --- .../bindings/regulator/fixed-regulator.txt | 29 ++++++++++ drivers/regulator/fixed.c | 65 ++++++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 Documentation/devicetree/bindings/regulator/fixed-regulator.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/regulator/fixed-regulator.txt b/Documentation/devicetree/bindings/regulator/fixed-regulator.txt new file mode 100644 index 00000000000..9cf57fd042d --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/fixed-regulator.txt @@ -0,0 +1,29 @@ +Fixed Voltage regulators + +Required properties: +- compatible: Must be "regulator-fixed"; + +Optional properties: +- gpio: gpio to use for enable control +- startup-delay-us: startup time in microseconds +- enable-active-high: Polarity of GPIO is Active high +If this property is missing, the default assumed is Active low. + +Any property defined as part of the core regulator +binding, defined in regulator.txt, can also be used. +However a fixed voltage regulator is expected to have the +regulator-min-microvolt and regulator-max-microvolt +to be the same. + +Example: + + abc: fixedregulator@0 { + compatible = "regulator-fixed"; + regulator-name = "fixed-supply"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + gpio = <&gpio1 16 0>; + startup-delay-us = <70000>; + enable-active-high; + regulator-boot-on + }; diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index 21ecf212a52..0650856b93c 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -27,6 +27,10 @@ #include #include #include +#include +#include +#include +#include struct fixed_voltage_data { struct regulator_desc desc; @@ -38,6 +42,53 @@ struct fixed_voltage_data { bool is_enabled; }; + +/** + * of_get_fixed_voltage_config - extract fixed_voltage_config structure info + * @dev: device requesting for fixed_voltage_config + * + * Populates fixed_voltage_config structure by extracting data from device + * tree node, returns a pointer to the populated structure of NULL if memory + * alloc fails. + */ +struct fixed_voltage_config *of_get_fixed_voltage_config(struct device *dev) +{ + struct fixed_voltage_config *config; + struct device_node *np = dev->of_node; + const __be32 *delay; + struct regulator_init_data *init_data; + + config = devm_kzalloc(dev, sizeof(struct fixed_voltage_config), + GFP_KERNEL); + if (!config) + return NULL; + + config->init_data = of_get_regulator_init_data(dev); + init_data = config->init_data; + + config->supply_name = init_data->constraints.name; + if (init_data->constraints.min_uV == init_data->constraints.max_uV) { + config->microvolts = init_data->constraints.min_uV; + } else { + dev_err(dev, + "Fixed regulator specified with variable voltages\n"); + return NULL; + } + + if (init_data->constraints.boot_on) + config->enabled_at_boot = true; + + config->gpio = of_get_named_gpio(np, "gpio", 0); + delay = of_get_property(np, "startup-delay-us", NULL); + if (delay) + config->startup_delay = be32_to_cpu(*delay); + + if (of_find_property(np, "enable-active-high", NULL)) + config->enable_high = true; + + return config; +} + static int fixed_voltage_is_enabled(struct regulator_dev *dev) { struct fixed_voltage_data *data = rdev_get_drvdata(dev); @@ -109,6 +160,9 @@ static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev) struct fixed_voltage_data *drvdata; int ret; + if (pdev->dev.of_node) + config = of_get_fixed_voltage_config(&pdev->dev); + drvdata = kzalloc(sizeof(struct fixed_voltage_data), GFP_KERNEL); if (drvdata == NULL) { dev_err(&pdev->dev, "Failed to allocate device data\n"); @@ -217,12 +271,23 @@ static int __devexit reg_fixed_voltage_remove(struct platform_device *pdev) return 0; } +#if defined(CONFIG_OF) +static const struct of_device_id fixed_of_match[] __devinitconst = { + { .compatible = "regulator-fixed", }, + {}, +}; +MODULE_DEVICE_TABLE(of, fixed_of_match); +#else +#define fixed_of_match NULL +#endif + static struct platform_driver regulator_fixed_voltage_driver = { .probe = reg_fixed_voltage_probe, .remove = __devexit_p(reg_fixed_voltage_remove), .driver = { .name = "reg-fixed-voltage", .owner = THIS_MODULE, + .of_match_table = fixed_of_match, }, }; -- cgit v1.2.3-70-g09d2 From 91610d830dbc90ebf01fd255873d8277bf72d040 Mon Sep 17 00:00:00 2001 From: Liu Gang Date: Sat, 12 Nov 2011 20:02:32 +0800 Subject: powerpc/fsl: Document rapidio node binding-information This document is created for powerpc rapidio and rmu nodes in dts file. These nodes can support two rapidio ports and message units. In addition, It explicates the properties and gives examples about rapidio and rmu nodes. Signed-off-by: Li Yang Signed-off-by: Jin Qing Signed-off-by: Liu Gang Acked-by: Alexandre Bounine Signed-off-by: Kumar Gala --- .../devicetree/bindings/powerpc/fsl/srio-rmu.txt | 163 +++++++++++++++++++++ .../devicetree/bindings/powerpc/fsl/srio.txt | 103 +++++++++++++ 2 files changed, 266 insertions(+) create mode 100644 Documentation/devicetree/bindings/powerpc/fsl/srio-rmu.txt create mode 100644 Documentation/devicetree/bindings/powerpc/fsl/srio.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/powerpc/fsl/srio-rmu.txt b/Documentation/devicetree/bindings/powerpc/fsl/srio-rmu.txt new file mode 100644 index 00000000000..b9a8a2bcfae --- /dev/null +++ b/Documentation/devicetree/bindings/powerpc/fsl/srio-rmu.txt @@ -0,0 +1,163 @@ +Message unit node: + +For SRIO controllers that implement the message unit as part of the controller +this node is required. For devices with RMAN this node should NOT exist. The +node is composed of three types of sub-nodes ("fsl-srio-msg-unit", +"fsl-srio-dbell-unit" and "fsl-srio-port-write-unit"). + +See srio.txt for more details about generic SRIO controller details. + + - compatible + Usage: required + Value type: + Definition: Must include "fsl,srio-rmu-vX.Y", "fsl,srio-rmu". + + The version X.Y should match the general SRIO controller's IP Block + revision register's Major(X) and Minor (Y) value. + + - reg + Usage: required + Value type: + Definition: A standard property. Specifies the physical address and + length of the SRIO configuration registers for message units + and doorbell units. + + - fsl,liodn + Usage: optional-but-recommended (for devices with PAMU) + Value type: + Definition: The logical I/O device number for the PAMU (IOMMU) to be + correctly configured for SRIO accesses. The property should + not exist on devices that do not support PAMU. + + The LIODN value is associated with all RMU transactions + (msg-unit, doorbell, port-write). + +Sub-Nodes for RMU: The RMU node is composed of multiple sub-nodes that +correspond to the actual sub-controllers in the RMU. The manual for a given +SoC will detail which and how many of these sub-controllers are implemented. + +Message Unit: + + - compatible + Usage: required + Value type: + Definition: Must include "fsl,srio-msg-unit-vX.Y", "fsl,srio-msg-unit". + + The version X.Y should match the general SRIO controller's IP Block + revision register's Major(X) and Minor (Y) value. + + - reg + Usage: required + Value type: + Definition: A standard property. Specifies the physical address and + length of the SRIO configuration registers for message units + and doorbell units. + + - interrupts + Usage: required + Value type: + Definition: Specifies the interrupts generated by this device. The + value of the interrupts property consists of one interrupt + specifier. The format of the specifier is defined by the + binding document describing the node's interrupt parent. + + A pair of IRQs are specified in this property. The first + element is associated with the transmit (TX) interrupt and the + second element is associated with the receive (RX) interrupt. + +Doorbell Unit: + + - compatible + Usage: required + Value type: + Definition: Must include: + "fsl,srio-dbell-unit-vX.Y", "fsl,srio-dbell-unit" + + The version X.Y should match the general SRIO controller's IP Block + revision register's Major(X) and Minor (Y) value. + + - reg + Usage: required + Value type: + Definition: A standard property. Specifies the physical address and + length of the SRIO configuration registers for message units + and doorbell units. + + - interrupts + Usage: required + Value type: + Definition: Specifies the interrupts generated by this device. The + value of the interrupts property consists of one interrupt + specifier. The format of the specifier is defined by the + binding document describing the node's interrupt parent. + + A pair of IRQs are specified in this property. The first + element is associated with the transmit (TX) interrupt and the + second element is associated with the receive (RX) interrupt. + +Port-Write Unit: + + - compatible + Usage: required + Value type: + Definition: Must include: + "fsl,srio-port-write-unit-vX.Y", "fsl,srio-port-write-unit" + + The version X.Y should match the general SRIO controller's IP Block + revision register's Major(X) and Minor (Y) value. + + - reg + Usage: required + Value type: + Definition: A standard property. Specifies the physical address and + length of the SRIO configuration registers for message units + and doorbell units. + + - interrupts + Usage: required + Value type: + Definition: Specifies the interrupts generated by this device. The + value of the interrupts property consists of one interrupt + specifier. The format of the specifier is defined by the + binding document describing the node's interrupt parent. + + A single IRQ that handles port-write conditions is + specified by this property. (Typically shared with error). + + Note: All other standard properties (see the ePAPR) are allowed + but are optional. + +Example: + rmu: rmu@d3000 { + compatible = "fsl,srio-rmu"; + reg = <0xd3000 0x400>; + ranges = <0x0 0xd3000 0x400>; + fsl,liodn = <0xc8>; + + message-unit@0 { + compatible = "fsl,srio-msg-unit"; + reg = <0x0 0x100>; + interrupts = < + 60 2 0 0 /* msg1_tx_irq */ + 61 2 0 0>;/* msg1_rx_irq */ + }; + message-unit@100 { + compatible = "fsl,srio-msg-unit"; + reg = <0x100 0x100>; + interrupts = < + 62 2 0 0 /* msg2_tx_irq */ + 63 2 0 0>;/* msg2_rx_irq */ + }; + doorbell-unit@400 { + compatible = "fsl,srio-dbell-unit"; + reg = <0x400 0x80>; + interrupts = < + 56 2 0 0 /* bell_outb_irq */ + 57 2 0 0>;/* bell_inb_irq */ + }; + port-write-unit@4e0 { + compatible = "fsl,srio-port-write-unit"; + reg = <0x4e0 0x20>; + interrupts = <16 2 1 11>; + }; + }; diff --git a/Documentation/devicetree/bindings/powerpc/fsl/srio.txt b/Documentation/devicetree/bindings/powerpc/fsl/srio.txt new file mode 100644 index 00000000000..b039bcbee13 --- /dev/null +++ b/Documentation/devicetree/bindings/powerpc/fsl/srio.txt @@ -0,0 +1,103 @@ +* Freescale Serial RapidIO (SRIO) Controller + +RapidIO port node: +Properties: + - compatible + Usage: required + Value type: + Definition: Must include "fsl,srio" for IP blocks with IP Block + Revision Register (SRIO IPBRR1) Major ID equal to 0x01c0. + + Optionally, a compatiable string of "fsl,srio-vX.Y" where X is Major + version in IP Block Revision Register and Y is Minor version. If this + compatiable is provided it should be ordered before "fsl,srio". + + - reg + Usage: required + Value type: + Definition: A standard property. Specifies the physical address and + length of the SRIO configuration registers. The size should + be set to 0x11000. + + - interrupts + Usage: required + Value type: + Definition: Specifies the interrupts generated by this device. The + value of the interrupts property consists of one interrupt + specifier. The format of the specifier is defined by the + binding document describing the node's interrupt parent. + + A single IRQ that handles error conditions is specified by this + property. (Typically shared with port-write). + + - fsl,srio-rmu-handle: + Usage: required if rmu node is defined + Value type: + Definition: A single value that points to the RMU. + (See srio-rmu.txt for more details on RMU node binding) + +Port Child Nodes: There should a port child node for each port that exists in +the controller. The ports are numbered starting at one (1) and should have +the following properties: + + - cell-index + Usage: required + Value type: + Definition: A standard property. Matches the port id. + + - ranges + Usage: required if local access windows preset + Value type: + Definition: A standard property. Utilized to describe the memory mapped + IO space utilized by the controller. This corresponds to the + setting of the local access windows that are targeted to this + SRIO port. + + - fsl,liodn + Usage: optional-but-recommended (for devices with PAMU) + Value type: + Definition: The logical I/O device number for the PAMU (IOMMU) to be + correctly configured for SRIO accesses. The property should + not exist on devices that do not support PAMU. + + For HW (ie, the P4080) that only supports a LIODN for both + memory and maintenance transactions then a single LIODN is + represented in the property for both transactions. + + For HW (ie, the P304x/P5020, etc) that supports an LIODN for + memory transactions and a unique LIODN for maintenance + transactions then a pair of LIODNs are represented in the + property. Within the pair, the first element represents the + LIODN associated with memory transactions and the second element + represents the LIODN associated with maintenance transactions + for the port. + +Note: All other standard properties (see ePAPR) are allowed but are optional. + +Example: + + rapidio: rapidio@ffe0c0000 { + #address-cells = <2>; + #size-cells = <2>; + reg = <0xf 0xfe0c0000 0 0x11000>; + compatible = "fsl,srio"; + interrupts = <16 2 1 11>; /* err_irq */ + fsl,srio-rmu-handle = <&rmu>; + ranges; + + port1 { + cell-index = <1>; + #address-cells = <2>; + #size-cells = <2>; + fsl,liodn = <34>; + ranges = <0 0 0xc 0x20000000 0 0x10000000>; + }; + + port2 { + cell-index = <2>; + #address-cells = <2>; + #size-cells = <2>; + fsl,liodn = <48>; + ranges = <0 0 0xc 0x30000000 0 0x10000000>; + }; + }; -- cgit v1.2.3-70-g09d2 From 6c75ea1e582d12120072cae742a0d63ea8ac8c65 Mon Sep 17 00:00:00 2001 From: Rhyland Klein Date: Wed, 14 Sep 2011 13:19:07 -0700 Subject: bq20z75: Devicetree init support Adding support to generate platform data when kernel is configured through device tree. Also adding the binding for the TI bq20z75 fuel gadge and the bq20z75 driver. Signed-off-by: Rhyland Klein Acked-by: Grant Likely Signed-off-by: Anton Vorontsov --- .../bindings/power_supply/ti_bq20z75.txt | 23 +++++++ drivers/power/bq20z75.c | 77 ++++++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 Documentation/devicetree/bindings/power_supply/ti_bq20z75.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/power_supply/ti_bq20z75.txt b/Documentation/devicetree/bindings/power_supply/ti_bq20z75.txt new file mode 100644 index 00000000000..7571294f411 --- /dev/null +++ b/Documentation/devicetree/bindings/power_supply/ti_bq20z75.txt @@ -0,0 +1,23 @@ +TI bq20z75 +~~~~~~~~~~ + +Required properties : + - compatible : "ti,bq20z75" + +Optional properties : + - ti,i2c-retry-count : The number of times to retry i2c transactions on i2c + IO failure. + - ti,poll-retry-count : The number of times to try looking for new status + after an external change notification. + - ti,battery-detect-gpios : The gpio which signals battery detection and + a flag specifying its polarity. + +Example: + + bq20z75@b { + compatible = "ti,bq20z75"; + reg = < 0xb >; + ti,i2c-retry-count = <2>; + ti,poll-retry-count = <10>; + ti,battery-detect-gpios = <&gpio-controller 122 1>; + } diff --git a/drivers/power/bq20z75.c b/drivers/power/bq20z75.c index 9c5e5beda3a..ce95ff79101 100644 --- a/drivers/power/bq20z75.c +++ b/drivers/power/bq20z75.c @@ -613,6 +613,80 @@ static void bq20z75_delayed_work(struct work_struct *work) } } +#if defined(CONFIG_OF) + +#include +#include + +static const struct of_device_id bq20z75_dt_ids[] = { + { .compatible = "ti,bq20z75" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, bq20z75_dt_ids); + +static struct bq20z75_platform_data *bq20z75_of_populate_pdata( + struct i2c_client *client) +{ + struct device_node *of_node = client->dev.of_node; + struct bq20z75_platform_data *pdata = client->dev.platform_data; + enum of_gpio_flags gpio_flags; + int rc; + u32 prop; + + /* verify this driver matches this device */ + if (!of_node) + return NULL; + + /* if platform data is set, honor it */ + if (pdata) + return pdata; + + /* first make sure at least one property is set, otherwise + * it won't change behavior from running without pdata. + */ + if (!of_get_property(of_node, "ti,i2c-retry-count", NULL) && + !of_get_property(of_node, "ti,poll-retry-count", NULL) && + !of_get_property(of_node, "ti,battery-detect-gpios", NULL)) + goto of_out; + + pdata = devm_kzalloc(&client->dev, sizeof(struct bq20z75_platform_data), + GFP_KERNEL); + if (!pdata) + goto of_out; + + rc = of_property_read_u32(of_node, "ti,i2c-retry-count", &prop); + if (!rc) + pdata->i2c_retry_count = prop; + + rc = of_property_read_u32(of_node, "ti,poll-retry-count", &prop); + if (!rc) + pdata->poll_retry_count = prop; + + if (!of_get_property(of_node, "ti,battery-detect-gpios", NULL)) { + pdata->battery_detect = -1; + goto of_out; + } + + pdata->battery_detect = of_get_named_gpio_flags(of_node, + "ti,battery-detect-gpios", 0, &gpio_flags); + + if (gpio_flags & OF_GPIO_ACTIVE_LOW) + pdata->battery_detect_present = 0; + else + pdata->battery_detect_present = 1; + +of_out: + return pdata; +} +#else +#define bq20z75_dt_ids NULL +static struct bq20z75_platform_data *bq20z75_of_populate_pdata( + struct i2c_client *client) +{ + return client->dev.platform_data; +} +#endif + static int __devinit bq20z75_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -642,6 +716,8 @@ static int __devinit bq20z75_probe(struct i2c_client *client, bq20z75_device->power_supply.external_power_changed = bq20z75_external_power_changed; + pdata = bq20z75_of_populate_pdata(client); + if (pdata) { bq20z75_device->gpio_detect = gpio_is_valid(pdata->battery_detect); @@ -775,6 +851,7 @@ static struct i2c_driver bq20z75_battery_driver = { .id_table = bq20z75_id, .driver = { .name = "bq20z75-battery", + .of_match_table = bq20z75_dt_ids, }, }; -- cgit v1.2.3-70-g09d2 From 7990b0d7ec449b10da383bab191eb487185aadce Mon Sep 17 00:00:00 2001 From: Marc Dietrich Date: Tue, 1 Nov 2011 21:37:04 +0100 Subject: staging: nvec: add device tree support This adds device tree support to the nvec driver. By using this method it is no longer necessary to specify platform data through a board file. Signed-off-by: Marc Dietrich Acked-by: Stephen Warren Cc: Julian Andres Klode Cc: Grant Likely Acked-by: Olof Johansson Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/nvec/nvec_nvidia.txt | 9 +++++++ drivers/staging/nvec/nvec.c | 30 ++++++++++++++++++++-- 2 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 Documentation/devicetree/bindings/nvec/nvec_nvidia.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/nvec/nvec_nvidia.txt b/Documentation/devicetree/bindings/nvec/nvec_nvidia.txt new file mode 100644 index 00000000000..5aeee53ff9f --- /dev/null +++ b/Documentation/devicetree/bindings/nvec/nvec_nvidia.txt @@ -0,0 +1,9 @@ +NVIDIA compliant embedded controller + +Required properties: +- compatible : should be "nvidia,nvec". +- reg : the iomem of the i2c slave controller +- interrupts : the interrupt line of the i2c slave controller +- clock-frequency : the frequency of the i2c bus +- gpios : the gpio used for ec request +- slave-addr: the i2c address of the slave controller diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c index e06b867d1e0..fafdfa25e13 100644 --- a/drivers/staging/nvec/nvec.c +++ b/drivers/staging/nvec/nvec.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include #include #include @@ -727,8 +729,24 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, nvec); nvec->dev = &pdev->dev; - nvec->gpio = pdata->gpio; - nvec->i2c_addr = pdata->i2c_addr; + + if (pdata) { + nvec->gpio = pdata->gpio; + nvec->i2c_addr = pdata->i2c_addr; + } else if (nvec->dev->of_node) { + nvec->gpio = of_get_named_gpio(nvec->dev->of_node, "request-gpios", 0); + if (nvec->gpio < 0) { + dev_err(&pdev->dev, "no gpio specified"); + goto failed; + } + if (of_property_read_u32(nvec->dev->of_node, "slave-addr", &nvec->i2c_addr)) { + dev_err(&pdev->dev, "no i2c address specified"); + goto failed; + } + } else { + dev_err(&pdev->dev, "no platform data\n"); + goto failed; + } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { @@ -893,6 +911,13 @@ static int tegra_nvec_resume(struct platform_device *pdev) #define tegra_nvec_resume NULL #endif +/* Match table for of_platform binding */ +static const struct of_device_id nvidia_nvec_of_match[] __devinitconst = { + { .compatible = "nvidia,nvec", }, + {}, +}; +MODULE_DEVICE_TABLE(of, nvidia_nvec_of_match); + static struct platform_driver nvec_device_driver = { .probe = tegra_nvec_probe, .remove = __devexit_p(tegra_nvec_remove), @@ -901,6 +926,7 @@ static struct platform_driver nvec_device_driver = { .driver = { .name = "nvec", .owner = THIS_MODULE, + .of_match_table = nvidia_nvec_of_match, } }; -- cgit v1.2.3-70-g09d2 From 7728c14a785f934ffccc4f45ecd9646fc07ea679 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Mon, 28 Nov 2011 21:37:16 +0800 Subject: regulator: fix label names used in device tree bindings Device tree compiler does not recognize '-' in label name. Instead, '_' works fine. Signed-off-by: Shawn Guo Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/regulator/regulator.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt index 82bef20d4c4..5b7a408acda 100644 --- a/Documentation/devicetree/bindings/regulator/regulator.txt +++ b/Documentation/devicetree/bindings/regulator/regulator.txt @@ -32,15 +32,15 @@ its just seen as a special case of a regulator being a consumer itself. Example of a consumer device node (mmc) referencing two -regulators (twl-reg1 and twl-reg2), +regulators (twl_reg1 and twl_reg2), - twl-reg1: regulator@0 { + twl_reg1: regulator@0 { ... ... ... }; - twl-reg2: regulator@1 { + twl_reg2: regulator@1 { ... ... ... @@ -49,6 +49,6 @@ regulators (twl-reg1 and twl-reg2), mmc: mmc@0x0 { ... ... - vmmc-supply = <&twl-reg1>; - vmmcaux-supply = <&twl-reg2>; + vmmc-supply = <&twl_reg1>; + vmmcaux-supply = <&twl_reg2>; }; -- cgit v1.2.3-70-g09d2 From 85c10f28286148ee5cdba1d22c81936ff160596e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 22 Nov 2011 17:18:19 +0000 Subject: net: add calxeda xgmac ethernet driver Add support for the XGMAC 10Gb ethernet device in the Calxeda Highbank SOC. Signed-off-by: Rob Herring Signed-off-by: David S. Miller --- .../devicetree/bindings/net/calxeda-xgmac.txt | 15 + drivers/net/ethernet/Kconfig | 1 + drivers/net/ethernet/Makefile | 1 + drivers/net/ethernet/calxeda/Kconfig | 7 + drivers/net/ethernet/calxeda/Makefile | 1 + drivers/net/ethernet/calxeda/xgmac.c | 1928 ++++++++++++++++++++ 6 files changed, 1953 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/calxeda-xgmac.txt create mode 100644 drivers/net/ethernet/calxeda/Kconfig create mode 100644 drivers/net/ethernet/calxeda/Makefile create mode 100644 drivers/net/ethernet/calxeda/xgmac.c (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/net/calxeda-xgmac.txt b/Documentation/devicetree/bindings/net/calxeda-xgmac.txt new file mode 100644 index 00000000000..411727a3f82 --- /dev/null +++ b/Documentation/devicetree/bindings/net/calxeda-xgmac.txt @@ -0,0 +1,15 @@ +* Calxeda Highbank 10Gb XGMAC Ethernet + +Required properties: +- compatible : Should be "calxeda,hb-xgmac" +- reg : Address and length of the register set for the device +- interrupts : Should contain 3 xgmac interrupts. The 1st is main interrupt. + The 2nd is pwr mgt interrupt. The 3rd is low power state interrupt. + +Example: + +ethernet@fff50000 { + compatible = "calxeda,hb-xgmac"; + reg = <0xfff50000 0x1000>; + interrupts = <0 77 4 0 78 4 0 79 4>; +}; diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig index 597f4d45c63..3474a61d470 100644 --- a/drivers/net/ethernet/Kconfig +++ b/drivers/net/ethernet/Kconfig @@ -28,6 +28,7 @@ source "drivers/net/ethernet/cadence/Kconfig" source "drivers/net/ethernet/adi/Kconfig" source "drivers/net/ethernet/broadcom/Kconfig" source "drivers/net/ethernet/brocade/Kconfig" +source "drivers/net/ethernet/calxeda/Kconfig" source "drivers/net/ethernet/chelsio/Kconfig" source "drivers/net/ethernet/cirrus/Kconfig" source "drivers/net/ethernet/cisco/Kconfig" diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile index be5dde04026..cd6d69a6a7d 100644 --- a/drivers/net/ethernet/Makefile +++ b/drivers/net/ethernet/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_NET_ATMEL) += cadence/ obj-$(CONFIG_NET_BFIN) += adi/ obj-$(CONFIG_NET_VENDOR_BROADCOM) += broadcom/ obj-$(CONFIG_NET_VENDOR_BROCADE) += brocade/ +obj-$(CONFIG_NET_CALXEDA_XGMAC) += calxeda/ obj-$(CONFIG_NET_VENDOR_CHELSIO) += chelsio/ obj-$(CONFIG_NET_VENDOR_CIRRUS) += cirrus/ obj-$(CONFIG_NET_VENDOR_CISCO) += cisco/ diff --git a/drivers/net/ethernet/calxeda/Kconfig b/drivers/net/ethernet/calxeda/Kconfig new file mode 100644 index 00000000000..a52e725c861 --- /dev/null +++ b/drivers/net/ethernet/calxeda/Kconfig @@ -0,0 +1,7 @@ +config NET_CALXEDA_XGMAC + tristate "Calxeda 1G/10G XGMAC Ethernet driver" + + select CRC32 + help + This is the driver for the XGMAC Ethernet IP block found on Calxeda + Highbank platforms. diff --git a/drivers/net/ethernet/calxeda/Makefile b/drivers/net/ethernet/calxeda/Makefile new file mode 100644 index 00000000000..f0ef08067f9 --- /dev/null +++ b/drivers/net/ethernet/calxeda/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_NET_CALXEDA_XGMAC) += xgmac.o diff --git a/drivers/net/ethernet/calxeda/xgmac.c b/drivers/net/ethernet/calxeda/xgmac.c new file mode 100644 index 00000000000..107c1b01080 --- /dev/null +++ b/drivers/net/ethernet/calxeda/xgmac.c @@ -0,0 +1,1928 @@ +/* + * Copyright 2010-2011 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 +#include +#include +#include +#include + +/* XGMAC Register definitions */ +#define XGMAC_CONTROL 0x00000000 /* MAC Configuration */ +#define XGMAC_FRAME_FILTER 0x00000004 /* MAC Frame Filter */ +#define XGMAC_FLOW_CTRL 0x00000018 /* MAC Flow Control */ +#define XGMAC_VLAN_TAG 0x0000001C /* VLAN Tags */ +#define XGMAC_VERSION 0x00000020 /* Version */ +#define XGMAC_VLAN_INCL 0x00000024 /* VLAN tag for tx frames */ +#define XGMAC_LPI_CTRL 0x00000028 /* LPI Control and Status */ +#define XGMAC_LPI_TIMER 0x0000002C /* LPI Timers Control */ +#define XGMAC_TX_PACE 0x00000030 /* Transmit Pace and Stretch */ +#define XGMAC_VLAN_HASH 0x00000034 /* VLAN Hash Table */ +#define XGMAC_DEBUG 0x00000038 /* Debug */ +#define XGMAC_INT_STAT 0x0000003C /* Interrupt and Control */ +#define XGMAC_ADDR_HIGH(reg) (0x00000040 + ((reg) * 8)) +#define XGMAC_ADDR_LOW(reg) (0x00000044 + ((reg) * 8)) +#define XGMAC_HASH(n) (0x00000300 + (n) * 4) /* HASH table regs */ +#define XGMAC_NUM_HASH 16 +#define XGMAC_OMR 0x00000400 +#define XGMAC_REMOTE_WAKE 0x00000700 /* Remote Wake-Up Frm Filter */ +#define XGMAC_PMT 0x00000704 /* PMT Control and Status */ +#define XGMAC_MMC_CTRL 0x00000800 /* XGMAC MMC Control */ +#define XGMAC_MMC_INTR_RX 0x00000804 /* Recieve Interrupt */ +#define XGMAC_MMC_INTR_TX 0x00000808 /* Transmit Interrupt */ +#define XGMAC_MMC_INTR_MASK_RX 0x0000080c /* Recieve Interrupt Mask */ +#define XGMAC_MMC_INTR_MASK_TX 0x00000810 /* Transmit Interrupt Mask */ + +/* Hardware TX Statistics Counters */ +#define XGMAC_MMC_TXOCTET_GB_LO 0x00000814 +#define XGMAC_MMC_TXOCTET_GB_HI 0x00000818 +#define XGMAC_MMC_TXFRAME_GB_LO 0x0000081C +#define XGMAC_MMC_TXFRAME_GB_HI 0x00000820 +#define XGMAC_MMC_TXBCFRAME_G 0x00000824 +#define XGMAC_MMC_TXMCFRAME_G 0x0000082C +#define XGMAC_MMC_TXUCFRAME_GB 0x00000864 +#define XGMAC_MMC_TXMCFRAME_GB 0x0000086C +#define XGMAC_MMC_TXBCFRAME_GB 0x00000874 +#define XGMAC_MMC_TXUNDERFLOW 0x0000087C +#define XGMAC_MMC_TXOCTET_G_LO 0x00000884 +#define XGMAC_MMC_TXOCTET_G_HI 0x00000888 +#define XGMAC_MMC_TXFRAME_G_LO 0x0000088C +#define XGMAC_MMC_TXFRAME_G_HI 0x00000890 +#define XGMAC_MMC_TXPAUSEFRAME 0x00000894 +#define XGMAC_MMC_TXVLANFRAME 0x0000089C + +/* Hardware RX Statistics Counters */ +#define XGMAC_MMC_RXFRAME_GB_LO 0x00000900 +#define XGMAC_MMC_RXFRAME_GB_HI 0x00000904 +#define XGMAC_MMC_RXOCTET_GB_LO 0x00000908 +#define XGMAC_MMC_RXOCTET_GB_HI 0x0000090C +#define XGMAC_MMC_RXOCTET_G_LO 0x00000910 +#define XGMAC_MMC_RXOCTET_G_HI 0x00000914 +#define XGMAC_MMC_RXBCFRAME_G 0x00000918 +#define XGMAC_MMC_RXMCFRAME_G 0x00000920 +#define XGMAC_MMC_RXCRCERR 0x00000928 +#define XGMAC_MMC_RXRUNT 0x00000930 +#define XGMAC_MMC_RXJABBER 0x00000934 +#define XGMAC_MMC_RXUCFRAME_G 0x00000970 +#define XGMAC_MMC_RXLENGTHERR 0x00000978 +#define XGMAC_MMC_RXPAUSEFRAME 0x00000988 +#define XGMAC_MMC_RXOVERFLOW 0x00000990 +#define XGMAC_MMC_RXVLANFRAME 0x00000998 +#define XGMAC_MMC_RXWATCHDOG 0x000009a0 + +/* DMA Control and Status Registers */ +#define XGMAC_DMA_BUS_MODE 0x00000f00 /* Bus Mode */ +#define XGMAC_DMA_TX_POLL 0x00000f04 /* Transmit Poll Demand */ +#define XGMAC_DMA_RX_POLL 0x00000f08 /* Received Poll Demand */ +#define XGMAC_DMA_RX_BASE_ADDR 0x00000f0c /* Receive List Base */ +#define XGMAC_DMA_TX_BASE_ADDR 0x00000f10 /* Transmit List Base */ +#define XGMAC_DMA_STATUS 0x00000f14 /* Status Register */ +#define XGMAC_DMA_CONTROL 0x00000f18 /* Ctrl (Operational Mode) */ +#define XGMAC_DMA_INTR_ENA 0x00000f1c /* Interrupt Enable */ +#define XGMAC_DMA_MISS_FRAME_CTR 0x00000f20 /* Missed Frame Counter */ +#define XGMAC_DMA_RI_WDOG_TIMER 0x00000f24 /* RX Intr Watchdog Timer */ +#define XGMAC_DMA_AXI_BUS 0x00000f28 /* AXI Bus Mode */ +#define XGMAC_DMA_AXI_STATUS 0x00000f2C /* AXI Status */ +#define XGMAC_DMA_HW_FEATURE 0x00000f58 /* Enabled Hardware Features */ + +#define XGMAC_ADDR_AE 0x80000000 +#define XGMAC_MAX_FILTER_ADDR 31 + +/* PMT Control and Status */ +#define XGMAC_PMT_POINTER_RESET 0x80000000 +#define XGMAC_PMT_GLBL_UNICAST 0x00000200 +#define XGMAC_PMT_WAKEUP_RX_FRM 0x00000040 +#define XGMAC_PMT_MAGIC_PKT 0x00000020 +#define XGMAC_PMT_WAKEUP_FRM_EN 0x00000004 +#define XGMAC_PMT_MAGIC_PKT_EN 0x00000002 +#define XGMAC_PMT_POWERDOWN 0x00000001 + +#define XGMAC_CONTROL_SPD 0x40000000 /* Speed control */ +#define XGMAC_CONTROL_SPD_MASK 0x60000000 +#define XGMAC_CONTROL_SPD_1G 0x60000000 +#define XGMAC_CONTROL_SPD_2_5G 0x40000000 +#define XGMAC_CONTROL_SPD_10G 0x00000000 +#define XGMAC_CONTROL_SARC 0x10000000 /* Source Addr Insert/Replace */ +#define XGMAC_CONTROL_SARK_MASK 0x18000000 +#define XGMAC_CONTROL_CAR 0x04000000 /* CRC Addition/Replacement */ +#define XGMAC_CONTROL_CAR_MASK 0x06000000 +#define XGMAC_CONTROL_DP 0x01000000 /* Disable Padding */ +#define XGMAC_CONTROL_WD 0x00800000 /* Disable Watchdog on rx */ +#define XGMAC_CONTROL_JD 0x00400000 /* Jabber disable */ +#define XGMAC_CONTROL_JE 0x00100000 /* Jumbo frame */ +#define XGMAC_CONTROL_LM 0x00001000 /* Loop-back mode */ +#define XGMAC_CONTROL_IPC 0x00000400 /* Checksum Offload */ +#define XGMAC_CONTROL_ACS 0x00000080 /* Automatic Pad/FCS Strip */ +#define XGMAC_CONTROL_DDIC 0x00000010 /* Disable Deficit Idle Count */ +#define XGMAC_CONTROL_TE 0x00000008 /* Transmitter Enable */ +#define XGMAC_CONTROL_RE 0x00000004 /* Receiver Enable */ + +/* XGMAC Frame Filter defines */ +#define XGMAC_FRAME_FILTER_PR 0x00000001 /* Promiscuous Mode */ +#define XGMAC_FRAME_FILTER_HUC 0x00000002 /* Hash Unicast */ +#define XGMAC_FRAME_FILTER_HMC 0x00000004 /* Hash Multicast */ +#define XGMAC_FRAME_FILTER_DAIF 0x00000008 /* DA Inverse Filtering */ +#define XGMAC_FRAME_FILTER_PM 0x00000010 /* Pass all multicast */ +#define XGMAC_FRAME_FILTER_DBF 0x00000020 /* Disable Broadcast frames */ +#define XGMAC_FRAME_FILTER_SAIF 0x00000100 /* Inverse Filtering */ +#define XGMAC_FRAME_FILTER_SAF 0x00000200 /* Source Address Filter */ +#define XGMAC_FRAME_FILTER_HPF 0x00000400 /* Hash or perfect Filter */ +#define XGMAC_FRAME_FILTER_VHF 0x00000800 /* VLAN Hash Filter */ +#define XGMAC_FRAME_FILTER_VPF 0x00001000 /* VLAN Perfect Filter */ +#define XGMAC_FRAME_FILTER_RA 0x80000000 /* Receive all mode */ + +/* XGMAC FLOW CTRL defines */ +#define XGMAC_FLOW_CTRL_PT_MASK 0xffff0000 /* Pause Time Mask */ +#define XGMAC_FLOW_CTRL_PT_SHIFT 16 +#define XGMAC_FLOW_CTRL_DZQP 0x00000080 /* Disable Zero-Quanta Phase */ +#define XGMAC_FLOW_CTRL_PLT 0x00000020 /* Pause Low Threshhold */ +#define XGMAC_FLOW_CTRL_PLT_MASK 0x00000030 /* PLT MASK */ +#define XGMAC_FLOW_CTRL_UP 0x00000008 /* Unicast Pause Frame Detect */ +#define XGMAC_FLOW_CTRL_RFE 0x00000004 /* Rx Flow Control Enable */ +#define XGMAC_FLOW_CTRL_TFE 0x00000002 /* Tx Flow Control Enable */ +#define XGMAC_FLOW_CTRL_FCB_BPA 0x00000001 /* Flow Control Busy ... */ + +/* XGMAC_INT_STAT reg */ +#define XGMAC_INT_STAT_PMT 0x0080 /* PMT Interrupt Status */ +#define XGMAC_INT_STAT_LPI 0x0040 /* LPI Interrupt Status */ + +/* DMA Bus Mode register defines */ +#define DMA_BUS_MODE_SFT_RESET 0x00000001 /* Software Reset */ +#define DMA_BUS_MODE_DSL_MASK 0x0000007c /* Descriptor Skip Length */ +#define DMA_BUS_MODE_DSL_SHIFT 2 /* (in DWORDS) */ +#define DMA_BUS_MODE_ATDS 0x00000080 /* Alternate Descriptor Size */ + +/* Programmable burst length */ +#define DMA_BUS_MODE_PBL_MASK 0x00003f00 /* Programmable Burst Len */ +#define DMA_BUS_MODE_PBL_SHIFT 8 +#define DMA_BUS_MODE_FB 0x00010000 /* Fixed burst */ +#define DMA_BUS_MODE_RPBL_MASK 0x003e0000 /* Rx-Programmable Burst Len */ +#define DMA_BUS_MODE_RPBL_SHIFT 17 +#define DMA_BUS_MODE_USP 0x00800000 +#define DMA_BUS_MODE_8PBL 0x01000000 +#define DMA_BUS_MODE_AAL 0x02000000 + +/* DMA Bus Mode register defines */ +#define DMA_BUS_PR_RATIO_MASK 0x0000c000 /* Rx/Tx priority ratio */ +#define DMA_BUS_PR_RATIO_SHIFT 14 +#define DMA_BUS_FB 0x00010000 /* Fixed Burst */ + +/* DMA Control register defines */ +#define DMA_CONTROL_ST 0x00002000 /* Start/Stop Transmission */ +#define DMA_CONTROL_SR 0x00000002 /* Start/Stop Receive */ +#define DMA_CONTROL_DFF 0x01000000 /* Disable flush of rx frames */ + +/* DMA Normal interrupt */ +#define DMA_INTR_ENA_NIE 0x00010000 /* Normal Summary */ +#define DMA_INTR_ENA_AIE 0x00008000 /* Abnormal Summary */ +#define DMA_INTR_ENA_ERE 0x00004000 /* Early Receive */ +#define DMA_INTR_ENA_FBE 0x00002000 /* Fatal Bus Error */ +#define DMA_INTR_ENA_ETE 0x00000400 /* Early Transmit */ +#define DMA_INTR_ENA_RWE 0x00000200 /* Receive Watchdog */ +#define DMA_INTR_ENA_RSE 0x00000100 /* Receive Stopped */ +#define DMA_INTR_ENA_RUE 0x00000080 /* Receive Buffer Unavailable */ +#define DMA_INTR_ENA_RIE 0x00000040 /* Receive Interrupt */ +#define DMA_INTR_ENA_UNE 0x00000020 /* Tx Underflow */ +#define DMA_INTR_ENA_OVE 0x00000010 /* Receive Overflow */ +#define DMA_INTR_ENA_TJE 0x00000008 /* Transmit Jabber */ +#define DMA_INTR_ENA_TUE 0x00000004 /* Transmit Buffer Unavail */ +#define DMA_INTR_ENA_TSE 0x00000002 /* Transmit Stopped */ +#define DMA_INTR_ENA_TIE 0x00000001 /* Transmit Interrupt */ + +#define DMA_INTR_NORMAL (DMA_INTR_ENA_NIE | DMA_INTR_ENA_RIE | \ + DMA_INTR_ENA_TUE) + +#define DMA_INTR_ABNORMAL (DMA_INTR_ENA_AIE | DMA_INTR_ENA_FBE | \ + DMA_INTR_ENA_RWE | DMA_INTR_ENA_RSE | \ + DMA_INTR_ENA_RUE | DMA_INTR_ENA_UNE | \ + DMA_INTR_ENA_OVE | DMA_INTR_ENA_TJE | \ + DMA_INTR_ENA_TSE) + +/* DMA default interrupt mask */ +#define DMA_INTR_DEFAULT_MASK (DMA_INTR_NORMAL | DMA_INTR_ABNORMAL) + +/* DMA Status register defines */ +#define DMA_STATUS_GMI 0x08000000 /* MMC interrupt */ +#define DMA_STATUS_GLI 0x04000000 /* GMAC Line interface int */ +#define DMA_STATUS_EB_MASK 0x00380000 /* Error Bits Mask */ +#define DMA_STATUS_EB_TX_ABORT 0x00080000 /* Error Bits - TX Abort */ +#define DMA_STATUS_EB_RX_ABORT 0x00100000 /* Error Bits - RX Abort */ +#define DMA_STATUS_TS_MASK 0x00700000 /* Transmit Process State */ +#define DMA_STATUS_TS_SHIFT 20 +#define DMA_STATUS_RS_MASK 0x000e0000 /* Receive Process State */ +#define DMA_STATUS_RS_SHIFT 17 +#define DMA_STATUS_NIS 0x00010000 /* Normal Interrupt Summary */ +#define DMA_STATUS_AIS 0x00008000 /* Abnormal Interrupt Summary */ +#define DMA_STATUS_ERI 0x00004000 /* Early Receive Interrupt */ +#define DMA_STATUS_FBI 0x00002000 /* Fatal Bus Error Interrupt */ +#define DMA_STATUS_ETI 0x00000400 /* Early Transmit Interrupt */ +#define DMA_STATUS_RWT 0x00000200 /* Receive Watchdog Timeout */ +#define DMA_STATUS_RPS 0x00000100 /* Receive Process Stopped */ +#define DMA_STATUS_RU 0x00000080 /* Receive Buffer Unavailable */ +#define DMA_STATUS_RI 0x00000040 /* Receive Interrupt */ +#define DMA_STATUS_UNF 0x00000020 /* Transmit Underflow */ +#define DMA_STATUS_OVF 0x00000010 /* Receive Overflow */ +#define DMA_STATUS_TJT 0x00000008 /* Transmit Jabber Timeout */ +#define DMA_STATUS_TU 0x00000004 /* Transmit Buffer Unavail */ +#define DMA_STATUS_TPS 0x00000002 /* Transmit Process Stopped */ +#define DMA_STATUS_TI 0x00000001 /* Transmit Interrupt */ + +/* Common MAC defines */ +#define MAC_ENABLE_TX 0x00000008 /* Transmitter Enable */ +#define MAC_ENABLE_RX 0x00000004 /* Receiver Enable */ + +/* XGMAC Operation Mode Register */ +#define XGMAC_OMR_TSF 0x00200000 /* TX FIFO Store and Forward */ +#define XGMAC_OMR_FTF 0x00100000 /* Flush Transmit FIFO */ +#define XGMAC_OMR_TTC 0x00020000 /* Transmit Threshhold Ctrl */ +#define XGMAC_OMR_TTC_MASK 0x00030000 +#define XGMAC_OMR_RFD 0x00006000 /* FC Deactivation Threshhold */ +#define XGMAC_OMR_RFD_MASK 0x00007000 /* FC Deact Threshhold MASK */ +#define XGMAC_OMR_RFA 0x00000600 /* FC Activation Threshhold */ +#define XGMAC_OMR_RFA_MASK 0x00000E00 /* FC Act Threshhold MASK */ +#define XGMAC_OMR_EFC 0x00000100 /* Enable Hardware FC */ +#define XGMAC_OMR_FEF 0x00000080 /* Forward Error Frames */ +#define XGMAC_OMR_DT 0x00000040 /* Drop TCP/IP csum Errors */ +#define XGMAC_OMR_RSF 0x00000020 /* RX FIFO Store and Forward */ +#define XGMAC_OMR_RTC 0x00000010 /* RX Threshhold Ctrl */ +#define XGMAC_OMR_RTC_MASK 0x00000018 /* RX Threshhold Ctrl MASK */ + +/* XGMAC HW Features Register */ +#define DMA_HW_FEAT_TXCOESEL 0x00010000 /* TX Checksum offload */ + +#define XGMAC_MMC_CTRL_CNT_FRZ 0x00000008 + +/* XGMAC Descriptor Defines */ +#define MAX_DESC_BUF_SZ (0x2000 - 8) + +#define RXDESC_EXT_STATUS 0x00000001 +#define RXDESC_CRC_ERR 0x00000002 +#define RXDESC_RX_ERR 0x00000008 +#define RXDESC_RX_WDOG 0x00000010 +#define RXDESC_FRAME_TYPE 0x00000020 +#define RXDESC_GIANT_FRAME 0x00000080 +#define RXDESC_LAST_SEG 0x00000100 +#define RXDESC_FIRST_SEG 0x00000200 +#define RXDESC_VLAN_FRAME 0x00000400 +#define RXDESC_OVERFLOW_ERR 0x00000800 +#define RXDESC_LENGTH_ERR 0x00001000 +#define RXDESC_SA_FILTER_FAIL 0x00002000 +#define RXDESC_DESCRIPTOR_ERR 0x00004000 +#define RXDESC_ERROR_SUMMARY 0x00008000 +#define RXDESC_FRAME_LEN_OFFSET 16 +#define RXDESC_FRAME_LEN_MASK 0x3fff0000 +#define RXDESC_DA_FILTER_FAIL 0x40000000 + +#define RXDESC1_END_RING 0x00008000 + +#define RXDESC_IP_PAYLOAD_MASK 0x00000003 +#define RXDESC_IP_PAYLOAD_UDP 0x00000001 +#define RXDESC_IP_PAYLOAD_TCP 0x00000002 +#define RXDESC_IP_PAYLOAD_ICMP 0x00000003 +#define RXDESC_IP_HEADER_ERR 0x00000008 +#define RXDESC_IP_PAYLOAD_ERR 0x00000010 +#define RXDESC_IPV4_PACKET 0x00000040 +#define RXDESC_IPV6_PACKET 0x00000080 +#define TXDESC_UNDERFLOW_ERR 0x00000001 +#define TXDESC_JABBER_TIMEOUT 0x00000002 +#define TXDESC_LOCAL_FAULT 0x00000004 +#define TXDESC_REMOTE_FAULT 0x00000008 +#define TXDESC_VLAN_FRAME 0x00000010 +#define TXDESC_FRAME_FLUSHED 0x00000020 +#define TXDESC_IP_HEADER_ERR 0x00000040 +#define TXDESC_PAYLOAD_CSUM_ERR 0x00000080 +#define TXDESC_ERROR_SUMMARY 0x00008000 +#define TXDESC_SA_CTRL_INSERT 0x00040000 +#define TXDESC_SA_CTRL_REPLACE 0x00080000 +#define TXDESC_2ND_ADDR_CHAINED 0x00100000 +#define TXDESC_END_RING 0x00200000 +#define TXDESC_CSUM_IP 0x00400000 +#define TXDESC_CSUM_IP_PAYLD 0x00800000 +#define TXDESC_CSUM_ALL 0x00C00000 +#define TXDESC_CRC_EN_REPLACE 0x01000000 +#define TXDESC_CRC_EN_APPEND 0x02000000 +#define TXDESC_DISABLE_PAD 0x04000000 +#define TXDESC_FIRST_SEG 0x10000000 +#define TXDESC_LAST_SEG 0x20000000 +#define TXDESC_INTERRUPT 0x40000000 + +#define DESC_OWN 0x80000000 +#define DESC_BUFFER1_SZ_MASK 0x00001fff +#define DESC_BUFFER2_SZ_MASK 0x1fff0000 +#define DESC_BUFFER2_SZ_OFFSET 16 + +struct xgmac_dma_desc { + __le32 flags; + __le32 buf_size; + __le32 buf1_addr; /* Buffer 1 Address Pointer */ + __le32 buf2_addr; /* Buffer 2 Address Pointer */ + __le32 ext_status; + __le32 res[3]; +}; + +struct xgmac_extra_stats { + /* Transmit errors */ + unsigned long tx_jabber; + unsigned long tx_frame_flushed; + unsigned long tx_payload_error; + unsigned long tx_ip_header_error; + unsigned long tx_local_fault; + unsigned long tx_remote_fault; + /* Receive errors */ + unsigned long rx_watchdog; + unsigned long rx_da_filter_fail; + unsigned long rx_sa_filter_fail; + unsigned long rx_payload_error; + unsigned long rx_ip_header_error; + /* Tx/Rx IRQ errors */ + unsigned long tx_undeflow; + unsigned long tx_process_stopped; + unsigned long rx_buf_unav; + unsigned long rx_process_stopped; + unsigned long tx_early; + unsigned long fatal_bus_error; +}; + +struct xgmac_priv { + struct xgmac_dma_desc *dma_rx; + struct sk_buff **rx_skbuff; + unsigned int rx_tail; + unsigned int rx_head; + + struct xgmac_dma_desc *dma_tx; + struct sk_buff **tx_skbuff; + unsigned int tx_head; + unsigned int tx_tail; + + void __iomem *base; + struct sk_buff_head rx_recycle; + unsigned int dma_buf_sz; + dma_addr_t dma_rx_phy; + dma_addr_t dma_tx_phy; + + struct net_device *dev; + struct device *device; + struct napi_struct napi; + + struct xgmac_extra_stats xstats; + + spinlock_t stats_lock; + int pmt_irq; + char rx_pause; + char tx_pause; + int wolopts; +}; + +/* XGMAC Configuration Settings */ +#define MAX_MTU 9000 +#define PAUSE_TIME 0x400 + +#define DMA_RX_RING_SZ 256 +#define DMA_TX_RING_SZ 128 +/* minimum number of free TX descriptors required to wake up TX process */ +#define TX_THRESH (DMA_TX_RING_SZ/4) + +/* DMA descriptor ring helpers */ +#define dma_ring_incr(n, s) (((n) + 1) & ((s) - 1)) +#define dma_ring_space(h, t, s) CIRC_SPACE(h, t, s) +#define dma_ring_cnt(h, t, s) CIRC_CNT(h, t, s) + +/* XGMAC Descriptor Access Helpers */ +static inline void desc_set_buf_len(struct xgmac_dma_desc *p, u32 buf_sz) +{ + if (buf_sz > MAX_DESC_BUF_SZ) + p->buf_size = cpu_to_le32(MAX_DESC_BUF_SZ | + (buf_sz - MAX_DESC_BUF_SZ) << DESC_BUFFER2_SZ_OFFSET); + else + p->buf_size = cpu_to_le32(buf_sz); +} + +static inline int desc_get_buf_len(struct xgmac_dma_desc *p) +{ + u32 len = cpu_to_le32(p->flags); + return (len & DESC_BUFFER1_SZ_MASK) + + ((len & DESC_BUFFER2_SZ_MASK) >> DESC_BUFFER2_SZ_OFFSET); +} + +static inline void desc_init_rx_desc(struct xgmac_dma_desc *p, int ring_size, + int buf_sz) +{ + struct xgmac_dma_desc *end = p + ring_size - 1; + + memset(p, 0, sizeof(*p) * ring_size); + + for (; p <= end; p++) + desc_set_buf_len(p, buf_sz); + + end->buf_size |= cpu_to_le32(RXDESC1_END_RING); +} + +static inline void desc_init_tx_desc(struct xgmac_dma_desc *p, u32 ring_size) +{ + memset(p, 0, sizeof(*p) * ring_size); + p[ring_size - 1].flags = cpu_to_le32(TXDESC_END_RING); +} + +static inline int desc_get_owner(struct xgmac_dma_desc *p) +{ + return le32_to_cpu(p->flags) & DESC_OWN; +} + +static inline void desc_set_rx_owner(struct xgmac_dma_desc *p) +{ + /* Clear all fields and set the owner */ + p->flags = cpu_to_le32(DESC_OWN); +} + +static inline void desc_set_tx_owner(struct xgmac_dma_desc *p, u32 flags) +{ + u32 tmpflags = le32_to_cpu(p->flags); + tmpflags &= TXDESC_END_RING; + tmpflags |= flags | DESC_OWN; + p->flags = cpu_to_le32(tmpflags); +} + +static inline int desc_get_tx_ls(struct xgmac_dma_desc *p) +{ + return le32_to_cpu(p->flags) & TXDESC_LAST_SEG; +} + +static inline u32 desc_get_buf_addr(struct xgmac_dma_desc *p) +{ + return le32_to_cpu(p->buf1_addr); +} + +static inline void desc_set_buf_addr(struct xgmac_dma_desc *p, + u32 paddr, int len) +{ + p->buf1_addr = cpu_to_le32(paddr); + if (len > MAX_DESC_BUF_SZ) + p->buf2_addr = cpu_to_le32(paddr + MAX_DESC_BUF_SZ); +} + +static inline void desc_set_buf_addr_and_size(struct xgmac_dma_desc *p, + u32 paddr, int len) +{ + desc_set_buf_len(p, len); + desc_set_buf_addr(p, paddr, len); +} + +static inline int desc_get_rx_frame_len(struct xgmac_dma_desc *p) +{ + u32 data = le32_to_cpu(p->flags); + u32 len = (data & RXDESC_FRAME_LEN_MASK) >> RXDESC_FRAME_LEN_OFFSET; + if (data & RXDESC_FRAME_TYPE) + len -= ETH_FCS_LEN; + + return len; +} + +static void xgmac_dma_flush_tx_fifo(void __iomem *ioaddr) +{ + int timeout = 1000; + u32 reg = readl(ioaddr + XGMAC_OMR); + writel(reg | XGMAC_OMR_FTF, ioaddr + XGMAC_OMR); + + while ((timeout-- > 0) && readl(ioaddr + XGMAC_OMR) & XGMAC_OMR_FTF) + udelay(1); +} + +static int desc_get_tx_status(struct xgmac_priv *priv, struct xgmac_dma_desc *p) +{ + struct xgmac_extra_stats *x = &priv->xstats; + u32 status = le32_to_cpu(p->flags); + + if (!(status & TXDESC_ERROR_SUMMARY)) + return 0; + + netdev_dbg(priv->dev, "tx desc error = 0x%08x\n", status); + if (status & TXDESC_JABBER_TIMEOUT) + x->tx_jabber++; + if (status & TXDESC_FRAME_FLUSHED) + x->tx_frame_flushed++; + if (status & TXDESC_UNDERFLOW_ERR) + xgmac_dma_flush_tx_fifo(priv->base); + if (status & TXDESC_IP_HEADER_ERR) + x->tx_ip_header_error++; + if (status & TXDESC_LOCAL_FAULT) + x->tx_local_fault++; + if (status & TXDESC_REMOTE_FAULT) + x->tx_remote_fault++; + if (status & TXDESC_PAYLOAD_CSUM_ERR) + x->tx_payload_error++; + + return -1; +} + +static int desc_get_rx_status(struct xgmac_priv *priv, struct xgmac_dma_desc *p) +{ + struct xgmac_extra_stats *x = &priv->xstats; + int ret = CHECKSUM_UNNECESSARY; + u32 status = le32_to_cpu(p->flags); + u32 ext_status = le32_to_cpu(p->ext_status); + + if (status & RXDESC_DA_FILTER_FAIL) { + netdev_dbg(priv->dev, "XGMAC RX : Dest Address filter fail\n"); + x->rx_da_filter_fail++; + return -1; + } + + /* Check if packet has checksum already */ + if ((status & RXDESC_FRAME_TYPE) && (status & RXDESC_EXT_STATUS) && + !(ext_status & RXDESC_IP_PAYLOAD_MASK)) + ret = CHECKSUM_NONE; + + netdev_dbg(priv->dev, "rx status - frame type=%d, csum = %d, ext stat %08x\n", + (status & RXDESC_FRAME_TYPE) ? 1 : 0, ret, ext_status); + + if (!(status & RXDESC_ERROR_SUMMARY)) + return ret; + + /* Handle any errors */ + if (status & (RXDESC_DESCRIPTOR_ERR | RXDESC_OVERFLOW_ERR | + RXDESC_GIANT_FRAME | RXDESC_LENGTH_ERR | RXDESC_CRC_ERR)) + return -1; + + if (status & RXDESC_EXT_STATUS) { + if (ext_status & RXDESC_IP_HEADER_ERR) + x->rx_ip_header_error++; + if (ext_status & RXDESC_IP_PAYLOAD_ERR) + x->rx_payload_error++; + netdev_dbg(priv->dev, "IP checksum error - stat %08x\n", + ext_status); + return CHECKSUM_NONE; + } + + return ret; +} + +static inline void xgmac_mac_enable(void __iomem *ioaddr) +{ + u32 value = readl(ioaddr + XGMAC_CONTROL); + value |= MAC_ENABLE_RX | MAC_ENABLE_TX; + writel(value, ioaddr + XGMAC_CONTROL); + + value = readl(ioaddr + XGMAC_DMA_CONTROL); + value |= DMA_CONTROL_ST | DMA_CONTROL_SR; + writel(value, ioaddr + XGMAC_DMA_CONTROL); +} + +static inline void xgmac_mac_disable(void __iomem *ioaddr) +{ + u32 value = readl(ioaddr + XGMAC_DMA_CONTROL); + value &= ~(DMA_CONTROL_ST | DMA_CONTROL_SR); + writel(value, ioaddr + XGMAC_DMA_CONTROL); + + value = readl(ioaddr + XGMAC_CONTROL); + value &= ~(MAC_ENABLE_TX | MAC_ENABLE_RX); + writel(value, ioaddr + XGMAC_CONTROL); +} + +static void xgmac_set_mac_addr(void __iomem *ioaddr, unsigned char *addr, + int num) +{ + u32 data; + + data = (addr[5] << 8) | addr[4] | (num ? XGMAC_ADDR_AE : 0); + writel(data, ioaddr + XGMAC_ADDR_HIGH(num)); + data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0]; + writel(data, ioaddr + XGMAC_ADDR_LOW(num)); +} + +static void xgmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr, + int num) +{ + u32 hi_addr, lo_addr; + + /* Read the MAC address from the hardware */ + hi_addr = readl(ioaddr + XGMAC_ADDR_HIGH(num)); + lo_addr = readl(ioaddr + XGMAC_ADDR_LOW(num)); + + /* Extract the MAC address from the high and low words */ + addr[0] = lo_addr & 0xff; + addr[1] = (lo_addr >> 8) & 0xff; + addr[2] = (lo_addr >> 16) & 0xff; + addr[3] = (lo_addr >> 24) & 0xff; + addr[4] = hi_addr & 0xff; + addr[5] = (hi_addr >> 8) & 0xff; +} + +static int xgmac_set_flow_ctrl(struct xgmac_priv *priv, int rx, int tx) +{ + u32 reg; + unsigned int flow = 0; + + priv->rx_pause = rx; + priv->tx_pause = tx; + + if (rx || tx) { + if (rx) + flow |= XGMAC_FLOW_CTRL_RFE; + if (tx) + flow |= XGMAC_FLOW_CTRL_TFE; + + flow |= XGMAC_FLOW_CTRL_PLT | XGMAC_FLOW_CTRL_UP; + flow |= (PAUSE_TIME << XGMAC_FLOW_CTRL_PT_SHIFT); + + writel(flow, priv->base + XGMAC_FLOW_CTRL); + + reg = readl(priv->base + XGMAC_OMR); + reg |= XGMAC_OMR_EFC; + writel(reg, priv->base + XGMAC_OMR); + } else { + writel(0, priv->base + XGMAC_FLOW_CTRL); + + reg = readl(priv->base + XGMAC_OMR); + reg &= ~XGMAC_OMR_EFC; + writel(reg, priv->base + XGMAC_OMR); + } + + return 0; +} + +static void xgmac_rx_refill(struct xgmac_priv *priv) +{ + struct xgmac_dma_desc *p; + dma_addr_t paddr; + + while (dma_ring_space(priv->rx_head, priv->rx_tail, DMA_RX_RING_SZ) > 1) { + int entry = priv->rx_head; + struct sk_buff *skb; + + p = priv->dma_rx + entry; + + if (priv->rx_skbuff[entry] != NULL) + continue; + + skb = __skb_dequeue(&priv->rx_recycle); + if (skb == NULL) + skb = netdev_alloc_skb(priv->dev, priv->dma_buf_sz); + if (unlikely(skb == NULL)) + break; + + priv->rx_skbuff[entry] = skb; + paddr = dma_map_single(priv->device, skb->data, + priv->dma_buf_sz, DMA_FROM_DEVICE); + desc_set_buf_addr(p, paddr, priv->dma_buf_sz); + + netdev_dbg(priv->dev, "rx ring: head %d, tail %d\n", + priv->rx_head, priv->rx_tail); + + priv->rx_head = dma_ring_incr(priv->rx_head, DMA_RX_RING_SZ); + /* Ensure descriptor is in memory before handing to h/w */ + wmb(); + desc_set_rx_owner(p); + } +} + +/** + * init_xgmac_dma_desc_rings - init the RX/TX descriptor rings + * @dev: net device structure + * Description: this function initializes the DMA RX/TX descriptors + * and allocates the socket buffers. + */ +static int xgmac_dma_desc_rings_init(struct net_device *dev) +{ + struct xgmac_priv *priv = netdev_priv(dev); + unsigned int bfsize; + + /* Set the Buffer size according to the MTU; + * indeed, in case of jumbo we need to bump-up the buffer sizes. + */ + bfsize = ALIGN(dev->mtu + ETH_HLEN + ETH_FCS_LEN + NET_IP_ALIGN + 64, + 64); + + netdev_dbg(priv->dev, "mtu [%d] bfsize [%d]\n", dev->mtu, bfsize); + + priv->rx_skbuff = kzalloc(sizeof(struct sk_buff *) * DMA_RX_RING_SZ, + GFP_KERNEL); + if (!priv->rx_skbuff) + return -ENOMEM; + + priv->dma_rx = dma_alloc_coherent(priv->device, + DMA_RX_RING_SZ * + sizeof(struct xgmac_dma_desc), + &priv->dma_rx_phy, + GFP_KERNEL); + if (!priv->dma_rx) + goto err_dma_rx; + + priv->tx_skbuff = kzalloc(sizeof(struct sk_buff *) * DMA_TX_RING_SZ, + GFP_KERNEL); + if (!priv->tx_skbuff) + goto err_tx_skb; + + priv->dma_tx = dma_alloc_coherent(priv->device, + DMA_TX_RING_SZ * + sizeof(struct xgmac_dma_desc), + &priv->dma_tx_phy, + GFP_KERNEL); + if (!priv->dma_tx) + goto err_dma_tx; + + netdev_dbg(priv->dev, "DMA desc rings: virt addr (Rx %p, " + "Tx %p)\n\tDMA phy addr (Rx 0x%08x, Tx 0x%08x)\n", + priv->dma_rx, priv->dma_tx, + (unsigned int)priv->dma_rx_phy, (unsigned int)priv->dma_tx_phy); + + priv->rx_tail = 0; + priv->rx_head = 0; + priv->dma_buf_sz = bfsize; + desc_init_rx_desc(priv->dma_rx, DMA_RX_RING_SZ, priv->dma_buf_sz); + xgmac_rx_refill(priv); + + priv->tx_tail = 0; + priv->tx_head = 0; + desc_init_tx_desc(priv->dma_tx, DMA_TX_RING_SZ); + + writel(priv->dma_tx_phy, priv->base + XGMAC_DMA_TX_BASE_ADDR); + writel(priv->dma_rx_phy, priv->base + XGMAC_DMA_RX_BASE_ADDR); + + return 0; + +err_dma_tx: + kfree(priv->tx_skbuff); +err_tx_skb: + dma_free_coherent(priv->device, + DMA_RX_RING_SZ * sizeof(struct xgmac_dma_desc), + priv->dma_rx, priv->dma_rx_phy); +err_dma_rx: + kfree(priv->rx_skbuff); + return -ENOMEM; +} + +static void xgmac_free_rx_skbufs(struct xgmac_priv *priv) +{ + int i; + struct xgmac_dma_desc *p; + + if (!priv->rx_skbuff) + return; + + for (i = 0; i < DMA_RX_RING_SZ; i++) { + if (priv->rx_skbuff[i] == NULL) + continue; + + p = priv->dma_rx + i; + dma_unmap_single(priv->device, desc_get_buf_addr(p), + priv->dma_buf_sz, DMA_FROM_DEVICE); + dev_kfree_skb_any(priv->rx_skbuff[i]); + priv->rx_skbuff[i] = NULL; + } +} + +static void xgmac_free_tx_skbufs(struct xgmac_priv *priv) +{ + int i, f; + struct xgmac_dma_desc *p; + + if (!priv->tx_skbuff) + return; + + for (i = 0; i < DMA_TX_RING_SZ; i++) { + if (priv->tx_skbuff[i] == NULL) + continue; + + p = priv->dma_tx + i; + dma_unmap_single(priv->device, desc_get_buf_addr(p), + desc_get_buf_len(p), DMA_TO_DEVICE); + + for (f = 0; f < skb_shinfo(priv->tx_skbuff[i])->nr_frags; f++) { + p = priv->dma_tx + i++; + dma_unmap_page(priv->device, desc_get_buf_addr(p), + desc_get_buf_len(p), DMA_TO_DEVICE); + } + + dev_kfree_skb_any(priv->tx_skbuff[i]); + priv->tx_skbuff[i] = NULL; + } +} + +static void xgmac_free_dma_desc_rings(struct xgmac_priv *priv) +{ + /* Release the DMA TX/RX socket buffers */ + xgmac_free_rx_skbufs(priv); + xgmac_free_tx_skbufs(priv); + + /* Free the consistent memory allocated for descriptor rings */ + if (priv->dma_tx) { + dma_free_coherent(priv->device, + DMA_TX_RING_SZ * sizeof(struct xgmac_dma_desc), + priv->dma_tx, priv->dma_tx_phy); + priv->dma_tx = NULL; + } + if (priv->dma_rx) { + dma_free_coherent(priv->device, + DMA_RX_RING_SZ * sizeof(struct xgmac_dma_desc), + priv->dma_rx, priv->dma_rx_phy); + priv->dma_rx = NULL; + } + kfree(priv->rx_skbuff); + priv->rx_skbuff = NULL; + kfree(priv->tx_skbuff); + priv->tx_skbuff = NULL; +} + +/** + * xgmac_tx: + * @priv: private driver structure + * Description: it reclaims resources after transmission completes. + */ +static void xgmac_tx_complete(struct xgmac_priv *priv) +{ + int i; + void __iomem *ioaddr = priv->base; + + writel(DMA_STATUS_TU | DMA_STATUS_NIS, ioaddr + XGMAC_DMA_STATUS); + + while (dma_ring_cnt(priv->tx_head, priv->tx_tail, DMA_TX_RING_SZ)) { + unsigned int entry = priv->tx_tail; + struct sk_buff *skb = priv->tx_skbuff[entry]; + struct xgmac_dma_desc *p = priv->dma_tx + entry; + + /* Check if the descriptor is owned by the DMA. */ + if (desc_get_owner(p)) + break; + + /* Verify tx error by looking at the last segment */ + if (desc_get_tx_ls(p)) + desc_get_tx_status(priv, p); + + netdev_dbg(priv->dev, "tx ring: curr %d, dirty %d\n", + priv->tx_head, priv->tx_tail); + + dma_unmap_single(priv->device, desc_get_buf_addr(p), + desc_get_buf_len(p), DMA_TO_DEVICE); + + priv->tx_skbuff[entry] = NULL; + priv->tx_tail = dma_ring_incr(entry, DMA_TX_RING_SZ); + + if (!skb) { + continue; + } + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + entry = priv->tx_tail = dma_ring_incr(priv->tx_tail, + DMA_TX_RING_SZ); + p = priv->dma_tx + priv->tx_tail; + + dma_unmap_page(priv->device, desc_get_buf_addr(p), + desc_get_buf_len(p), DMA_TO_DEVICE); + } + + /* + * If there's room in the queue (limit it to size) + * we add this skb back into the pool, + * if it's the right size. + */ + if ((skb_queue_len(&priv->rx_recycle) < + DMA_RX_RING_SZ) && + skb_recycle_check(skb, priv->dma_buf_sz)) + __skb_queue_head(&priv->rx_recycle, skb); + else + dev_kfree_skb(skb); + } + + if (dma_ring_space(priv->tx_head, priv->tx_tail, DMA_TX_RING_SZ) > + TX_THRESH) + netif_wake_queue(priv->dev); +} + +/** + * xgmac_tx_err: + * @priv: pointer to the private device structure + * Description: it cleans the descriptors and restarts the transmission + * in case of errors. + */ +static void xgmac_tx_err(struct xgmac_priv *priv) +{ + u32 reg, value, inten; + + netif_stop_queue(priv->dev); + + inten = readl(priv->base + XGMAC_DMA_INTR_ENA); + writel(0, priv->base + XGMAC_DMA_INTR_ENA); + + reg = readl(priv->base + XGMAC_DMA_CONTROL); + writel(reg & ~DMA_CONTROL_ST, priv->base + XGMAC_DMA_CONTROL); + do { + value = readl(priv->base + XGMAC_DMA_STATUS) & 0x700000; + } while (value && (value != 0x600000)); + + xgmac_free_tx_skbufs(priv); + desc_init_tx_desc(priv->dma_tx, DMA_TX_RING_SZ); + priv->tx_tail = 0; + priv->tx_head = 0; + writel(reg | DMA_CONTROL_ST, priv->base + XGMAC_DMA_CONTROL); + + writel(DMA_STATUS_TU | DMA_STATUS_TPS | DMA_STATUS_NIS | DMA_STATUS_AIS, + priv->base + XGMAC_DMA_STATUS); + writel(inten, priv->base + XGMAC_DMA_INTR_ENA); + + netif_wake_queue(priv->dev); +} + +static int xgmac_hw_init(struct net_device *dev) +{ + u32 value, ctrl; + int limit; + struct xgmac_priv *priv = netdev_priv(dev); + void __iomem *ioaddr = priv->base; + + /* Save the ctrl register value */ + ctrl = readl(ioaddr + XGMAC_CONTROL) & XGMAC_CONTROL_SPD_MASK; + + /* SW reset */ + value = DMA_BUS_MODE_SFT_RESET; + writel(value, ioaddr + XGMAC_DMA_BUS_MODE); + limit = 15000; + while (limit-- && + (readl(ioaddr + XGMAC_DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET)) + cpu_relax(); + if (limit < 0) + return -EBUSY; + + value = (0x10 << DMA_BUS_MODE_PBL_SHIFT) | + (0x10 << DMA_BUS_MODE_RPBL_SHIFT) | + DMA_BUS_MODE_FB | DMA_BUS_MODE_ATDS | DMA_BUS_MODE_AAL; + writel(value, ioaddr + XGMAC_DMA_BUS_MODE); + + /* Enable interrupts */ + writel(DMA_INTR_DEFAULT_MASK, ioaddr + XGMAC_DMA_STATUS); + writel(DMA_INTR_DEFAULT_MASK, ioaddr + XGMAC_DMA_INTR_ENA); + + /* XGMAC requires AXI bus init. This is a 'magic number' for now */ + writel(0x000100E, ioaddr + XGMAC_DMA_AXI_BUS); + + ctrl |= XGMAC_CONTROL_DDIC | XGMAC_CONTROL_JE | XGMAC_CONTROL_ACS | + XGMAC_CONTROL_CAR; + if (dev->features & NETIF_F_RXCSUM) + ctrl |= XGMAC_CONTROL_IPC; + writel(ctrl, ioaddr + XGMAC_CONTROL); + + value = DMA_CONTROL_DFF; + writel(value, ioaddr + XGMAC_DMA_CONTROL); + + /* Set the HW DMA mode and the COE */ + writel(XGMAC_OMR_TSF | XGMAC_OMR_RSF | XGMAC_OMR_RFD | XGMAC_OMR_RFA, + ioaddr + XGMAC_OMR); + + /* Reset the MMC counters */ + writel(1, ioaddr + XGMAC_MMC_CTRL); + return 0; +} + +/** + * xgmac_open - open entry point of the driver + * @dev : pointer to the device structure. + * Description: + * This function is the open entry point of the driver. + * Return value: + * 0 on success and an appropriate (-)ve integer as defined in errno.h + * file on failure. + */ +static int xgmac_open(struct net_device *dev) +{ + int ret; + struct xgmac_priv *priv = netdev_priv(dev); + void __iomem *ioaddr = priv->base; + + /* Check that the MAC address is valid. If its not, refuse + * to bring the device up. The user must specify an + * address using the following linux command: + * ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx */ + if (!is_valid_ether_addr(dev->dev_addr)) { + random_ether_addr(dev->dev_addr); + netdev_dbg(priv->dev, "generated random MAC address %pM\n", + dev->dev_addr); + } + + skb_queue_head_init(&priv->rx_recycle); + memset(&priv->xstats, 0, sizeof(struct xgmac_extra_stats)); + + /* Initialize the XGMAC and descriptors */ + xgmac_hw_init(dev); + xgmac_set_mac_addr(ioaddr, dev->dev_addr, 0); + xgmac_set_flow_ctrl(priv, priv->rx_pause, priv->tx_pause); + + ret = xgmac_dma_desc_rings_init(dev); + if (ret < 0) + return ret; + + /* Enable the MAC Rx/Tx */ + xgmac_mac_enable(ioaddr); + + napi_enable(&priv->napi); + netif_start_queue(dev); + + return 0; +} + +/** + * xgmac_release - close entry point of the driver + * @dev : device pointer. + * Description: + * This is the stop entry point of the driver. + */ +static int xgmac_stop(struct net_device *dev) +{ + struct xgmac_priv *priv = netdev_priv(dev); + + netif_stop_queue(dev); + + if (readl(priv->base + XGMAC_DMA_INTR_ENA)) + napi_disable(&priv->napi); + + writel(0, priv->base + XGMAC_DMA_INTR_ENA); + skb_queue_purge(&priv->rx_recycle); + + /* Disable the MAC core */ + xgmac_mac_disable(priv->base); + + /* Release and free the Rx/Tx resources */ + xgmac_free_dma_desc_rings(priv); + + return 0; +} + +/** + * xgmac_xmit: + * @skb : the socket buffer + * @dev : device pointer + * Description : Tx entry point of the driver. + */ +static netdev_tx_t xgmac_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct xgmac_priv *priv = netdev_priv(dev); + unsigned int entry; + int i; + int nfrags = skb_shinfo(skb)->nr_frags; + struct xgmac_dma_desc *desc, *first; + unsigned int desc_flags; + unsigned int len; + dma_addr_t paddr; + + if (dma_ring_space(priv->tx_head, priv->tx_tail, DMA_TX_RING_SZ) < + (nfrags + 1)) { + writel(DMA_INTR_DEFAULT_MASK | DMA_INTR_ENA_TIE, + priv->base + XGMAC_DMA_INTR_ENA); + netif_stop_queue(dev); + return NETDEV_TX_BUSY; + } + + desc_flags = (skb->ip_summed == CHECKSUM_PARTIAL) ? + TXDESC_CSUM_ALL : 0; + entry = priv->tx_head; + desc = priv->dma_tx + entry; + first = desc; + + len = skb_headlen(skb); + paddr = dma_map_single(priv->device, skb->data, len, DMA_TO_DEVICE); + if (dma_mapping_error(priv->device, paddr)) { + dev_kfree_skb(skb); + return -EIO; + } + priv->tx_skbuff[entry] = skb; + desc_set_buf_addr_and_size(desc, paddr, len); + + for (i = 0; i < nfrags; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + + len = frag->size; + + paddr = skb_frag_dma_map(priv->device, frag, 0, len, + DMA_TO_DEVICE); + if (dma_mapping_error(priv->device, paddr)) { + dev_kfree_skb(skb); + return -EIO; + } + + entry = dma_ring_incr(entry, DMA_TX_RING_SZ); + desc = priv->dma_tx + entry; + priv->tx_skbuff[entry] = NULL; + + desc_set_buf_addr_and_size(desc, paddr, len); + if (i < (nfrags - 1)) + desc_set_tx_owner(desc, desc_flags); + } + + /* Interrupt on completition only for the latest segment */ + if (desc != first) + desc_set_tx_owner(desc, desc_flags | + TXDESC_LAST_SEG | TXDESC_INTERRUPT); + else + desc_flags |= TXDESC_LAST_SEG | TXDESC_INTERRUPT; + + /* Set owner on first desc last to avoid race condition */ + wmb(); + desc_set_tx_owner(first, desc_flags | TXDESC_FIRST_SEG); + + priv->tx_head = dma_ring_incr(entry, DMA_TX_RING_SZ); + + writel(1, priv->base + XGMAC_DMA_TX_POLL); + + return NETDEV_TX_OK; +} + +static int xgmac_rx(struct xgmac_priv *priv, int limit) +{ + unsigned int entry; + unsigned int count = 0; + struct xgmac_dma_desc *p; + + while (count < limit) { + int ip_checksum; + struct sk_buff *skb; + int frame_len; + + writel(DMA_STATUS_RI | DMA_STATUS_NIS, + priv->base + XGMAC_DMA_STATUS); + + entry = priv->rx_tail; + p = priv->dma_rx + entry; + if (desc_get_owner(p)) + break; + + count++; + priv->rx_tail = dma_ring_incr(priv->rx_tail, DMA_RX_RING_SZ); + + /* read the status of the incoming frame */ + ip_checksum = desc_get_rx_status(priv, p); + if (ip_checksum < 0) + continue; + + skb = priv->rx_skbuff[entry]; + if (unlikely(!skb)) { + netdev_err(priv->dev, "Inconsistent Rx descriptor chain\n"); + break; + } + priv->rx_skbuff[entry] = NULL; + + frame_len = desc_get_rx_frame_len(p); + netdev_dbg(priv->dev, "RX frame size %d, COE status: %d\n", + frame_len, ip_checksum); + + skb_put(skb, frame_len); + dma_unmap_single(priv->device, desc_get_buf_addr(p), + frame_len, DMA_FROM_DEVICE); + + skb->protocol = eth_type_trans(skb, priv->dev); + skb->ip_summed = ip_checksum; + if (ip_checksum == CHECKSUM_NONE) + netif_receive_skb(skb); + else + napi_gro_receive(&priv->napi, skb); + } + + xgmac_rx_refill(priv); + + writel(1, priv->base + XGMAC_DMA_RX_POLL); + + return count; +} + +/** + * xgmac_poll - xgmac poll method (NAPI) + * @napi : pointer to the napi structure. + * @budget : maximum number of packets that the current CPU can receive from + * all interfaces. + * Description : + * This function implements the the reception process. + * Also it runs the TX completion thread + */ +static int xgmac_poll(struct napi_struct *napi, int budget) +{ + struct xgmac_priv *priv = container_of(napi, + struct xgmac_priv, napi); + int work_done = 0; + + xgmac_tx_complete(priv); + work_done = xgmac_rx(priv, budget); + + if (work_done < budget) { + napi_complete(napi); + writel(DMA_INTR_DEFAULT_MASK, priv->base + XGMAC_DMA_INTR_ENA); + } + return work_done; +} + +/** + * xgmac_tx_timeout + * @dev : Pointer to net device structure + * Description: this function is called when a packet transmission fails to + * complete within a reasonable tmrate. The driver will mark the error in the + * netdev structure and arrange for the device to be reset to a sane state + * in order to transmit a new packet. + */ +static void xgmac_tx_timeout(struct net_device *dev) +{ + struct xgmac_priv *priv = netdev_priv(dev); + + /* Clear Tx resources and restart transmitting again */ + xgmac_tx_err(priv); +} + +/** + * xgmac_set_rx_mode - entry point for multicast addressing + * @dev : pointer to the device structure + * Description: + * This function is a driver entry point which gets called by the kernel + * whenever multicast addresses must be enabled/disabled. + * Return value: + * void. + */ +static void xgmac_set_rx_mode(struct net_device *dev) +{ + int i; + struct xgmac_priv *priv = netdev_priv(dev); + void __iomem *ioaddr = priv->base; + unsigned int value = 0; + u32 hash_filter[XGMAC_NUM_HASH]; + int reg = 1; + struct netdev_hw_addr *ha; + bool use_hash = false; + + netdev_dbg(priv->dev, "# mcasts %d, # unicast %d\n", + netdev_mc_count(dev), netdev_uc_count(dev)); + + if (dev->flags & IFF_PROMISC) { + writel(XGMAC_FRAME_FILTER_PR, ioaddr + XGMAC_FRAME_FILTER); + return; + } + + memset(hash_filter, 0, sizeof(hash_filter)); + + if (netdev_uc_count(dev) > XGMAC_MAX_FILTER_ADDR) { + use_hash = true; + value |= XGMAC_FRAME_FILTER_HUC | XGMAC_FRAME_FILTER_HPF; + } + netdev_for_each_uc_addr(ha, dev) { + if (use_hash) { + u32 bit_nr = ~ether_crc(ETH_ALEN, ha->addr) >> 23; + + /* The most significant 4 bits determine the register to + * use (H/L) while the other 5 bits determine the bit + * within the register. */ + hash_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); + } else { + xgmac_set_mac_addr(ioaddr, ha->addr, reg); + reg++; + } + } + + if (dev->flags & IFF_ALLMULTI) { + value |= XGMAC_FRAME_FILTER_PM; + goto out; + } + + if ((netdev_mc_count(dev) + reg - 1) > XGMAC_MAX_FILTER_ADDR) { + use_hash = true; + value |= XGMAC_FRAME_FILTER_HMC | XGMAC_FRAME_FILTER_HPF; + } + netdev_for_each_mc_addr(ha, dev) { + if (use_hash) { + u32 bit_nr = ~ether_crc(ETH_ALEN, ha->addr) >> 23; + + /* The most significant 4 bits determine the register to + * use (H/L) while the other 5 bits determine the bit + * within the register. */ + hash_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); + } else { + xgmac_set_mac_addr(ioaddr, ha->addr, reg); + reg++; + } + } + +out: + for (i = 0; i < XGMAC_NUM_HASH; i++) + writel(hash_filter[i], ioaddr + XGMAC_HASH(i)); + + writel(value, ioaddr + XGMAC_FRAME_FILTER); +} + +/** + * xgmac_change_mtu - entry point to change MTU size for the device. + * @dev : device pointer. + * @new_mtu : the new MTU size for the device. + * Description: the Maximum Transfer Unit (MTU) is used by the network layer + * to drive packet transmission. Ethernet has an MTU of 1500 octets + * (ETH_DATA_LEN). This value can be changed with ifconfig. + * Return value: + * 0 on success and an appropriate (-)ve integer as defined in errno.h + * file on failure. + */ +static int xgmac_change_mtu(struct net_device *dev, int new_mtu) +{ + struct xgmac_priv *priv = netdev_priv(dev); + int old_mtu; + + if ((new_mtu < 46) || (new_mtu > MAX_MTU)) { + netdev_err(priv->dev, "invalid MTU, max MTU is: %d\n", MAX_MTU); + return -EINVAL; + } + + old_mtu = dev->mtu; + dev->mtu = new_mtu; + + /* return early if the buffer sizes will not change */ + if (old_mtu <= ETH_DATA_LEN && new_mtu <= ETH_DATA_LEN) + return 0; + if (old_mtu == new_mtu) + return 0; + + /* Stop everything, get ready to change the MTU */ + if (!netif_running(dev)) + return 0; + + /* Bring the interface down and then back up */ + xgmac_stop(dev); + return xgmac_open(dev); +} + +static irqreturn_t xgmac_pmt_interrupt(int irq, void *dev_id) +{ + u32 intr_status; + struct net_device *dev = (struct net_device *)dev_id; + struct xgmac_priv *priv = netdev_priv(dev); + void __iomem *ioaddr = priv->base; + + intr_status = readl(ioaddr + XGMAC_INT_STAT); + if (intr_status & XGMAC_INT_STAT_PMT) { + netdev_dbg(priv->dev, "received Magic frame\n"); + /* clear the PMT bits 5 and 6 by reading the PMT */ + readl(ioaddr + XGMAC_PMT); + } + return IRQ_HANDLED; +} + +static irqreturn_t xgmac_interrupt(int irq, void *dev_id) +{ + u32 intr_status; + bool tx_err = false; + struct net_device *dev = (struct net_device *)dev_id; + struct xgmac_priv *priv = netdev_priv(dev); + struct xgmac_extra_stats *x = &priv->xstats; + + /* read the status register (CSR5) */ + intr_status = readl(priv->base + XGMAC_DMA_STATUS); + intr_status &= readl(priv->base + XGMAC_DMA_INTR_ENA); + writel(intr_status, priv->base + XGMAC_DMA_STATUS); + + /* It displays the DMA process states (CSR5 register) */ + /* ABNORMAL interrupts */ + if (unlikely(intr_status & DMA_STATUS_AIS)) { + if (intr_status & DMA_STATUS_TJT) { + netdev_err(priv->dev, "transmit jabber\n"); + x->tx_jabber++; + } + if (intr_status & DMA_STATUS_RU) + x->rx_buf_unav++; + if (intr_status & DMA_STATUS_RPS) { + netdev_err(priv->dev, "receive process stopped\n"); + x->rx_process_stopped++; + } + if (intr_status & DMA_STATUS_ETI) { + netdev_err(priv->dev, "transmit early interrupt\n"); + x->tx_early++; + } + if (intr_status & DMA_STATUS_TPS) { + netdev_err(priv->dev, "transmit process stopped\n"); + x->tx_process_stopped++; + tx_err = true; + } + if (intr_status & DMA_STATUS_FBI) { + netdev_err(priv->dev, "fatal bus error\n"); + x->fatal_bus_error++; + tx_err = true; + } + + if (tx_err) + xgmac_tx_err(priv); + } + + /* TX/RX NORMAL interrupts */ + if (intr_status & (DMA_STATUS_RI | DMA_STATUS_TU)) { + writel(DMA_INTR_ABNORMAL, priv->base + XGMAC_DMA_INTR_ENA); + napi_schedule(&priv->napi); + } + + return IRQ_HANDLED; +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +/* Polling receive - used by NETCONSOLE and other diagnostic tools + * to allow network I/O with interrupts disabled. */ +static void xgmac_poll_controller(struct net_device *dev) +{ + disable_irq(dev->irq); + xgmac_interrupt(dev->irq, dev); + enable_irq(dev->irq); +} +#endif + +struct rtnl_link_stats64 * +xgmac_get_stats64(struct net_device *dev, + struct rtnl_link_stats64 *storage) +{ + struct xgmac_priv *priv = netdev_priv(dev); + void __iomem *base = priv->base; + u32 count; + + spin_lock_bh(&priv->stats_lock); + writel(XGMAC_MMC_CTRL_CNT_FRZ, base + XGMAC_MMC_CTRL); + + storage->rx_bytes = readl(base + XGMAC_MMC_RXOCTET_G_LO); + storage->rx_bytes |= (u64)(readl(base + XGMAC_MMC_RXOCTET_G_HI)) << 32; + + storage->rx_packets = readl(base + XGMAC_MMC_RXFRAME_GB_LO); + storage->multicast = readl(base + XGMAC_MMC_RXMCFRAME_G); + storage->rx_crc_errors = readl(base + XGMAC_MMC_RXCRCERR); + storage->rx_length_errors = readl(base + XGMAC_MMC_RXLENGTHERR); + storage->rx_missed_errors = readl(base + XGMAC_MMC_RXOVERFLOW); + + storage->tx_bytes = readl(base + XGMAC_MMC_TXOCTET_G_LO); + storage->tx_bytes |= (u64)(readl(base + XGMAC_MMC_TXOCTET_G_HI)) << 32; + + count = readl(base + XGMAC_MMC_TXFRAME_GB_LO); + storage->tx_errors = count - readl(base + XGMAC_MMC_TXFRAME_G_LO); + storage->tx_packets = count; + storage->tx_fifo_errors = readl(base + XGMAC_MMC_TXUNDERFLOW); + + writel(0, base + XGMAC_MMC_CTRL); + spin_unlock_bh(&priv->stats_lock); + return storage; +} + +static int xgmac_set_mac_address(struct net_device *dev, void *p) +{ + struct xgmac_priv *priv = netdev_priv(dev); + void __iomem *ioaddr = priv->base; + struct sockaddr *addr = p; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + + xgmac_set_mac_addr(ioaddr, dev->dev_addr, 0); + + return 0; +} + +static int xgmac_set_features(struct net_device *dev, netdev_features_t features) +{ + u32 ctrl; + struct xgmac_priv *priv = netdev_priv(dev); + void __iomem *ioaddr = priv->base; + u32 changed = dev->features ^ features; + + if (!(changed & NETIF_F_RXCSUM)) + return 0; + + ctrl = readl(ioaddr + XGMAC_CONTROL); + if (features & NETIF_F_RXCSUM) + ctrl |= XGMAC_CONTROL_IPC; + else + ctrl &= ~XGMAC_CONTROL_IPC; + writel(ctrl, ioaddr + XGMAC_CONTROL); + + return 0; +} + +static const struct net_device_ops xgmac_netdev_ops = { + .ndo_open = xgmac_open, + .ndo_start_xmit = xgmac_xmit, + .ndo_stop = xgmac_stop, + .ndo_change_mtu = xgmac_change_mtu, + .ndo_set_rx_mode = xgmac_set_rx_mode, + .ndo_tx_timeout = xgmac_tx_timeout, + .ndo_get_stats64 = xgmac_get_stats64, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = xgmac_poll_controller, +#endif + .ndo_set_mac_address = xgmac_set_mac_address, + .ndo_set_features = xgmac_set_features, +}; + +static int xgmac_ethtool_getsettings(struct net_device *dev, + struct ethtool_cmd *cmd) +{ + cmd->autoneg = 0; + cmd->duplex = DUPLEX_FULL; + ethtool_cmd_speed_set(cmd, 10000); + cmd->supported = 0; + cmd->advertising = 0; + cmd->transceiver = XCVR_INTERNAL; + return 0; +} + +static void xgmac_get_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct xgmac_priv *priv = netdev_priv(netdev); + + pause->rx_pause = priv->rx_pause; + pause->tx_pause = priv->tx_pause; +} + +static int xgmac_set_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct xgmac_priv *priv = netdev_priv(netdev); + + if (pause->autoneg) + return -EINVAL; + + return xgmac_set_flow_ctrl(priv, pause->rx_pause, pause->tx_pause); +} + +struct xgmac_stats { + char stat_string[ETH_GSTRING_LEN]; + int stat_offset; + bool is_reg; +}; + +#define XGMAC_STAT(m) \ + { #m, offsetof(struct xgmac_priv, xstats.m), false } +#define XGMAC_HW_STAT(m, reg_offset) \ + { #m, reg_offset, true } + +static const struct xgmac_stats xgmac_gstrings_stats[] = { + XGMAC_STAT(tx_frame_flushed), + XGMAC_STAT(tx_payload_error), + XGMAC_STAT(tx_ip_header_error), + XGMAC_STAT(tx_local_fault), + XGMAC_STAT(tx_remote_fault), + XGMAC_STAT(tx_early), + XGMAC_STAT(tx_process_stopped), + XGMAC_STAT(tx_jabber), + XGMAC_STAT(rx_buf_unav), + XGMAC_STAT(rx_process_stopped), + XGMAC_STAT(rx_payload_error), + XGMAC_STAT(rx_ip_header_error), + XGMAC_STAT(rx_da_filter_fail), + XGMAC_STAT(rx_sa_filter_fail), + XGMAC_STAT(fatal_bus_error), + XGMAC_HW_STAT(rx_watchdog, XGMAC_MMC_RXWATCHDOG), + XGMAC_HW_STAT(tx_vlan, XGMAC_MMC_TXVLANFRAME), + XGMAC_HW_STAT(rx_vlan, XGMAC_MMC_RXVLANFRAME), + XGMAC_HW_STAT(tx_pause, XGMAC_MMC_TXPAUSEFRAME), + XGMAC_HW_STAT(rx_pause, XGMAC_MMC_RXPAUSEFRAME), +}; +#define XGMAC_STATS_LEN ARRAY_SIZE(xgmac_gstrings_stats) + +static void xgmac_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *dummy, + u64 *data) +{ + struct xgmac_priv *priv = netdev_priv(dev); + void *p = priv; + int i; + + for (i = 0; i < XGMAC_STATS_LEN; i++) { + if (xgmac_gstrings_stats[i].is_reg) + *data++ = readl(priv->base + + xgmac_gstrings_stats[i].stat_offset); + else + *data++ = *(u32 *)(p + + xgmac_gstrings_stats[i].stat_offset); + } +} + +static int xgmac_get_sset_count(struct net_device *netdev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return XGMAC_STATS_LEN; + default: + return -EINVAL; + } +} + +static void xgmac_get_strings(struct net_device *dev, u32 stringset, + u8 *data) +{ + int i; + u8 *p = data; + + switch (stringset) { + case ETH_SS_STATS: + for (i = 0; i < XGMAC_STATS_LEN; i++) { + memcpy(p, xgmac_gstrings_stats[i].stat_string, + ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; + } + break; + default: + WARN_ON(1); + break; + } +} + +static void xgmac_get_wol(struct net_device *dev, + struct ethtool_wolinfo *wol) +{ + struct xgmac_priv *priv = netdev_priv(dev); + + if (device_can_wakeup(priv->device)) { + wol->supported = WAKE_MAGIC | WAKE_UCAST; + wol->wolopts = priv->wolopts; + } +} + +static int xgmac_set_wol(struct net_device *dev, + struct ethtool_wolinfo *wol) +{ + struct xgmac_priv *priv = netdev_priv(dev); + u32 support = WAKE_MAGIC | WAKE_UCAST; + + if (!device_can_wakeup(priv->device)) + return -ENOTSUPP; + + if (wol->wolopts & ~support) + return -EINVAL; + + priv->wolopts = wol->wolopts; + + if (wol->wolopts) { + device_set_wakeup_enable(priv->device, 1); + enable_irq_wake(dev->irq); + } else { + device_set_wakeup_enable(priv->device, 0); + disable_irq_wake(dev->irq); + } + + return 0; +} + +static struct ethtool_ops xgmac_ethtool_ops = { + .get_settings = xgmac_ethtool_getsettings, + .get_link = ethtool_op_get_link, + .get_pauseparam = xgmac_get_pauseparam, + .set_pauseparam = xgmac_set_pauseparam, + .get_ethtool_stats = xgmac_get_ethtool_stats, + .get_strings = xgmac_get_strings, + .get_wol = xgmac_get_wol, + .set_wol = xgmac_set_wol, + .get_sset_count = xgmac_get_sset_count, +}; + +/** + * xgmac_probe + * @pdev: platform device pointer + * Description: the driver is initialized through platform_device. + */ +static int xgmac_probe(struct platform_device *pdev) +{ + int ret = 0; + struct resource *res; + struct net_device *ndev = NULL; + struct xgmac_priv *priv = NULL; + u32 uid; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + if (!request_mem_region(res->start, resource_size(res), pdev->name)) + return -EBUSY; + + ndev = alloc_etherdev(sizeof(struct xgmac_priv)); + if (!ndev) { + ret = -ENOMEM; + goto err_alloc; + } + + SET_NETDEV_DEV(ndev, &pdev->dev); + priv = netdev_priv(ndev); + platform_set_drvdata(pdev, ndev); + ether_setup(ndev); + ndev->netdev_ops = &xgmac_netdev_ops; + SET_ETHTOOL_OPS(ndev, &xgmac_ethtool_ops); + spin_lock_init(&priv->stats_lock); + + priv->device = &pdev->dev; + priv->dev = ndev; + priv->rx_pause = 1; + priv->tx_pause = 1; + + priv->base = ioremap(res->start, resource_size(res)); + if (!priv->base) { + netdev_err(ndev, "ioremap failed\n"); + ret = -ENOMEM; + goto err_io; + } + + uid = readl(priv->base + XGMAC_VERSION); + netdev_info(ndev, "h/w version is 0x%x\n", uid); + + writel(0, priv->base + XGMAC_DMA_INTR_ENA); + ndev->irq = platform_get_irq(pdev, 0); + if (ndev->irq == -ENXIO) { + netdev_err(ndev, "No irq resource\n"); + ret = ndev->irq; + goto err_irq; + } + + ret = request_irq(ndev->irq, xgmac_interrupt, 0, + dev_name(&pdev->dev), ndev); + if (ret < 0) { + netdev_err(ndev, "Could not request irq %d - ret %d)\n", + ndev->irq, ret); + goto err_irq; + } + + priv->pmt_irq = platform_get_irq(pdev, 1); + if (priv->pmt_irq == -ENXIO) { + netdev_err(ndev, "No pmt irq resource\n"); + ret = priv->pmt_irq; + goto err_pmt_irq; + } + + ret = request_irq(priv->pmt_irq, xgmac_pmt_interrupt, 0, + dev_name(&pdev->dev), ndev); + if (ret < 0) { + netdev_err(ndev, "Could not request irq %d - ret %d)\n", + priv->pmt_irq, ret); + goto err_pmt_irq; + } + + device_set_wakeup_capable(&pdev->dev, 1); + if (device_can_wakeup(priv->device)) + priv->wolopts = WAKE_MAGIC; /* Magic Frame as default */ + + ndev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA; + if (readl(priv->base + XGMAC_DMA_HW_FEATURE) & DMA_HW_FEAT_TXCOESEL) + ndev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_RXCSUM; + ndev->features |= ndev->hw_features; + ndev->priv_flags |= IFF_UNICAST_FLT; + + /* Get the MAC address */ + xgmac_get_mac_addr(priv->base, ndev->dev_addr, 0); + if (!is_valid_ether_addr(ndev->dev_addr)) + netdev_warn(ndev, "MAC address %pM not valid", + ndev->dev_addr); + + netif_napi_add(ndev, &priv->napi, xgmac_poll, 64); + ret = register_netdev(ndev); + if (ret) + goto err_reg; + + return 0; + +err_reg: + netif_napi_del(&priv->napi); + free_irq(priv->pmt_irq, ndev); +err_pmt_irq: + free_irq(ndev->irq, ndev); +err_irq: + iounmap(priv->base); +err_io: + free_netdev(ndev); +err_alloc: + release_mem_region(res->start, resource_size(res)); + platform_set_drvdata(pdev, NULL); + return ret; +} + +/** + * xgmac_dvr_remove + * @pdev: platform device pointer + * Description: this function resets the TX/RX processes, disables the MAC RX/TX + * changes the link status, releases the DMA descriptor rings, + * unregisters the MDIO bus and unmaps the allocated memory. + */ +static int xgmac_remove(struct platform_device *pdev) +{ + struct net_device *ndev = platform_get_drvdata(pdev); + struct xgmac_priv *priv = netdev_priv(ndev); + struct resource *res; + + xgmac_mac_disable(priv->base); + + /* Free the IRQ lines */ + free_irq(ndev->irq, ndev); + free_irq(priv->pmt_irq, ndev); + + platform_set_drvdata(pdev, NULL); + unregister_netdev(ndev); + netif_napi_del(&priv->napi); + + iounmap(priv->base); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, resource_size(res)); + + free_netdev(ndev); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static void xgmac_pmt(void __iomem *ioaddr, unsigned long mode) +{ + unsigned int pmt = 0; + + if (mode & WAKE_MAGIC) + pmt |= XGMAC_PMT_POWERDOWN | XGMAC_PMT_MAGIC_PKT; + if (mode & WAKE_UCAST) + pmt |= XGMAC_PMT_POWERDOWN | XGMAC_PMT_GLBL_UNICAST; + + writel(pmt, ioaddr + XGMAC_PMT); +} + +static int xgmac_suspend(struct device *dev) +{ + struct net_device *ndev = platform_get_drvdata(to_platform_device(dev)); + struct xgmac_priv *priv = netdev_priv(ndev); + u32 value; + + if (!ndev || !netif_running(ndev)) + return 0; + + netif_device_detach(ndev); + napi_disable(&priv->napi); + writel(0, priv->base + XGMAC_DMA_INTR_ENA); + + if (device_may_wakeup(priv->device)) { + /* Stop TX/RX DMA Only */ + value = readl(priv->base + XGMAC_DMA_CONTROL); + value &= ~(DMA_CONTROL_ST | DMA_CONTROL_SR); + writel(value, priv->base + XGMAC_DMA_CONTROL); + + xgmac_pmt(priv->base, priv->wolopts); + } else + xgmac_mac_disable(priv->base); + + return 0; +} + +static int xgmac_resume(struct device *dev) +{ + struct net_device *ndev = platform_get_drvdata(to_platform_device(dev)); + struct xgmac_priv *priv = netdev_priv(ndev); + void __iomem *ioaddr = priv->base; + + if (!netif_running(ndev)) + return 0; + + xgmac_pmt(ioaddr, 0); + + /* Enable the MAC and DMA */ + xgmac_mac_enable(ioaddr); + writel(DMA_INTR_DEFAULT_MASK, ioaddr + XGMAC_DMA_STATUS); + writel(DMA_INTR_DEFAULT_MASK, ioaddr + XGMAC_DMA_INTR_ENA); + + netif_device_attach(ndev); + napi_enable(&priv->napi); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(xgmac_pm_ops, xgmac_suspend, xgmac_resume); +#define XGMAC_PM_OPS (&xgmac_pm_ops) +#else +#define XGMAC_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP */ + +static const struct of_device_id xgmac_of_match[] = { + { .compatible = "calxeda,hb-xgmac", }, + {}, +}; +MODULE_DEVICE_TABLE(of, xgmac_of_match); + +static struct platform_driver xgmac_driver = { + .driver = { + .name = "calxedaxgmac", + .of_match_table = xgmac_of_match, + }, + .probe = xgmac_probe, + .remove = xgmac_remove, + .driver.pm = XGMAC_PM_OPS, +}; + +module_platform_driver(xgmac_driver); + +MODULE_AUTHOR("Calxeda, Inc."); +MODULE_DESCRIPTION("Calxeda 10G XGMAC driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-70-g09d2 From bf55499e6ee927e047feed85349365481289bd75 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 29 Nov 2011 18:36:48 -0700 Subject: ASoC: Tegra I2S: Add device tree binding Signed-off-by: Stephen Warren Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/tegra20-i2s.txt | 17 ++++++++++++++ sound/soc/tegra/tegra_i2s.c | 27 ++++++++++++++++++---- 2 files changed, 39 insertions(+), 5 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/tegra20-i2s.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/sound/tegra20-i2s.txt b/Documentation/devicetree/bindings/sound/tegra20-i2s.txt new file mode 100644 index 00000000000..0df2b5c816e --- /dev/null +++ b/Documentation/devicetree/bindings/sound/tegra20-i2s.txt @@ -0,0 +1,17 @@ +NVIDIA Tegra 20 I2S controller + +Required properties: +- compatible : "nvidia,tegra20-i2s" +- reg : Should contain I2S registers location and length +- interrupts : Should contain I2S interrupt +- nvidia,dma-request-selector : The Tegra DMA controller's phandle and + request selector for this I2S controller + +Example: + +i2s@70002800 { + compatible = "nvidia,tegra20-i2s"; + reg = <0x70002800 0x200>; + interrupts = < 45 >; + nvidia,dma-request-selector = < &apbdma 2 >; +}; diff --git a/sound/soc/tegra/tegra_i2s.c b/sound/soc/tegra/tegra_i2s.c index ca4d0c0a913..33509de5254 100644 --- a/sound/soc/tegra/tegra_i2s.c +++ b/sound/soc/tegra/tegra_i2s.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -331,6 +332,8 @@ static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev) { struct tegra_i2s * i2s; struct resource *mem, *memregion, *dmareq; + u32 of_dma[2]; + u32 dma_ch; int ret; i2s = devm_kzalloc(&pdev->dev, sizeof(struct tegra_i2s), GFP_KERNEL); @@ -360,9 +363,16 @@ static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev) dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0); if (!dmareq) { - dev_err(&pdev->dev, "No DMA resource\n"); - ret = -ENODEV; - goto err_clk_put; + if (of_property_read_u32_array(pdev->dev.of_node, + "nvidia,dma-request-selector", + of_dma, 2) < 0) { + dev_err(&pdev->dev, "No DMA resource\n"); + ret = -ENODEV; + goto err_clk_put; + } + dma_ch = of_dma[1]; + } else { + dma_ch = dmareq->start; } memregion = devm_request_mem_region(&pdev->dev, mem->start, @@ -383,12 +393,12 @@ static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev) i2s->capture_dma_data.addr = mem->start + TEGRA_I2S_FIFO2; i2s->capture_dma_data.wrap = 4; i2s->capture_dma_data.width = 32; - i2s->capture_dma_data.req_sel = dmareq->start; + i2s->capture_dma_data.req_sel = dma_ch; i2s->playback_dma_data.addr = mem->start + TEGRA_I2S_FIFO1; i2s->playback_dma_data.wrap = 4; i2s->playback_dma_data.width = 32; - i2s->playback_dma_data.req_sel = dmareq->start; + i2s->playback_dma_data.req_sel = dma_ch; i2s->reg_ctrl = TEGRA_I2S_CTRL_FIFO_FORMAT_PACKED; @@ -422,10 +432,16 @@ static int __devexit tegra_i2s_platform_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id tegra_i2s_of_match[] __devinitconst = { + { .compatible = "nvidia,tegra20-i2s", }, + {}, +}; + static struct platform_driver tegra_i2s_driver = { .driver = { .name = DRV_NAME, .owner = THIS_MODULE, + .of_match_table = tegra_i2s_of_match, }, .probe = tegra_i2s_platform_probe, .remove = __devexit_p(tegra_i2s_platform_remove), @@ -436,3 +452,4 @@ MODULE_AUTHOR("Stephen Warren "); MODULE_DESCRIPTION("Tegra I2S ASoC driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" DRV_NAME); +MODULE_DEVICE_TABLE(of, tegra_i2s_of_match); -- cgit v1.2.3-70-g09d2 From e285e44d91fe5a89e0d9fe4f5dda4f9e8c8a3c7e Mon Sep 17 00:00:00 2001 From: Wolfgang Grandegger Date: Wed, 30 Nov 2011 23:41:20 +0000 Subject: can: cc770: add platform bus driver for the CC770 and AN82527 This driver works with both, static platform data and device tree bindings. It has been tested on a TQM855L board with two AN82527 CAN controllers on the local bus. CC: Devicetree-discuss@lists.ozlabs.org CC: linuxppc-dev@ozlabs.org CC: Kumar Gala Signed-off-by: Wolfgang Grandegger Acked-by: Marc Kleine-Budde Signed-off-by: David S. Miller --- .../devicetree/bindings/net/can/cc770.txt | 53 ++++ drivers/net/can/cc770/Kconfig | 7 + drivers/net/can/cc770/Makefile | 1 + drivers/net/can/cc770/cc770_platform.c | 272 +++++++++++++++++++++ 4 files changed, 333 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/can/cc770.txt create mode 100644 drivers/net/can/cc770/cc770_platform.c (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/net/can/cc770.txt b/Documentation/devicetree/bindings/net/can/cc770.txt new file mode 100644 index 00000000000..77027bf6460 --- /dev/null +++ b/Documentation/devicetree/bindings/net/can/cc770.txt @@ -0,0 +1,53 @@ +Memory mapped Bosch CC770 and Intel AN82527 CAN controller + +Note: The CC770 is a CAN controller from Bosch, which is 100% +compatible with the old AN82527 from Intel, but with "bugs" being fixed. + +Required properties: + +- compatible : should be "bosch,cc770" for the CC770 and "intc,82527" + for the AN82527. + +- reg : should specify the chip select, address offset and size required + to map the registers of the controller. The size is usually 0x80. + +- interrupts : property with a value describing the interrupt source + (number and sensitivity) required for the controller. + +Optional properties: + +- bosch,external-clock-frequency : frequency of the external oscillator + clock in Hz. Note that the internal clock frequency used by the + controller is half of that value. If not specified, a default + value of 16000000 (16 MHz) is used. + +- bosch,clock-out-frequency : slock frequency in Hz on the CLKOUT pin. + If not specified or if the specified value is 0, the CLKOUT pin + will be disabled. + +- bosch,slew-rate : slew rate of the CLKOUT signal. If not specified, + a resonable value will be calculated. + +- bosch,disconnect-rx0-input : see data sheet. + +- bosch,disconnect-rx1-input : see data sheet. + +- bosch,disconnect-tx1-output : see data sheet. + +- bosch,polarity-dominant : see data sheet. + +- bosch,divide-memory-clock : see data sheet. + +- bosch,iso-low-speed-mux : see data sheet. + +For further information, please have a look to the CC770 or AN82527. + +Examples: + +can@3,100 { + compatible = "bosch,cc770"; + reg = <3 0x100 0x80>; + interrupts = <2 0>; + interrupt-parent = <&mpic>; + bosch,external-clock-frequency = <16000000>; +}; diff --git a/drivers/net/can/cc770/Kconfig b/drivers/net/can/cc770/Kconfig index 28e4d4810f4..22c07a8c8b4 100644 --- a/drivers/net/can/cc770/Kconfig +++ b/drivers/net/can/cc770/Kconfig @@ -11,4 +11,11 @@ config CAN_CC770_ISA connected to the ISA bus using I/O port, memory mapped or indirect access. +config CAN_CC770_PLATFORM + tristate "Generic Platform Bus based CC770 driver" + ---help--- + This driver adds support for the CC770 and AN82527 chips + connected to the "platform bus" (Linux abstraction for directly + to the processor attached devices). + endif diff --git a/drivers/net/can/cc770/Makefile b/drivers/net/can/cc770/Makefile index 872ecffa80b..9fb8321b33e 100644 --- a/drivers/net/can/cc770/Makefile +++ b/drivers/net/can/cc770/Makefile @@ -4,5 +4,6 @@ obj-$(CONFIG_CAN_CC770) += cc770.o obj-$(CONFIG_CAN_CC770_ISA) += cc770_isa.o +obj-$(CONFIG_CAN_CC770_PLATFORM) += cc770_platform.o ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG diff --git a/drivers/net/can/cc770/cc770_platform.c b/drivers/net/can/cc770/cc770_platform.c new file mode 100644 index 00000000000..53115eee807 --- /dev/null +++ b/drivers/net/can/cc770/cc770_platform.c @@ -0,0 +1,272 @@ +/* + * Driver for CC770 and AN82527 CAN controllers on the platform bus + * + * Copyright (C) 2009, 2011 Wolfgang Grandegger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the version 2 of the GNU General Public License + * as published by the Free Software Foundation + * + * 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. + */ + +/* + * If platform data are used you should have similar definitions + * in your board-specific code: + * + * static struct cc770_platform_data myboard_cc770_pdata = { + * .osc_freq = 16000000, + * .cir = 0x41, + * .cor = 0x20, + * .bcr = 0x40, + * }; + * + * Please see include/linux/can/platform/cc770.h for description of + * above fields. + * + * If the device tree is used, you need a CAN node definition in your + * DTS file similar to: + * + * can@3,100 { + * compatible = "bosch,cc770"; + * reg = <3 0x100 0x80>; + * interrupts = <2 0>; + * interrupt-parent = <&mpic>; + * bosch,external-clock-frequency = <16000000>; + * }; + * + * See "Documentation/devicetree/bindings/net/can/cc770.txt" for further + * information. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cc770.h" + +#define DRV_NAME "cc770_platform" + +MODULE_AUTHOR("Wolfgang Grandegger "); +MODULE_DESCRIPTION("Socket-CAN driver for CC770 on the platform bus"); +MODULE_LICENSE("GPL v2"); + +#define CC770_PLATFORM_CAN_CLOCK 16000000 + +static u8 cc770_platform_read_reg(const struct cc770_priv *priv, int reg) +{ + return ioread8(priv->reg_base + reg); +} + +static void cc770_platform_write_reg(const struct cc770_priv *priv, int reg, + u8 val) +{ + iowrite8(val, priv->reg_base + reg); +} + +static int __devinit cc770_get_of_node_data(struct platform_device *pdev, + struct cc770_priv *priv) +{ + struct device_node *np = pdev->dev.of_node; + const u32 *prop; + int prop_size; + u32 clkext; + + prop = of_get_property(np, "bosch,external-clock-frequency", + &prop_size); + if (prop && (prop_size == sizeof(u32))) + clkext = *prop; + else + clkext = CC770_PLATFORM_CAN_CLOCK; /* default */ + priv->can.clock.freq = clkext; + + /* The system clock may not exceed 10 MHz */ + if (priv->can.clock.freq > 10000000) { + priv->cpu_interface |= CPUIF_DSC; + priv->can.clock.freq /= 2; + } + + /* The memory clock may not exceed 8 MHz */ + if (priv->can.clock.freq > 8000000) + priv->cpu_interface |= CPUIF_DMC; + + if (of_get_property(np, "bosch,divide-memory-clock", NULL)) + priv->cpu_interface |= CPUIF_DMC; + if (of_get_property(np, "bosch,iso-low-speed-mux", NULL)) + priv->cpu_interface |= CPUIF_MUX; + + if (!of_get_property(np, "bosch,no-comperator-bypass", NULL)) + priv->bus_config |= BUSCFG_CBY; + if (of_get_property(np, "bosch,disconnect-rx0-input", NULL)) + priv->bus_config |= BUSCFG_DR0; + if (of_get_property(np, "bosch,disconnect-rx1-input", NULL)) + priv->bus_config |= BUSCFG_DR1; + if (of_get_property(np, "bosch,disconnect-tx1-output", NULL)) + priv->bus_config |= BUSCFG_DT1; + if (of_get_property(np, "bosch,polarity-dominant", NULL)) + priv->bus_config |= BUSCFG_POL; + + prop = of_get_property(np, "bosch,clock-out-frequency", &prop_size); + if (prop && (prop_size == sizeof(u32)) && *prop > 0) { + u32 cdv = clkext / *prop; + int slew; + + if (cdv > 0 && cdv < 16) { + priv->cpu_interface |= CPUIF_CEN; + priv->clkout |= (cdv - 1) & CLKOUT_CD_MASK; + + prop = of_get_property(np, "bosch,slew-rate", + &prop_size); + if (prop && (prop_size == sizeof(u32))) { + slew = *prop; + } else { + /* Determine default slew rate */ + slew = (CLKOUT_SL_MASK >> + CLKOUT_SL_SHIFT) - + ((cdv * clkext - 1) / 8000000); + if (slew < 0) + slew = 0; + } + priv->clkout |= (slew << CLKOUT_SL_SHIFT) & + CLKOUT_SL_MASK; + } else { + dev_dbg(&pdev->dev, "invalid clock-out-frequency\n"); + } + } + + return 0; +} + +static int __devinit cc770_get_platform_data(struct platform_device *pdev, + struct cc770_priv *priv) +{ + + struct cc770_platform_data *pdata = pdev->dev.platform_data; + + priv->can.clock.freq = pdata->osc_freq; + if (priv->cpu_interface | CPUIF_DSC) + priv->can.clock.freq /= 2; + priv->clkout = pdata->cor; + priv->bus_config = pdata->bcr; + priv->cpu_interface = pdata->cir; + + return 0; +} + +static int __devinit cc770_platform_probe(struct platform_device *pdev) +{ + struct net_device *dev; + struct cc770_priv *priv; + struct resource *mem; + resource_size_t mem_size; + void __iomem *base; + int err, irq; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + irq = platform_get_irq(pdev, 0); + if (!mem || irq <= 0) + return -ENODEV; + + mem_size = resource_size(mem); + if (!request_mem_region(mem->start, mem_size, pdev->name)) + return -EBUSY; + + base = ioremap(mem->start, mem_size); + if (!base) { + err = -ENOMEM; + goto exit_release_mem; + } + + dev = alloc_cc770dev(0); + if (!dev) { + err = -ENOMEM; + goto exit_unmap_mem; + } + + dev->irq = irq; + priv = netdev_priv(dev); + priv->read_reg = cc770_platform_read_reg; + priv->write_reg = cc770_platform_write_reg; + priv->irq_flags = IRQF_SHARED; + priv->reg_base = base; + + if (pdev->dev.of_node) + err = cc770_get_of_node_data(pdev, priv); + else if (pdev->dev.platform_data) + err = cc770_get_platform_data(pdev, priv); + else + err = -ENODEV; + if (err) + goto exit_free_cc770; + + dev_dbg(&pdev->dev, + "reg_base=0x%p irq=%d clock=%d cpu_interface=0x%02x " + "bus_config=0x%02x clkout=0x%02x\n", + priv->reg_base, dev->irq, priv->can.clock.freq, + priv->cpu_interface, priv->bus_config, priv->clkout); + + dev_set_drvdata(&pdev->dev, dev); + SET_NETDEV_DEV(dev, &pdev->dev); + + err = register_cc770dev(dev); + if (err) { + dev_err(&pdev->dev, + "couldn't register CC700 device (err=%d)\n", err); + goto exit_free_cc770; + } + + return 0; + +exit_free_cc770: + free_cc770dev(dev); +exit_unmap_mem: + iounmap(base); +exit_release_mem: + release_mem_region(mem->start, mem_size); + + return err; +} + +static int __devexit cc770_platform_remove(struct platform_device *pdev) +{ + struct net_device *dev = dev_get_drvdata(&pdev->dev); + struct cc770_priv *priv = netdev_priv(dev); + struct resource *mem; + + unregister_cc770dev(dev); + iounmap(priv->reg_base); + free_cc770dev(dev); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(mem->start, resource_size(mem)); + + return 0; +} + +static struct of_device_id __devinitdata cc770_platform_table[] = { + {.compatible = "bosch,cc770"}, /* CC770 from Bosch */ + {.compatible = "intc,82527"}, /* AN82527 from Intel CP */ + {}, +}; + +static struct platform_driver cc770_platform_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = cc770_platform_table, + }, + .probe = cc770_platform_probe, + .remove = __devexit_p(cc770_platform_remove), +}; + +module_platform_driver(cc770_platform_driver); -- cgit v1.2.3-70-g09d2 From 5d680b3a84b3e870fc1ea01495935e58e17de7aa Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 2 Dec 2011 15:08:41 -0700 Subject: ASoC: WM8903: Add device tree binding Document the device tree binding for the WM8903 codec, and modify the driver to extract platform data from the device tree, if present. Based on work by John Bonesio, but significantly reworked since then. Signed-off-by: Stephen Warren Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/wm8903.txt | 50 ++++++++++++++++++++++ sound/soc/codecs/wm8903.c | 49 +++++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/wm8903.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/sound/wm8903.txt b/Documentation/devicetree/bindings/sound/wm8903.txt new file mode 100644 index 00000000000..f102cbc4269 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/wm8903.txt @@ -0,0 +1,50 @@ +WM8903 audio CODEC + +This device supports I2C only. + +Required properties: + + - compatible : "wlf,wm8903" + + - reg : the I2C address of the device. + + - gpio-controller : Indicates this device is a GPIO controller. + + - #gpio-cells : Should be two. The first cell is the pin number and the + second cell is used to specify optional parameters (currently unused). + +Optional properties: + + - interrupts : The interrupt line the codec is connected to. + + - micdet-cfg : Default register value for R6 (Mic Bias). If absent, the + default is 0. + + - micdet-delay : The debounce delay for microphone detection in mS. If + absent, the default is 100. + + - gpio-cfg : A list of GPIO configuration register values. The list must + be 5 entries long. If absent, no configuration of these registers is + performed. If any entry has the value 0xffffffff, that GPIO's + configuration will not be modified. + +Example: + +codec: wm8903@1a { + compatible = "wlf,wm8903"; + reg = <0x1a>; + interrupts = < 347 >; + + gpio-controller; + #gpio-cells = <2>; + + micdet-cfg = <0>; + micdet-delay = <100>; + gpio-cfg = < + 0x0600 /* DMIC_LR, output */ + 0x0680 /* DMIC_DAT, input */ + 0x0000 /* GPIO, output, low */ + 0x0200 /* Interrupt, output */ + 0x01a0 /* BCLK, input, active high */ + >; +}; diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index b4f2c906b2f..adfbefaaab2 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -2070,6 +2070,49 @@ static int wm8903_set_pdata_irq_trigger(struct i2c_client *i2c, return 0; } +static int wm8903_set_pdata_from_of(struct i2c_client *i2c, + struct wm8903_platform_data *pdata) +{ + const struct device_node *np = i2c->dev.of_node; + u32 val32; + int i; + + if (of_property_read_u32(np, "micdet-cfg", &val32) >= 0) + pdata->micdet_cfg = val32; + + if (of_property_read_u32(np, "micdet-delay", &val32) >= 0) + pdata->micdet_delay = val32; + + if (of_property_read_u32_array(np, "gpio-cfg", pdata->gpio_cfg, + ARRAY_SIZE(pdata->gpio_cfg)) >= 0) { + /* + * In device tree: 0 means "write 0", + * 0xffffffff means "don't touch". + * + * In platform data: 0 means "don't touch", + * 0x8000 means "write 0". + * + * Note: WM8903_GPIO_CONFIG_ZERO == 0x8000. + * + * Convert from DT to pdata representation here, + * so no other code needs to change. + */ + for (i = 0; i < ARRAY_SIZE(pdata->gpio_cfg); i++) { + if (pdata->gpio_cfg[i] == 0) { + pdata->gpio_cfg[i] = WM8903_GPIO_CONFIG_ZERO; + } else if (pdata->gpio_cfg[i] == 0xffffffff) { + pdata->gpio_cfg[i] = 0; + } else if (pdata->gpio_cfg[i] > 0x7fff) { + dev_err(&i2c->dev, "Invalid gpio-cfg[%d] %x\n", + i, pdata->gpio_cfg[i]); + return -EINVAL; + } + } + } + + return 0; +} + static __devinit int wm8903_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -2111,6 +2154,12 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c, if (ret != 0) return ret; } + + if (i2c->dev.of_node) { + ret = wm8903_set_pdata_from_of(i2c, wm8903->pdata); + if (ret != 0) + return ret; + } } ret = regmap_read(wm8903->regmap, WM8903_SW_RESET_AND_ID, &val); -- cgit v1.2.3-70-g09d2 From c27317c0ed114152d02b2ed40056f232e5732b9d Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Fri, 4 Nov 2011 09:12:39 +0000 Subject: arm/dt: add basic usb nodes to tegra device trees For now they are a minimal binding. It needs to be amended with vendor-specific settings for phy setup and link tuning, etc. v2: Added bindings specification and phy_type properties Signed-off-by: Olof Johansson Acked-by: Grant Likely Acked-by: Stephen Warren --- Documentation/devicetree/bindings/usb/tegra-usb.txt | 13 +++++++++++++ arch/arm/boot/dts/tegra-seaboard.dts | 4 ++++ arch/arm/boot/dts/tegra20.dtsi | 21 +++++++++++++++++++++ 3 files changed, 38 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/tegra-usb.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/usb/tegra-usb.txt b/Documentation/devicetree/bindings/usb/tegra-usb.txt new file mode 100644 index 00000000000..035d63d5646 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/tegra-usb.txt @@ -0,0 +1,13 @@ +Tegra SOC USB controllers + +The device node for a USB controller that is part of a Tegra +SOC is as described in the document "Open Firmware Recommended +Practice : Universal Serial Bus" with the following modifications +and additions : + +Required properties : + - compatible : Should be "nvidia,tegra20-ehci" for USB controllers + used in host mode. + - phy_type : Should be one of "ulpi" or "utmi". + - nvidia,vbus-gpio : If present, specifies a gpio that needs to be + activated for the bus to be powered. diff --git a/arch/arm/boot/dts/tegra-seaboard.dts b/arch/arm/boot/dts/tegra-seaboard.dts index a72299b8e66..88c682a26cb 100644 --- a/arch/arm/boot/dts/tegra-seaboard.dts +++ b/arch/arm/boot/dts/tegra-seaboard.dts @@ -29,4 +29,8 @@ sdhci@c8000600 { support-8bit; }; + + usb@c5000000 { + nvidia,vbus-gpio = <&gpio 24 0>; /* PD0 */ + }; }; diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index 65d7e6a333e..795b921d92f 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -143,5 +143,26 @@ reg = <0xc8000600 0x200>; interrupts = < 63 >; }; + + usb@c5000000 { + compatible = "nvidia,tegra20-ehci", "usb-ehci"; + reg = <0xc5000000 0x4000>; + interrupts = < 52 >; + phy_type = "utmi"; + }; + + usb@c5004000 { + compatible = "nvidia,tegra20-ehci", "usb-ehci"; + reg = <0xc5004000 0x4000>; + interrupts = < 53 >; + phy_type = "ulpi"; + }; + + usb@c5008000 { + compatible = "nvidia,tegra20-ehci", "usb-ehci"; + reg = <0xc5008000 0x4000>; + interrupts = < 129 >; + phy_type = "utmi"; + }; }; -- cgit v1.2.3-70-g09d2 From cf763c2e606e9e427ed854c470911e816be1101e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 22 Nov 2011 18:22:29 +0000 Subject: mfd: Add basic device tree binding for wm8994 Add a placeholder device tree binding for the wm8994 driver. At present the binding is essentially null as none of the platform data is supported, and at least some of that will depend on the pending regulator bindings. Signed-off-by: Mark Brown Acked-by: Samuel Ortiz --- Documentation/devicetree/bindings/sound/wm8994.txt | 18 ++++++++++++++++++ drivers/mfd/wm8994-core.c | 9 +++++++++ 2 files changed, 27 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/wm8994.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/sound/wm8994.txt b/Documentation/devicetree/bindings/sound/wm8994.txt new file mode 100644 index 00000000000..7a7eb1e7bda --- /dev/null +++ b/Documentation/devicetree/bindings/sound/wm8994.txt @@ -0,0 +1,18 @@ +WM1811/WM8994/WM8958 audio CODEC + +These devices support both I2C and SPI (configured with pin strapping +on the board). + +Required properties: + + - compatible : "wlf,wm1811", "wlf,wm8994", "wlf,wm8958" + + - reg : the I2C address of the device for I2C, the chip select + number for SPI. + +Example: + +codec: wm8994@1a { + compatible = "wlf,wm8994"; + reg = <0x1a>; +}; diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 5d6ba132837..74d4746086c 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -581,6 +581,14 @@ static void wm8994_device_exit(struct wm8994 *wm8994) kfree(wm8994); } +static const struct of_device_id wm8994_of_match[] = { + { .compatible = "wlf,wm1811", }, + { .compatible = "wlf,wm8994", }, + { .compatible = "wlf,wm8958", }, + { } +}; +MODULE_DEVICE_TABLE(of, wm8994_of_match); + static int wm8994_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -633,6 +641,7 @@ static struct i2c_driver wm8994_i2c_driver = { .name = "wm8994", .owner = THIS_MODULE, .pm = &wm8994_pm_ops, + .of_match_table = wm8994_of_match, }, .probe = wm8994_i2c_probe, .remove = wm8994_i2c_remove, -- cgit v1.2.3-70-g09d2 From 3c8276c6bc912025db50ff7e93af6bc7c3de0c8c Mon Sep 17 00:00:00 2001 From: Richard Zhao Date: Wed, 14 Dec 2011 09:26:46 +0800 Subject: arm/imx6: add imx6q sabrelite board support - Add basic board dts file - Add board compatible string to mach-imx6q. - Update fsl DT board doc. Signed-off-by: Richard Zhao Signed-off-by: Shawn Guo --- Documentation/devicetree/bindings/arm/fsl.txt | 4 +++ arch/arm/boot/dts/imx6q-sabrelite.dts | 49 +++++++++++++++++++++++++++ arch/arm/mach-imx/mach-imx6q.c | 1 + 3 files changed, 54 insertions(+) create mode 100644 arch/arm/boot/dts/imx6q-sabrelite.dts (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/arm/fsl.txt b/Documentation/devicetree/bindings/arm/fsl.txt index c9848ad0e2e..d4e50adbba4 100644 --- a/Documentation/devicetree/bindings/arm/fsl.txt +++ b/Documentation/devicetree/bindings/arm/fsl.txt @@ -24,3 +24,7 @@ Required root node properties: i.MX6 Quad SABRE Automotive Board Required root node properties: - compatible = "fsl,imx6q-sabreauto", "fsl,imx6q"; + +i.MX6 Quad SABRE Lite Board +Required root node properties: + - compatible = "fsl,imx6q-sabrelite", "fsl,imx6q"; diff --git a/arch/arm/boot/dts/imx6q-sabrelite.dts b/arch/arm/boot/dts/imx6q-sabrelite.dts new file mode 100644 index 00000000000..08d920de728 --- /dev/null +++ b/arch/arm/boot/dts/imx6q-sabrelite.dts @@ -0,0 +1,49 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * 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 + */ + +/dts-v1/; +/include/ "imx6q.dtsi" + +/ { + model = "Freescale i.MX6 Quad SABRE Lite Board"; + compatible = "fsl,imx6q-sabrelite", "fsl,imx6q"; + + memory { + reg = <0x10000000 0x40000000>; + }; + + soc { + aips-bus@02100000 { /* AIPS2 */ + enet@02188000 { + phy-mode = "rgmii"; + phy-reset-gpios = <&gpio3 23 0>; + status = "okay"; + }; + + usdhc@02198000 { /* uSDHC3 */ + cd-gpios = <&gpio7 0 0>; + wp-gpios = <&gpio7 1 0>; + status = "okay"; + }; + + usdhc@0219c000 { /* uSDHC4 */ + cd-gpios = <&gpio2 6 0>; + wp-gpios = <&gpio2 7 0>; + status = "okay"; + }; + + uart2: uart@021e8000 { + status = "okay"; + }; + }; + }; +}; diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index 8deb012189b..d24d6c485ee 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -73,6 +73,7 @@ static struct sys_timer imx6q_timer = { static const char *imx6q_dt_compat[] __initdata = { "fsl,imx6q-sabreauto", + "fsl,imx6q-sabrelite", NULL, }; -- cgit v1.2.3-70-g09d2 From 752baf5647d40dc67dc1b74125fa693ac2137563 Mon Sep 17 00:00:00 2001 From: Dirk Behme Date: Thu, 8 Dec 2011 08:22:01 +0100 Subject: arm/imx6q: Rename Sabreauto to Armadillo2 The Sabreauto board was renamed to Armadillo2 recently. To avoid confusion, rename Sabreauto to Armadillo2/arm2. Signed-off-by: Dirk Behme Signed-off-by: Shawn Guo --- Documentation/devicetree/bindings/arm/fsl.txt | 4 +- arch/arm/boot/dts/imx6q-arm2.dts | 62 +++++++++++++++++++++++++++ arch/arm/boot/dts/imx6q-sabreauto.dts | 62 --------------------------- arch/arm/mach-imx/mach-imx6q.c | 2 +- 4 files changed, 65 insertions(+), 65 deletions(-) create mode 100644 arch/arm/boot/dts/imx6q-arm2.dts delete mode 100644 arch/arm/boot/dts/imx6q-sabreauto.dts (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/arm/fsl.txt b/Documentation/devicetree/bindings/arm/fsl.txt index d4e50adbba4..54bdddadf1c 100644 --- a/Documentation/devicetree/bindings/arm/fsl.txt +++ b/Documentation/devicetree/bindings/arm/fsl.txt @@ -21,9 +21,9 @@ i.MX53 Smart Mobile Reference Design Board Required root node properties: - compatible = "fsl,imx53-smd", "fsl,imx53"; -i.MX6 Quad SABRE Automotive Board +i.MX6 Quad Armadillo2 Board Required root node properties: - - compatible = "fsl,imx6q-sabreauto", "fsl,imx6q"; + - compatible = "fsl,imx6q-arm2", "fsl,imx6q"; i.MX6 Quad SABRE Lite Board Required root node properties: diff --git a/arch/arm/boot/dts/imx6q-arm2.dts b/arch/arm/boot/dts/imx6q-arm2.dts new file mode 100644 index 00000000000..c3977e0478b --- /dev/null +++ b/arch/arm/boot/dts/imx6q-arm2.dts @@ -0,0 +1,62 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * 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 + */ + +/dts-v1/; +/include/ "imx6q.dtsi" + +/ { + model = "Freescale i.MX6 Quad Armadillo2 Board"; + compatible = "fsl,imx6q-arm2", "fsl,imx6q"; + + chosen { + bootargs = "console=ttymxc0,115200 root=/dev/mmcblk3p3 rootwait"; + }; + + memory { + reg = <0x10000000 0x80000000>; + }; + + soc { + aips-bus@02100000 { /* AIPS2 */ + enet@02188000 { + phy-mode = "rgmii"; + local-mac-address = [00 04 9F 01 1B 61]; + status = "okay"; + }; + + usdhc@02198000 { /* uSDHC3 */ + cd-gpios = <&gpio6 11 0>; + wp-gpios = <&gpio6 14 0>; + status = "okay"; + }; + + usdhc@0219c000 { /* uSDHC4 */ + fsl,card-wired; + status = "okay"; + }; + + uart4: uart@021f0000 { + status = "okay"; + }; + }; + }; + + leds { + compatible = "gpio-leds"; + + debug-led { + label = "Heartbeat"; + gpios = <&gpio3 25 0>; + linux,default-trigger = "heartbeat"; + }; + }; +}; diff --git a/arch/arm/boot/dts/imx6q-sabreauto.dts b/arch/arm/boot/dts/imx6q-sabreauto.dts deleted file mode 100644 index eef6d640e65..00000000000 --- a/arch/arm/boot/dts/imx6q-sabreauto.dts +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2011 Freescale Semiconductor, Inc. - * Copyright 2011 Linaro Ltd. - * - * 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 - */ - -/dts-v1/; -/include/ "imx6q.dtsi" - -/ { - model = "Freescale i.MX6 Quad SABRE Automotive Board"; - compatible = "fsl,imx6q-sabreauto", "fsl,imx6q"; - - chosen { - bootargs = "console=ttymxc0,115200 root=/dev/mmcblk3p3 rootwait"; - }; - - memory { - reg = <0x10000000 0x80000000>; - }; - - soc { - aips-bus@02100000 { /* AIPS2 */ - enet@02188000 { - phy-mode = "rgmii"; - local-mac-address = [00 04 9F 01 1B 61]; - status = "okay"; - }; - - usdhc@02198000 { /* uSDHC3 */ - cd-gpios = <&gpio6 11 0>; - wp-gpios = <&gpio6 14 0>; - status = "okay"; - }; - - usdhc@0219c000 { /* uSDHC4 */ - fsl,card-wired; - status = "okay"; - }; - - uart4: uart@021f0000 { - status = "okay"; - }; - }; - }; - - leds { - compatible = "gpio-leds"; - - debug-led { - label = "Heartbeat"; - gpios = <&gpio3 25 0>; - linux,default-trigger = "heartbeat"; - }; - }; -}; diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index b2c3f69fb4e..bee633496f7 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -93,7 +93,7 @@ static struct sys_timer imx6q_timer = { }; static const char *imx6q_dt_compat[] __initdata = { - "fsl,imx6q-sabreauto", + "fsl,imx6q-arm2", "fsl,imx6q-sabrelite", NULL, }; -- cgit v1.2.3-70-g09d2 From fb97a8466522f8f35ab886f7af8eefefa0a4905e Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Fri, 18 Nov 2011 15:29:25 +0100 Subject: net/macb: add DT support for Cadence macb/gem driver Allow the device tree to provide the mac address and the phy mode. Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD [nicolas.ferre@atmel.com: change "compatible" node property, doc and DT hwaddr] Signed-off-by: Nicolas Ferre [jamie@jamieiles.com: add "gem" compatibility strings and doc] Acked-by: Jamie Iles Acked-by: David S. Miller --- Documentation/devicetree/bindings/net/macb.txt | 25 +++++++++ drivers/net/ethernet/cadence/macb.c | 73 +++++++++++++++++++++++--- drivers/net/ethernet/cadence/macb.h | 2 + 3 files changed, 92 insertions(+), 8 deletions(-) create mode 100644 Documentation/devicetree/bindings/net/macb.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/net/macb.txt b/Documentation/devicetree/bindings/net/macb.txt new file mode 100644 index 00000000000..44afa0e5057 --- /dev/null +++ b/Documentation/devicetree/bindings/net/macb.txt @@ -0,0 +1,25 @@ +* Cadence MACB/GEM Ethernet controller + +Required properties: +- compatible: Should be "cdns,[-]{macb|gem}" + Use "cdns,at91sam9260-macb" Atmel at91sam9260 and at91sam9263 SoCs. + Use "cdns,at32ap7000-macb" for other 10/100 usage or use the generic form: "cdns,macb". + Use "cnds,pc302-gem" for Picochip picoXcell pc302 and later devices based on + the Cadence GEM, or the generic form: "cdns,gem". +- reg: Address and length of the register set for the device +- interrupts: Should contain macb interrupt +- phy-mode: String, operation mode of the PHY interface. + Supported values are: "mii", "rmii", "gmii", "rgmii". + +Optional properties: +- local-mac-address: 6 bytes, mac address + +Examples: + + macb0: ethernet@fffc4000 { + compatible = "cdns,at32ap7000-macb"; + reg = <0xfffc4000 0x4000>; + interrupts = <21>; + phy-mode = "rmii"; + local-mac-address = [3a 0e 03 04 05 06]; + }; diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 64d61461bdc..baf1a0d88d8 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include "macb.h" @@ -191,7 +193,6 @@ static int macb_mii_probe(struct net_device *dev) { struct macb *bp = netdev_priv(dev); struct phy_device *phydev; - struct macb_platform_data *pdata; int ret; phydev = phy_find_first(bp->mii_bus); @@ -200,14 +201,11 @@ static int macb_mii_probe(struct net_device *dev) return -1; } - pdata = bp->pdev->dev.platform_data; /* TODO : add pin_irq */ /* attach the mac to the phy */ ret = phy_connect_direct(dev, phydev, &macb_handle_link_change, 0, - pdata && pdata->is_rmii ? - PHY_INTERFACE_MODE_RMII : - PHY_INTERFACE_MODE_MII); + bp->phy_interface); if (ret) { netdev_err(dev, "Could not attach to PHY\n"); return ret; @@ -1244,6 +1242,52 @@ static const struct net_device_ops macb_netdev_ops = { #endif }; +#if defined(CONFIG_OF) +static const struct of_device_id macb_dt_ids[] = { + { .compatible = "cdns,at32ap7000-macb" }, + { .compatible = "cdns,at91sam9260-macb" }, + { .compatible = "cdns,macb" }, + { .compatible = "cdns,pc302-gem" }, + { .compatible = "cdns,gem" }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, macb_dt_ids); + +static int __devinit macb_get_phy_mode_dt(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + + if (np) + return of_get_phy_mode(np); + + return -ENODEV; +} + +static int __devinit macb_get_hwaddr_dt(struct macb *bp) +{ + struct device_node *np = bp->pdev->dev.of_node; + if (np) { + const char *mac = of_get_mac_address(np); + if (mac) { + memcpy(bp->dev->dev_addr, mac, ETH_ALEN); + return 0; + } + } + + return -ENODEV; +} +#else +static int __devinit macb_get_phy_mode_dt(struct platform_device *pdev) +{ + return -ENODEV; +} +static int __devinit macb_get_hwaddr_dt(struct macb *bp) +{ + return -ENODEV; +} +#endif + static int __init macb_probe(struct platform_device *pdev) { struct macb_platform_data *pdata; @@ -1318,10 +1362,22 @@ static int __init macb_probe(struct platform_device *pdev) config |= macb_dbw(bp); macb_writel(bp, NCFGR, config); - macb_get_hwaddr(bp); - pdata = pdev->dev.platform_data; + err = macb_get_hwaddr_dt(bp); + if (err < 0) + macb_get_hwaddr(bp); + + err = macb_get_phy_mode_dt(pdev); + if (err < 0) { + pdata = pdev->dev.platform_data; + if (pdata && pdata->is_rmii) + bp->phy_interface = PHY_INTERFACE_MODE_RMII; + else + bp->phy_interface = PHY_INTERFACE_MODE_MII; + } else { + bp->phy_interface = err; + } - if (pdata && pdata->is_rmii) + if (bp->phy_interface == PHY_INTERFACE_MODE_RMII) #if defined(CONFIG_ARCH_AT91) macb_or_gem_writel(bp, USRIO, (MACB_BIT(RMII) | MACB_BIT(CLKEN))); @@ -1444,6 +1500,7 @@ static struct platform_driver macb_driver = { .driver = { .name = "macb", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(macb_dt_ids), }, }; diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index 193107884a5..335e288f531 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -532,6 +532,8 @@ struct macb { unsigned int link; unsigned int speed; unsigned int duplex; + + phy_interface_t phy_interface; }; static inline bool macb_is_gem(struct macb *bp) -- cgit v1.2.3-70-g09d2 From d92b0dfc5078aeec869d58372dbda5e16739b8de Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Wed, 14 Dec 2011 17:25:45 +0530 Subject: omap-serial: Add minimal device tree support Adapt the driver to device tree and pass minimal platform data from device tree needed for console boot. No power management features will be suppported for now since it requires more tweaks around OCP settings to toggle forceidle/noidle/smartidle bits and handling remote wakeup and dynamic muxing. Signed-off-by: Rajendra Nayak Reviewed-by: Rob Herring Signed-off-by: Tony Lindgren --- .../devicetree/bindings/serial/omap_serial.txt | 10 +++++ drivers/tty/serial/omap-serial.c | 45 ++++++++++++++++++++-- 2 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 Documentation/devicetree/bindings/serial/omap_serial.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/serial/omap_serial.txt b/Documentation/devicetree/bindings/serial/omap_serial.txt new file mode 100644 index 00000000000..342eedd1005 --- /dev/null +++ b/Documentation/devicetree/bindings/serial/omap_serial.txt @@ -0,0 +1,10 @@ +OMAP UART controller + +Required properties: +- compatible : should be "ti,omap2-uart" for OMAP2 controllers +- compatible : should be "ti,omap3-uart" for OMAP3 controllers +- compatible : should be "ti,omap4-uart" for OMAP4 controllers +- ti,hwmods : Must be "uart", n being the instance number (1-based) + +Optional properties: +- clock-frequency : frequency of the clock input to the UART diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index c5b545f19a1..ca24ab37d11 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -1325,6 +1326,19 @@ static void uart_tx_dma_callback(int lch, u16 ch_status, void *data) return; } +static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev) +{ + struct omap_uart_port_info *omap_up_info; + + omap_up_info = devm_kzalloc(dev, sizeof(*omap_up_info), GFP_KERNEL); + if (!omap_up_info) + return NULL; /* out of memory */ + + of_property_read_u32(dev->of_node, "clock-frequency", + &omap_up_info->uartclk); + return omap_up_info; +} + static int serial_omap_probe(struct platform_device *pdev) { struct uart_omap_port *up; @@ -1332,6 +1346,9 @@ static int serial_omap_probe(struct platform_device *pdev) struct omap_uart_port_info *omap_up_info = pdev->dev.platform_data; int ret = -ENOSPC; + if (pdev->dev.of_node) + omap_up_info = of_get_uart_port_info(&pdev->dev); + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) { dev_err(&pdev->dev, "no mem resource?\n"); @@ -1376,9 +1393,20 @@ static int serial_omap_probe(struct platform_device *pdev) up->port.regshift = 2; up->port.fifosize = 64; up->port.ops = &serial_omap_pops; - up->port.line = pdev->id; - sprintf(up->name, "OMAP UART%d", up->port.line); + if (pdev->dev.of_node) + up->port.line = of_alias_get_id(pdev->dev.of_node, "serial"); + else + up->port.line = pdev->id; + + if (up->port.line < 0) { + dev_err(&pdev->dev, "failed to get alias/pdev id, errno %d\n", + up->port.line); + ret = -ENODEV; + goto err; + } + + sprintf(up->name, "OMAP UART%d", up->port.line); up->port.mapbase = mem->start; up->port.membase = ioremap(mem->start, resource_size(mem)); if (!up->port.membase) { @@ -1531,7 +1559,7 @@ static int serial_omap_runtime_suspend(struct device *dev) if (!up) return -EINVAL; - if (!pdata->enable_wakeup) + if (!pdata || !pdata->enable_wakeup) return 0; if (pdata->get_context_loss_count) @@ -1592,12 +1620,23 @@ static const struct dev_pm_ops serial_omap_dev_pm_ops = { serial_omap_runtime_resume, NULL) }; +#if defined(CONFIG_OF) +static const struct of_device_id omap_serial_of_match[] = { + { .compatible = "ti,omap2-uart" }, + { .compatible = "ti,omap3-uart" }, + { .compatible = "ti,omap4-uart" }, + {}, +}; +MODULE_DEVICE_TABLE(of, omap_serial_of_match); +#endif + static struct platform_driver serial_omap_driver = { .probe = serial_omap_probe, .remove = serial_omap_remove, .driver = { .name = DRIVER_NAME, .pm = &serial_omap_dev_pm_ops, + .of_match_table = of_match_ptr(omap_serial_of_match), }, }; -- cgit v1.2.3-70-g09d2 From c3e00a0eff4c05717915ac7a8e4646db3882aebf Mon Sep 17 00:00:00 2001 From: Peter De Schrijver Date: Wed, 14 Dec 2011 17:03:13 +0200 Subject: arm/tegra: initial device tree for tegra30 This patch adds the initial device tree for tegra30 Signed-off-by: Peter De Schrijver Acked-by: Stephen Warren Acked-by: Colin Cross Signed-off-by: Olof Johansson --- Documentation/devicetree/bindings/arm/tegra.txt | 14 +++ arch/arm/boot/dts/tegra30.dtsi | 127 ++++++++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/tegra.txt create mode 100644 arch/arm/boot/dts/tegra30.dtsi (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/arm/tegra.txt b/Documentation/devicetree/bindings/arm/tegra.txt new file mode 100644 index 00000000000..6e69d2e5e76 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/tegra.txt @@ -0,0 +1,14 @@ +NVIDIA Tegra device tree bindings +------------------------------------------- + +Boards with the tegra20 SoC shall have the following properties: + +Required root node property: + +compatible = "nvidia,tegra20"; + +Boards with the tegra30 SoC shall have the following properties: + +Required root node property: + +compatible = "nvidia,tegra30"; diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi new file mode 100644 index 00000000000..ee7db9892e0 --- /dev/null +++ b/arch/arm/boot/dts/tegra30.dtsi @@ -0,0 +1,127 @@ +/include/ "skeleton.dtsi" + +/ { + compatible = "nvidia,tegra30"; + interrupt-parent = <&intc>; + + intc: interrupt-controller@50041000 { + compatible = "arm,cortex-a9-gic"; + interrupt-controller; + #interrupt-cells = <3>; + reg = < 0x50041000 0x1000 >, + < 0x50040100 0x0100 >; + }; + + i2c@7000c000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c"; + reg = <0x7000C000 0x100>; + interrupts = < 0 38 0x04 >; + }; + + i2c@7000c400 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c"; + reg = <0x7000C400 0x100>; + interrupts = < 0 84 0x04 >; + }; + + i2c@7000c500 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c"; + reg = <0x7000C500 0x100>; + interrupts = < 0 92 0x04 >; + }; + + i2c@7000c700 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c"; + reg = <0x7000c700 0x100>; + interrupts = < 0 120 0x04 >; + }; + + i2c@7000d000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c"; + reg = <0x7000D000 0x100>; + interrupts = < 0 53 0x04 >; + }; + + gpio: gpio@6000d000 { + compatible = "nvidia,tegra30-gpio", "nvidia,tegra20-gpio"; + reg = < 0x6000d000 0x1000 >; + interrupts = < 0 32 0x04 0 33 0x04 0 34 0x04 0 35 0x04 0 55 0x04 0 87 0x04 0 89 0x04 >; + #gpio-cells = <2>; + gpio-controller; + }; + + serial@70006000 { + compatible = "nvidia,tegra30-uart", "nvidia,tegra20-uart"; + reg = <0x70006000 0x40>; + reg-shift = <2>; + interrupts = < 0 36 0x04 >; + }; + + serial@70006040 { + compatible = "nvidia,tegra30-uart", "nvidia,tegra20-uart"; + reg = <0x70006040 0x40>; + reg-shift = <2>; + interrupts = < 0 37 0x04 >; + }; + + serial@70006200 { + compatible = "nvidia,tegra30-uart", "nvidia,tegra20-uart"; + reg = <0x70006200 0x100>; + reg-shift = <2>; + interrupts = < 0 46 0x04 >; + }; + + serial@70006300 { + compatible = "nvidia,tegra30-uart", "nvidia,tegra20-uart"; + reg = <0x70006300 0x100>; + reg-shift = <2>; + interrupts = < 0 90 0x04 >; + }; + + serial@70006400 { + compatible = "nvidia,tegra30-uart", "nvidia,tegra20-uart"; + reg = <0x70006400 0x100>; + reg-shift = <2>; + interrupts = < 0 91 0x04 >; + }; + + sdhci@78000000 { + compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci"; + reg = <0x78000000 0x200>; + interrupts = < 0 14 0x04 >; + }; + + sdhci@78000200 { + compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci"; + reg = <0x78000200 0x200>; + interrupts = < 0 15 0x04 >; + }; + + sdhci@78000400 { + compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci"; + reg = <0x78000400 0x200>; + interrupts = < 0 19 0x04 >; + }; + + sdhci@78000600 { + compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci"; + reg = <0x78000600 0x200>; + interrupts = < 0 31 0x04 >; + }; + + pinmux: pinmux@70000000 { + compatible = "nvidia,tegra30-pinmux"; + reg = < 0x70000868 0xd0 /* Pad control registers */ + 0x70003000 0x3e0 >; /* Mux registers */ + }; +}; -- cgit v1.2.3-70-g09d2 From 44ad56b7df54cbc8063b46883d183e4e2f09f831 Mon Sep 17 00:00:00 2001 From: David Daney Date: Wed, 14 Dec 2011 15:26:19 -0800 Subject: OF/device-tree: Add some entries to vendor-prefixes.txt We are currently using 'cavium', 'cortina' and 'st', add them to the list of known prefixes. Signed-off-by: David Daney Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/vendor-prefixes.txt | 3 +++ 1 file changed, 3 insertions(+) (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 874921e9780..18626965159 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -8,7 +8,9 @@ amcc Applied Micro Circuits Corporation (APM, formally AMCC) apm Applied Micro Circuits Corporation (APM) arm ARM Ltd. atmel Atmel Corporation +cavium Cavium, Inc. chrp Common Hardware Reference Platform +cortina Cortina Systems, Inc. dallas Maxim Integrated Products (formerly Dallas Semiconductor) denx Denx Software Engineering epson Seiko Epson Corp. @@ -36,6 +38,7 @@ schindler Schindler sil Silicon Image simtek sirf SiRF Technology, Inc. +st STMicroelectronics stericsson ST-Ericsson ti Texas Instruments xlnx Xilinx -- cgit v1.2.3-70-g09d2 From 07cdf36d8c4ba4ad0db13228eb25bcd3d5138b29 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Mon, 12 Dec 2011 15:55:36 -0700 Subject: ASoC: Tegra+WM8903 machine: Add device tree binding This driver is parameterized in two ways: a) Platform data, which supplies the set of GPIOs used by the driver. These GPIOs can now be parsed out of device tree. b) Machine-specific DAPM route arrays embedded into the ASoC machine driver itself. Historically, the driver picks the appropriate array to use using machine_is_*(). The driver now requires this array to be parsed from device tree when instantiated through device tree, using the core ASoC support for this parsing. Based on work by John Bonesio, but significantly reworked since then. Signed-off-by: Stephen Warren Signed-off-by: Mark Brown --- .../bindings/sound/tegra-audio-wm8903.txt | 71 ++++++++++++ sound/soc/tegra/tegra_wm8903.c | 128 +++++++++++++++++---- 2 files changed, 174 insertions(+), 25 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/tegra-audio-wm8903.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/sound/tegra-audio-wm8903.txt b/Documentation/devicetree/bindings/sound/tegra-audio-wm8903.txt new file mode 100644 index 00000000000..d5b0da8bf1d --- /dev/null +++ b/Documentation/devicetree/bindings/sound/tegra-audio-wm8903.txt @@ -0,0 +1,71 @@ +NVIDIA Tegra audio complex + +Required properties: +- compatible : "nvidia,tegra-audio-wm8903" +- nvidia,model : The user-visible name of this sound complex. +- nvidia,audio-routing : A list of the connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. Valid names for sources and + sinks are the WM8903's pins, and the jacks on the board: + + WM8903 pins: + + * IN1L + * IN1R + * IN2L + * IN2R + * IN3L + * IN3R + * DMICDAT + * HPOUTL + * HPOUTR + * LINEOUTL + * LINEOUTR + * LOP + * LON + * ROP + * RON + * MICBIAS + + Board connectors: + + * Headphone Jack + * Int Spk + * Mic Jack + +- nvidia,i2s-controller : The phandle of the Tegra I2S1 controller +- nvidia,audio-codec : The phandle of the WM8903 audio codec + +Optional properties: +- nvidia,spkr-en-gpios : The GPIO that enables the speakers +- nvidia,hp-mute-gpios : The GPIO that mutes the headphones +- nvidia,hp-det-gpios : The GPIO that detect headphones are plugged in +- nvidia,int-mic-en-gpios : The GPIO that enables the internal microphone +- nvidia,ext-mic-en-gpios : The GPIO that enables the external microphone + +Example: + +sound { + compatible = "nvidia,tegra-audio-wm8903-harmony", + "nvidia,tegra-audio-wm8903" + nvidia,model = "tegra-wm8903-harmony"; + + nvidia,audio-routing = + "Headphone Jack", "HPOUTR", + "Headphone Jack", "HPOUTL", + "Int Spk", "ROP", + "Int Spk", "RON", + "Int Spk", "LOP", + "Int Spk", "LON", + "Mic Jack", "MICBIAS", + "IN1L", "Mic Jack"; + + nvidia,i2s-controller = <&i2s1>; + nvidia,audio-codec = <&wm8903>; + + nvidia,spkr-en-gpios = <&codec 2 0>; + nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */ + nvidia,int-mic-en-gpios = <&gpio 184 0>; /*gpio PX0 */ + nvidia,ext-mic-en-gpios = <&gpio 185 0>; /* gpio PX1 */ +}; + diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c index ba2d23ea642..4677f266630 100644 --- a/sound/soc/tegra/tegra_wm8903.c +++ b/sound/soc/tegra/tegra_wm8903.c @@ -34,6 +34,7 @@ #include #include #include +#include #include @@ -59,8 +60,9 @@ #define GPIO_HP_DET BIT(4) struct tegra_wm8903 { + struct tegra_wm8903_platform_data pdata; + struct platform_device *pcm_dev; struct tegra_asoc_utils_data util_data; - struct tegra_wm8903_platform_data *pdata; int gpio_requested; }; @@ -160,7 +162,7 @@ static int tegra_wm8903_event_int_spk(struct snd_soc_dapm_widget *w, struct snd_soc_dapm_context *dapm = w->dapm; struct snd_soc_card *card = dapm->card; struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); - struct tegra_wm8903_platform_data *pdata = machine->pdata; + struct tegra_wm8903_platform_data *pdata = &machine->pdata; if (!(machine->gpio_requested & GPIO_SPKR_EN)) return 0; @@ -177,7 +179,7 @@ static int tegra_wm8903_event_hp(struct snd_soc_dapm_widget *w, struct snd_soc_dapm_context *dapm = w->dapm; struct snd_soc_card *card = dapm->card; struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); - struct tegra_wm8903_platform_data *pdata = machine->pdata; + struct tegra_wm8903_platform_data *pdata = &machine->pdata; if (!(machine->gpio_requested & GPIO_HP_MUTE)) return 0; @@ -246,9 +248,36 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_dapm_context *dapm = &codec->dapm; struct snd_soc_card *card = codec->card; struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); - struct tegra_wm8903_platform_data *pdata = machine->pdata; + struct tegra_wm8903_platform_data *pdata = &machine->pdata; + struct device_node *np = card->dev->of_node; int ret; + if (card->dev->platform_data) { + memcpy(pdata, card->dev->platform_data, sizeof(*pdata)); + } else if (np) { + /* + * This part must be in init() rather than probe() in order to + * guarantee that the WM8903 has been probed, and hence its + * GPIO controller registered, which is a pre-condition for + * of_get_named_gpio() to be able to map the phandles in the + * properties to the controller node. Given this, all + * pdata handling is in init() for consistency. + */ + pdata->gpio_spkr_en = of_get_named_gpio(np, + "nvidia,spkr-en-gpios", 0); + pdata->gpio_hp_mute = of_get_named_gpio(np, + "nvidia,hp-mute-gpios", 0); + pdata->gpio_hp_det = of_get_named_gpio(np, + "nvidia,hp-det-gpios", 0); + pdata->gpio_int_mic_en = of_get_named_gpio(np, + "nvidia,int-mic-en-gpios", 0); + pdata->gpio_ext_mic_en = of_get_named_gpio(np, + "nvidia,ext-mic-en-gpios", 0); + } else { + dev_err(card->dev, "No platform data supplied\n"); + return -EINVAL; + } + if (gpio_is_valid(pdata->gpio_spkr_en)) { ret = gpio_request(pdata->gpio_spkr_en, "spkr_en"); if (ret) { @@ -348,11 +377,9 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev) { struct snd_soc_card *card = &snd_soc_tegra_wm8903; struct tegra_wm8903 *machine; - struct tegra_wm8903_platform_data *pdata; int ret; - pdata = pdev->dev.platform_data; - if (!pdata) { + if (!pdev->dev.platform_data && !pdev->dev.of_node) { dev_err(&pdev->dev, "No platform data supplied\n"); return -EINVAL; } @@ -364,31 +391,70 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev) ret = -ENOMEM; goto err; } - - machine->pdata = pdata; - - ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); - if (ret) - goto err; + machine->pcm_dev = ERR_PTR(-EINVAL); card->dev = &pdev->dev; platform_set_drvdata(pdev, card); snd_soc_card_set_drvdata(card, machine); - if (machine_is_harmony()) { - card->dapm_routes = harmony_audio_map; - card->num_dapm_routes = ARRAY_SIZE(harmony_audio_map); - } else if (machine_is_seaboard()) { - card->dapm_routes = seaboard_audio_map; - card->num_dapm_routes = ARRAY_SIZE(seaboard_audio_map); - } else if (machine_is_kaen()) { - card->dapm_routes = kaen_audio_map; - card->num_dapm_routes = ARRAY_SIZE(kaen_audio_map); + if (pdev->dev.of_node) { + ret = snd_soc_of_parse_card_name(card, "nvidia,model"); + if (ret) + goto err; + + ret = snd_soc_of_parse_audio_routing(card, + "nvidia,audio-routing"); + if (ret) + goto err; + + tegra_wm8903_dai.codec_name = NULL; + tegra_wm8903_dai.codec_of_node = of_parse_phandle( + pdev->dev.of_node, "nvidia,audio-codec", 0); + if (!tegra_wm8903_dai.codec_of_node) { + dev_err(&pdev->dev, + "Property 'nvidia,audio-codec' missing or invalid\n"); + ret = -EINVAL; + goto err; + } + + tegra_wm8903_dai.cpu_dai_name = NULL; + tegra_wm8903_dai.cpu_dai_of_node = of_parse_phandle( + pdev->dev.of_node, "nvidia,i2s-controller", 0); + if (!tegra_wm8903_dai.cpu_dai_of_node) { + dev_err(&pdev->dev, + "Property 'nvidia,i2s-controller' missing or invalid\n"); + ret = -EINVAL; + goto err; + } + + machine->pcm_dev = platform_device_register_simple( + "tegra-pcm-audio", -1, NULL, 0); + if (IS_ERR(machine->pcm_dev)) { + dev_err(&pdev->dev, + "Can't instantiate tegra-pcm-audio\n"); + ret = PTR_ERR(machine->pcm_dev); + goto err; + } } else { - card->dapm_routes = aebl_audio_map; - card->num_dapm_routes = ARRAY_SIZE(aebl_audio_map); + if (machine_is_harmony()) { + card->dapm_routes = harmony_audio_map; + card->num_dapm_routes = ARRAY_SIZE(harmony_audio_map); + } else if (machine_is_seaboard()) { + card->dapm_routes = seaboard_audio_map; + card->num_dapm_routes = ARRAY_SIZE(seaboard_audio_map); + } else if (machine_is_kaen()) { + card->dapm_routes = kaen_audio_map; + card->num_dapm_routes = ARRAY_SIZE(kaen_audio_map); + } else { + card->dapm_routes = aebl_audio_map; + card->num_dapm_routes = ARRAY_SIZE(aebl_audio_map); + } } + ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); + if (ret) + goto err_unregister; + ret = snd_soc_register_card(card); if (ret) { dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", @@ -400,6 +466,9 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev) err_fini_utils: tegra_asoc_utils_fini(&machine->util_data); +err_unregister: + if (!IS_ERR(machine->pcm_dev)) + platform_device_unregister(machine->pcm_dev); err: return ret; } @@ -408,7 +477,7 @@ static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); - struct tegra_wm8903_platform_data *pdata = machine->pdata; + struct tegra_wm8903_platform_data *pdata = &machine->pdata; if (machine->gpio_requested & GPIO_HP_DET) snd_soc_jack_free_gpios(&tegra_wm8903_hp_jack, @@ -427,15 +496,23 @@ static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev) snd_soc_unregister_card(card); tegra_asoc_utils_fini(&machine->util_data); + if (!IS_ERR(machine->pcm_dev)) + platform_device_unregister(machine->pcm_dev); return 0; } +static const struct of_device_id tegra_wm8903_of_match[] __devinitconst = { + { .compatible = "nvidia,tegra-audio-wm8903", }, + {}, +}; + static struct platform_driver tegra_wm8903_driver = { .driver = { .name = DRV_NAME, .owner = THIS_MODULE, .pm = &snd_soc_pm_ops, + .of_match_table = tegra_wm8903_of_match, }, .probe = tegra_wm8903_driver_probe, .remove = __devexit_p(tegra_wm8903_driver_remove), @@ -446,3 +523,4 @@ MODULE_AUTHOR("Stephen Warren "); MODULE_DESCRIPTION("Tegra+WM8903 machine ASoC driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" DRV_NAME); +MODULE_DEVICE_TABLE(of, tegra_wm8903_of_match); -- cgit v1.2.3-70-g09d2 From 659d73ada5d6869dc18838c9125731a750389019 Mon Sep 17 00:00:00 2001 From: Thomas Abraham Date: Mon, 7 Nov 2011 01:02:21 +0530 Subject: gpio/samsung: Add device tree support for EXYNOS4 As gpio chips get registered, a device tree node which represents the gpio chip is searched and attached to it. A translate function is also provided to convert the gpio specifier into actual platform settings for pin function selection, pull up/down and driver strength settings. Signed-off-by: Thomas Abraham Acked-by: Grant Likely [kgene.kim@samsung.com: fixed build error] Signed-off-by: Kukjin Kim --- .../devicetree/bindings/gpio/gpio-samsung.txt | 40 ++++++++++++ drivers/gpio/gpio-samsung.c | 72 ++++++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpio/gpio-samsung.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/gpio/gpio-samsung.txt b/Documentation/devicetree/bindings/gpio/gpio-samsung.txt new file mode 100644 index 00000000000..8f50fe5e6c4 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-samsung.txt @@ -0,0 +1,40 @@ +Samsung Exynos4 GPIO Controller + +Required properties: +- compatible: Compatible property value should be "samsung,exynos4-gpio>". + +- reg: Physical base address of the controller and length of memory mapped + region. + +- #gpio-cells: Should be 4. The syntax of the gpio specifier used by client nodes + should be the following with values derived from the SoC user manual. + <[phandle of the gpio controller node] + [pin number within the gpio controller] + [mux function] + [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. + - Drive Strength: 0 - 1x, + 1 - 3x, + 2 - 2x, + 3 - 4x + +- gpio-controller: Specifies that the node is a gpio controller. +- #address-cells: should be 1. +- #size-cells: should be 1. + +Example: + + gpa0: gpio-controller@11400000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "samsung,exynos4-gpio"; + reg = <0x11400000 0x20>; + #gpio-cells = <4>; + gpio-controller; + }; diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index 86625185271..6b4d23fd158 100644 --- a/drivers/gpio/gpio-samsung.c +++ b/drivers/gpio/gpio-samsung.c @@ -24,6 +24,9 @@ #include #include #include +#include +#include +#include #include @@ -2374,6 +2377,63 @@ static struct samsung_gpio_chip exynos4_gpios_3[] = { #endif }; +#if defined(CONFIG_ARCH_EXYNOS4) && defined(CONFIG_OF) +static int exynos4_gpio_xlate(struct gpio_chip *gc, struct device_node *np, + const void *gpio_spec, u32 *flags) +{ + const __be32 *gpio = gpio_spec; + const u32 n = be32_to_cpup(gpio); + unsigned int pin = gc->base + be32_to_cpu(gpio[0]); + + if (WARN_ON(gc->of_gpio_n_cells < 4)) + return -EINVAL; + + if (n > gc->ngpio) + return -EINVAL; + + if (s3c_gpio_cfgpin(pin, S3C_GPIO_SFN(be32_to_cpu(gpio[1])))) + pr_warn("gpio_xlate: failed to set pin function\n"); + if (s3c_gpio_setpull(pin, be32_to_cpu(gpio[2]))) + pr_warn("gpio_xlate: failed to set pin pull up/down\n"); + if (s5p_gpio_set_drvstr(pin, be32_to_cpu(gpio[3]))) + pr_warn("gpio_xlate: failed to set pin drive strength\n"); + + return n; +} + +static const struct of_device_id exynos4_gpio_dt_match[] __initdata = { + { .compatible = "samsung,exynos4-gpio", }, + {} +}; + +static __init void exynos4_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip, + u64 base, u64 offset) +{ + struct gpio_chip *gc = &chip->chip; + u64 address; + + if (!of_have_populated_dt()) + return; + + address = chip->base ? base + ((u32)chip->base & 0xfff) : base + offset; + gc->of_node = of_find_matching_node_by_address(NULL, + exynos4_gpio_dt_match, address); + if (!gc->of_node) { + pr_info("gpio: device tree node not found for gpio controller" + " with base address %08llx\n", address); + return; + } + gc->of_gpio_n_cells = 4; + gc->of_xlate = exynos4_gpio_xlate; +} +#elif defined(CONFIG_ARCH_EXYNOS4) +static __init void exynos4_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip, + u64 base, u64 offset) +{ + return; +} +#endif /* defined(CONFIG_ARCH_EXYNOS4) && defined(CONFIG_OF) */ + /* TODO: cleanup soc_is_* */ static __init int samsung_gpiolib_init(void) { @@ -2455,6 +2515,10 @@ static __init int samsung_gpiolib_init(void) chip->config = &exynos4_gpio_cfg; chip->group = group++; } +#ifdef CONFIG_CPU_EXYNOS4210 + exynos4_gpiolib_attach_ofnode(chip, + EXYNOS4_PA_GPIO1, i * 0x20); +#endif } samsung_gpiolib_add_4bit_chips(exynos4_gpios_1, nr_chips, S5P_VA_GPIO1); @@ -2467,6 +2531,10 @@ static __init int samsung_gpiolib_init(void) chip->config = &exynos4_gpio_cfg; chip->group = group++; } +#ifdef CONFIG_CPU_EXYNOS4210 + exynos4_gpiolib_attach_ofnode(chip, + EXYNOS4_PA_GPIO2, i * 0x20); +#endif } samsung_gpiolib_add_4bit_chips(exynos4_gpios_2, nr_chips, S5P_VA_GPIO2); @@ -2479,6 +2547,10 @@ static __init int samsung_gpiolib_init(void) chip->config = &exynos4_gpio_cfg; chip->group = group++; } +#ifdef CONFIG_CPU_EXYNOS4210 + exynos4_gpiolib_attach_ofnode(chip, + EXYNOS4_PA_GPIO3, i * 0x20); +#endif } samsung_gpiolib_add_4bit_chips(exynos4_gpios_3, nr_chips, S5P_VA_GPIO3); -- cgit v1.2.3-70-g09d2 From 26c919e1d3f4dff87ad50e104670f048cbc69b17 Mon Sep 17 00:00:00 2001 From: Thomas Abraham Date: Sun, 6 Nov 2011 22:10:44 +0530 Subject: serial: samsung: add device tree support Add device tree based discovery support for Samsung's uart controller. Cc: Ben Dooks Acked-by: Grant Likely Signed-off-by: Thomas Abraham Signed-off-by: Kukjin Kim --- .../devicetree/bindings/serial/samsung_uart.txt | 14 +++++++++ drivers/tty/serial/samsung.c | 36 ++++++++++++++++++++-- 2 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 Documentation/devicetree/bindings/serial/samsung_uart.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/serial/samsung_uart.txt b/Documentation/devicetree/bindings/serial/samsung_uart.txt new file mode 100644 index 00000000000..2c8a17cf5cb --- /dev/null +++ b/Documentation/devicetree/bindings/serial/samsung_uart.txt @@ -0,0 +1,14 @@ +* Samsung's UART Controller + +The Samsung's UART controller is used for interfacing SoC with serial communicaion +devices. + +Required properties: +- compatible: should be + - "samsung,exynos4210-uart", for UART's compatible with Exynos4210 uart ports. + +- reg: base physical address of the controller and length of memory mapped + region. + +- interrupts: interrupt number to the cpu. The interrupt specifier format depends + on the interrupt controller parent. diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index c89987b64c1..efe3756b53f 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -42,6 +42,7 @@ #include #include #include +#include #include @@ -1163,10 +1164,26 @@ static ssize_t s3c24xx_serial_show_clksrc(struct device *dev, static DEVICE_ATTR(clock_source, S_IRUGO, s3c24xx_serial_show_clksrc, NULL); + /* Device driver serial port probe */ +static const struct of_device_id s3c24xx_uart_dt_match[]; static int probe_index; +static inline struct s3c24xx_serial_drv_data *s3c24xx_get_driver_data( + struct platform_device *pdev) +{ +#ifdef CONFIG_OF + if (pdev->dev.of_node) { + const struct of_device_id *match; + match = of_match_node(s3c24xx_uart_dt_match, pdev->dev.of_node); + return (struct s3c24xx_serial_drv_data *)match->data; + } +#endif + return (struct s3c24xx_serial_drv_data *) + platform_get_device_id(pdev)->driver_data; +} + static int s3c24xx_serial_probe(struct platform_device *pdev) { struct s3c24xx_uart_port *ourport; @@ -1176,8 +1193,11 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) ourport = &s3c24xx_serial_ports[probe_index]; - ourport->drv_data = (struct s3c24xx_serial_drv_data *) - platform_get_device_id(pdev)->driver_data; + ourport->drv_data = s3c24xx_get_driver_data(pdev); + if (!ourport->drv_data) { + dev_err(&pdev->dev, "could not find driver data\n"); + return -ENODEV; + } ourport->info = ourport->drv_data->info; ourport->cfg = (pdev->dev.platform_data) ? @@ -1626,6 +1646,17 @@ static struct platform_device_id s3c24xx_serial_driver_ids[] = { }; MODULE_DEVICE_TABLE(platform, s3c24xx_serial_driver_ids); +#ifdef CONFIG_OF +static const struct of_device_id s3c24xx_uart_dt_match[] = { + { .compatible = "samsung,exynos4210-uart", + .data = &exynos4210_serial_drv_data }, + {}, +}; +MODULE_DEVICE_TABLE(of, s3c24xx_uart_dt_match); +#else +#define s3c24xx_uart_dt_match NULL +#endif + static struct platform_driver samsung_serial_driver = { .probe = s3c24xx_serial_probe, .remove = __devexit_p(s3c24xx_serial_remove), @@ -1634,6 +1665,7 @@ static struct platform_driver samsung_serial_driver = { .name = "samsung-uart", .owner = THIS_MODULE, .pm = SERIAL_SAMSUNG_PM_OPS, + .of_match_table = s3c24xx_uart_dt_match, }, }; -- cgit v1.2.3-70-g09d2 From 93ed55441245a39e3935f5cf1af3e22febcce905 Mon Sep 17 00:00:00 2001 From: Thomas Abraham Date: Mon, 24 Oct 2011 11:43:31 +0200 Subject: DMA: PL330: Add device tree support For PL330 dma controllers instantiated from device tree, the channel lookup is based on phandle of the dma controller and dma request id specified by the client node. During probe, the private data of each channel of the controller is set to point to the device node of the dma controller. The 'chan_id' of the each channel is used as the dma request id. Client driver requesting dma channels specify the phandle of the dma controller and the request id. The pl330 filter function converts the phandle to the device node pointer and matches that with channel's private data. If a match is found, the request id from the client node and the 'chan_id' of the channel is matched. A channel is found if both the values match. Acked-by: Jassi Brar Acked-by: Boojin Kim Signed-off-by: Thomas Abraham Reviewed-by: Rob Herring Acked-by: Grant Likely Acked-by: Vinod Koul Signed-off-by: Kukjin Kim --- .../devicetree/bindings/dma/arm-pl330.txt | 30 ++++++++++++++++++++ drivers/dma/pl330.c | 33 +++++++++++++++++++--- 2 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 Documentation/devicetree/bindings/dma/arm-pl330.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/dma/arm-pl330.txt b/Documentation/devicetree/bindings/dma/arm-pl330.txt new file mode 100644 index 00000000000..a4cd273b2a6 --- /dev/null +++ b/Documentation/devicetree/bindings/dma/arm-pl330.txt @@ -0,0 +1,30 @@ +* ARM PrimeCell PL330 DMA Controller + +The ARM PrimeCell PL330 DMA controller can move blocks of memory contents +between memory and peripherals or memory to memory. + +Required properties: + - compatible: should include both "arm,pl330" and "arm,primecell". + - reg: physical base address of the controller and length of memory mapped + region. + - interrupts: interrupt number to the cpu. + +Example: + + pdma0: pdma@12680000 { + compatible = "arm,pl330", "arm,primecell"; + reg = <0x12680000 0x1000>; + interrupts = <99>; + }; + +Client drivers (device nodes requiring dma transfers from dev-to-mem or +mem-to-dev) should specify the DMA channel numbers using a two-value pair +as shown below. + + [property name] = <[phandle of the dma controller] [dma request id]>; + + where 'dma request id' is the dma request number which is connected + to the client controller. The 'property name' is recommended to be + of the form -dma-channel. + + Example: tx-dma-channel = <&pdma0 12>; diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 317aaeaa6f6..a626e15799a 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -19,6 +19,7 @@ #include #include #include +#include #define NR_DEFAULT_DESC 16 @@ -277,6 +278,20 @@ bool pl330_filter(struct dma_chan *chan, void *param) if (chan->device->dev->driver != &pl330_driver.drv) return false; +#ifdef CONFIG_OF + if (chan->device->dev->of_node) { + const __be32 *prop_value; + phandle phandle; + struct device_node *node; + + prop_value = ((struct property *)param)->value; + phandle = be32_to_cpup(prop_value++); + node = of_find_node_by_phandle(phandle); + return ((chan->private == node) && + (chan->chan_id == be32_to_cpup(prop_value))); + } +#endif + peri_id = chan->private; return *peri_id == (unsigned)param; } @@ -855,12 +870,17 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) INIT_LIST_HEAD(&pd->channels); /* Initialize channel parameters */ - num_chan = max(pdat ? pdat->nr_valid_peri : 0, (u8)pi->pcfg.num_chan); + num_chan = max(pdat ? pdat->nr_valid_peri : (u8)pi->pcfg.num_peri, + (u8)pi->pcfg.num_chan); pdmac->peripherals = kzalloc(num_chan * sizeof(*pch), GFP_KERNEL); for (i = 0; i < num_chan; i++) { pch = &pdmac->peripherals[i]; - pch->chan.private = pdat ? &pdat->peri_id[i] : NULL; + if (!adev->dev.of_node) + pch->chan.private = pdat ? &pdat->peri_id[i] : NULL; + else + pch->chan.private = adev->dev.of_node; + INIT_LIST_HEAD(&pch->work_list); spin_lock_init(&pch->lock); pch->pl330_chid = NULL; @@ -872,10 +892,15 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) } pd->dev = &adev->dev; - if (pdat) + if (pdat) { pd->cap_mask = pdat->cap_mask; - else + } else { dma_cap_set(DMA_MEMCPY, pd->cap_mask); + if (pi->pcfg.num_peri) { + dma_cap_set(DMA_SLAVE, pd->cap_mask); + dma_cap_set(DMA_CYCLIC, pd->cap_mask); + } + } pd->device_alloc_chan_resources = pl330_alloc_chan_resources; pd->device_free_chan_resources = pl330_free_chan_resources; -- cgit v1.2.3-70-g09d2 From b3d6ac3e5f937440a362c0fa187257fa1197f5b9 Mon Sep 17 00:00:00 2001 From: Thomas Abraham Date: Wed, 2 Nov 2011 19:37:22 +0900 Subject: input: samsung-keypad: Add device tree support Add device tree based discovery support for Samsung's keypad controller. Cc: Joonyoung Shim Cc: Donghwa Lee Signed-off-by: Thomas Abraham Acked-by: Grant Likely Signed-off-by: Kukjin Kim --- .../devicetree/bindings/input/samsung-keypad.txt | 88 +++++++++++ drivers/input/keyboard/samsung-keypad.c | 174 +++++++++++++++++++-- 2 files changed, 250 insertions(+), 12 deletions(-) create mode 100644 Documentation/devicetree/bindings/input/samsung-keypad.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/input/samsung-keypad.txt b/Documentation/devicetree/bindings/input/samsung-keypad.txt new file mode 100644 index 00000000000..ce3e394c0e6 --- /dev/null +++ b/Documentation/devicetree/bindings/input/samsung-keypad.txt @@ -0,0 +1,88 @@ +* Samsung's Keypad Controller device tree bindings + +Samsung'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 + - "samsung,s3c6410-keypad": For controllers compatible with s3c6410 keypad + controller. + - "samsung,s5pv210-keypad": For controllers compatible with s5pv210 keypad + controller. + +- reg: physical base address of the controller and length of memory mapped + region. + +- interrupts: The interrupt number to the cpu. + +Required Board Specific Properties: +- samsung,keypad-num-rows: Number of row lines connected to the keypad + controller. + +- samsung,keypad-num-columns: Number of column lines connected to the + keypad controller. + +- row-gpios: List of gpios used as row lines. The gpio specifier for + this property depends on the gpio controller to which these row lines + are connected. + +- col-gpios: List of gpios used as column lines. The gpio specifier for + this property depends on the gpio controller to which these column + lines are connected. + +- Keys represented as child nodes: Each key connected to the keypad + controller is represented as a child node to the keypad controller + device node and should include the following properties. + - keypad,row: the row number to which the key is connected. + - keypad,column: the column number to which the key is connected. + - linux,code: the key-code to be reported when the key is pressed + and released. + +Optional Properties specific to linux: +- linux,keypad-no-autorepeat: do no enable autorepeat feature. +- linux,keypad-wakeup: use any event on keypad as wakeup event. + + +Example: + keypad@100A0000 { + compatible = "samsung,s5pv210-keypad"; + reg = <0x100A0000 0x100>; + interrupts = <173>; + samsung,keypad-num-rows = <2>; + samsung,keypad-num-columns = <8>; + linux,input-no-autorepeat; + linux,input-wakeup; + + row-gpios = <&gpx2 0 3 3 0 + &gpx2 1 3 3 0>; + + col-gpios = <&gpx1 0 3 0 0 + &gpx1 1 3 0 0 + &gpx1 2 3 0 0 + &gpx1 3 3 0 0 + &gpx1 4 3 0 0 + &gpx1 5 3 0 0 + &gpx1 6 3 0 0 + &gpx1 7 3 0 0>; + + key_1 { + keypad,row = <0>; + keypad,column = <3>; + linux,code = <2>; + }; + + key_2 { + keypad,row = <0>; + keypad,column = <4>; + linux,code = <3>; + }; + + key_3 { + keypad,row = <0>; + keypad,column = <5>; + linux,code = <4>; + }; + }; diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c index f689f49e310..8a0060cd398 100644 --- a/drivers/input/keyboard/samsung-keypad.c +++ b/drivers/input/keyboard/samsung-keypad.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include #include @@ -68,31 +70,26 @@ struct samsung_keypad { wait_queue_head_t wait; bool stopped; int irq; + enum samsung_keypad_type type; unsigned int row_shift; unsigned int rows; unsigned int cols; unsigned int row_state[SAMSUNG_MAX_COLS]; +#ifdef CONFIG_OF + int row_gpios[SAMSUNG_MAX_ROWS]; + int col_gpios[SAMSUNG_MAX_COLS]; +#endif unsigned short keycodes[]; }; -static int samsung_keypad_is_s5pv210(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - enum samsung_keypad_type type = - platform_get_device_id(pdev)->driver_data; - - return type == KEYPAD_TYPE_S5PV210; -} - static void samsung_keypad_scan(struct samsung_keypad *keypad, unsigned int *row_state) { - struct device *dev = keypad->input_dev->dev.parent; unsigned int col; unsigned int val; for (col = 0; col < keypad->cols; col++) { - if (samsung_keypad_is_s5pv210(dev)) { + if (keypad->type == KEYPAD_TYPE_S5PV210) { val = S5PV210_KEYIFCOLEN_MASK; val &= ~(1 << col) << 8; } else { @@ -235,6 +232,126 @@ static void samsung_keypad_close(struct input_dev *input_dev) samsung_keypad_stop(keypad); } +#ifdef CONFIG_OF +static struct samsung_keypad_platdata *samsung_keypad_parse_dt( + struct device *dev) +{ + struct samsung_keypad_platdata *pdata; + struct matrix_keymap_data *keymap_data; + uint32_t *keymap, num_rows = 0, num_cols = 0; + struct device_node *np = dev->of_node, *key_np; + unsigned int key_count = 0; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(dev, "could not allocate memory for platform data\n"); + return NULL; + } + + of_property_read_u32(np, "samsung,keypad-num-rows", &num_rows); + of_property_read_u32(np, "samsung,keypad-num-columns", &num_cols); + if (!num_rows || !num_cols) { + dev_err(dev, "number of keypad rows/columns not specified\n"); + return NULL; + } + pdata->rows = num_rows; + pdata->cols = num_cols; + + keymap_data = devm_kzalloc(dev, sizeof(*keymap_data), GFP_KERNEL); + if (!keymap_data) { + dev_err(dev, "could not allocate memory for keymap data\n"); + return NULL; + } + pdata->keymap_data = keymap_data; + + for_each_child_of_node(np, key_np) + key_count++; + + keymap_data->keymap_size = key_count; + keymap = devm_kzalloc(dev, sizeof(uint32_t) * key_count, GFP_KERNEL); + if (!keymap) { + dev_err(dev, "could not allocate memory for keymap\n"); + return NULL; + } + keymap_data->keymap = keymap; + + for_each_child_of_node(np, key_np) { + u32 row, col, key_code; + of_property_read_u32(key_np, "keypad,row", &row); + of_property_read_u32(key_np, "keypad,column", &col); + of_property_read_u32(key_np, "linux,code", &key_code); + *keymap++ = KEY(row, col, key_code); + } + + if (of_get_property(np, "linux,input-no-autorepeat", NULL)) + pdata->no_autorepeat = true; + if (of_get_property(np, "linux,input-wakeup", NULL)) + pdata->wakeup = true; + + return pdata; +} + +static void samsung_keypad_parse_dt_gpio(struct device *dev, + struct samsung_keypad *keypad) +{ + struct device_node *np = dev->of_node; + int gpio, ret, row, col; + + for (row = 0; row < keypad->rows; row++) { + gpio = of_get_named_gpio(np, "row-gpios", row); + keypad->row_gpios[row] = gpio; + if (!gpio_is_valid(gpio)) { + dev_err(dev, "keypad row[%d]: invalid gpio %d\n", + row, gpio); + continue; + } + + ret = gpio_request(gpio, "keypad-row"); + if (ret) + dev_err(dev, "keypad row[%d] gpio request failed\n", + row); + } + + for (col = 0; col < keypad->cols; col++) { + gpio = of_get_named_gpio(np, "col-gpios", col); + keypad->col_gpios[col] = gpio; + if (!gpio_is_valid(gpio)) { + dev_err(dev, "keypad column[%d]: invalid gpio %d\n", + col, gpio); + continue; + } + + ret = gpio_request(gpio, "keypad-col"); + if (ret) + dev_err(dev, "keypad column[%d] gpio request failed\n", + col); + } +} + +static void samsung_keypad_dt_gpio_free(struct samsung_keypad *keypad) +{ + int cnt; + + for (cnt = 0; cnt < keypad->rows; cnt++) + if (gpio_is_valid(keypad->row_gpios[cnt])) + gpio_free(keypad->row_gpios[cnt]); + + for (cnt = 0; cnt < keypad->cols; cnt++) + if (gpio_is_valid(keypad->col_gpios[cnt])) + gpio_free(keypad->col_gpios[cnt]); +} +#else +static +struct samsung_keypad_platdata *samsung_keypad_parse_dt(struct device *dev) +{ + return NULL; +} + +static void samsung_keypad_dt_gpio_free(struct samsung_keypad *keypad) +{ +} +#endif + static int __devinit samsung_keypad_probe(struct platform_device *pdev) { const struct samsung_keypad_platdata *pdata; @@ -246,7 +363,10 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev) unsigned int keymap_size; int error; - pdata = pdev->dev.platform_data; + if (pdev->dev.of_node) + pdata = samsung_keypad_parse_dt(&pdev->dev); + else + pdata = pdev->dev.platform_data; if (!pdata) { dev_err(&pdev->dev, "no platform data defined\n"); return -EINVAL; @@ -303,6 +423,16 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev) keypad->cols = pdata->cols; init_waitqueue_head(&keypad->wait); + if (pdev->dev.of_node) { +#ifdef CONFIG_OF + samsung_keypad_parse_dt_gpio(&pdev->dev, keypad); + keypad->type = of_device_is_compatible(pdev->dev.of_node, + "samsung,s5pv210-keypad"); +#endif + } else { + keypad->type = platform_get_device_id(pdev)->driver_data; + } + input_dev->name = pdev->name; input_dev->id.bustype = BUS_HOST; input_dev->dev.parent = &pdev->dev; @@ -343,12 +473,19 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, pdata->wakeup); platform_set_drvdata(pdev, keypad); + + if (pdev->dev.of_node) { + devm_kfree(&pdev->dev, (void *)pdata->keymap_data->keymap); + devm_kfree(&pdev->dev, (void *)pdata->keymap_data); + devm_kfree(&pdev->dev, (void *)pdata); + } return 0; err_free_irq: free_irq(keypad->irq, keypad); err_put_clk: clk_put(keypad->clk); + samsung_keypad_dt_gpio_free(keypad); err_unmap_base: iounmap(keypad->base); err_free_mem: @@ -374,6 +511,7 @@ static int __devexit samsung_keypad_remove(struct platform_device *pdev) free_irq(keypad->irq, keypad); clk_put(keypad->clk); + samsung_keypad_dt_gpio_free(keypad); iounmap(keypad->base); kfree(keypad); @@ -447,6 +585,17 @@ static const struct dev_pm_ops samsung_keypad_pm_ops = { }; #endif +#ifdef CONFIG_OF +static const struct of_device_id samsung_keypad_dt_match[] = { + { .compatible = "samsung,s3c6410-keypad" }, + { .compatible = "samsung,s5pv210-keypad" }, + {}, +}; +MODULE_DEVICE_TABLE(of, samsung_keypad_dt_match); +#else +#define samsung_keypad_dt_match NULL +#endif + static struct platform_device_id samsung_keypad_driver_ids[] = { { .name = "samsung-keypad", @@ -465,6 +614,7 @@ static struct platform_driver samsung_keypad_driver = { .driver = { .name = "samsung-keypad", .owner = THIS_MODULE, + .of_match_table = samsung_keypad_dt_match, #ifdef CONFIG_PM .pm = &samsung_keypad_pm_ops, #endif -- cgit v1.2.3-70-g09d2 From 39ce4084a604a3ef0e2836e074c02bbbcc7c1509 Mon Sep 17 00:00:00 2001 From: Thomas Abraham Date: Mon, 24 Oct 2011 14:49:04 +0200 Subject: rtc: rtc-s3c: Add device tree support Add device tree based discovery support for Samsung's rtc controller. Cc: Ben Dooks Signed-off-by: Thomas Abraham Acked-by: Grant Likely Signed-off-by: Kukjin Kim --- Documentation/devicetree/bindings/rtc/s3c-rtc.txt | 20 ++++++++++++++++++++ drivers/rtc/rtc-s3c.c | 21 ++++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/rtc/s3c-rtc.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/rtc/s3c-rtc.txt b/Documentation/devicetree/bindings/rtc/s3c-rtc.txt new file mode 100644 index 00000000000..90ec45fd33e --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/s3c-rtc.txt @@ -0,0 +1,20 @@ +* Samsung's S3C Real Time Clock controller + +Required properties: +- compatible: should be one of the following. + * "samsung,s3c2410-rtc" - for controllers compatible with s3c2410 rtc. + * "samsung,s3c6410-rtc" - for controllers compatible with s3c6410 rtc. +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: Two interrupt numbers to the cpu should be specified. First + interrupt number is the rtc alarm interupt and second interrupt number + is the rtc tick interrupt. The number of cells representing a interrupt + depends on the parent interrupt controller. + +Example: + + rtc@10070000 { + compatible = "samsung,s3c6410-rtc"; + reg = <0x10070000 0x100>; + interrupts = <44 0 45 0>; + }; diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 5b979d9cc33..175067a17c4 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -507,7 +508,13 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) goto err_nortc; } - s3c_rtc_cpu_type = platform_get_device_id(pdev)->driver_data; +#ifdef CONFIG_OF + if (pdev->dev.of_node) + s3c_rtc_cpu_type = of_device_is_compatible(pdev->dev.of_node, + "samsung,s3c6410-rtc") ? TYPE_S3C64XX : TYPE_S3C2410; + else +#endif + s3c_rtc_cpu_type = platform_get_device_id(pdev)->driver_data; /* Check RTC Time */ @@ -629,6 +636,17 @@ static int s3c_rtc_resume(struct platform_device *pdev) #define s3c_rtc_resume NULL #endif +#ifdef CONFIG_OF +static const struct of_device_id s3c_rtc_dt_match[] = { + { .compatible = "samsung,s3c2410-rtc" }, + { .compatible = "samsung,s3c6410-rtc" }, + {}, +}; +MODULE_DEVICE_TABLE(of, s3c_rtc_dt_match); +#else +#define s3c_rtc_dt_match NULL +#endif + static struct platform_device_id s3c_rtc_driver_ids[] = { { .name = "s3c2410-rtc", @@ -651,6 +669,7 @@ static struct platform_driver s3c_rtc_driver = { .driver = { .name = "s3c-rtc", .owner = THIS_MODULE, + .of_match_table = s3c_rtc_dt_match, }, }; -- cgit v1.2.3-70-g09d2 From 6b5ab4f442e32f248b6fad29aafd1d5153f4dbd3 Mon Sep 17 00:00:00 2001 From: Thomas Abraham Date: Sun, 6 Nov 2011 21:54:27 +0530 Subject: ARM: EXYNOS: Add Exynos4 device tree enabled board file Add a new EXYNOS4 compatible device tree enabled board file. Boards based on the EXYNOS4 family of SoC's can use this as the machine/board file. When using this machine fike, a corresponding device tree blob which describes the board's properties should be supplied at boot time to the kernel. Signed-off-by: Thomas Abraham Acked-by: Grant Likely Signed-off-by: Kukjin Kim --- .../devicetree/bindings/arm/insignal-boards.txt | 8 ++ .../devicetree/bindings/arm/samsung-boards.txt | 8 ++ arch/arm/mach-exynos/Kconfig | 14 ++++ arch/arm/mach-exynos/Makefile | 2 + arch/arm/mach-exynos/mach-exynos4-dt.c | 85 ++++++++++++++++++++++ 5 files changed, 117 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/insignal-boards.txt create mode 100644 Documentation/devicetree/bindings/arm/samsung-boards.txt create mode 100644 arch/arm/mach-exynos/mach-exynos4-dt.c (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/arm/insignal-boards.txt b/Documentation/devicetree/bindings/arm/insignal-boards.txt new file mode 100644 index 00000000000..524c3dc5d80 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/insignal-boards.txt @@ -0,0 +1,8 @@ +* Insignal's Exynos4210 based Origen evaluation board + +Origen low-cost evaluation board is based on Samsung's Exynos4210 SoC. + +Required root node properties: + - compatible = should be one or more of the following. + (a) "samsung,smdkv310" - for Samsung's SMDKV310 eval board. + (b) "samsung,exynos4210" - for boards based on Exynos4210 SoC. diff --git a/Documentation/devicetree/bindings/arm/samsung-boards.txt b/Documentation/devicetree/bindings/arm/samsung-boards.txt new file mode 100644 index 00000000000..0bf68be56fd --- /dev/null +++ b/Documentation/devicetree/bindings/arm/samsung-boards.txt @@ -0,0 +1,8 @@ +* Samsung's Exynos4210 based SMDKV310 evaluation board + +SMDKV310 evaluation board is based on Samsung's Exynos4210 SoC. + +Required root node properties: + - compatible = should be one or more of the following. + (a) "samsung,smdkv310" - for Samsung's SMDKV310 eval board. + (b) "samsung,exynos4210" - for boards based on Exynos4210 SoC. diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index 68e4ab0c937..0afcc3b0f87 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -337,6 +337,20 @@ config MACH_SMDK4412 Machine support for Samsung SMDK4412 endif +comment "Flattened Device Tree based board for Exynos4 based SoC" + +config MACH_EXYNOS4_DT + bool "Samsung Exynos4 Machine using device tree" + select CPU_EXYNOS4210 + select USE_OF + select ARM_AMBA + select HAVE_SAMSUNG_KEYPAD if INPUT_KEYBOARD + help + Machine support for Samsung Exynos4 machine with device tree enabled. + Select this if a fdt blob is available for the Exynos4 SoC based board. + Note: This is under development and not all peripherals can be supported + with this machine file. + if ARCH_EXYNOS4 comment "Configuration for HSMMC 8-bit bus width" diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile index cb6fb0e8bca..8d85ae635ac 100644 --- a/arch/arm/mach-exynos/Makefile +++ b/arch/arm/mach-exynos/Makefile @@ -37,6 +37,8 @@ obj-$(CONFIG_MACH_ORIGEN) += mach-origen.o obj-$(CONFIG_MACH_SMDK4212) += mach-smdk4x12.o obj-$(CONFIG_MACH_SMDK4412) += mach-smdk4x12.o +obj-$(CONFIG_MACH_EXYNOS4_DT) += mach-exynos4-dt.o + # device support obj-$(CONFIG_ARCH_EXYNOS4) += dev-audio.o diff --git a/arch/arm/mach-exynos/mach-exynos4-dt.c b/arch/arm/mach-exynos/mach-exynos4-dt.c new file mode 100644 index 00000000000..85fa02767d6 --- /dev/null +++ b/arch/arm/mach-exynos/mach-exynos4-dt.c @@ -0,0 +1,85 @@ +/* + * Samsung's Exynos4210 flattened device tree enabled machine + * + * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * Copyright (c) 2010-2011 Linaro Ltd. + * www.linaro.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include +#include + +#include +#include + +#include +#include +#include + +/* + * The following lookup table is used to override device names when devices + * are registered from device tree. This is temporarily added to enable + * device tree support addition for the Exynos4 architecture. + * + * For drivers that require platform data to be provided from the machine + * file, a platform data pointer can also be supplied along with the + * devices names. Usually, the platform data elements that cannot be parsed + * from the device tree by the drivers (example: function pointers) are + * supplied. But it should be noted that this is a temporary mechanism and + * at some point, the drivers should be capable of parsing all the platform + * data from the device tree. + */ +static const struct of_dev_auxdata exynos4210_auxdata_lookup[] __initconst = { + OF_DEV_AUXDATA("samsung,exynos4210-uart", S5P_PA_UART0, + "exynos4210-uart.0", NULL), + OF_DEV_AUXDATA("samsung,exynos4210-uart", S5P_PA_UART1, + "exynos4210-uart.1", NULL), + OF_DEV_AUXDATA("samsung,exynos4210-uart", S5P_PA_UART2, + "exynos4210-uart.2", NULL), + OF_DEV_AUXDATA("samsung,exynos4210-uart", S5P_PA_UART3, + "exynos4210-uart.3", NULL), + OF_DEV_AUXDATA("samsung,exynos4210-sdhci", EXYNOS4_PA_HSMMC(0), + "exynos4-sdhci.0", NULL), + OF_DEV_AUXDATA("samsung,exynos4210-sdhci", EXYNOS4_PA_HSMMC(1), + "exynos4-sdhci.1", NULL), + OF_DEV_AUXDATA("samsung,exynos4210-sdhci", EXYNOS4_PA_HSMMC(2), + "exynos4-sdhci.2", NULL), + OF_DEV_AUXDATA("samsung,exynos4210-sdhci", EXYNOS4_PA_HSMMC(3), + "exynos4-sdhci.3", NULL), + OF_DEV_AUXDATA("samsung,s3c2440-i2c", EXYNOS4_PA_IIC(0), + "s3c2440-i2c.0", NULL), + OF_DEV_AUXDATA("arm,pl330", EXYNOS4_PA_PDMA0, "dma-pl330.0", NULL), + OF_DEV_AUXDATA("arm,pl330", EXYNOS4_PA_PDMA1, "dma-pl330.1", NULL), + {}, +}; + +static void __init exynos4210_dt_map_io(void) +{ + s5p_init_io(NULL, 0, S5P_VA_CHIPID); + s3c24xx_init_clocks(24000000); +} + +static void __init exynos4210_dt_machine_init(void) +{ + of_platform_populate(NULL, of_default_bus_match_table, + exynos4210_auxdata_lookup, NULL); +} + +static char const *exynos4210_dt_compat[] __initdata = { + "samsung,exynos4210", + NULL +}; + +DT_MACHINE_START(EXYNOS4210_DT, "Samsung Exynos4 (Flattened Device Tree)") + /* Maintainer: Thomas Abraham */ + .init_irq = exynos4_init_irq, + .map_io = exynos4210_dt_map_io, + .init_machine = exynos4210_dt_machine_init, + .timer = &exynos4_timer, + .dt_compat = exynos4210_dt_compat, +MACHINE_END -- cgit v1.2.3-70-g09d2 From 02bca5ff270774d4b4929de8b62ab96708065386 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Tue, 27 Dec 2011 11:18:46 -0800 Subject: dt/i2c: Enumerate some of the known trivial i2c devices Based on recent discussions, we apparently want to do bindings even for trivial i2c devices, even though they have for years just been added. So start a table of the currently known ones for others to be added to over time. (I am intentionally letting lines go over 80 characters to make it easier to sort the file). Signed-off-by: Olof Johansson Signed-off-by: Rob Herring --- .../devicetree/bindings/i2c/trivial-devices.txt | 58 ++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/trivial-devices.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/i2c/trivial-devices.txt b/Documentation/devicetree/bindings/i2c/trivial-devices.txt new file mode 100644 index 00000000000..1a85f986961 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/trivial-devices.txt @@ -0,0 +1,58 @@ +This is a list of trivial i2c devices that have simple device tree +bindings, consisting only of a compatible field, an address and +possibly an interrupt line. + +If a device needs more specific bindings, such as properties to +describe some aspect of it, there needs to be a specific binding +document for it just like any other devices. + + +Compatible Vendor / Chip +========== ============= +ad,ad7414 SMBus/I2C Digital Temperature Sensor in 6-Pin SOT with SMBus Alert and Over Temperature Pin +ad,adm9240 ADM9240: Complete System Hardware Monitor for uProcessor-Based Systems +adi,adt7461 +/-1C TDM Extended Temp Range I.C +adt7461 +/-1C TDM Extended Temp Range I.C +at,24c08 i2c serial eeprom (24cxx) +atmel,24c02 i2c serial eeprom (24cxx) +catalyst,24c32 i2c serial eeprom +dallas,ds1307 64 x 8, Serial, I2C Real-Time Clock +dallas,ds1338 I2C RTC with 56-Byte NV RAM +dallas,ds1339 I2C Serial Real-Time Clock +dallas,ds1340 I2C RTC with Trickle Charger +dallas,ds1374 I2C, 32-Bit Binary Counter Watchdog RTC with Trickle Charger and Reset Input/Output +dallas,ds1631 High-Precision Digital Thermometer +dallas,ds1682 Total-Elapsed-Time Recorder with Alarm +dallas,ds1775 Tiny Digital Thermometer and Thermostat +dallas,ds3232 Extremely Accurate I²C RTC with Integrated Crystal and SRAM +dallas,ds4510 CPU Supervisor with Nonvolatile Memory and Programmable I/O +dallas,ds75 Digital Thermometer and Thermostat +dialog,da9053 DA9053: flexible system level PMIC with multicore support +epson,rx8025 High-Stability. I2C-Bus INTERFACE REAL TIME CLOCK MODULE +epson,rx8581 I2C-BUS INTERFACE REAL TIME CLOCK MODULE +fsl,mag3110 MAG3110: Xtrinsic High Accuracy, 3D Magnetometer +fsl,mc13892 MC13892: Power Management Integrated Circuit (PMIC) for i.MX35/51 +fsl,mma8450 MMA8450Q: Xtrinsic Low-power, 3-axis Xtrinsic Accelerometer +fsl,mpr121 MPR121: Proximity Capacitive Touch Sensor Controller +fsl,sgtl5000 SGTL5000: Ultra Low-Power Audio Codec +maxim,ds1050 5 Bit Programmable, Pulse-Width Modulator +maxim,max1237 Low-Power, 4-/12-Channel, 2-Wire Serial, 12-Bit ADCs +maxim,max6625 9-Bit/12-Bit Temperature Sensors with I²C-Compatible Serial Interface +mc,rv3029c2 Real Time Clock Module with I2C-Bus +national,lm75 I2C TEMP SENSOR +national,lm80 Serial Interface ACPI-Compatible Microprocessor System Hardware Monitor +national,lm92 ±0.33°C Accurate, 12-Bit + Sign Temperature Sensor and Thermal Window Comparator with Two-Wire Interface +nxp,pca9556 Octal SMBus and I2C registered interface +nxp,pca9557 8-bit I2C-bus and SMBus I/O port with reset +nxp,pcf8563 Real-time clock/calendar +ovti,ov5642 OV5642: Color CMOS QSXGA (5-megapixel) Image Sensor with OmniBSI and Embedded TrueFocus +pericom,pt7c4338 Real-time Clock Module +plx,pex8648 48-Lane, 12-Port PCI Express Gen 2 (5.0 GT/s) Switch +ramtron,24c64 i2c serial eeprom (24cxx) +ricoh,rs5c372a I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC +samsung,24ad0xd1 S524AD0XF1 (128K/256K-bit Serial EEPROM for Low Power) +st-micro,24c256 i2c serial eeprom (24cxx) +stm,m41t00 Serial Access TIMEKEEPER +stm,m41t62 Serial real-time clock (RTC) with alarm +stm,m41t80 M41T80 - SERIAL ACCESS RTC WITH ALARMS +ti,tsc2003 I2C Touch-Screen Controller -- cgit v1.2.3-70-g09d2 From af71100c7acf3ccaf95044cd5e9e866178e5f8a1 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 8 Nov 2011 14:43:47 -0600 Subject: i2c-designware: add OF binding support Add of_match_table and DT style i2c registration to designware i2c driver. Refactored for pci/plat split by Dirk Brandewie. Signed-off-by: Rob Herring Acked-by: Grant Likely Signed-off-by: Dirk Brandewie --- .../devicetree/bindings/i2c/i2c-designware.txt | 22 ++++++++++++++++++++++ drivers/i2c/busses/i2c-designware-platdrv.c | 12 ++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/i2c-designware.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/i2c/i2c-designware.txt b/Documentation/devicetree/bindings/i2c/i2c-designware.txt new file mode 100644 index 00000000000..e42a2ee233e --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-designware.txt @@ -0,0 +1,22 @@ +* Synopsys DesignWare I2C + +Required properties : + + - compatible : should be "snps,designware-i2c" + - reg : Offset and length of the register set for the device + - interrupts : where IRQ is the interrupt number. + +Recommended properties : + + - clock-frequency : desired I2C bus clock frequency in Hz. + +Example : + + i2c@f0000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,designware-i2c"; + reg = <0xf0000 0x1000>; + interrupts = <11>; + clock-frequency = <400000>; + }; diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 2d3657ab125..5244c4724df 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -137,6 +138,7 @@ static int __devinit dw_i2c_probe(struct platform_device *pdev) sizeof(adap->name)); adap->algo = &i2c_dw_algo; adap->dev.parent = &pdev->dev; + adap->dev.of_node = pdev->dev.of_node; adap->nr = pdev->id; r = i2c_add_numbered_adapter(adap); @@ -144,6 +146,7 @@ static int __devinit dw_i2c_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failure adding adapter\n"); goto err_free_irq; } + of_i2c_register_devices(adap); return 0; @@ -187,6 +190,14 @@ static int __devexit dw_i2c_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_OF +static const struct of_device_id dw_i2c_of_match[] = { + { .compatible = "snps,designware-i2c", }, + {}, +}; +MODULE_DEVICE_TABLE(of, dw_i2c_of_match); +#endif + /* work with hotplug and coldplug */ MODULE_ALIAS("platform:i2c_designware"); @@ -195,6 +206,7 @@ static struct platform_driver dw_i2c_driver = { .driver = { .name = "i2c_designware", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(dw_i2c_of_match), }, }; -- cgit v1.2.3-70-g09d2 From a445c7f0afb9114ef3de2d123f2c851787cf9d11 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Thu, 29 Dec 2011 09:58:16 -0800 Subject: Input: tegra-kbc - add device tree bindings This adds a simple device tree binding to the tegra keyboard controller. Also, mark the default keymap as __devinitdata since it is not referenced after boot. Signed-off-by: Olof Johansson Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/tegra-kbc.txt | 18 +++++ drivers/input/keyboard/tegra-kbc.c | 92 ++++++++++++++++++++-- 2 files changed, 102 insertions(+), 8 deletions(-) create mode 100644 Documentation/devicetree/bindings/input/tegra-kbc.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/input/tegra-kbc.txt b/Documentation/devicetree/bindings/input/tegra-kbc.txt new file mode 100644 index 00000000000..5ecfa99089b --- /dev/null +++ b/Documentation/devicetree/bindings/input/tegra-kbc.txt @@ -0,0 +1,18 @@ +* Tegra keyboard controller + +Required properties: +- compatible: "nvidia,tegra20-kbc" + +Optional properties: +- debounce-delay: delay in milliseconds per row scan for debouncing +- repeat-delay: delay in milliseconds before repeat starts +- ghost-filter: enable ghost filtering for this device +- wakeup-source: configure keyboard as a wakeup source for suspend/resume + +Example: + +keyboard: keyboard { + compatible = "nvidia,tegra20-kbc"; + reg = <0x7000e200 0x100>; + ghost-filter; +}; diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c index 08d02f2c6a8..b77725db4be 100644 --- a/drivers/input/keyboard/tegra-kbc.c +++ b/drivers/input/keyboard/tegra-kbc.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -82,7 +83,7 @@ struct tegra_kbc { struct clk *clk; }; -static const u32 tegra_kbc_default_keymap[] = { +static const u32 tegra_kbc_default_keymap[] __devinitdata = { KEY(0, 2, KEY_W), KEY(0, 3, KEY_S), KEY(0, 4, KEY_A), @@ -217,7 +218,8 @@ static const u32 tegra_kbc_default_keymap[] = { KEY(31, 4, KEY_HELP), }; -static const struct matrix_keymap_data tegra_kbc_default_keymap_data = { +static const +struct matrix_keymap_data tegra_kbc_default_keymap_data __devinitdata = { .keymap = tegra_kbc_default_keymap, .keymap_size = ARRAY_SIZE(tegra_kbc_default_keymap), }; @@ -576,6 +578,56 @@ tegra_kbc_check_pin_cfg(const struct tegra_kbc_platform_data *pdata, return true; } +#ifdef CONFIG_OF +static struct tegra_kbc_platform_data * __devinit +tegra_kbc_dt_parse_pdata(struct platform_device *pdev) +{ + struct tegra_kbc_platform_data *pdata; + struct device_node *np = pdev->dev.of_node; + + if (!np) + return NULL; + + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return NULL; + + if (!of_property_read_u32(np, "debounce-delay", &prop)) + pdata->debounce_cnt = prop; + + if (!of_property_read_u32(np, "repeat-delay", &prop)) + pdata->repeat_cnt = prop; + + if (of_find_property(np, "needs-ghost-filter", NULL)) + pdata->use_ghost_filter = true; + + if (of_find_property(np, "wakeup-source", NULL)) + pdata->wakeup = true; + + /* + * All currently known keymaps with device tree support use the same + * pin_cfg, so set it up here. + */ + for (i = 0; i < KBC_MAX_ROW; i++) { + pdata->pin_cfg[i].num = i; + pdata->pin_cfg[i].is_row = true; + } + + for (i = 0; i < KBC_MAX_COL; i++) { + pdata->pin_cfg[KBC_MAX_ROW + i].num = i; + pdata->pin_cfg[KBC_MAX_ROW + i].is_row = false; + } + + return pdata; +} +#else +static inline struct tegra_kbc_platform_data *tegra_kbc_dt_parse_pdata( + struct platform_device *pdev) +{ + return NULL; +} +#endif + static int __devinit tegra_kbc_probe(struct platform_device *pdev) { const struct tegra_kbc_platform_data *pdata = pdev->dev.platform_data; @@ -590,21 +642,28 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev) unsigned int scan_time_rows; if (!pdata) - return -EINVAL; + pdata = tegra_kbc_dt_parse_pdata(pdev); - if (!tegra_kbc_check_pin_cfg(pdata, &pdev->dev, &num_rows)) + if (!pdata) return -EINVAL; + if (!tegra_kbc_check_pin_cfg(pdata, &pdev->dev, &num_rows)) { + err = -EINVAL; + goto err_free_pdata; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "failed to get I/O memory\n"); - return -ENXIO; + err = -ENXIO; + goto err_free_pdata; } irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "failed to get keyboard IRQ\n"); - return -ENXIO; + err = -ENXIO; + goto err_free_pdata; } kbc = kzalloc(sizeof(*kbc), GFP_KERNEL); @@ -706,6 +765,9 @@ err_free_mem_region: err_free_mem: input_free_device(input_dev); kfree(kbc); +err_free_pdata: + if (!pdev->dev.platform_data) + kfree(pdata); return err; } @@ -715,6 +777,8 @@ static int __devexit tegra_kbc_remove(struct platform_device *pdev) struct tegra_kbc *kbc = platform_get_drvdata(pdev); struct resource *res; + platform_set_drvdata(pdev, NULL); + free_irq(kbc->irq, pdev); clk_put(kbc->clk); @@ -723,9 +787,14 @@ static int __devexit tegra_kbc_remove(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(res->start, resource_size(res)); - kfree(kbc); + /* + * If we do not have platform data attached to the device we + * allocated it ourselves and thus need to free it. + */ + if (!pdev->dev.platform_data) + kfree(kbc->pdata); - platform_set_drvdata(pdev, NULL); + kfree(kbc); return 0; } @@ -793,6 +862,12 @@ static int tegra_kbc_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(tegra_kbc_pm_ops, tegra_kbc_suspend, tegra_kbc_resume); +static const struct of_device_id tegra_kbc_of_match[] = { + { .compatible = "nvidia,tegra20-kbc", }, + { }, +}; +MODULE_DEVICE_TABLE(of, tegra_kbc_of_match); + static struct platform_driver tegra_kbc_driver = { .probe = tegra_kbc_probe, .remove = __devexit_p(tegra_kbc_remove), @@ -800,6 +875,7 @@ static struct platform_driver tegra_kbc_driver = { .name = "tegra-kbc", .owner = THIS_MODULE, .pm = &tegra_kbc_pm_ops, + .of_match_table = tegra_kbc_of_match, }, }; module_platform_driver(tegra_kbc_driver); -- cgit v1.2.3-70-g09d2 From 35f3da32af0e8970cc41288d4a7e3bd32399900e Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Mon, 5 Dec 2011 15:23:55 +0100 Subject: of/address: Add reg-names property to name an iomem resource Add a reg-names property to allow for reg regions to be reference by name instead of by index. Some devices have multiple register regions which are more naturally referenced by name. If the name is available, use it to name the resource when creating a devices. Otherwise keep the device name. Signed-off-by: Benoit Cousson Cc: Grant Likely Cc: Rob Herring [Generalized documentation to be for any -names property] Signed-off-by: Grant Likely --- .../devicetree/bindings/resource-names.txt | 50 ++++++++++++++++++++++ drivers/of/address.c | 16 ++++--- 2 files changed, 61 insertions(+), 5 deletions(-) create mode 100644 Documentation/devicetree/bindings/resource-names.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/resource-names.txt b/Documentation/devicetree/bindings/resource-names.txt new file mode 100644 index 00000000000..8405b956aca --- /dev/null +++ b/Documentation/devicetree/bindings/resource-names.txt @@ -0,0 +1,50 @@ +Some properties contain an ordered list of 1 or more datum which are +normally accessed by index. However, some devices will have multiple +values which are more naturally accessed by name. Device nodes can +include a supplemental property for assigning names to each of the list +items. The names property consists of a list of strings in the same +order as the data in the resource property. + +The following supplemental names properties are defined. + +Resource Property Supplemental Names Property +----------------- --------------------------- +reg reg-names +clocks clock-names +interrupts interrupt-names + +Usage: + +The -names property must be used in conjunction with the normal resource +property. If not it will be ignored. + +Examples: + +l4-abe { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <1>; + ranges = <0 0 0x48000000 0x00001000>, /* MPU path */ + <1 0 0x49000000 0x00001000>; /* L3 path */ + mcasp { + compatible = "ti,mcasp"; + reg = <0 0x10 0x10>, <0 0x20 0x10>, + <1 0x10 0x10>, <1 0x20 0x10>; + reg-names = "mpu", "dat", + "dma", "dma_dat"; + }; + + timer { + compatible = "ti,timer"; + reg = <0 0x40 0x10>, <1 0x40 0x10>; + reg-names = "mpu", "dma"; + }; +}; + + +usb { + compatible = "ti,usb-host"; + reg = <0x4a064000 0x800>, <0x4a064800 0x200>, + <0x4a064c00 0x200>; + reg-names = "config", "ohci", "ehci"; +}; diff --git a/drivers/of/address.c b/drivers/of/address.c index 72c33fbe451..66d96f14c27 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -14,7 +14,7 @@ static struct of_bus *of_match_bus(struct device_node *np); static int __of_address_to_resource(struct device_node *dev, const __be32 *addrp, u64 size, unsigned int flags, - struct resource *r); + const char *name, struct resource *r); /* Debug utility */ #ifdef DEBUG @@ -215,7 +215,7 @@ int of_pci_address_to_resource(struct device_node *dev, int bar, addrp = of_get_pci_address(dev, bar, &size, &flags); if (addrp == NULL) return -EINVAL; - return __of_address_to_resource(dev, addrp, size, flags, r); + return __of_address_to_resource(dev, addrp, size, flags, NULL, r); } EXPORT_SYMBOL_GPL(of_pci_address_to_resource); #endif /* CONFIG_PCI */ @@ -529,7 +529,7 @@ EXPORT_SYMBOL(of_get_address); static int __of_address_to_resource(struct device_node *dev, const __be32 *addrp, u64 size, unsigned int flags, - struct resource *r) + const char *name, struct resource *r) { u64 taddr; @@ -551,7 +551,8 @@ static int __of_address_to_resource(struct device_node *dev, r->end = taddr + size - 1; } r->flags = flags; - r->name = dev->full_name; + r->name = name ? name : dev->full_name; + return 0; } @@ -569,11 +570,16 @@ int of_address_to_resource(struct device_node *dev, int index, const __be32 *addrp; u64 size; unsigned int flags; + const char *name = NULL; addrp = of_get_address(dev, index, &size, &flags); if (addrp == NULL) return -EINVAL; - return __of_address_to_resource(dev, addrp, size, flags, r); + + /* Get optional "reg-names" property to add a name to a resource */ + of_property_read_string_index(dev, "reg-names", index, &name); + + return __of_address_to_resource(dev, addrp, size, flags, name, r); } EXPORT_SYMBOL_GPL(of_address_to_resource); -- cgit v1.2.3-70-g09d2 From 661db794eb8179c7bea02f159bb691a2fff4a8e0 Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Mon, 5 Dec 2011 15:23:56 +0100 Subject: of/irq: Add interrupts-names property to name an irq resource Add a interrupts-names property to allow the possibility to provide a name to any interrupts entries. If the name is available, use it to name the resource, otherwise keep the device full name. Signed-off-by: Benoit Cousson Cc: Grant Likely Cc: Rob Herring [grant.likely: use "interrupt-names" and tidy documentation] Signed-off-by: Grant Likely --- Documentation/devicetree/bindings/resource-names.txt | 4 ++++ drivers/of/irq.c | 11 ++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/resource-names.txt b/Documentation/devicetree/bindings/resource-names.txt index 8405b956aca..e280fef6f26 100644 --- a/Documentation/devicetree/bindings/resource-names.txt +++ b/Documentation/devicetree/bindings/resource-names.txt @@ -32,6 +32,8 @@ l4-abe { <1 0x10 0x10>, <1 0x20 0x10>; reg-names = "mpu", "dat", "dma", "dma_dat"; + interrupts = <11>, <12>; + interrupt-names = "rx", "tx"; }; timer { @@ -47,4 +49,6 @@ usb { reg = <0x4a064000 0x800>, <0x4a064800 0x200>, <0x4a064c00 0x200>; reg-names = "config", "ohci", "ehci"; + interrupts = <14>, <15>; + interrupt-names = "ohci", "ehci"; }; diff --git a/drivers/of/irq.c b/drivers/of/irq.c index 0f0cfa3bca3..9cf00602f56 100644 --- a/drivers/of/irq.c +++ b/drivers/of/irq.c @@ -341,9 +341,18 @@ int of_irq_to_resource(struct device_node *dev, int index, struct resource *r) /* Only dereference the resource if both the * resource and the irq are valid. */ if (r && irq) { + const char *name = NULL; + + /* + * Get optional "interrupts-names" property to add a name + * to the resource. + */ + of_property_read_string_index(dev, "interrupt-names", index, + &name); + r->start = r->end = irq; r->flags = IORESOURCE_IRQ; - r->name = dev->full_name; + r->name = name ? name : dev->full_name; } return irq; -- cgit v1.2.3-70-g09d2 From 1c84b60b813cb10476618b2311a89e31018b2cc4 Mon Sep 17 00:00:00 2001 From: Rhyland Klein Date: Mon, 5 Dec 2011 17:50:47 -0800 Subject: devicetree-bindings: Add vendor entry for Smart Battery Systems Signed-off-by: Rhyland Klein Signed-off-by: Anton Vorontsov --- Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index e8552782b44..9f7bef601e0 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -32,6 +32,7 @@ powervr Imagination Technologies qcom Qualcomm, Inc. ramtron Ramtron International samsung Samsung Semiconductor +sbs Smart Battery System schindler Schindler simtek sirf SiRF Technology, Inc. -- cgit v1.2.3-70-g09d2 From e57f1b68c4066459ed9e49177cdcefa6973ce9d2 Mon Sep 17 00:00:00 2001 From: Rhyland Klein Date: Mon, 5 Dec 2011 17:50:48 -0800 Subject: devicetree-bindings: Propagate bq20z75->sbs rename to dt bindings Signed-off-by: Rhyland Klein Signed-off-by: Anton Vorontsov --- .../bindings/power_supply/sbs_sbs-battery.txt | 23 ++++++++++++++++++++++ .../bindings/power_supply/ti_bq20z75.txt | 23 ---------------------- 2 files changed, 23 insertions(+), 23 deletions(-) create mode 100644 Documentation/devicetree/bindings/power_supply/sbs_sbs-battery.txt delete mode 100644 Documentation/devicetree/bindings/power_supply/ti_bq20z75.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/power_supply/sbs_sbs-battery.txt b/Documentation/devicetree/bindings/power_supply/sbs_sbs-battery.txt new file mode 100644 index 00000000000..c40e8926fac --- /dev/null +++ b/Documentation/devicetree/bindings/power_supply/sbs_sbs-battery.txt @@ -0,0 +1,23 @@ +SBS sbs-battery +~~~~~~~~~~ + +Required properties : + - compatible : "sbs,sbs-battery" + +Optional properties : + - sbs,i2c-retry-count : The number of times to retry i2c transactions on i2c + IO failure. + - sbs,poll-retry-count : The number of times to try looking for new status + after an external change notification. + - sbs,battery-detect-gpios : The gpio which signals battery detection and + a flag specifying its polarity. + +Example: + + bq20z75@b { + compatible = "sbs,sbs-battery"; + reg = < 0xb >; + sbs,i2c-retry-count = <2>; + sbs,poll-retry-count = <10>; + sbs,battery-detect-gpios = <&gpio-controller 122 1>; + } diff --git a/Documentation/devicetree/bindings/power_supply/ti_bq20z75.txt b/Documentation/devicetree/bindings/power_supply/ti_bq20z75.txt deleted file mode 100644 index 7571294f411..00000000000 --- a/Documentation/devicetree/bindings/power_supply/ti_bq20z75.txt +++ /dev/null @@ -1,23 +0,0 @@ -TI bq20z75 -~~~~~~~~~~ - -Required properties : - - compatible : "ti,bq20z75" - -Optional properties : - - ti,i2c-retry-count : The number of times to retry i2c transactions on i2c - IO failure. - - ti,poll-retry-count : The number of times to try looking for new status - after an external change notification. - - ti,battery-detect-gpios : The gpio which signals battery detection and - a flag specifying its polarity. - -Example: - - bq20z75@b { - compatible = "ti,bq20z75"; - reg = < 0xb >; - ti,i2c-retry-count = <2>; - ti,poll-retry-count = <10>; - ti,battery-detect-gpios = <&gpio-controller 122 1>; - } -- cgit v1.2.3-70-g09d2 From 35ca98423a4c61decc20cd1d1e78a7fd7111e4db Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 22 Nov 2011 18:59:28 +0000 Subject: mfd: Add basic device tree binding for wm8994 Add a placeholder device tree binding for the wm8994 driver. At present the binding is essentially null as none of the platform data is supported, and at least some of that will depend on the pending regulator bindings. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- Documentation/devicetree/bindings/sound/wm8994.txt | 18 ++++++++++++++++++ drivers/mfd/wm8994-core.c | 9 +++++++++ 2 files changed, 27 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/wm8994.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/sound/wm8994.txt b/Documentation/devicetree/bindings/sound/wm8994.txt new file mode 100644 index 00000000000..7a7eb1e7bda --- /dev/null +++ b/Documentation/devicetree/bindings/sound/wm8994.txt @@ -0,0 +1,18 @@ +WM1811/WM8994/WM8958 audio CODEC + +These devices support both I2C and SPI (configured with pin strapping +on the board). + +Required properties: + + - compatible : "wlf,wm1811", "wlf,wm8994", "wlf,wm8958" + + - reg : the I2C address of the device for I2C, the chip select + number for SPI. + +Example: + +codec: wm8994@1a { + compatible = "wlf,wm8994"; + reg = <0x1a>; +}; diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 776298b313a..e6663248141 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -582,6 +582,14 @@ static void wm8994_device_exit(struct wm8994 *wm8994) regmap_exit(wm8994->regmap); } +static const struct of_device_id wm8994_of_match[] = { + { .compatible = "wlf,wm1811", }, + { .compatible = "wlf,wm8994", }, + { .compatible = "wlf,wm8958", }, + { } +}; +MODULE_DEVICE_TABLE(of, wm8994_of_match); + static int wm8994_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -633,6 +641,7 @@ static struct i2c_driver wm8994_i2c_driver = { .name = "wm8994", .owner = THIS_MODULE, .pm = &wm8994_pm_ops, + .of_match_table = wm8994_of_match, }, .probe = wm8994_i2c_probe, .remove = wm8994_i2c_remove, -- cgit v1.2.3-70-g09d2 From 876989d58658858f27a461f0b4b43fa750a208f4 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Mon, 12 Dec 2011 18:52:57 +0100 Subject: mfd: Add device tree probe support for mc13xxx This adds device tree probe support for mc13xxx mfd driver. Signed-off-by: Shawn Guo Signed-off-by: Samuel Ortiz --- Documentation/devicetree/bindings/mfd/mc13xxx.txt | 53 +++++++++++ drivers/mfd/mc13xxx-core.c | 106 +++++++++++++++------- 2 files changed, 128 insertions(+), 31 deletions(-) create mode 100644 Documentation/devicetree/bindings/mfd/mc13xxx.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/mfd/mc13xxx.txt b/Documentation/devicetree/bindings/mfd/mc13xxx.txt new file mode 100644 index 00000000000..4ed46a61063 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/mc13xxx.txt @@ -0,0 +1,53 @@ +* Freescale MC13783/MC13892 Power Management Integrated Circuit (PMIC) + +Required properties: +- compatible : Should be "fsl,mc13783" or "fsl,mc13892" + +Optional properties: +- fsl,mc13xxx-uses-adc : Indicate the ADC is being used +- fsl,mc13xxx-uses-codec : Indicate the Audio Codec is being used +- fsl,mc13xxx-uses-rtc : Indicate the RTC is being used +- fsl,mc13xxx-uses-touch : Indicate the touchscreen controller is being used + +Sub-nodes: +- regulators : Contain the regulator nodes. The name of regulator node + is being used by mc13xxx regulator driver to find the correct relator + device. + + The bindings details of individual regulator device can be found in: + Documentation/devicetree/bindings/regulator/regulator.txt + +Examples: + +ecspi@70010000 { /* ECSPI1 */ + fsl,spi-num-chipselects = <2>; + cs-gpios = <&gpio3 24 0>, /* GPIO4_24 */ + <&gpio3 25 0>; /* GPIO4_25 */ + status = "okay"; + + pmic: mc13892@0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,mc13892"; + spi-max-frequency = <6000000>; + reg = <0>; + interrupt-parent = <&gpio0>; + interrupts = <8>; + + regulators { + sw1_reg: mc13892__sw1 { + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1375000>; + regulator-boot-on; + regulator-always-on; + }; + + sw2_reg: mc13892__sw2 { + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1850000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; +}; diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index d0d3dfafba5..7122386b4e3 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c @@ -18,11 +18,15 @@ #include #include #include +#include +#include +#include struct mc13xxx { struct spi_device *spidev; struct mutex lock; int irq; + int flags; irq_handler_t irqhandler[MC13XXX_NUM_IRQ]; void *irqdata[MC13XXX_NUM_IRQ]; @@ -550,10 +554,7 @@ static const char *mc13xxx_get_chipname(struct mc13xxx *mc13xxx) int mc13xxx_get_flags(struct mc13xxx *mc13xxx) { - struct mc13xxx_platform_data *pdata = - dev_get_platdata(&mc13xxx->spidev->dev); - - return pdata->flags; + return mc13xxx->flags; } EXPORT_SYMBOL(mc13xxx_get_flags); @@ -696,17 +697,67 @@ static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format) return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL, 0); } +#ifdef CONFIG_OF +static int mc13xxx_probe_flags_dt(struct mc13xxx *mc13xxx) +{ + struct device_node *np = mc13xxx->spidev->dev.of_node; + + if (!np) + return -ENODEV; + + if (of_get_property(np, "fsl,mc13xxx-uses-adc", NULL)) + mc13xxx->flags |= MC13XXX_USE_ADC; + + if (of_get_property(np, "fsl,mc13xxx-uses-codec", NULL)) + mc13xxx->flags |= MC13XXX_USE_CODEC; + + if (of_get_property(np, "fsl,mc13xxx-uses-rtc", NULL)) + mc13xxx->flags |= MC13XXX_USE_RTC; + + if (of_get_property(np, "fsl,mc13xxx-uses-touch", NULL)) + mc13xxx->flags |= MC13XXX_USE_TOUCHSCREEN; + + return 0; +} +#else +static inline int mc13xxx_probe_flags_dt(struct mc13xxx *mc13xxx) +{ + return -ENODEV; +} +#endif + +static const struct spi_device_id mc13xxx_device_id[] = { + { + .name = "mc13783", + .driver_data = MC13XXX_ID_MC13783, + }, { + .name = "mc13892", + .driver_data = MC13XXX_ID_MC13892, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(spi, mc13xxx_device_id); + +static const struct of_device_id mc13xxx_dt_ids[] = { + { .compatible = "fsl,mc13783", .data = (void *) MC13XXX_ID_MC13783, }, + { .compatible = "fsl,mc13892", .data = (void *) MC13XXX_ID_MC13892, }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mc13xxx_dt_ids); + static int mc13xxx_probe(struct spi_device *spi) { + const struct of_device_id *of_id; + struct spi_driver *sdrv = to_spi_driver(spi->dev.driver); struct mc13xxx *mc13xxx; struct mc13xxx_platform_data *pdata = dev_get_platdata(&spi->dev); enum mc13xxx_id id; int ret; - if (!pdata) { - dev_err(&spi->dev, "invalid platform data\n"); - return -EINVAL; - } + of_id = of_match_device(mc13xxx_dt_ids, &spi->dev); + if (of_id) + sdrv->id_table = &mc13xxx_device_id[(enum mc13xxx_id) of_id->data]; mc13xxx = kzalloc(sizeof(*mc13xxx), GFP_KERNEL); if (!mc13xxx) @@ -749,28 +800,33 @@ err_revision: mc13xxx_unlock(mc13xxx); - if (pdata->flags & MC13XXX_USE_ADC) + if (mc13xxx_probe_flags_dt(mc13xxx) < 0 && pdata) + mc13xxx->flags = pdata->flags; + + if (mc13xxx->flags & MC13XXX_USE_ADC) mc13xxx_add_subdevice(mc13xxx, "%s-adc"); - if (pdata->flags & MC13XXX_USE_CODEC) + if (mc13xxx->flags & MC13XXX_USE_CODEC) mc13xxx_add_subdevice(mc13xxx, "%s-codec"); - mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator", - &pdata->regulators, sizeof(pdata->regulators)); - - if (pdata->flags & MC13XXX_USE_RTC) + if (mc13xxx->flags & MC13XXX_USE_RTC) mc13xxx_add_subdevice(mc13xxx, "%s-rtc"); - if (pdata->flags & MC13XXX_USE_TOUCHSCREEN) + if (mc13xxx->flags & MC13XXX_USE_TOUCHSCREEN) mc13xxx_add_subdevice(mc13xxx, "%s-ts"); - if (pdata->leds) + if (pdata) { + mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator", + &pdata->regulators, sizeof(pdata->regulators)); mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led", pdata->leds, sizeof(*pdata->leds)); - - if (pdata->buttons) mc13xxx_add_subdevice_pdata(mc13xxx, "%s-pwrbutton", pdata->buttons, sizeof(*pdata->buttons)); + } else { + mc13xxx_add_subdevice(mc13xxx, "%s-regulator"); + mc13xxx_add_subdevice(mc13xxx, "%s-led"); + mc13xxx_add_subdevice(mc13xxx, "%s-pwrbutton"); + } return 0; } @@ -788,24 +844,12 @@ static int __devexit mc13xxx_remove(struct spi_device *spi) return 0; } -static const struct spi_device_id mc13xxx_device_id[] = { - { - .name = "mc13783", - .driver_data = MC13XXX_ID_MC13783, - }, { - .name = "mc13892", - .driver_data = MC13XXX_ID_MC13892, - }, { - /* sentinel */ - } -}; -MODULE_DEVICE_TABLE(spi, mc13xxx_device_id); - static struct spi_driver mc13xxx_driver = { .id_table = mc13xxx_device_id, .driver = { .name = "mc13xxx", .owner = THIS_MODULE, + .of_match_table = mc13xxx_dt_ids, }, .probe = mc13xxx_probe, .remove = __devexit_p(mc13xxx_remove), -- cgit v1.2.3-70-g09d2 From aeb5032b3f8b9ab69daa545777433fa94b3494c4 Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Mon, 29 Aug 2011 16:20:23 +0200 Subject: mfd: twl-core: Add initial DT support for twl4030/twl6030 Add initial device-tree support for twl familly chips. The current version is missing the regulator entries due to the lack of DT regulator bindings for the moment. Only the simple sub-modules that do not depend on platform_data information can be initialized properly. Add irqdomain support. Add documentation for the Texas Instruments TWL Integrated Chip. Signed-off-by: Benoit Cousson Cc: Balaji T K Cc: Graeme Gregory Signed-off-by: Samuel Ortiz Acked-by: Rob Herring [grant.likely@secretlab.ca: Fix IRQ_DOMAIN dependency in kconfig] Cc: Grant Likely --- .../devicetree/bindings/mfd/twl-familly.txt | 47 ++++++++++++++++++++ drivers/mfd/Kconfig | 2 +- drivers/mfd/twl-core.c | 51 +++++++++++++++++++++- 3 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 Documentation/devicetree/bindings/mfd/twl-familly.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/mfd/twl-familly.txt b/Documentation/devicetree/bindings/mfd/twl-familly.txt new file mode 100644 index 00000000000..a66fcf94675 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/twl-familly.txt @@ -0,0 +1,47 @@ +Texas Instruments TWL family + +The TWLs are Integrated Power Management Chips. +Some version might contain much more analog function like +USB transceiver or Audio amplifier. +These chips are connected to an i2c bus. + + +Required properties: +- compatible : Must be "ti,twl4030"; + For Integrated power-management/audio CODEC device used in OMAP3 + based boards +- compatible : Must be "ti,twl6030"; + For Integrated power-management used in OMAP4 based boards +- interrupts : This i2c device has an IRQ line connected to the main SoC +- interrupt-controller : Since the twl support several interrupts internally, + it is considered as an interrupt controller cascaded to the SoC one. +- #interrupt-cells = <1>; +- interrupt-parent : The parent interrupt controller. + +Optional node: +- Child nodes contain in the twl. The twl family is made of several variants + that support a different number of features. + The children nodes will thus depend of the capability of the variant. + + +Example: +/* + * Integrated Power Management Chip + * http://www.ti.com/lit/ds/symlink/twl6030.pdf + */ +twl@48 { + compatible = "ti,twl6030"; + reg = <0x48>; + interrupts = <39>; /* IRQ_SYS_1N cascaded to gic */ + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&gic>; + #address-cells = <1>; + #size-cells = <0>; + + twl_rtc { + compatible = "ti,twl_rtc"; + interrupts = <11>; + reg = <0>; + }; +}; diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 0f6db32240f..08a3e087bce 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -200,7 +200,7 @@ config MENELAUS config TWL4030_CORE bool "Texas Instruments TWL4030/TWL5030/TWL6030/TPS659x0 Support" - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y && GENERIC_HARDIRQS && IRQ_DOMAIN help Say yes here if you have TWL4030 / TWL6030 family chip on your board. This core driver provides register access and IRQ handling diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 61e70cfaa77..e04e04ddc15 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -34,6 +34,11 @@ #include #include #include +#include +#include +#include +#include +#include #include @@ -144,6 +149,9 @@ #define TWL_MODULE_LAST TWL4030_MODULE_LAST +#define TWL4030_NR_IRQS 8 +#define TWL6030_NR_IRQS 20 + /* Base Address defns for twl4030_map[] */ /* subchip/slave 0 - USB ID */ @@ -255,6 +263,7 @@ struct twl_client { static struct twl_client twl_modules[TWL_NUM_SLAVES]; +static struct irq_domain domain; /* mapping the module id to slave id and base address */ struct twl_mapping { @@ -1183,14 +1192,48 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) int status; unsigned i; struct twl4030_platform_data *pdata = client->dev.platform_data; + struct device_node *node = client->dev.of_node; u8 temp; int ret = 0; + int nr_irqs = TWL4030_NR_IRQS; + + if ((id->driver_data) & TWL6030_CLASS) + nr_irqs = TWL6030_NR_IRQS; + + if (node && !pdata) { + /* + * XXX: Temporary pdata until the information is correctly + * retrieved by every TWL modules from DT. + */ + pdata = devm_kzalloc(&client->dev, + sizeof(struct twl4030_platform_data), + GFP_KERNEL); + if (!pdata) + return -ENOMEM; + } if (!pdata) { dev_dbg(&client->dev, "no platform data?\n"); return -EINVAL; } + status = irq_alloc_descs(-1, pdata->irq_base, nr_irqs, 0); + if (IS_ERR_VALUE(status)) { + dev_err(&client->dev, "Fail to allocate IRQ descs\n"); + return status; + } + + pdata->irq_base = status; + pdata->irq_end = pdata->irq_base + nr_irqs; + + domain.irq_base = pdata->irq_base; + domain.nr_irq = nr_irqs; +#ifdef CONFIG_OF_IRQ + domain.of_node = of_node_get(node); + domain.ops = &irq_domain_simple_ops; +#endif + irq_domain_add(&domain); + if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) { dev_dbg(&client->dev, "can't talk I2C?\n"); return -EIO; @@ -1270,7 +1313,13 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1); } - status = add_children(pdata, id->driver_data); +#ifdef CONFIG_OF_DEVICE + if (node) + status = of_platform_populate(node, NULL, NULL, &client->dev); + else +#endif + status = add_children(pdata, id->driver_data); + fail: if (status < 0) twl_remove(client); -- cgit v1.2.3-70-g09d2 From 5d26dc821ad214906d63bbeda5cdb95ac9798ab0 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Wed, 21 Dec 2011 23:00:44 +0800 Subject: mfd: Improve mc13xxx dt binding document It improves mc13xxx dt binding document on how the regulator name is being used for binding a mc13892 regulator device. Signed-off-by: Shawn Guo Reviewed-by: Mark Brown Signed-off-by: Samuel Ortiz --- Documentation/devicetree/bindings/mfd/mc13xxx.txt | 31 ++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/mfd/mc13xxx.txt b/Documentation/devicetree/bindings/mfd/mc13xxx.txt index 4ed46a61063..19f6af47a79 100644 --- a/Documentation/devicetree/bindings/mfd/mc13xxx.txt +++ b/Documentation/devicetree/bindings/mfd/mc13xxx.txt @@ -10,9 +10,34 @@ Optional properties: - fsl,mc13xxx-uses-touch : Indicate the touchscreen controller is being used Sub-nodes: -- regulators : Contain the regulator nodes. The name of regulator node - is being used by mc13xxx regulator driver to find the correct relator - device. +- regulators : Contain the regulator nodes. The MC13892 regulators are + bound using their names as listed below with their registers and bits + for enabling. + + vcoincell : regulator VCOINCELL (register 13, bit 23) + sw1 : regulator SW1 (register 24, bit 0) + sw2 : regulator SW2 (register 25, bit 0) + sw3 : regulator SW3 (register 26, bit 0) + sw4 : regulator SW4 (register 27, bit 0) + swbst : regulator SWBST (register 29, bit 20) + vgen1 : regulator VGEN1 (register 32, bit 0) + viohi : regulator VIOHI (register 32, bit 3) + vdig : regulator VDIG (register 32, bit 9) + vgen2 : regulator VGEN2 (register 32, bit 12) + vpll : regulator VPLL (register 32, bit 15) + vusb2 : regulator VUSB2 (register 32, bit 18) + vgen3 : regulator VGEN3 (register 33, bit 0) + vcam : regulator VCAM (register 33, bit 6) + vvideo : regulator VVIDEO (register 33, bit 12) + vaudio : regulator VAUDIO (register 33, bit 15) + vsd : regulator VSD (register 33, bit 18) + gpo1 : regulator GPO1 (register 34, bit 6) + gpo2 : regulator GPO2 (register 34, bit 8) + gpo3 : regulator GPO3 (register 34, bit 10) + gpo4 : regulator GPO4 (register 34, bit 12) + pwgt1spi : regulator PWGT1SPI (register 34, bit 15) + pwgt2spi : regulator PWGT2SPI (register 34, bit 16) + vusb : regulator VUSB (register 50, bit 3) The bindings details of individual regulator device can be found in: Documentation/devicetree/bindings/regulator/regulator.txt -- cgit v1.2.3-70-g09d2 From 775c32208708de3e2e2379c85e429ab11957f864 Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Sun, 18 Dec 2011 10:00:49 +0000 Subject: mtd: gpio-nand: add device tree bindings Add device tree bindings so that the gpio-nand driver may be instantiated from the device tree. This also allows the partitions to be specified in the device tree. v7: - restore runtime device tree/non device tree detection v6: - convert to mtd_device_parse_register() v5: - fold dt config helpers into a single gpio_nand_of_get_config() v4: - get io sync address from gpio-control-nand,io-sync-reg property rather than a resource - clarified a few details in the binding v3: - remove redundant cast and a couple of whitespace/naming changes v2: - add CONFIG_OF guards for non-dt platforms - compatible becomes gpio-control-nand - clarify some binding details Signed-off-by: Jamie Iles Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- .../devicetree/bindings/mtd/gpio-control-nand.txt | 44 ++++++++ drivers/mtd/nand/gpio.c | 115 +++++++++++++++++++-- 2 files changed, 152 insertions(+), 7 deletions(-) create mode 100644 Documentation/devicetree/bindings/mtd/gpio-control-nand.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/mtd/gpio-control-nand.txt b/Documentation/devicetree/bindings/mtd/gpio-control-nand.txt new file mode 100644 index 00000000000..719f4dc58df --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/gpio-control-nand.txt @@ -0,0 +1,44 @@ +GPIO assisted NAND flash + +The GPIO assisted NAND flash uses a memory mapped interface to +read/write the NAND commands and data and GPIO pins for the control +signals. + +Required properties: +- compatible : "gpio-control-nand" +- reg : should specify localbus chip select and size used for the chip. The + resource describes the data bus connected to the NAND flash and all accesses + are made in native endianness. +- #address-cells, #size-cells : Must be present if the device has sub-nodes + representing partitions. +- gpios : specifies the gpio pins to control the NAND device. nwp is an + optional gpio and may be set to 0 if not present. + +Optional properties: +- bank-width : Width (in bytes) of the device. If not present, the width + defaults to 1 byte. +- chip-delay : chip dependent delay for transferring data from array to + read registers (tR). If not present then a default of 20us is used. +- gpio-control-nand,io-sync-reg : A 64-bit physical address for a read + location used to guard against bus reordering with regards to accesses to + the GPIO's and the NAND flash data bus. If present, then after changing + GPIO state and before and after command byte writes, this register will be + read to ensure that the GPIO accesses have completed. + +Examples: + +gpio-nand@1,0 { + compatible = "gpio-control-nand"; + reg = <1 0x0000 0x2>; + #address-cells = <1>; + #size-cells = <1>; + gpios = <&banka 1 0 /* rdy */ + &banka 2 0 /* nce */ + &banka 3 0 /* ale */ + &banka 4 0 /* cle */ + 0 /* nwp */>; + + partition@0 { + ... + }; +}; diff --git a/drivers/mtd/nand/gpio.c b/drivers/mtd/nand/gpio.c index 2c2060b2800..27000a5f5f4 100644 --- a/drivers/mtd/nand/gpio.c +++ b/drivers/mtd/nand/gpio.c @@ -27,6 +27,9 @@ #include #include #include +#include +#include +#include struct gpiomtd { void __iomem *io_sync; @@ -171,6 +174,96 @@ static int gpio_nand_devready(struct mtd_info *mtd) return gpio_get_value(gpiomtd->plat.gpio_rdy); } +#ifdef CONFIG_OF +static const struct of_device_id gpio_nand_id_table[] = { + { .compatible = "gpio-control-nand" }, + {} +}; +MODULE_DEVICE_TABLE(of, gpio_nand_id_table); + +static int gpio_nand_get_config_of(const struct device *dev, + struct gpio_nand_platdata *plat) +{ + u32 val; + + if (!of_property_read_u32(dev->of_node, "bank-width", &val)) { + if (val == 2) { + plat->options |= NAND_BUSWIDTH_16; + } else if (val != 1) { + dev_err(dev, "invalid bank-width %u\n", val); + return -EINVAL; + } + } + + plat->gpio_rdy = of_get_gpio(dev->of_node, 0); + plat->gpio_nce = of_get_gpio(dev->of_node, 1); + plat->gpio_ale = of_get_gpio(dev->of_node, 2); + plat->gpio_cle = of_get_gpio(dev->of_node, 3); + plat->gpio_nwp = of_get_gpio(dev->of_node, 4); + + if (!of_property_read_u32(dev->of_node, "chip-delay", &val)) + plat->chip_delay = val; + + return 0; +} + +static struct resource *gpio_nand_get_io_sync_of(struct platform_device *pdev) +{ + struct resource *r = devm_kzalloc(&pdev->dev, sizeof(*r), GFP_KERNEL); + u64 addr; + + if (!r || of_property_read_u64(pdev->dev.of_node, + "gpio-control-nand,io-sync-reg", &addr)) + return NULL; + + r->start = addr; + r->end = r->start + 0x3; + r->flags = IORESOURCE_MEM; + + return r; +} +#else /* CONFIG_OF */ +#define gpio_nand_id_table NULL +static inline int gpio_nand_get_config_of(const struct device *dev, + struct gpio_nand_platdata *plat) +{ + return -ENOSYS; +} + +static inline struct resource * +gpio_nand_get_io_sync_of(struct platform_device *pdev) +{ + return NULL; +} +#endif /* CONFIG_OF */ + +static inline int gpio_nand_get_config(const struct device *dev, + struct gpio_nand_platdata *plat) +{ + int ret = gpio_nand_get_config_of(dev, plat); + + if (!ret) + return ret; + + if (dev->platform_data) { + memcpy(plat, dev->platform_data, sizeof(*plat)); + return 0; + } + + return -EINVAL; +} + +static inline struct resource * +gpio_nand_get_io_sync(struct platform_device *pdev) +{ + struct resource *r = gpio_nand_get_io_sync_of(pdev); + + if (r) + return r; + + return platform_get_resource(pdev, IORESOURCE_MEM, 1); +} + static int __devexit gpio_nand_remove(struct platform_device *dev) { struct gpiomtd *gpiomtd = platform_get_drvdata(dev); @@ -178,7 +271,7 @@ static int __devexit gpio_nand_remove(struct platform_device *dev) nand_release(&gpiomtd->mtd_info); - res = platform_get_resource(dev, IORESOURCE_MEM, 1); + res = gpio_nand_get_io_sync(dev); iounmap(gpiomtd->io_sync); if (res) release_mem_region(res->start, resource_size(res)); @@ -226,9 +319,10 @@ static int __devinit gpio_nand_probe(struct platform_device *dev) struct gpiomtd *gpiomtd; struct nand_chip *this; struct resource *res0, *res1; - int ret; + struct mtd_part_parser_data ppdata = {}; + int ret = 0; - if (!dev->dev.platform_data) + if (!dev->dev.of_node && !dev->dev.platform_data) return -EINVAL; res0 = platform_get_resource(dev, IORESOURCE_MEM, 0); @@ -248,7 +342,7 @@ static int __devinit gpio_nand_probe(struct platform_device *dev) goto err_map; } - res1 = platform_get_resource(dev, IORESOURCE_MEM, 1); + res1 = gpio_nand_get_io_sync(dev); if (res1) { gpiomtd->io_sync = request_and_remap(res1, 4, "NAND sync", &ret); if (!gpiomtd->io_sync) { @@ -257,7 +351,9 @@ static int __devinit gpio_nand_probe(struct platform_device *dev) } } - memcpy(&gpiomtd->plat, dev->dev.platform_data, sizeof(gpiomtd->plat)); + ret = gpio_nand_get_config(&dev->dev, &gpiomtd->plat); + if (ret) + goto err_nce; ret = gpio_request(gpiomtd->plat.gpio_nce, "NAND NCE"); if (ret) @@ -316,8 +412,12 @@ static int __devinit gpio_nand_probe(struct platform_device *dev) gpiomtd->plat.adjust_parts(&gpiomtd->plat, gpiomtd->mtd_info.size); - mtd_device_register(&gpiomtd->mtd_info, gpiomtd->plat.parts, - gpiomtd->plat.num_parts); + ppdata.of_node = dev->dev.of_node; + ret = mtd_device_parse_register(&gpiomtd->mtd_info, NULL, &ppdata, + gpiomtd->plat.parts, + gpiomtd->plat.num_parts); + if (ret) + goto err_wp; platform_set_drvdata(dev, gpiomtd); return 0; @@ -352,6 +452,7 @@ static struct platform_driver gpio_nand_driver = { .remove = gpio_nand_remove, .driver = { .name = "gpio-nand", + .of_match_table = gpio_nand_id_table, }, }; -- cgit v1.2.3-70-g09d2 From 948170f8944dfd29d13612fff48110a9814daeb1 Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Tue, 10 Jan 2012 15:10:59 -0800 Subject: drivers/rtc/rtc-twl.c: add DT support for RTC inside twl4030/twl6030 Add the DT support for the TI rtc-twl present in the twl4030 and twl6030 devices. Signed-off-by: Benoit Cousson Acked-by: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/devicetree/bindings/rtc/twl-rtc.txt | 12 ++++++++++++ drivers/rtc/rtc-twl.c | 10 ++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 Documentation/devicetree/bindings/rtc/twl-rtc.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/rtc/twl-rtc.txt b/Documentation/devicetree/bindings/rtc/twl-rtc.txt new file mode 100644 index 00000000000..596e0c97be7 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/twl-rtc.txt @@ -0,0 +1,12 @@ +* TI twl RTC + +The TWL family (twl4030/6030) contains a RTC. + +Required properties: +- compatible : Should be twl4030-rtc + +Examples: + +rtc@0 { + compatible = "ti,twl4030-rtc"; +}; diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c index 20687d55e7a..d43b4f6eb4e 100644 --- a/drivers/rtc/rtc-twl.c +++ b/drivers/rtc/rtc-twl.c @@ -550,6 +550,11 @@ static int twl_rtc_resume(struct platform_device *pdev) #define twl_rtc_resume NULL #endif +static const struct of_device_id twl_rtc_of_match[] = { + {.compatible = "ti,twl4030-rtc", }, + { }, +}; +MODULE_DEVICE_TABLE(of, twl_rtc_of_match); MODULE_ALIAS("platform:twl_rtc"); static struct platform_driver twl4030rtc_driver = { @@ -559,8 +564,9 @@ static struct platform_driver twl4030rtc_driver = { .suspend = twl_rtc_suspend, .resume = twl_rtc_resume, .driver = { - .owner = THIS_MODULE, - .name = "twl_rtc", + .owner = THIS_MODULE, + .name = "twl_rtc", + .of_match_table = twl_rtc_of_match, }, }; -- cgit v1.2.3-70-g09d2 From 6145197be6cc0583fa1a2f4ec1079d366137061e Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Thu, 22 Dec 2011 15:56:36 +0100 Subject: i2c: OMAP: Add DT support for i2c controller Add initial DT support to retrieve the frequency using a DT attribute instead of the pdata pointer if of_node exist. Add documentation for omap i2c controller binding. Based on original patches from Manju and Grant. Signed-off-by: Benoit Cousson Cc: Ben Dooks Reviewed-by: Rob Herring Acked-by: Grant Likely Signed-off-by: Kevin Hilman --- Documentation/devicetree/bindings/i2c/omap-i2c.txt | 30 ++++++ drivers/i2c/busses/i2c-omap.c | 102 ++++++++++++++------- 2 files changed, 97 insertions(+), 35 deletions(-) create mode 100644 Documentation/devicetree/bindings/i2c/omap-i2c.txt (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/i2c/omap-i2c.txt b/Documentation/devicetree/bindings/i2c/omap-i2c.txt new file mode 100644 index 00000000000..56564aa4b44 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/omap-i2c.txt @@ -0,0 +1,30 @@ +I2C for OMAP platforms + +Required properties : +- compatible : Must be "ti,omap3-i2c" or "ti,omap4-i2c" +- ti,hwmods : Must be "i2c", n being the instance number (1-based) +- #address-cells = <1>; +- #size-cells = <0>; + +Recommended properties : +- clock-frequency : Desired I2C bus clock frequency in Hz. Otherwise + the default 100 kHz frequency will be used. + +Optional properties: +- Child nodes conforming to i2c bus binding + +Note: Current implementation will fetch base address, irq and dma +from omap hwmod data base during device registration. +Future plan is to migrate hwmod data base contents into device tree +blob so that, all the required data will be used from device tree dts +file. + +Examples : + +i2c1: i2c@0 { + compatible = "ti,omap3-i2c"; + #address-cells = <1>; + #size-cells = <0>; + ti,hwmods = "i2c1"; + clock-frequency = <400000>; +}; diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index e0733b77607..f713eac5504 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -37,6 +37,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -182,7 +185,9 @@ struct omap_i2c_dev { u32 latency; /* maximum mpu wkup latency */ void (*set_mpu_wkup_lat)(struct device *dev, long latency); - u32 speed; /* Speed of bus in Khz */ + u32 speed; /* Speed of bus in kHz */ + u32 dtrev; /* extra revision from DT */ + u32 flags; u16 cmd_err; u8 *buf; u8 *regs; @@ -266,11 +271,7 @@ static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg) static void omap_i2c_unidle(struct omap_i2c_dev *dev) { - struct omap_i2c_bus_platform_data *pdata; - - pdata = dev->dev->platform_data; - - if (pdata->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) { + if (dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) { omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, dev->pscstate); omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, dev->scllstate); @@ -291,13 +292,10 @@ static void omap_i2c_unidle(struct omap_i2c_dev *dev) static void omap_i2c_idle(struct omap_i2c_dev *dev) { - struct omap_i2c_bus_platform_data *pdata; u16 iv; - pdata = dev->dev->platform_data; - dev->iestate = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); - if (pdata->rev == OMAP_I2C_IP_VERSION_2) + if (dev->dtrev == OMAP_I2C_IP_VERSION_2) omap_i2c_write_reg(dev, OMAP_I2C_IP_V2_IRQENABLE_CLR, 1); else omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0); @@ -320,9 +318,6 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) unsigned long timeout; unsigned long internal_clk = 0; struct clk *fclk; - struct omap_i2c_bus_platform_data *pdata; - - pdata = dev->dev->platform_data; if (dev->rev >= OMAP_I2C_OMAP1_REV_2) { /* Disable I2C controller before soft reset */ @@ -373,7 +368,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) } omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); - if (pdata->flags & OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK) { + if (dev->flags & OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK) { /* * The I2C functional clock is the armxor_ck, so there's * no need to get "armxor_ck" separately. Now, if OMAP2420 @@ -397,7 +392,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) psc = fclk_rate / 12000000; } - if (!(pdata->flags & OMAP_I2C_FLAG_SIMPLE_CLOCK)) { + if (!(dev->flags & OMAP_I2C_FLAG_SIMPLE_CLOCK)) { /* * HSI2C controller internal clk rate should be 19.2 Mhz for @@ -406,7 +401,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) * The filter is iclk (fclk for HS) period. */ if (dev->speed > 400 || - pdata->flags & OMAP_I2C_FLAG_FORCE_19200_INT_CLK) + dev->flags & OMAP_I2C_FLAG_FORCE_19200_INT_CLK) internal_clk = 19200; else if (dev->speed > 100) internal_clk = 9600; @@ -475,7 +470,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) dev->errata = 0; - if (pdata->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207) + if (dev->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207) dev->errata |= I2C_OMAP_ERRATA_I207; /* Enable interrupts */ @@ -484,7 +479,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) OMAP_I2C_IE_AL) | ((dev->fifo_size) ? (OMAP_I2C_IE_RDR | OMAP_I2C_IE_XDR) : 0); omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate); - if (pdata->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) { + if (dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) { dev->pscstate = psc; dev->scllstate = scll; dev->sclhstate = sclh; @@ -804,9 +799,6 @@ omap_i2c_isr(int this_irq, void *dev_id) u16 bits; u16 stat, w; int err, count = 0; - struct omap_i2c_bus_platform_data *pdata; - - pdata = dev->dev->platform_data; if (pm_runtime_suspended(dev->dev)) return IRQ_NONE; @@ -873,7 +865,7 @@ complete: * Data reg in 2430, omap3 and * omap4 is 8 bit wide */ - if (pdata->flags & + if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { if (dev->buf_len) { *dev->buf++ = w >> 8; @@ -916,7 +908,7 @@ complete: * Data reg in 2430, omap3 and * omap4 is 8 bit wide */ - if (pdata->flags & + if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { if (dev->buf_len) { w |= *dev->buf++ << 8; @@ -963,6 +955,32 @@ static const struct i2c_algorithm omap_i2c_algo = { .functionality = omap_i2c_func, }; +#ifdef CONFIG_OF +static struct omap_i2c_bus_platform_data omap3_pdata = { + .rev = OMAP_I2C_IP_VERSION_1, + .flags = OMAP_I2C_FLAG_APPLY_ERRATA_I207 | + OMAP_I2C_FLAG_RESET_REGS_POSTIDLE | + OMAP_I2C_FLAG_BUS_SHIFT_2, +}; + +static struct omap_i2c_bus_platform_data omap4_pdata = { + .rev = OMAP_I2C_IP_VERSION_2, +}; + +static const struct of_device_id omap_i2c_of_match[] = { + { + .compatible = "ti,omap4-i2c", + .data = &omap4_pdata, + }, + { + .compatible = "ti,omap3-i2c", + .data = &omap3_pdata, + }, + { }, +}; +MODULE_DEVICE_TABLE(of, omap_i2c_of_match); +#endif + static int __devinit omap_i2c_probe(struct platform_device *pdev) { @@ -970,9 +988,10 @@ omap_i2c_probe(struct platform_device *pdev) struct i2c_adapter *adap; struct resource *mem, *irq, *ioarea; struct omap_i2c_bus_platform_data *pdata = pdev->dev.platform_data; + struct device_node *node = pdev->dev.of_node; + const struct of_device_id *match; irq_handler_t isr; int r; - u32 speed = 0; /* NOTE: driver uses the static register mapping */ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -999,15 +1018,24 @@ omap_i2c_probe(struct platform_device *pdev) goto err_release_region; } - if (pdata != NULL) { - speed = pdata->clkrate; + match = of_match_device(omap_i2c_of_match, &pdev->dev); + if (match) { + u32 freq = 100000; /* default to 100000 Hz */ + + pdata = match->data; + dev->dtrev = pdata->rev; + dev->flags = pdata->flags; + + of_property_read_u32(node, "clock-frequency", &freq); + /* convert DT freq value in Hz into kHz for speed */ + dev->speed = freq / 1000; + } else if (pdata != NULL) { + dev->speed = pdata->clkrate; + dev->flags = pdata->flags; dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat; - } else { - speed = 100; /* Default speed */ - dev->set_mpu_wkup_lat = NULL; + dev->dtrev = pdata->rev; } - dev->speed = speed; dev->dev = &pdev->dev; dev->irq = irq->start; dev->base = ioremap(mem->start, resource_size(mem)); @@ -1018,9 +1046,9 @@ omap_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dev); - dev->reg_shift = (pdata->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3; + dev->reg_shift = (dev->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3; - if (pdata->rev == OMAP_I2C_IP_VERSION_2) + if (dev->dtrev == OMAP_I2C_IP_VERSION_2) dev->regs = (u8 *)reg_map_ip_v2; else dev->regs = (u8 *)reg_map_ip_v1; @@ -1033,7 +1061,7 @@ omap_i2c_probe(struct platform_device *pdev) if (dev->rev <= OMAP_I2C_REV_ON_3430) dev->errata |= I2C_OMAP3_1P153; - if (!(pdata->flags & OMAP_I2C_FLAG_NO_FIFO)) { + if (!(dev->flags & OMAP_I2C_FLAG_NO_FIFO)) { u16 s; /* Set up the fifo size - Get total size */ @@ -1056,7 +1084,7 @@ omap_i2c_probe(struct platform_device *pdev) /* calculate wakeup latency constraint for MPU */ if (dev->set_mpu_wkup_lat != NULL) dev->latency = (1000000 * dev->fifo_size) / - (1000 * speed / 8); + (1000 * dev->speed / 8); } /* reset ASAP, clearing any IRQs */ @@ -1072,7 +1100,7 @@ omap_i2c_probe(struct platform_device *pdev) } dev_info(dev->dev, "bus %d rev%d.%d.%d at %d kHz\n", pdev->id, - pdata->rev, dev->rev >> 4, dev->rev & 0xf, dev->speed); + dev->dtrev, dev->rev >> 4, dev->rev & 0xf, dev->speed); pm_runtime_put(dev->dev); @@ -1083,6 +1111,7 @@ omap_i2c_probe(struct platform_device *pdev) strlcpy(adap->name, "OMAP I2C adapter", sizeof(adap->name)); adap->algo = &omap_i2c_algo; adap->dev.parent = &pdev->dev; + adap->dev.of_node = pdev->dev.of_node; /* i2c device drivers may be active on return from add_adapter() */ adap->nr = pdev->id; @@ -1092,6 +1121,8 @@ omap_i2c_probe(struct platform_device *pdev) goto err_free_irq; } + of_i2c_register_devices(adap); + return 0; err_free_irq: @@ -1164,6 +1195,7 @@ static struct platform_driver omap_i2c_driver = { .name = "omap_i2c", .owner = THIS_MODULE, .pm = OMAP_I2C_PM_OPS, + .of_match_table = of_match_ptr(omap_i2c_of_match), }, }; -- cgit v1.2.3-70-g09d2