提交 43a0a98a 编写于 作者: L Linus Torvalds

Merge tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc

Pull ARM SoC driver updates from Olof Johansson:
 "Driver updates for ARM SoCs.

  A slew of changes this release cycle.  The reset driver tree, that we
  merge through arm-soc for historical reasons, is also sizable this
  time around.

  Among the changes:

   - clps711x: Treewide changes to compatible strings, merged here for simplicity.
   - Qualcomm: SCM firmware driver cleanups, move to platform driver
   - ux500: Major cleanups, removal of old mach-specific infrastructure.
   - Atmel external bus memory driver
   - Move of brcmstb platform to the rest of bcm
   - PMC driver updates for tegra, various fixes and improvements
   - Samsung platform driver updates to support 64-bit Exynos platforms
   - Reset controller cleanups moving to devm_reset_controller_register() APIs
   - Reset controller driver for Amlogic Meson
   - Reset controller driver for Hisilicon hi6220
   - ARM SCPI power domain support"

* tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (100 commits)
  ARM: ux500: consolidate base platform files
  ARM: ux500: move soc_id driver to drivers/soc
  ARM: ux500: call ux500_setup_id later
  ARM: ux500: consolidate soc_device code in id.c
  ARM: ux500: remove cpu_is_u* helpers
  ARM: ux500: use CLK_OF_DECLARE()
  ARM: ux500: move l2x0 init to .init_irq
  mfd: db8500 stop passing around platform data
  ASoC: ab8500-codec: remove platform data based probe
  ARM: ux500: move ab8500_regulator_plat_data into driver
  ARM: ux500: remove unused regulator data
  soc: raspberrypi-power: add CONFIG_OF dependency
  firmware: scpi: add CONFIG_OF dependency
  video: clps711x-fb: Changing the compatibility string to match with the smallest supported chip
  input: clps711x-keypad: Changing the compatibility string to match with the smallest supported chip
  pwm: clps711x: Changing the compatibility string to match with the smallest supported chip
  serial: clps711x: Changing the compatibility string to match with the smallest supported chip
  irqchip: clps711x: Changing the compatibility string to match with the smallest supported chip
  clocksource: clps711x: Changing the compatibility string to match with the smallest supported chip
  clk: clps711x: Changing the compatibility string to match with the smallest supported chip
  ...
...@@ -87,10 +87,33 @@ Required properties: ...@@ -87,10 +87,33 @@ Required properties:
implementation for the IDs to use. For Juno implementation for the IDs to use. For Juno
R0 and Juno R1 refer to [3]. R0 and Juno R1 refer to [3].
Power domain bindings for the power domains based on SCPI Message Protocol
------------------------------------------------------------
This binding uses the generic power domain binding[4].
PM domain providers
===================
Required properties:
- #power-domain-cells : Should be 1. Contains the device or the power
domain ID value used by SCPI commands.
- num-domains: Total number of power domains provided by SCPI. This is
needed as the SCPI message protocol lacks a mechanism to
query this information at runtime.
PM domain consumers
===================
Required properties:
- power-domains : A phandle and PM domain specifier as defined by bindings of
the power controller specified by phandle.
[0] http://infocenter.arm.com/help/topic/com.arm.doc.dui0922b/index.html [0] http://infocenter.arm.com/help/topic/com.arm.doc.dui0922b/index.html
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt [1] Documentation/devicetree/bindings/clock/clock-bindings.txt
[2] Documentation/devicetree/bindings/thermal/thermal.txt [2] Documentation/devicetree/bindings/thermal/thermal.txt
[3] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0922b/apas03s22.html [3] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0922b/apas03s22.html
[4] Documentation/devicetree/bindings/power/power_domain.txt
Example: Example:
...@@ -144,6 +167,12 @@ scpi_protocol: scpi@2e000000 { ...@@ -144,6 +167,12 @@ scpi_protocol: scpi@2e000000 {
compatible = "arm,scpi-sensors"; compatible = "arm,scpi-sensors";
#thermal-sensor-cells = <1>; #thermal-sensor-cells = <1>;
}; };
scpi_devpd: scpi-power-domains {
compatible = "arm,scpi-power-domains";
num-domains = <2>;
#power-domain-cells = <1>;
};
}; };
cpu@0 { cpu@0 {
...@@ -156,6 +185,7 @@ hdlcd@7ff60000 { ...@@ -156,6 +185,7 @@ hdlcd@7ff60000 {
... ...
reg = <0 0x7ff60000 0 0x1000>; reg = <0 0x7ff60000 0 0x1000>;
clocks = <&scpi_clk 4>; clocks = <&scpi_clk 4>;
power-domains = <&scpi_devpd 1>;
}; };
thermal-zones { thermal-zones {
...@@ -186,3 +216,7 @@ The thermal-sensors property in the soc_thermal node uses the ...@@ -186,3 +216,7 @@ The thermal-sensors property in the soc_thermal node uses the
temperature sensor provided by SCP firmware to setup a thermal temperature sensor provided by SCP firmware to setup a thermal
zone. The ID "3" is the sensor identifier for the temperature sensor zone. The ID "3" is the sensor identifier for the temperature sensor
as used by the firmware. as used by the firmware.
The num-domains property in scpi-power-domains domain specifies that
SCPI provides 2 power domains. The hdlcd node uses the power domain with
domain ID 1.
NVIDIA Tegra ACONNECT Bus
The Tegra ACONNECT bus is an AXI switch which is used to connnect various
components inside the Audio Processing Engine (APE). All CPU accesses to
the APE subsystem go through the ACONNECT via an APB to AXI wrapper.
Required properties:
- compatible: Must be "nvidia,tegra210-aconnect".
- clocks: Must contain the entries for the APE clock (TEGRA210_CLK_APE),
and APE interface clock (TEGRA210_CLK_APB2APE).
- clock-names: Must contain the names "ape" and "apb2ape" for the corresponding
'clocks' entries.
- power-domains: Must contain a phandle that points to the audio powergate
(namely 'aud') for Tegra210.
- #address-cells: The number of cells used to represent physical base addresses
in the aconnect address space. Should be 1.
- #size-cells: The number of cells used to represent the size of an address
range in the aconnect address space. Should be 1.
- ranges: Mapping of the aconnect address space to the CPU address space.
All devices accessed via the ACONNNECT are described by child-nodes.
Example:
aconnect@702c0000 {
compatible = "nvidia,tegra210-aconnect";
clocks = <&tegra_car TEGRA210_CLK_APE>,
<&tegra_car TEGRA210_CLK_APB2APE>;
clock-names = "ape", "apb2ape";
power-domains = <&pd_audio>;
#address-cells = <1>;
#size-cells = <1>;
ranges = <0x702c0000 0x0 0x702c0000 0x00040000>;
status = "disabled";
child1 {
...
};
child2 {
...
};
};
* Clock bindings for the Cirrus Logic CLPS711X CPUs * Clock bindings for the Cirrus Logic CLPS711X CPUs
Required properties: Required properties:
- compatible : Shall contain "cirrus,clps711x-clk". - compatible : Shall contain "cirrus,ep7209-clk".
- reg : Address of the internal register set. - reg : Address of the internal register set.
- startup-frequency: Factory set CPU startup frequency in HZ. - startup-frequency: Factory set CPU startup frequency in HZ.
- #clock-cells : Should be <1>. - #clock-cells : Should be <1>.
...@@ -13,7 +13,7 @@ for the full list of CLPS711X clock IDs. ...@@ -13,7 +13,7 @@ for the full list of CLPS711X clock IDs.
Example: Example:
clks: clks@80000000 { clks: clks@80000000 {
#clock-cells = <1>; #clock-cells = <1>;
compatible = "cirrus,ep7312-clk", "cirrus,clps711x-clk"; compatible = "cirrus,ep7312-clk", "cirrus,ep7209-clk";
reg = <0x80000000 0xc000>; reg = <0x80000000 0xc000>;
startup-frequency = <73728000>; startup-frequency = <73728000>;
}; };
* Currus Logic CLPS711X Framebuffer * Currus Logic CLPS711X Framebuffer
Required properties: Required properties:
- compatible: Shall contain "cirrus,clps711x-fb". - compatible: Shall contain "cirrus,ep7209-fb".
- reg : Physical base address and length of the controller's registers + - reg : Physical base address and length of the controller's registers +
location and size of the framebuffer memory. location and size of the framebuffer memory.
- clocks : phandle + clock specifier pair of the FB reference clock. - clocks : phandle + clock specifier pair of the FB reference clock.
...@@ -18,7 +18,7 @@ Optional properties: ...@@ -18,7 +18,7 @@ Optional properties:
Example: Example:
fb: fb@800002c0 { fb: fb@800002c0 {
compatible = "cirrus,ep7312-fb", "cirrus,clps711x-fb"; compatible = "cirrus,ep7312-fb", "cirrus,ep7209-fb";
reg = <0x800002c0 0xd44>, <0x60000000 0xc000>; reg = <0x800002c0 0xd44>, <0x60000000 0xc000>;
clocks = <&clks 2>; clocks = <&clks 2>;
lcd-supply = <&reg5v0>; lcd-supply = <&reg5v0>;
......
* Cirrus Logic CLPS711X matrix keypad device tree bindings * Cirrus Logic CLPS711X matrix keypad device tree bindings
Required Properties: Required Properties:
- compatible: Shall contain "cirrus,clps711x-keypad". - compatible: Shall contain "cirrus,ep7209-keypad".
- row-gpios: List of GPIOs used as row lines. - row-gpios: List of GPIOs used as row lines.
- poll-interval: Poll interval time in milliseconds. - poll-interval: Poll interval time in milliseconds.
- linux,keymap: The definition can be found at - linux,keymap: The definition can be found at
...@@ -12,7 +12,7 @@ Optional Properties: ...@@ -12,7 +12,7 @@ Optional Properties:
Example: Example:
keypad { keypad {
compatible = "cirrus,ep7312-keypad", "cirrus,clps711x-keypad"; compatible = "cirrus,ep7312-keypad", "cirrus,ep7209-keypad";
autorepeat; autorepeat;
poll-interval = <120>; poll-interval = <120>;
row-gpios = <&porta 0 0>, row-gpios = <&porta 0 0>,
......
...@@ -2,7 +2,7 @@ Cirrus Logic CLPS711X Interrupt Controller ...@@ -2,7 +2,7 @@ Cirrus Logic CLPS711X Interrupt Controller
Required properties: Required properties:
- compatible: Should be "cirrus,clps711x-intc". - compatible: Should be "cirrus,ep7209-intc".
- reg: Specifies base physical address of the registers set. - reg: Specifies base physical address of the registers set.
- interrupt-controller: Identifies the node as an interrupt controller. - interrupt-controller: Identifies the node as an interrupt controller.
- #interrupt-cells: Specifies the number of cells needed to encode an - #interrupt-cells: Specifies the number of cells needed to encode an
...@@ -34,7 +34,7 @@ ID Name Description ...@@ -34,7 +34,7 @@ ID Name Description
Example: Example:
intc: interrupt-controller { intc: interrupt-controller {
compatible = "cirrus,clps711x-intc"; compatible = "cirrus,ep7312-intc", "cirrus,ep7209-intc";
reg = <0x80000000 0x4000>; reg = <0x80000000 0x4000>;
interrupt-controller; interrupt-controller;
#interrupt-cells = <1>; #interrupt-cells = <1>;
......
Device-Tree bindings for LIRC TX driver for Nokia N900(RX51)
Required properties:
- compatible: should be "nokia,n900-ir".
- pwms: specifies PWM used for IR signal transmission.
Example node:
pwm9: dmtimer-pwm@9 {
compatible = "ti,omap-dmtimer-pwm";
ti,timers = <&timer9>;
ti,clock-source = <0x00>; /* timer_sys_ck */
#pwm-cells = <3>;
};
ir: n900-ir {
compatible = "nokia,n900-ir";
pwms = <&pwm9 0 26316 0>; /* 38000 Hz */
};
* Device tree bindings for Atmel EBI
The External Bus Interface (EBI) controller is a bus where you can connect
asynchronous (NAND, NOR, SRAM, ....) and synchronous memories (SDR/DDR SDRAMs).
The EBI provides a glue-less interface to asynchronous memories through the SMC
(Static Memory Controller).
Required properties:
- compatible: "atmel,at91sam9260-ebi"
"atmel,at91sam9261-ebi"
"atmel,at91sam9263-ebi0"
"atmel,at91sam9263-ebi1"
"atmel,at91sam9rl-ebi"
"atmel,at91sam9g45-ebi"
"atmel,at91sam9x5-ebi"
"atmel,sama5d3-ebi"
- reg: Contains offset/length value for EBI memory mapping.
This property might contain several entries if the EBI
memory range is not contiguous
- #address-cells: Must be 2.
The first cell encodes the CS.
The second cell encode the offset into the CS memory
range.
- #size-cells: Must be set to 1.
- ranges: Encodes CS to memory region association.
- clocks: Clock feeding the EBI controller.
See clock-bindings.txt
Children device nodes are representing device connected to the EBI bus.
Required device node properties:
- reg: Contains the chip-select id, the offset and the length
of the memory region requested by the device.
EBI bus configuration will be defined directly in the device subnode.
Optional EBI/SMC properties:
- atmel,smc-bus-width: width of the asynchronous device's data bus
8, 16 or 32.
Default to 8 when undefined.
- atmel,smc-byte-access-type "write" or "select" (see Atmel datasheet).
Default to "select" when undefined.
- atmel,smc-read-mode "nrd" or "ncs".
Default to "ncs" when undefined.
- atmel,smc-write-mode "nwe" or "ncs".
Default to "ncs" when undefined.
- atmel,smc-exnw-mode "disabled", "frozen" or "ready".
Default to "disabled" when undefined.
- atmel,smc-page-mode enable page mode if present. The provided value
defines the page size (supported values: 4, 8,
16 and 32).
- atmel,smc-tdf-mode: "normal" or "optimized". When set to
"optimized" the data float time is optimized
depending on the next device being accessed
(next device setup time is subtracted to the
current device data float time).
Default to "normal" when undefined.
If at least one atmel,smc- property is defined the following SMC timing
properties become mandatory. In the other hand, if none of the atmel,smc-
properties are specified, we assume that the EBI bus configuration will be
handled by the sub-device driver, and none of those properties should be
defined.
All the timings are expressed in nanoseconds (see Atmel datasheet for a full
description).
- atmel,smc-ncs-rd-setup-ns
- atmel,smc-nrd-setup-ns
- atmel,smc-ncs-wr-setup-ns
- atmel,smc-nwe-setup-ns
- atmel,smc-ncs-rd-pulse-ns
- atmel,smc-nrd-pulse-ns
- atmel,smc-ncs-wr-pulse-ns
- atmel,smc-nwe-pulse-ns
- atmel,smc-nwe-cycle-ns
- atmel,smc-nrd-cycle-ns
- atmel,smc-tdf-ns
Example:
ebi: ebi@10000000 {
compatible = "atmel,sama5d3-ebi";
#address-cells = <2>;
#size-cells = <1>;
atmel,smc = <&hsmc>;
atmel,matrix = <&matrix>;
reg = <0x10000000 0x10000000
0x40000000 0x30000000>;
ranges = <0x0 0x0 0x10000000 0x10000000
0x1 0x0 0x40000000 0x10000000
0x2 0x0 0x50000000 0x10000000
0x3 0x0 0x60000000 0x10000000>;
clocks = <&mck>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_ebi_addr>;
nor: flash@0,0 {
compatible = "cfi-flash";
#address-cells = <1>;
#size-cells = <1>;
reg = <0x0 0x0 0x1000000>;
bank-width = <2>;
atmel,smc-read-mode = "nrd";
atmel,smc-write-mode = "nwe";
atmel,smc-bus-width = <16>;
atmel,smc-ncs-rd-setup-ns = <0>;
atmel,smc-ncs-wr-setup-ns = <0>;
atmel,smc-nwe-setup-ns = <8>;
atmel,smc-nrd-setup-ns = <16>;
atmel,smc-ncs-rd-pulse-ns = <84>;
atmel,smc-ncs-wr-pulse-ns = <84>;
atmel,smc-nrd-pulse-ns = <76>;
atmel,smc-nwe-pulse-ns = <76>;
atmel,smc-nrd-cycle-ns = <107>;
atmel,smc-nwe-cycle-ns = <84>;
atmel,smc-tdf-ns = <16>;
};
};
* Cirris Logic CLPS711X PWM controller * Cirris Logic CLPS711X PWM controller
Required properties: Required properties:
- compatible: Shall contain "cirrus,clps711x-pwm". - compatible: Shall contain "cirrus,ep7209-pwm".
- reg: Physical base address and length of the controller's registers. - reg: Physical base address and length of the controller's registers.
- clocks: phandle + clock specifier pair of the PWM reference clock. - clocks: phandle + clock specifier pair of the PWM reference clock.
- #pwm-cells: Should be 1. The cell specifies the index of the channel. - #pwm-cells: Should be 1. The cell specifies the index of the channel.
Example: Example:
pwm: pwm@80000400 { pwm: pwm@80000400 {
compatible = "cirrus,ep7312-pwm", compatible = "cirrus,ep7312-pwm", "cirrus,ep7209-pwm";
"cirrus,clps711x-pwm";
reg = <0x80000400 0x4>; reg = <0x80000400 0x4>;
clocks = <&clks 8>; clocks = <&clks 8>;
#pwm-cells = <1>; #pwm-cells = <1>;
......
...@@ -9,6 +9,10 @@ Required properties: ...@@ -9,6 +9,10 @@ Required properties:
Optional properties: Optional properties:
- ti,prescaler: Should be a value between 0 and 7, see the timers datasheet - ti,prescaler: Should be a value between 0 and 7, see the timers datasheet
- ti,clock-source: Set dmtimer parent clock, values between 0 and 2:
- 0x00 - high-frequency system clock (timer_sys_ck)
- 0x01 - 32-kHz always-on clock (timer_32k_ck)
- 0x02 - external clock (timer_ext_ck, OMAP2 only)
Example: Example:
pwm9: dmtimer-pwm@9 { pwm9: dmtimer-pwm@9 {
......
Amlogic Meson SoC Reset Controller
=======================================
Please also refer to reset.txt in this directory for common reset
controller binding usage.
Required properties:
- compatible: Should be "amlogic,meson8b-reset" or "amlogic,meson-gxbb-reset"
- reg: should contain the register address base
- #reset-cells: 1, see below
example:
reset: reset-controller {
compatible = "amlogic,meson-gxbb-reset";
reg = <0x0 0x04404 0x0 0x20>;
#reset-cells = <1>;
};
...@@ -8,7 +8,9 @@ The reset controller registers are part of the system-ctl block on ...@@ -8,7 +8,9 @@ The reset controller registers are part of the system-ctl block on
hi6220 SoC. hi6220 SoC.
Required properties: Required properties:
- compatible: may be "hisilicon,hi6220-sysctrl" - compatible: should be one of the following:
- "hisilicon,hi6220-sysctrl", "syscon" : For peripheral reset controller.
- "hisilicon,hi6220-mediactrl", "syscon" : For media reset controller.
- reg: should be register base and length as documented in the - reg: should be register base and length as documented in the
datasheet datasheet
- #reset-cells: 1, see below - #reset-cells: 1, see below
......
TI SysCon Reset Controller
=======================
Almost all SoCs have hardware modules that require reset control in addition
to clock and power control for their functionality. The reset control is
typically provided by means of memory-mapped I/O registers. These registers are
sometimes a part of a larger register space region implementing various
functionalities. This register range is best represented as a syscon node to
allow multiple entities to access their relevant registers in the common
register space.
A SysCon Reset Controller node defines a device that uses a syscon node
and provides reset management functionality for various hardware modules
present on the SoC.
SysCon Reset Controller Node
============================
Each of the reset provider/controller nodes should be a child of a syscon
node and have the following properties.
Required properties:
--------------------
- compatible : Should be,
"ti,k2e-pscrst"
"ti,k2l-pscrst"
"ti,k2hk-pscrst"
"ti,syscon-reset"
- #reset-cells : Should be 1. Please see the reset consumer node below
for usage details
- ti,reset-bits : Contains the reset control register information
Should contain 7 cells for each reset exposed to
consumers, defined as:
Cell #1 : offset of the reset assert control
register from the syscon register base
Cell #2 : bit position of the reset in the reset
assert control register
Cell #3 : offset of the reset deassert control
register from the syscon register base
Cell #4 : bit position of the reset in the reset
deassert control register
Cell #5 : offset of the reset status register
from the syscon register base
Cell #6 : bit position of the reset in the
reset status register
Cell #7 : Flags used to control reset behavior,
availible flags defined in the DT include
file <dt-bindings/reset/ti-syscon.h>
SysCon Reset Consumer Nodes
===========================
Each of the reset consumer nodes should have the following properties,
in addition to their own properties.
Required properties:
--------------------
- resets : A phandle to the reset controller node and an index number
to a reset specifier as defined above.
Please also refer to Documentation/devicetree/bindings/reset/reset.txt for
common reset controller usage by consumers.
Example:
--------
The following example demonstrates a syscon node, the reset controller node
using the syscon node, and a consumer (a DSP device) on the TI Keystone 2
Edison SoC.
/ {
soc {
psc: power-sleep-controller@02350000 {
compatible = "syscon", "simple-mfd";
reg = <0x02350000 0x1000>;
pscrst: psc-reset {
compatible = "ti,k2e-pscrst", "ti,syscon-reset";
#reset-cells = <1>;
ti,reset-bits = <
0xa3c 8 0xa3c 8 0x83c 8 (ASSERT_SET|DEASSERT_CLEAR|STATUS_SET) /* 0: pcrst-dsp0 */
0xa40 5 0xa44 3 0 0 (ASSERT_SET|DEASSERT_CLEAR|STATUS_NONE) /* 1: pcrst-example */
>;
};
};
dsp0: dsp0 {
...
resets = <&pscrst 0>;
...
};
};
};
* Cirrus Logic CLPS711X Universal Asynchronous Receiver/Transmitter (UART) * Cirrus Logic CLPS711X Universal Asynchronous Receiver/Transmitter (UART)
Required properties: Required properties:
- compatible: Should be "cirrus,clps711x-uart". - compatible: Should be "cirrus,ep7209-uart".
- reg: Address and length of the register set for the device. - reg: Address and length of the register set for the device.
- interrupts: Should contain UART TX and RX interrupt. - interrupts: Should contain UART TX and RX interrupt.
- clocks: Should contain UART core clock number. - clocks: Should contain UART core clock number.
...@@ -20,7 +20,7 @@ Example: ...@@ -20,7 +20,7 @@ Example:
}; };
uart1: uart@80000480 { uart1: uart@80000480 {
compatible = "cirrus,clps711x-uart"; compatible = "cirrus,ep7312-uart","cirrus,ep7209-uart";
reg = <0x80000480 0x80>; reg = <0x80000480 0x80>;
interrupts = <12 13>; interrupts = <12 13>;
clocks = <&clks 11>; clocks = <&clks 11>;
......
...@@ -68,7 +68,7 @@ important. ...@@ -68,7 +68,7 @@ important.
Value type: <u32> Value type: <u32>
Definition: must be 2 - denoting the bit in the entry and IRQ flags Definition: must be 2 - denoting the bit in the entry and IRQ flags
- #qcom,state-cells: - #qcom,smem-state-cells:
Usage: required for outgoing entries Usage: required for outgoing entries
Value type: <u32> Value type: <u32>
Definition: must be 1 - denoting the bit in the entry Definition: must be 1 - denoting the bit in the entry
...@@ -92,7 +92,7 @@ wcnss-smp2p { ...@@ -92,7 +92,7 @@ wcnss-smp2p {
wcnss_smp2p_out: master-kernel { wcnss_smp2p_out: master-kernel {
qcom,entry-name = "master-kernel"; qcom,entry-name = "master-kernel";
#qcom,state-cells = <1>; #qcom,smem-state-cells = <1>;
}; };
wcnss_smp2p_in: slave-kernel { wcnss_smp2p_in: slave-kernel {
......
...@@ -51,7 +51,7 @@ important. ...@@ -51,7 +51,7 @@ important.
Definition: specifies the offset, in words, of the first bit for this Definition: specifies the offset, in words, of the first bit for this
entry entry
- #qcom,state-cells: - #qcom,smem-state-cells:
Usage: required for local entry Usage: required for local entry
Value type: <u32> Value type: <u32>
Definition: must be 1 - denotes bit number Definition: must be 1 - denotes bit number
...@@ -91,7 +91,7 @@ smsm { ...@@ -91,7 +91,7 @@ smsm {
apps_smsm: apps@0 { apps_smsm: apps@0 {
reg = <0>; reg = <0>;
#qcom,state-cells = <1>; #qcom,smem-state-cells = <1>;
}; };
wcnss_smsm: wcnss@7 { wcnss_smsm: wcnss@7 {
......
* Cirrus Logic CLPS711X Timer Counter * Cirrus Logic CLPS711X Timer Counter
Required properties: Required properties:
- compatible: Shall contain "cirrus,clps711x-timer". - compatible: Shall contain "cirrus,ep7209-timer".
- reg : Address and length of the register set. - reg : Address and length of the register set.
- interrupts: The interrupt number of the timer. - interrupts: The interrupt number of the timer.
- clocks : phandle of timer reference clock. - clocks : phandle of timer reference clock.
...@@ -15,14 +15,14 @@ Example: ...@@ -15,14 +15,14 @@ Example:
}; };
timer1: timer@80000300 { timer1: timer@80000300 {
compatible = "cirrus,ep7312-timer", "cirrus,clps711x-timer"; compatible = "cirrus,ep7312-timer", "cirrus,ep7209-timer";
reg = <0x80000300 0x4>; reg = <0x80000300 0x4>;
interrupts = <8>; interrupts = <8>;
clocks = <&clks 5>; clocks = <&clks 5>;
}; };
timer2: timer@80000340 { timer2: timer@80000340 {
compatible = "cirrus,ep7312-timer", "cirrus,clps711x-timer"; compatible = "cirrus,ep7312-timer", "cirrus,ep7209-timer";
reg = <0x80000340 0x4>; reg = <0x80000340 0x4>;
interrupts = <9>; interrupts = <9>;
clocks = <&clks 6>; clocks = <&clks 6>;
......
...@@ -352,6 +352,10 @@ REGULATOR ...@@ -352,6 +352,10 @@ REGULATOR
devm_regulator_put() devm_regulator_put()
devm_regulator_register() devm_regulator_register()
RESET
devm_reset_control_get()
devm_reset_controller_register()
SLAVE DMA ENGINE SLAVE DMA ENGINE
devm_acpi_dma_controller_register() devm_acpi_dma_controller_register()
......
...@@ -1536,6 +1536,7 @@ M: David Brown <david.brown@linaro.org> ...@@ -1536,6 +1536,7 @@ M: David Brown <david.brown@linaro.org>
L: linux-arm-msm@vger.kernel.org L: linux-arm-msm@vger.kernel.org
L: linux-soc@vger.kernel.org L: linux-soc@vger.kernel.org
S: Maintained S: Maintained
F: Documentation/devicetree/bindings/soc/qcom/
F: arch/arm/boot/dts/qcom-*.dts F: arch/arm/boot/dts/qcom-*.dts
F: arch/arm/boot/dts/qcom-*.dtsi F: arch/arm/boot/dts/qcom-*.dtsi
F: arch/arm/mach-qcom/ F: arch/arm/mach-qcom/
...@@ -1841,7 +1842,6 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) ...@@ -1841,7 +1842,6 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
T: git git://git.linaro.org/people/ulfh/clk.git T: git git://git.linaro.org/people/ulfh/clk.git
S: Maintained S: Maintained
F: drivers/clk/ux500/ F: drivers/clk/ux500/
F: include/linux/platform_data/clk-ux500.h
ARM/VERSATILE EXPRESS PLATFORM ARM/VERSATILE EXPRESS PLATFORM
M: Liviu Dudau <liviu.dudau@arm.com> M: Liviu Dudau <liviu.dudau@arm.com>
......
/*
* Samsung's Exynos SoC MFC (Video Codec) reserved memory common definition.
*
* Copyright (c) 2016 Samsung Electronics Co., Ltd
*
* 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.
*/
/ {
reserved-memory {
#address-cells = <1>;
#size-cells = <1>;
ranges;
mfc_left: region@51000000 {
compatible = "shared-dma-pool";
no-map;
reg = <0x51000000 0x800000>;
};
mfc_right: region@43000000 {
compatible = "shared-dma-pool";
no-map;
reg = <0x43000000 0x800000>;
};
};
};
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "exynos4210.dtsi" #include "exynos4210.dtsi"
#include <dt-bindings/gpio/gpio.h> #include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h> #include <dt-bindings/input/input.h>
#include "exynos-mfc-reserved-memory.dtsi"
/ { / {
model = "Insignal Origen evaluation board based on Exynos4210"; model = "Insignal Origen evaluation board based on Exynos4210";
...@@ -288,8 +289,7 @@ ...@@ -288,8 +289,7 @@
}; };
&mfc { &mfc {
samsung,mfc-r = <0x43000000 0x800000>; memory-region = <&mfc_left>, <&mfc_right>;
samsung,mfc-l = <0x51000000 0x800000>;
status = "okay"; status = "okay";
}; };
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
/dts-v1/; /dts-v1/;
#include "exynos4210.dtsi" #include "exynos4210.dtsi"
#include <dt-bindings/gpio/gpio.h> #include <dt-bindings/gpio/gpio.h>
#include "exynos-mfc-reserved-memory.dtsi"
/ { / {
model = "Samsung smdkv310 evaluation board based on Exynos4210"; model = "Samsung smdkv310 evaluation board based on Exynos4210";
...@@ -133,8 +134,7 @@ ...@@ -133,8 +134,7 @@
}; };
&mfc { &mfc {
samsung,mfc-r = <0x43000000 0x800000>; memory-region = <&mfc_left>, <&mfc_right>;
samsung,mfc-l = <0x51000000 0x800000>;
status = "okay"; status = "okay";
}; };
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "exynos4412.dtsi" #include "exynos4412.dtsi"
#include "exynos4412-ppmu-common.dtsi" #include "exynos4412-ppmu-common.dtsi"
#include <dt-bindings/gpio/gpio.h> #include <dt-bindings/gpio/gpio.h>
#include "exynos-mfc-reserved-memory.dtsi"
/ { / {
chosen { chosen {
...@@ -499,6 +500,11 @@ ...@@ -499,6 +500,11 @@
clock-names = "iis", "i2s_opclk0", "i2s_opclk1"; clock-names = "iis", "i2s_opclk0", "i2s_opclk1";
}; };
&mfc {
memory-region = <&mfc_left>, <&mfc_right>;
status = "okay";
};
&mixer { &mixer {
status = "okay"; status = "okay";
}; };
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "exynos4412.dtsi" #include "exynos4412.dtsi"
#include <dt-bindings/gpio/gpio.h> #include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h> #include <dt-bindings/input/input.h>
#include "exynos-mfc-reserved-memory.dtsi"
/ { / {
model = "Insignal Origen evaluation board based on Exynos4412"; model = "Insignal Origen evaluation board based on Exynos4412";
...@@ -466,8 +467,7 @@ ...@@ -466,8 +467,7 @@
}; };
&mfc { &mfc {
samsung,mfc-r = <0x43000000 0x800000>; memory-region = <&mfc_left>, <&mfc_right>;
samsung,mfc-l = <0x51000000 0x800000>;
status = "okay"; status = "okay";
}; };
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
/dts-v1/; /dts-v1/;
#include "exynos4412.dtsi" #include "exynos4412.dtsi"
#include "exynos-mfc-reserved-memory.dtsi"
/ { / {
model = "Samsung SMDK evaluation board based on Exynos4412"; model = "Samsung SMDK evaluation board based on Exynos4412";
...@@ -112,8 +113,7 @@ ...@@ -112,8 +113,7 @@
}; };
&mfc { &mfc {
samsung,mfc-r = <0x43000000 0x800000>; memory-region = <&mfc_left>, <&mfc_right>;
samsung,mfc-l = <0x51000000 0x800000>;
status = "okay"; status = "okay";
}; };
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <dt-bindings/interrupt-controller/irq.h> #include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/input/input.h> #include <dt-bindings/input/input.h>
#include "exynos5250.dtsi" #include "exynos5250.dtsi"
#include "exynos-mfc-reserved-memory.dtsi"
/ { / {
model = "Insignal Arndale evaluation board based on EXYNOS5250"; model = "Insignal Arndale evaluation board based on EXYNOS5250";
...@@ -516,8 +517,7 @@ ...@@ -516,8 +517,7 @@
}; };
&mfc { &mfc {
samsung,mfc-r = <0x43000000 0x800000>; memory-region = <&mfc_left>, <&mfc_right>;
samsung,mfc-l = <0x51000000 0x800000>;
}; };
&mmc_0 { &mmc_0 {
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <dt-bindings/gpio/gpio.h> #include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h> #include <dt-bindings/interrupt-controller/irq.h>
#include "exynos5250.dtsi" #include "exynos5250.dtsi"
#include "exynos-mfc-reserved-memory.dtsi"
/ { / {
model = "SAMSUNG SMDK5250 board based on EXYNOS5250"; model = "SAMSUNG SMDK5250 board based on EXYNOS5250";
...@@ -344,8 +345,7 @@ ...@@ -344,8 +345,7 @@
}; };
&mfc { &mfc {
samsung,mfc-r = <0x43000000 0x800000>; memory-region = <&mfc_left>, <&mfc_right>;
samsung,mfc-l = <0x51000000 0x800000>;
}; };
&mmc_0 { &mmc_0 {
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <dt-bindings/interrupt-controller/irq.h> #include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/input/input.h> #include <dt-bindings/input/input.h>
#include "exynos5250.dtsi" #include "exynos5250.dtsi"
#include "exynos-mfc-reserved-memory.dtsi"
/ { / {
model = "Google Spring"; model = "Google Spring";
...@@ -425,8 +426,7 @@ ...@@ -425,8 +426,7 @@
}; };
&mfc { &mfc {
samsung,mfc-r = <0x43000000 0x800000>; memory-region = <&mfc_left>, <&mfc_right>;
samsung,mfc-l = <0x51000000 0x800000>;
}; };
&mmc_0 { &mmc_0 {
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <dt-bindings/interrupt-controller/irq.h> #include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/input/input.h> #include <dt-bindings/input/input.h>
#include <dt-bindings/clock/samsung,s2mps11.h> #include <dt-bindings/clock/samsung,s2mps11.h>
#include "exynos-mfc-reserved-memory.dtsi"
/ { / {
model = "Insignal Arndale Octa evaluation board based on EXYNOS5420"; model = "Insignal Arndale Octa evaluation board based on EXYNOS5420";
...@@ -347,8 +348,7 @@ ...@@ -347,8 +348,7 @@
}; };
&mfc { &mfc {
samsung,mfc-r = <0x43000000 0x800000>; memory-region = <&mfc_left>, <&mfc_right>;
samsung,mfc-l = <0x51000000 0x800000>;
}; };
&mmc_0 { &mmc_0 {
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <dt-bindings/regulator/maxim,max77802.h> #include <dt-bindings/regulator/maxim,max77802.h>
#include "exynos5420.dtsi" #include "exynos5420.dtsi"
#include "exynos5420-cpus.dtsi" #include "exynos5420-cpus.dtsi"
#include "exynos-mfc-reserved-memory.dtsi"
/ { / {
model = "Google Peach Pit Rev 6+"; model = "Google Peach Pit Rev 6+";
...@@ -702,8 +703,7 @@ ...@@ -702,8 +703,7 @@
}; };
&mfc { &mfc {
samsung,mfc-r = <0x43000000 0x800000>; memory-region = <&mfc_left>, <&mfc_right>;
samsung,mfc-l = <0x51000000 0x800000>;
}; };
&mmc_0 { &mmc_0 {
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "exynos5420.dtsi" #include "exynos5420.dtsi"
#include "exynos5420-cpus.dtsi" #include "exynos5420-cpus.dtsi"
#include <dt-bindings/gpio/gpio.h> #include <dt-bindings/gpio/gpio.h>
#include "exynos-mfc-reserved-memory.dtsi"
/ { / {
model = "Samsung SMDK5420 board based on EXYNOS5420"; model = "Samsung SMDK5420 board based on EXYNOS5420";
...@@ -355,8 +356,7 @@ ...@@ -355,8 +356,7 @@
}; };
&mfc { &mfc {
samsung,mfc-r = <0x43000000 0x800000>; memory-region = <&mfc_left>, <&mfc_right>;
samsung,mfc-l = <0x51000000 0x800000>;
}; };
&mmc_0 { &mmc_0 {
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "exynos5800.dtsi" #include "exynos5800.dtsi"
#include "exynos5422-cpus.dtsi" #include "exynos5422-cpus.dtsi"
#include "exynos5422-cpu-thermal.dtsi" #include "exynos5422-cpu-thermal.dtsi"
#include "exynos-mfc-reserved-memory.dtsi"
/ { / {
memory { memory {
...@@ -406,8 +407,7 @@ ...@@ -406,8 +407,7 @@
}; };
&mfc { &mfc {
samsung,mfc-r = <0x43000000 0x800000>; memory-region = <&mfc_left>, <&mfc_right>;
samsung,mfc-l = <0x51000000 0x800000>;
}; };
&mmc_0 { &mmc_0 {
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <dt-bindings/regulator/maxim,max77802.h> #include <dt-bindings/regulator/maxim,max77802.h>
#include "exynos5800.dtsi" #include "exynos5800.dtsi"
#include "exynos5420-cpus.dtsi" #include "exynos5420-cpus.dtsi"
#include "exynos-mfc-reserved-memory.dtsi"
/ { / {
model = "Google Peach Pi Rev 10+"; model = "Google Peach Pi Rev 10+";
...@@ -670,8 +671,7 @@ ...@@ -670,8 +671,7 @@
}; };
&mfc { &mfc {
samsung,mfc-r = <0x43000000 0x800000>; memory-region = <&mfc_left>, <&mfc_right>;
samsung,mfc-l = <0x51000000 0x800000>;
}; };
&mmc_0 { &mmc_0 {
......
...@@ -18,6 +18,7 @@ menuconfig ARCH_EXYNOS ...@@ -18,6 +18,7 @@ menuconfig ARCH_EXYNOS
select EXYNOS_THERMAL select EXYNOS_THERMAL
select EXYNOS_PMU select EXYNOS_PMU
select EXYNOS_SROM select EXYNOS_SROM
select EXYNOS_PM_DOMAINS if PM_GENERIC_DOMAINS
select GPIOLIB select GPIOLIB
select HAVE_ARM_SCU if SMP select HAVE_ARM_SCU if SMP
select HAVE_S3C2410_I2C if I2C select HAVE_S3C2410_I2C if I2C
......
...@@ -13,7 +13,6 @@ obj-$(CONFIG_ARCH_EXYNOS) += exynos.o exynos-smc.o firmware.o ...@@ -13,7 +13,6 @@ obj-$(CONFIG_ARCH_EXYNOS) += exynos.o exynos-smc.o firmware.o
obj-$(CONFIG_EXYNOS_CPU_SUSPEND) += pm.o sleep.o obj-$(CONFIG_EXYNOS_CPU_SUSPEND) += pm.o sleep.o
obj-$(CONFIG_PM_SLEEP) += suspend.o obj-$(CONFIG_PM_SLEEP) += suspend.o
obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o
obj-$(CONFIG_SMP) += platsmp.o headsmp.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o
...@@ -23,5 +22,3 @@ AFLAGS_sleep.o :=-Wa,-march=armv7-a$(plus_sec) ...@@ -23,5 +22,3 @@ AFLAGS_sleep.o :=-Wa,-march=armv7-a$(plus_sec)
obj-$(CONFIG_EXYNOS5420_MCPM) += mcpm-exynos.o obj-$(CONFIG_EXYNOS5420_MCPM) += mcpm-exynos.o
CFLAGS_mcpm-exynos.o += -march=armv7-a CFLAGS_mcpm-exynos.o += -march=armv7-a
obj-$(CONFIG_S5P_DEV_MFC) += s5p-dev-mfc.o
...@@ -27,7 +27,6 @@ ...@@ -27,7 +27,6 @@
#include <plat/cpu.h> #include <plat/cpu.h>
#include "common.h" #include "common.h"
#include "mfc.h"
static struct map_desc exynos4_iodesc[] __initdata = { static struct map_desc exynos4_iodesc[] __initdata = {
{ {
...@@ -235,23 +234,6 @@ static char const *const exynos_dt_compat[] __initconst = { ...@@ -235,23 +234,6 @@ static char const *const exynos_dt_compat[] __initconst = {
NULL NULL
}; };
static void __init exynos_reserve(void)
{
#ifdef CONFIG_S5P_DEV_MFC
int i;
char *mfc_mem[] = {
"samsung,mfc-v5",
"samsung,mfc-v6",
"samsung,mfc-v7",
"samsung,mfc-v8",
};
for (i = 0; i < ARRAY_SIZE(mfc_mem); i++)
if (of_scan_flat_dt(s5p_fdt_alloc_mfc_mem, mfc_mem[i]))
break;
#endif
}
static void __init exynos_dt_fixup(void) static void __init exynos_dt_fixup(void)
{ {
/* /*
...@@ -273,6 +255,5 @@ DT_MACHINE_START(EXYNOS_DT, "SAMSUNG EXYNOS (Flattened Device Tree)") ...@@ -273,6 +255,5 @@ DT_MACHINE_START(EXYNOS_DT, "SAMSUNG EXYNOS (Flattened Device Tree)")
.init_machine = exynos_dt_machine_init, .init_machine = exynos_dt_machine_init,
.init_late = exynos_init_late, .init_late = exynos_init_late,
.dt_compat = exynos_dt_compat, .dt_compat = exynos_dt_compat,
.reserve = exynos_reserve,
.dt_fixup = exynos_dt_fixup, .dt_fixup = exynos_dt_fixup,
MACHINE_END MACHINE_END
/*
* Copyright (C) 2013 Samsung Electronics Co.Ltd
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#ifndef __MACH_EXYNOS_MFC_H
#define __MACH_EXYNOS_MFC_H __FILE__
int __init s5p_fdt_alloc_mfc_mem(unsigned long node, const char *uname,
int depth, void *data);
#endif /* __MACH_EXYNOS_MFC_H */
/*
* Copyright (C) 2010-2011 Samsung Electronics Co.Ltd
*
* Base S5P MFC resource and device definitions
*
* 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 <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/memblock.h>
#include <linux/ioport.h>
#include <linux/of_fdt.h>
#include <linux/of.h>
static struct platform_device s5p_device_mfc_l;
static struct platform_device s5p_device_mfc_r;
struct s5p_mfc_dt_meminfo {
unsigned long loff;
unsigned long lsize;
unsigned long roff;
unsigned long rsize;
char *compatible;
};
struct s5p_mfc_reserved_mem {
phys_addr_t base;
unsigned long size;
struct device *dev;
};
static struct s5p_mfc_reserved_mem s5p_mfc_mem[2] __initdata;
static void __init s5p_mfc_reserve_mem(phys_addr_t rbase, unsigned int rsize,
phys_addr_t lbase, unsigned int lsize)
{
int i;
s5p_mfc_mem[0].dev = &s5p_device_mfc_r.dev;
s5p_mfc_mem[0].base = rbase;
s5p_mfc_mem[0].size = rsize;
s5p_mfc_mem[1].dev = &s5p_device_mfc_l.dev;
s5p_mfc_mem[1].base = lbase;
s5p_mfc_mem[1].size = lsize;
for (i = 0; i < ARRAY_SIZE(s5p_mfc_mem); i++) {
struct s5p_mfc_reserved_mem *area = &s5p_mfc_mem[i];
if (memblock_remove(area->base, area->size)) {
printk(KERN_ERR "Failed to reserve memory for MFC device (%ld bytes at 0x%08lx)\n",
area->size, (unsigned long) area->base);
area->base = 0;
}
}
}
int __init s5p_fdt_alloc_mfc_mem(unsigned long node, const char *uname,
int depth, void *data)
{
const __be32 *prop;
int len;
struct s5p_mfc_dt_meminfo mfc_mem;
if (!data)
return 0;
if (!of_flat_dt_is_compatible(node, data))
return 0;
prop = of_get_flat_dt_prop(node, "samsung,mfc-l", &len);
if (!prop || (len != 2 * sizeof(unsigned long)))
return 0;
mfc_mem.loff = be32_to_cpu(prop[0]);
mfc_mem.lsize = be32_to_cpu(prop[1]);
prop = of_get_flat_dt_prop(node, "samsung,mfc-r", &len);
if (!prop || (len != 2 * sizeof(unsigned long)))
return 0;
mfc_mem.roff = be32_to_cpu(prop[0]);
mfc_mem.rsize = be32_to_cpu(prop[1]);
s5p_mfc_reserve_mem(mfc_mem.roff, mfc_mem.rsize,
mfc_mem.loff, mfc_mem.lsize);
return 1;
}
...@@ -1242,11 +1242,6 @@ static struct pwm_omap_dmtimer_pdata __maybe_unused pwm_dmtimer_pdata = { ...@@ -1242,11 +1242,6 @@ static struct pwm_omap_dmtimer_pdata __maybe_unused pwm_dmtimer_pdata = {
#if defined(CONFIG_IR_RX51) || defined(CONFIG_IR_RX51_MODULE) #if defined(CONFIG_IR_RX51) || defined(CONFIG_IR_RX51_MODULE)
static struct lirc_rx51_platform_data rx51_lirc_data = { static struct lirc_rx51_platform_data rx51_lirc_data = {
.set_max_mpu_wakeup_lat = omap_pm_set_max_mpu_wakeup_lat, .set_max_mpu_wakeup_lat = omap_pm_set_max_mpu_wakeup_lat,
.pwm_timer = 9, /* Use GPT 9 for CIR */
#if IS_ENABLED(CONFIG_OMAP_DM_TIMER)
.dmtimer = &pwm_dmtimer_pdata,
#endif
}; };
static struct platform_device rx51_lirc_device = { static struct platform_device rx51_lirc_device = {
......
...@@ -274,8 +274,6 @@ static struct platform_device omap3_rom_rng_device = { ...@@ -274,8 +274,6 @@ static struct platform_device omap3_rom_rng_device = {
}, },
}; };
static struct platform_device rx51_lirc_device;
static void __init nokia_n900_legacy_init(void) static void __init nokia_n900_legacy_init(void)
{ {
hsmmc2_internal_input_clk(); hsmmc2_internal_input_clk();
...@@ -294,10 +292,7 @@ static void __init nokia_n900_legacy_init(void) ...@@ -294,10 +292,7 @@ static void __init nokia_n900_legacy_init(void)
pr_info("RX-51: Registering OMAP3 HWRNG device\n"); pr_info("RX-51: Registering OMAP3 HWRNG device\n");
platform_device_register(&omap3_rom_rng_device); platform_device_register(&omap3_rom_rng_device);
} }
platform_device_register(&rx51_lirc_device);
} }
static void __init omap3_tao3530_legacy_init(void) static void __init omap3_tao3530_legacy_init(void)
...@@ -492,10 +487,6 @@ static struct pwm_omap_dmtimer_pdata pwm_dmtimer_pdata = { ...@@ -492,10 +487,6 @@ static struct pwm_omap_dmtimer_pdata pwm_dmtimer_pdata = {
static struct lirc_rx51_platform_data __maybe_unused rx51_lirc_data = { static struct lirc_rx51_platform_data __maybe_unused rx51_lirc_data = {
.set_max_mpu_wakeup_lat = omap_pm_set_max_mpu_wakeup_lat, .set_max_mpu_wakeup_lat = omap_pm_set_max_mpu_wakeup_lat,
.pwm_timer = 9, /* Use GPT 9 for CIR */
#if IS_ENABLED(CONFIG_OMAP_DM_TIMER)
.dmtimer = &pwm_dmtimer_pdata,
#endif
}; };
static struct platform_device __maybe_unused rx51_lirc_device = { static struct platform_device __maybe_unused rx51_lirc_device = {
...@@ -543,6 +534,7 @@ static struct of_dev_auxdata omap_auxdata_lookup[] __initdata = { ...@@ -543,6 +534,7 @@ static struct of_dev_auxdata omap_auxdata_lookup[] __initdata = {
&omap3_iommu_pdata), &omap3_iommu_pdata),
OF_DEV_AUXDATA("ti,omap3-hsmmc", 0x4809c000, "4809c000.mmc", &mmc_pdata[0]), OF_DEV_AUXDATA("ti,omap3-hsmmc", 0x4809c000, "4809c000.mmc", &mmc_pdata[0]),
OF_DEV_AUXDATA("ti,omap3-hsmmc", 0x480b4000, "480b4000.mmc", &mmc_pdata[1]), OF_DEV_AUXDATA("ti,omap3-hsmmc", 0x480b4000, "480b4000.mmc", &mmc_pdata[1]),
OF_DEV_AUXDATA("nokia,n900-ir", 0, "n900-ir", &rx51_lirc_data),
/* Only on am3517 */ /* Only on am3517 */
OF_DEV_AUXDATA("ti,davinci_mdio", 0x5c030000, "davinci_mdio.0", NULL), OF_DEV_AUXDATA("ti,davinci_mdio", 0x5c030000, "davinci_mdio.0", NULL),
OF_DEV_AUXDATA("ti,am3517-emac", 0x5c000000, "davinci_emac.0", OF_DEV_AUXDATA("ti,am3517-emac", 0x5c000000, "davinci_emac.0",
......
...@@ -2,11 +2,9 @@ ...@@ -2,11 +2,9 @@
# Makefile for the linux kernel, U8500 machine. # Makefile for the linux kernel, U8500 machine.
# #
obj-y := cpu.o id.o pm.o obj-y := pm.o
obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o
obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o
obj-$(CONFIG_MACH_MOP500) += board-mop500-regulators.o \ obj-$(CONFIG_MACH_MOP500) += board-mop500-audio.o
board-mop500-audio.o
obj-$(CONFIG_SMP) += platsmp.o obj-$(CONFIG_SMP) += platsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o
......
/*
* Copyright (C) ST-Ericsson SA 2010
*
* License Terms: GNU General Public License v2
*
* Authors: Sundar Iyer <sundar.iyer@stericsson.com>
* Bengt Jonsson <bengt.g.jonsson@stericsson.com>
* Daniel Willerud <daniel.willerud@stericsson.com>
*
* MOP500 board specific initialization for regulators
*/
#include <linux/kernel.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/ab8500.h>
#include "board-mop500-regulators.h"
#include "id.h"
static struct regulator_consumer_supply gpio_en_3v3_consumers[] = {
REGULATOR_SUPPLY("vdd33a", "smsc911x.0"),
};
struct regulator_init_data gpio_en_3v3_regulator = {
.constraints = {
.name = "EN-3V3",
.min_uV = 3300000,
.max_uV = 3300000,
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = ARRAY_SIZE(gpio_en_3v3_consumers),
.consumer_supplies = gpio_en_3v3_consumers,
};
/*
* TPS61052 regulator
*/
static struct regulator_consumer_supply tps61052_vaudio_consumers[] = {
/*
* Boost converter supply to raise voltage on audio speaker, this
* is actually connected to three pins, VInVhfL (left amplifier)
* VInVhfR (right amplifier) and VIntDClassInt - all three must
* be connected to the same voltage.
*/
REGULATOR_SUPPLY("vintdclassint", "ab8500-codec.0"),
};
struct regulator_init_data tps61052_regulator = {
.constraints = {
.name = "vaudio-hf",
.min_uV = 4500000,
.max_uV = 4500000,
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = ARRAY_SIZE(tps61052_vaudio_consumers),
.consumer_supplies = tps61052_vaudio_consumers,
};
static struct regulator_consumer_supply ab8500_vaux1_consumers[] = {
/* Main display, u8500 R3 uib */
REGULATOR_SUPPLY("vddi", "mcde_disp_sony_acx424akp.0"),
/* Main display, u8500 uib and ST uib */
REGULATOR_SUPPLY("vdd1", "samsung_s6d16d0.0"),
/* Secondary display, ST uib */
REGULATOR_SUPPLY("vdd1", "samsung_s6d16d0.1"),
/* SFH7741 proximity sensor */
REGULATOR_SUPPLY("vcc", "gpio-keys.0"),
/* BH1780GLS ambient light sensor */
REGULATOR_SUPPLY("vcc", "2-0029"),
/* lsm303dlh accelerometer */
REGULATOR_SUPPLY("vdd", "2-0018"),
/* lsm303dlhc accelerometer */
REGULATOR_SUPPLY("vdd", "2-0019"),
/* lsm303dlh magnetometer */
REGULATOR_SUPPLY("vdd", "2-001e"),
/* Rohm BU21013 Touchscreen devices */
REGULATOR_SUPPLY("avdd", "3-005c"),
REGULATOR_SUPPLY("avdd", "3-005d"),
/* Synaptics RMI4 Touchscreen device */
REGULATOR_SUPPLY("vdd", "3-004b"),
/* L3G4200D Gyroscope device */
REGULATOR_SUPPLY("vdd", "2-0068"),
/* Ambient light sensor device */
REGULATOR_SUPPLY("vdd", "3-0029"),
/* Pressure sensor device */
REGULATOR_SUPPLY("vdd", "2-005c"),
/* Cypress TrueTouch Touchscreen device */
REGULATOR_SUPPLY("vcpin", "spi8.0"),
/* Camera device */
REGULATOR_SUPPLY("vaux12v5", "mmio_camera"),
};
static struct regulator_consumer_supply ab8500_vaux2_consumers[] = {
/* On-board eMMC power */
REGULATOR_SUPPLY("vmmc", "sdi4"),
/* AB8500 audio codec */
REGULATOR_SUPPLY("vcc-N2158", "ab8500-codec.0"),
/* AB8500 accessory detect 1 */
REGULATOR_SUPPLY("vcc-N2158", "ab8500-acc-det.0"),
/* AB8500 Tv-out device */
REGULATOR_SUPPLY("vcc-N2158", "mcde_tv_ab8500.4"),
/* AV8100 HDMI device */
REGULATOR_SUPPLY("vcc-N2158", "av8100_hdmi.3"),
};
static struct regulator_consumer_supply ab8500_vaux3_consumers[] = {
REGULATOR_SUPPLY("v-SD-STM", "stm"),
/* External MMC slot power */
REGULATOR_SUPPLY("vmmc", "sdi0"),
};
static struct regulator_consumer_supply ab8505_vaux4_consumers[] = {
};
static struct regulator_consumer_supply ab8505_vaux5_consumers[] = {
};
static struct regulator_consumer_supply ab8505_vaux6_consumers[] = {
};
static struct regulator_consumer_supply ab8505_vaux8_consumers[] = {
/* AB8500 audio codec device */
REGULATOR_SUPPLY("v-aux8", NULL),
};
static struct regulator_consumer_supply ab8505_vadc_consumers[] = {
/* Internal general-purpose ADC */
REGULATOR_SUPPLY("vddadc", "ab8500-gpadc.0"),
/* ADC for charger */
REGULATOR_SUPPLY("vddadc", "ab8500-charger.0"),
};
static struct regulator_consumer_supply ab8500_vtvout_consumers[] = {
/* TV-out DENC supply */
REGULATOR_SUPPLY("vtvout", "ab8500-denc.0"),
/* Internal general-purpose ADC */
REGULATOR_SUPPLY("vddadc", "ab8500-gpadc.0"),
/* ADC for charger */
REGULATOR_SUPPLY("vddadc", "ab8500-charger.0"),
/* AB8500 Tv-out device */
REGULATOR_SUPPLY("vtvout", "mcde_tv_ab8500.4"),
};
static struct regulator_consumer_supply ab8500_vaud_consumers[] = {
/* AB8500 audio-codec main supply */
REGULATOR_SUPPLY("vaud", "ab8500-codec.0"),
};
static struct regulator_consumer_supply ab8500_vamic1_consumers[] = {
/* AB8500 audio-codec Mic1 supply */
REGULATOR_SUPPLY("vamic1", "ab8500-codec.0"),
};
static struct regulator_consumer_supply ab8500_vamic2_consumers[] = {
/* AB8500 audio-codec Mic2 supply */
REGULATOR_SUPPLY("vamic2", "ab8500-codec.0"),
};
static struct regulator_consumer_supply ab8500_vdmic_consumers[] = {
/* AB8500 audio-codec DMic supply */
REGULATOR_SUPPLY("vdmic", "ab8500-codec.0"),
};
static struct regulator_consumer_supply ab8500_vintcore_consumers[] = {
/* SoC core supply, no device */
REGULATOR_SUPPLY("v-intcore", NULL),
/* USB Transceiver */
REGULATOR_SUPPLY("vddulpivio18", "ab8500-usb.0"),
/* Handled by abx500 clk driver */
REGULATOR_SUPPLY("v-intcore", "abx500-clk.0"),
};
static struct regulator_consumer_supply ab8505_usb_consumers[] = {
/* HS USB OTG physical interface */
REGULATOR_SUPPLY("v-ape", NULL),
};
static struct regulator_consumer_supply ab8500_vana_consumers[] = {
/* DB8500 DSI */
REGULATOR_SUPPLY("vdddsi1v2", "mcde"),
REGULATOR_SUPPLY("vdddsi1v2", "b2r2_core"),
REGULATOR_SUPPLY("vdddsi1v2", "b2r2_1_core"),
REGULATOR_SUPPLY("vdddsi1v2", "dsilink.0"),
REGULATOR_SUPPLY("vdddsi1v2", "dsilink.1"),
REGULATOR_SUPPLY("vdddsi1v2", "dsilink.2"),
/* DB8500 CSI */
REGULATOR_SUPPLY("vddcsi1v2", "mmio_camera"),
};
/* ab8500 regulator register initialization */
static struct ab8500_regulator_reg_init ab8500_reg_init[] = {
/*
* VanaRequestCtrl = HP/LP depending on VxRequest
* VextSupply1RequestCtrl = HP/LP depending on VxRequest
*/
INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL2, 0xf0, 0x00),
/*
* VextSupply2RequestCtrl = HP/LP depending on VxRequest
* VextSupply3RequestCtrl = HP/LP depending on VxRequest
* Vaux1RequestCtrl = HP/LP depending on VxRequest
* Vaux2RequestCtrl = HP/LP depending on VxRequest
*/
INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL3, 0xff, 0x00),
/*
* Vaux3RequestCtrl = HP/LP depending on VxRequest
* SwHPReq = Control through SWValid disabled
*/
INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL4, 0x07, 0x00),
/*
* VanaSysClkReq1HPValid = disabled
* Vaux1SysClkReq1HPValid = disabled
* Vaux2SysClkReq1HPValid = disabled
* Vaux3SysClkReq1HPValid = disabled
*/
INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQ1HPVALID1, 0xe8, 0x00),
/*
* VextSupply1SysClkReq1HPValid = disabled
* VextSupply2SysClkReq1HPValid = disabled
* VextSupply3SysClkReq1HPValid = SysClkReq1 controlled
*/
INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQ1HPVALID2, 0x70, 0x40),
/*
* VanaHwHPReq1Valid = disabled
* Vaux1HwHPreq1Valid = disabled
* Vaux2HwHPReq1Valid = disabled
* Vaux3HwHPReqValid = disabled
*/
INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ1VALID1, 0xe8, 0x00),
/*
* VextSupply1HwHPReq1Valid = disabled
* VextSupply2HwHPReq1Valid = disabled
* VextSupply3HwHPReq1Valid = disabled
*/
INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ1VALID2, 0x07, 0x00),
/*
* VanaHwHPReq2Valid = disabled
* Vaux1HwHPReq2Valid = disabled
* Vaux2HwHPReq2Valid = disabled
* Vaux3HwHPReq2Valid = disabled
*/
INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ2VALID1, 0xe8, 0x00),
/*
* VextSupply1HwHPReq2Valid = disabled
* VextSupply2HwHPReq2Valid = disabled
* VextSupply3HwHPReq2Valid = HWReq2 controlled
*/
INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ2VALID2, 0x07, 0x04),
/*
* VanaSwHPReqValid = disabled
* Vaux1SwHPReqValid = disabled
*/
INIT_REGULATOR_REGISTER(AB8500_REGUSWHPREQVALID1, 0xa0, 0x00),
/*
* Vaux2SwHPReqValid = disabled
* Vaux3SwHPReqValid = disabled
* VextSupply1SwHPReqValid = disabled
* VextSupply2SwHPReqValid = disabled
* VextSupply3SwHPReqValid = disabled
*/
INIT_REGULATOR_REGISTER(AB8500_REGUSWHPREQVALID2, 0x1f, 0x00),
/*
* SysClkReq2Valid1 = SysClkReq2 controlled
* SysClkReq3Valid1 = disabled
* SysClkReq4Valid1 = SysClkReq4 controlled
* SysClkReq5Valid1 = disabled
* SysClkReq6Valid1 = SysClkReq6 controlled
* SysClkReq7Valid1 = disabled
* SysClkReq8Valid1 = disabled
*/
INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQVALID1, 0xfe, 0x2a),
/*
* SysClkReq2Valid2 = disabled
* SysClkReq3Valid2 = disabled
* SysClkReq4Valid2 = disabled
* SysClkReq5Valid2 = disabled
* SysClkReq6Valid2 = SysClkReq6 controlled
* SysClkReq7Valid2 = disabled
* SysClkReq8Valid2 = disabled
*/
INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQVALID2, 0xfe, 0x20),
/*
* VTVoutEna = disabled
* Vintcore12Ena = disabled
* Vintcore12Sel = 1.25 V
* Vintcore12LP = inactive (HP)
* VTVoutLP = inactive (HP)
*/
INIT_REGULATOR_REGISTER(AB8500_REGUMISC1, 0xfe, 0x10),
/*
* VaudioEna = disabled
* VdmicEna = disabled
* Vamic1Ena = disabled
* Vamic2Ena = disabled
*/
INIT_REGULATOR_REGISTER(AB8500_VAUDIOSUPPLY, 0x1e, 0x00),
/*
* Vamic1_dzout = high-Z when Vamic1 is disabled
* Vamic2_dzout = high-Z when Vamic2 is disabled
*/
INIT_REGULATOR_REGISTER(AB8500_REGUCTRL1VAMIC, 0x03, 0x00),
/*
* VPll = Hw controlled (NOTE! PRCMU bits)
* VanaRegu = force off
*/
INIT_REGULATOR_REGISTER(AB8500_VPLLVANAREGU, 0x0f, 0x02),
/*
* VrefDDREna = disabled
* VrefDDRSleepMode = inactive (no pulldown)
*/
INIT_REGULATOR_REGISTER(AB8500_VREFDDR, 0x03, 0x00),
/*
* VextSupply1Regu = force LP
* VextSupply2Regu = force OFF
* VextSupply3Regu = force HP (-> STBB2=LP and TPS=LP)
* ExtSupply2Bypass = ExtSupply12LPn ball is 0 when Ena is 0
* ExtSupply3Bypass = ExtSupply3LPn ball is 0 when Ena is 0
*/
INIT_REGULATOR_REGISTER(AB8500_EXTSUPPLYREGU, 0xff, 0x13),
/*
* Vaux1Regu = force HP
* Vaux2Regu = force off
*/
INIT_REGULATOR_REGISTER(AB8500_VAUX12REGU, 0x0f, 0x01),
/*
* Vaux3Regu = force off
*/
INIT_REGULATOR_REGISTER(AB8500_VRF1VAUX3REGU, 0x03, 0x00),
/*
* Vaux1Sel = 2.8 V
*/
INIT_REGULATOR_REGISTER(AB8500_VAUX1SEL, 0x0f, 0x0C),
/*
* Vaux2Sel = 2.9 V
*/
INIT_REGULATOR_REGISTER(AB8500_VAUX2SEL, 0x0f, 0x0d),
/*
* Vaux3Sel = 2.91 V
*/
INIT_REGULATOR_REGISTER(AB8500_VRF1VAUX3SEL, 0x07, 0x07),
/*
* VextSupply12LP = disabled (no LP)
*/
INIT_REGULATOR_REGISTER(AB8500_REGUCTRL2SPARE, 0x01, 0x00),
/*
* Vaux1Disch = short discharge time
* Vaux2Disch = short discharge time
* Vaux3Disch = short discharge time
* Vintcore12Disch = short discharge time
* VTVoutDisch = short discharge time
* VaudioDisch = short discharge time
*/
INIT_REGULATOR_REGISTER(AB8500_REGUCTRLDISCH, 0xfc, 0x00),
/*
* VanaDisch = short discharge time
* VdmicPullDownEna = pulldown disabled when Vdmic is disabled
* VdmicDisch = short discharge time
*/
INIT_REGULATOR_REGISTER(AB8500_REGUCTRLDISCH2, 0x16, 0x00),
};
/* AB8500 regulators */
static struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS] = {
/* supplies to the display/camera */
[AB8500_LDO_AUX1] = {
.supply_regulator = "ab8500-ext-supply3",
.constraints = {
.name = "V-DISPLAY",
.min_uV = 2800000,
.max_uV = 3300000,
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
REGULATOR_CHANGE_STATUS,
.boot_on = 1, /* display is on at boot */
},
.num_consumer_supplies = ARRAY_SIZE(ab8500_vaux1_consumers),
.consumer_supplies = ab8500_vaux1_consumers,
},
/* supplies to the on-board eMMC */
[AB8500_LDO_AUX2] = {
.supply_regulator = "ab8500-ext-supply3",
.constraints = {
.name = "V-eMMC1",
.min_uV = 1100000,
.max_uV = 3300000,
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
REGULATOR_CHANGE_STATUS |
REGULATOR_CHANGE_MODE,
.valid_modes_mask = REGULATOR_MODE_NORMAL |
REGULATOR_MODE_IDLE,
},
.num_consumer_supplies = ARRAY_SIZE(ab8500_vaux2_consumers),
.consumer_supplies = ab8500_vaux2_consumers,
},
/* supply for VAUX3, supplies to SDcard slots */
[AB8500_LDO_AUX3] = {
.supply_regulator = "ab8500-ext-supply3",
.constraints = {
.name = "V-MMC-SD",
.min_uV = 1100000,
.max_uV = 3300000,
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
REGULATOR_CHANGE_STATUS |
REGULATOR_CHANGE_MODE,
.valid_modes_mask = REGULATOR_MODE_NORMAL |
REGULATOR_MODE_IDLE,
},
.num_consumer_supplies = ARRAY_SIZE(ab8500_vaux3_consumers),
.consumer_supplies = ab8500_vaux3_consumers,
},
/* supply for tvout, gpadc, TVOUT LDO */
[AB8500_LDO_TVOUT] = {
.constraints = {
.name = "V-TVOUT",
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = ARRAY_SIZE(ab8500_vtvout_consumers),
.consumer_supplies = ab8500_vtvout_consumers,
},
/* supply for ab8500-vaudio, VAUDIO LDO */
[AB8500_LDO_AUDIO] = {
.constraints = {
.name = "V-AUD",
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = ARRAY_SIZE(ab8500_vaud_consumers),
.consumer_supplies = ab8500_vaud_consumers,
},
/* supply for v-anamic1 VAMic1-LDO */
[AB8500_LDO_ANAMIC1] = {
.constraints = {
.name = "V-AMIC1",
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = ARRAY_SIZE(ab8500_vamic1_consumers),
.consumer_supplies = ab8500_vamic1_consumers,
},
/* supply for v-amic2, VAMIC2 LDO, reuse constants for AMIC1 */
[AB8500_LDO_ANAMIC2] = {
.constraints = {
.name = "V-AMIC2",
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = ARRAY_SIZE(ab8500_vamic2_consumers),
.consumer_supplies = ab8500_vamic2_consumers,
},
/* supply for v-dmic, VDMIC LDO */
[AB8500_LDO_DMIC] = {
.constraints = {
.name = "V-DMIC",
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = ARRAY_SIZE(ab8500_vdmic_consumers),
.consumer_supplies = ab8500_vdmic_consumers,
},
/* supply for v-intcore12, VINTCORE12 LDO */
[AB8500_LDO_INTCORE] = {
.constraints = {
.name = "V-INTCORE",
.min_uV = 1250000,
.max_uV = 1350000,
.input_uV = 1800000,
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
REGULATOR_CHANGE_STATUS |
REGULATOR_CHANGE_MODE |
REGULATOR_CHANGE_DRMS,
.valid_modes_mask = REGULATOR_MODE_NORMAL |
REGULATOR_MODE_IDLE,
},
.num_consumer_supplies = ARRAY_SIZE(ab8500_vintcore_consumers),
.consumer_supplies = ab8500_vintcore_consumers,
},
/* supply for U8500 CSI-DSI, VANA LDO */
[AB8500_LDO_ANA] = {
.constraints = {
.name = "V-CSI-DSI",
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = ARRAY_SIZE(ab8500_vana_consumers),
.consumer_supplies = ab8500_vana_consumers,
},
};
/* supply for VextSupply3 */
static struct regulator_consumer_supply ab8500_ext_supply3_consumers[] = {
/* SIM supply for 3 V SIM cards */
REGULATOR_SUPPLY("vinvsim", "sim-detect.0"),
};
/* extended configuration for VextSupply2, only used for HREFP_V20 boards */
static struct ab8500_ext_regulator_cfg ab8500_ext_supply2 = {
.hwreq = true,
};
/*
* AB8500 external regulators
*/
static struct regulator_init_data ab8500_ext_regulators[] = {
/* fixed Vbat supplies VSMPS1_EXT_1V8 */
[AB8500_EXT_SUPPLY1] = {
.constraints = {
.name = "ab8500-ext-supply1",
.min_uV = 1800000,
.max_uV = 1800000,
.initial_mode = REGULATOR_MODE_IDLE,
.boot_on = 1,
.always_on = 1,
},
},
/* fixed Vbat supplies VSMPS2_EXT_1V36 and VSMPS5_EXT_1V15 */
[AB8500_EXT_SUPPLY2] = {
.constraints = {
.name = "ab8500-ext-supply2",
.min_uV = 1360000,
.max_uV = 1360000,
},
},
/* fixed Vbat supplies VSMPS3_EXT_3V4 and VSMPS4_EXT_3V4 */
[AB8500_EXT_SUPPLY3] = {
.constraints = {
.name = "ab8500-ext-supply3",
.min_uV = 3400000,
.max_uV = 3400000,
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
.boot_on = 1,
},
.num_consumer_supplies =
ARRAY_SIZE(ab8500_ext_supply3_consumers),
.consumer_supplies = ab8500_ext_supply3_consumers,
},
};
/* ab8505 regulator register initialization */
static struct ab8500_regulator_reg_init ab8505_reg_init[] = {
/*
* VarmRequestCtrl
* VsmpsCRequestCtrl
* VsmpsARequestCtrl
* VsmpsBRequestCtrl
*/
INIT_REGULATOR_REGISTER(AB8505_REGUREQUESTCTRL1, 0x00, 0x00),
/*
* VsafeRequestCtrl
* VpllRequestCtrl
* VanaRequestCtrl = HP/LP depending on VxRequest
*/
INIT_REGULATOR_REGISTER(AB8505_REGUREQUESTCTRL2, 0x30, 0x00),
/*
* Vaux1RequestCtrl = HP/LP depending on VxRequest
* Vaux2RequestCtrl = HP/LP depending on VxRequest
*/
INIT_REGULATOR_REGISTER(AB8505_REGUREQUESTCTRL3, 0xf0, 0x00),
/*
* Vaux3RequestCtrl = HP/LP depending on VxRequest
* SwHPReq = Control through SWValid disabled
*/
INIT_REGULATOR_REGISTER(AB8505_REGUREQUESTCTRL4, 0x07, 0x00),
/*
* VsmpsASysClkReq1HPValid
* VsmpsBSysClkReq1HPValid
* VsafeSysClkReq1HPValid
* VanaSysClkReq1HPValid = disabled
* VpllSysClkReq1HPValid
* Vaux1SysClkReq1HPValid = disabled
* Vaux2SysClkReq1HPValid = disabled
* Vaux3SysClkReq1HPValid = disabled
*/
INIT_REGULATOR_REGISTER(AB8505_REGUSYSCLKREQ1HPVALID1, 0xe8, 0x00),
/*
* VsmpsCSysClkReq1HPValid
* VarmSysClkReq1HPValid
* VbbSysClkReq1HPValid
* VsmpsMSysClkReq1HPValid
*/
INIT_REGULATOR_REGISTER(AB8505_REGUSYSCLKREQ1HPVALID2, 0x00, 0x00),
/*
* VsmpsAHwHPReq1Valid
* VsmpsBHwHPReq1Valid
* VsafeHwHPReq1Valid
* VanaHwHPReq1Valid = disabled
* VpllHwHPReq1Valid
* Vaux1HwHPreq1Valid = disabled
* Vaux2HwHPReq1Valid = disabled
* Vaux3HwHPReqValid = disabled
*/
INIT_REGULATOR_REGISTER(AB8505_REGUHWHPREQ1VALID1, 0xe8, 0x00),
/*
* VsmpsMHwHPReq1Valid
*/
INIT_REGULATOR_REGISTER(AB8505_REGUHWHPREQ1VALID2, 0x00, 0x00),
/*
* VsmpsAHwHPReq2Valid
* VsmpsBHwHPReq2Valid
* VsafeHwHPReq2Valid
* VanaHwHPReq2Valid = disabled
* VpllHwHPReq2Valid
* Vaux1HwHPReq2Valid = disabled
* Vaux2HwHPReq2Valid = disabled
* Vaux3HwHPReq2Valid = disabled
*/
INIT_REGULATOR_REGISTER(AB8505_REGUHWHPREQ2VALID1, 0xe8, 0x00),
/*
* VsmpsMHwHPReq2Valid
*/
INIT_REGULATOR_REGISTER(AB8505_REGUHWHPREQ2VALID2, 0x00, 0x00),
/**
* VsmpsCSwHPReqValid
* VarmSwHPReqValid
* VsmpsASwHPReqValid
* VsmpsBSwHPReqValid
* VsafeSwHPReqValid
* VanaSwHPReqValid
* VanaSwHPReqValid = disabled
* VpllSwHPReqValid
* Vaux1SwHPReqValid = disabled
*/
INIT_REGULATOR_REGISTER(AB8505_REGUSWHPREQVALID1, 0xa0, 0x00),
/*
* Vaux2SwHPReqValid = disabled
* Vaux3SwHPReqValid = disabled
* VsmpsMSwHPReqValid
*/
INIT_REGULATOR_REGISTER(AB8505_REGUSWHPREQVALID2, 0x03, 0x00),
/*
* SysClkReq2Valid1 = SysClkReq2 controlled
* SysClkReq3Valid1 = disabled
* SysClkReq4Valid1 = SysClkReq4 controlled
*/
INIT_REGULATOR_REGISTER(AB8505_REGUSYSCLKREQVALID1, 0x0e, 0x0a),
/*
* SysClkReq2Valid2 = disabled
* SysClkReq3Valid2 = disabled
* SysClkReq4Valid2 = disabled
*/
INIT_REGULATOR_REGISTER(AB8505_REGUSYSCLKREQVALID2, 0x0e, 0x00),
/*
* Vaux4SwHPReqValid
* Vaux4HwHPReq2Valid
* Vaux4HwHPReq1Valid
* Vaux4SysClkReq1HPValid
*/
INIT_REGULATOR_REGISTER(AB8505_REGUVAUX4REQVALID, 0x00, 0x00),
/*
* VadcEna = disabled
* VintCore12Ena = disabled
* VintCore12Sel = 1.25 V
* VintCore12LP = inactive (HP)
* VadcLP = inactive (HP)
*/
INIT_REGULATOR_REGISTER(AB8505_REGUMISC1, 0xfe, 0x10),
/*
* VaudioEna = disabled
* Vaux8Ena = disabled
* Vamic1Ena = disabled
* Vamic2Ena = disabled
*/
INIT_REGULATOR_REGISTER(AB8505_VAUDIOSUPPLY, 0x1e, 0x00),
/*
* Vamic1_dzout = high-Z when Vamic1 is disabled
* Vamic2_dzout = high-Z when Vamic2 is disabled
*/
INIT_REGULATOR_REGISTER(AB8505_REGUCTRL1VAMIC, 0x03, 0x00),
/*
* VsmpsARegu
* VsmpsASelCtrl
* VsmpsAAutoMode
* VsmpsAPWMMode
*/
INIT_REGULATOR_REGISTER(AB8505_VSMPSAREGU, 0x00, 0x00),
/*
* VsmpsBRegu
* VsmpsBSelCtrl
* VsmpsBAutoMode
* VsmpsBPWMMode
*/
INIT_REGULATOR_REGISTER(AB8505_VSMPSBREGU, 0x00, 0x00),
/*
* VsafeRegu
* VsafeSelCtrl
* VsafeAutoMode
* VsafePWMMode
*/
INIT_REGULATOR_REGISTER(AB8505_VSAFEREGU, 0x00, 0x00),
/*
* VPll = Hw controlled (NOTE! PRCMU bits)
* VanaRegu = force off
*/
INIT_REGULATOR_REGISTER(AB8505_VPLLVANAREGU, 0x0f, 0x02),
/*
* VextSupply1Regu = force OFF (OTP_ExtSupply12LPnPolarity 1)
* VextSupply2Regu = force OFF (OTP_ExtSupply12LPnPolarity 1)
* VextSupply3Regu = force OFF (OTP_ExtSupply3LPnPolarity 0)
* ExtSupply2Bypass = ExtSupply12LPn ball is 0 when Ena is 0
* ExtSupply3Bypass = ExtSupply3LPn ball is 0 when Ena is 0
*/
INIT_REGULATOR_REGISTER(AB8505_EXTSUPPLYREGU, 0xff, 0x30),
/*
* Vaux1Regu = force HP
* Vaux2Regu = force off
*/
INIT_REGULATOR_REGISTER(AB8505_VAUX12REGU, 0x0f, 0x01),
/*
* Vaux3Regu = force off
*/
INIT_REGULATOR_REGISTER(AB8505_VRF1VAUX3REGU, 0x03, 0x00),
/*
* VsmpsASel1
*/
INIT_REGULATOR_REGISTER(AB8505_VSMPSASEL1, 0x00, 0x00),
/*
* VsmpsASel2
*/
INIT_REGULATOR_REGISTER(AB8505_VSMPSASEL2, 0x00, 0x00),
/*
* VsmpsASel3
*/
INIT_REGULATOR_REGISTER(AB8505_VSMPSASEL3, 0x00, 0x00),
/*
* VsmpsBSel1
*/
INIT_REGULATOR_REGISTER(AB8505_VSMPSBSEL1, 0x00, 0x00),
/*
* VsmpsBSel2
*/
INIT_REGULATOR_REGISTER(AB8505_VSMPSBSEL2, 0x00, 0x00),
/*
* VsmpsBSel3
*/
INIT_REGULATOR_REGISTER(AB8505_VSMPSBSEL3, 0x00, 0x00),
/*
* VsafeSel1
*/
INIT_REGULATOR_REGISTER(AB8505_VSAFESEL1, 0x00, 0x00),
/*
* VsafeSel2
*/
INIT_REGULATOR_REGISTER(AB8505_VSAFESEL2, 0x00, 0x00),
/*
* VsafeSel3
*/
INIT_REGULATOR_REGISTER(AB8505_VSAFESEL3, 0x00, 0x00),
/*
* Vaux1Sel = 2.8 V
*/
INIT_REGULATOR_REGISTER(AB8505_VAUX1SEL, 0x0f, 0x0C),
/*
* Vaux2Sel = 2.9 V
*/
INIT_REGULATOR_REGISTER(AB8505_VAUX2SEL, 0x0f, 0x0d),
/*
* Vaux3Sel = 2.91 V
*/
INIT_REGULATOR_REGISTER(AB8505_VRF1VAUX3SEL, 0x07, 0x07),
/*
* Vaux4RequestCtrl
*/
INIT_REGULATOR_REGISTER(AB8505_VAUX4REQCTRL, 0x00, 0x00),
/*
* Vaux4Regu
*/
INIT_REGULATOR_REGISTER(AB8505_VAUX4REGU, 0x00, 0x00),
/*
* Vaux4Sel
*/
INIT_REGULATOR_REGISTER(AB8505_VAUX4SEL, 0x00, 0x00),
/*
* Vaux1Disch = short discharge time
* Vaux2Disch = short discharge time
* Vaux3Disch = short discharge time
* Vintcore12Disch = short discharge time
* VTVoutDisch = short discharge time
* VaudioDisch = short discharge time
*/
INIT_REGULATOR_REGISTER(AB8505_REGUCTRLDISCH, 0xfc, 0x00),
/*
* VanaDisch = short discharge time
* Vaux8PullDownEna = pulldown disabled when Vaux8 is disabled
* Vaux8Disch = short discharge time
*/
INIT_REGULATOR_REGISTER(AB8505_REGUCTRLDISCH2, 0x16, 0x00),
/*
* Vaux4Disch = short discharge time
*/
INIT_REGULATOR_REGISTER(AB8505_REGUCTRLDISCH3, 0x01, 0x00),
/*
* Vaux5Sel
* Vaux5LP
* Vaux5Ena
* Vaux5Disch
* Vaux5DisSfst
* Vaux5DisPulld
*/
INIT_REGULATOR_REGISTER(AB8505_CTRLVAUX5, 0x00, 0x00),
/*
* Vaux6Sel
* Vaux6LP
* Vaux6Ena
* Vaux6DisPulld
*/
INIT_REGULATOR_REGISTER(AB8505_CTRLVAUX6, 0x00, 0x00),
};
static struct regulator_init_data ab8505_regulators[AB8505_NUM_REGULATORS] = {
/* supplies to the display/camera */
[AB8505_LDO_AUX1] = {
.constraints = {
.name = "V-DISPLAY",
.min_uV = 2800000,
.max_uV = 3300000,
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
REGULATOR_CHANGE_STATUS,
.boot_on = 1, /* display is on at boot */
},
.num_consumer_supplies = ARRAY_SIZE(ab8500_vaux1_consumers),
.consumer_supplies = ab8500_vaux1_consumers,
},
/* supplies to the on-board eMMC */
[AB8505_LDO_AUX2] = {
.constraints = {
.name = "V-eMMC1",
.min_uV = 1100000,
.max_uV = 3300000,
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
REGULATOR_CHANGE_STATUS |
REGULATOR_CHANGE_MODE,
.valid_modes_mask = REGULATOR_MODE_NORMAL |
REGULATOR_MODE_IDLE,
},
.num_consumer_supplies = ARRAY_SIZE(ab8500_vaux2_consumers),
.consumer_supplies = ab8500_vaux2_consumers,
},
/* supply for VAUX3, supplies to SDcard slots */
[AB8505_LDO_AUX3] = {
.constraints = {
.name = "V-MMC-SD",
.min_uV = 1100000,
.max_uV = 3300000,
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
REGULATOR_CHANGE_STATUS |
REGULATOR_CHANGE_MODE,
.valid_modes_mask = REGULATOR_MODE_NORMAL |
REGULATOR_MODE_IDLE,
},
.num_consumer_supplies = ARRAY_SIZE(ab8500_vaux3_consumers),
.consumer_supplies = ab8500_vaux3_consumers,
},
/* supply for VAUX4, supplies to NFC and standalone secure element */
[AB8505_LDO_AUX4] = {
.constraints = {
.name = "V-NFC-SE",
.min_uV = 1100000,
.max_uV = 3300000,
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
REGULATOR_CHANGE_STATUS |
REGULATOR_CHANGE_MODE,
.valid_modes_mask = REGULATOR_MODE_NORMAL |
REGULATOR_MODE_IDLE,
},
.num_consumer_supplies = ARRAY_SIZE(ab8505_vaux4_consumers),
.consumer_supplies = ab8505_vaux4_consumers,
},
/* supply for VAUX5, supplies to TBD */
[AB8505_LDO_AUX5] = {
.constraints = {
.name = "V-AUX5",
.min_uV = 1050000,
.max_uV = 2790000,
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
REGULATOR_CHANGE_STATUS |
REGULATOR_CHANGE_MODE,
.valid_modes_mask = REGULATOR_MODE_NORMAL |
REGULATOR_MODE_IDLE,
},
.num_consumer_supplies = ARRAY_SIZE(ab8505_vaux5_consumers),
.consumer_supplies = ab8505_vaux5_consumers,
},
/* supply for VAUX6, supplies to TBD */
[AB8505_LDO_AUX6] = {
.constraints = {
.name = "V-AUX6",
.min_uV = 1050000,
.max_uV = 2790000,
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
REGULATOR_CHANGE_STATUS |
REGULATOR_CHANGE_MODE,
.valid_modes_mask = REGULATOR_MODE_NORMAL |
REGULATOR_MODE_IDLE,
},
.num_consumer_supplies = ARRAY_SIZE(ab8505_vaux6_consumers),
.consumer_supplies = ab8505_vaux6_consumers,
},
/* supply for gpadc, ADC LDO */
[AB8505_LDO_ADC] = {
.constraints = {
.name = "V-ADC",
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = ARRAY_SIZE(ab8505_vadc_consumers),
.consumer_supplies = ab8505_vadc_consumers,
},
/* supply for ab8500-vaudio, VAUDIO LDO */
[AB8505_LDO_AUDIO] = {
.constraints = {
.name = "V-AUD",
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = ARRAY_SIZE(ab8500_vaud_consumers),
.consumer_supplies = ab8500_vaud_consumers,
},
/* supply for v-anamic1 VAMic1-LDO */
[AB8505_LDO_ANAMIC1] = {
.constraints = {
.name = "V-AMIC1",
.valid_ops_mask = REGULATOR_CHANGE_STATUS |
REGULATOR_CHANGE_MODE,
.valid_modes_mask = REGULATOR_MODE_NORMAL |
REGULATOR_MODE_IDLE,
},
.num_consumer_supplies = ARRAY_SIZE(ab8500_vamic1_consumers),
.consumer_supplies = ab8500_vamic1_consumers,
},
/* supply for v-amic2, VAMIC2 LDO, reuse constants for AMIC1 */
[AB8505_LDO_ANAMIC2] = {
.constraints = {
.name = "V-AMIC2",
.valid_ops_mask = REGULATOR_CHANGE_STATUS |
REGULATOR_CHANGE_MODE,
.valid_modes_mask = REGULATOR_MODE_NORMAL |
REGULATOR_MODE_IDLE,
},
.num_consumer_supplies = ARRAY_SIZE(ab8500_vamic2_consumers),
.consumer_supplies = ab8500_vamic2_consumers,
},
/* supply for v-aux8, VAUX8 LDO */
[AB8505_LDO_AUX8] = {
.constraints = {
.name = "V-AUX8",
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = ARRAY_SIZE(ab8505_vaux8_consumers),
.consumer_supplies = ab8505_vaux8_consumers,
},
/* supply for v-intcore12, VINTCORE12 LDO */
[AB8505_LDO_INTCORE] = {
.constraints = {
.name = "V-INTCORE",
.min_uV = 1250000,
.max_uV = 1350000,
.input_uV = 1800000,
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
REGULATOR_CHANGE_STATUS |
REGULATOR_CHANGE_MODE |
REGULATOR_CHANGE_DRMS,
.valid_modes_mask = REGULATOR_MODE_NORMAL |
REGULATOR_MODE_IDLE,
},
.num_consumer_supplies = ARRAY_SIZE(ab8500_vintcore_consumers),
.consumer_supplies = ab8500_vintcore_consumers,
},
/* supply for LDO USB */
[AB8505_LDO_USB] = {
.constraints = {
.name = "V-USB",
.valid_ops_mask = REGULATOR_CHANGE_STATUS |
REGULATOR_CHANGE_MODE,
.valid_modes_mask = REGULATOR_MODE_NORMAL |
REGULATOR_MODE_IDLE,
},
.num_consumer_supplies = ARRAY_SIZE(ab8505_usb_consumers),
.consumer_supplies = ab8505_usb_consumers,
},
/* supply for U8500 CSI-DSI, VANA LDO */
[AB8505_LDO_ANA] = {
.constraints = {
.name = "V-CSI-DSI",
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = ARRAY_SIZE(ab8500_vana_consumers),
.consumer_supplies = ab8500_vana_consumers,
},
};
struct ab8500_regulator_platform_data ab8500_regulator_plat_data = {
.reg_init = ab8500_reg_init,
.num_reg_init = ARRAY_SIZE(ab8500_reg_init),
.regulator = ab8500_regulators,
.num_regulator = ARRAY_SIZE(ab8500_regulators),
.ext_regulator = ab8500_ext_regulators,
.num_ext_regulator = ARRAY_SIZE(ab8500_ext_regulators),
};
struct ab8500_regulator_platform_data ab8505_regulator_plat_data = {
.reg_init = ab8505_reg_init,
.num_reg_init = ARRAY_SIZE(ab8505_reg_init),
.regulator = ab8505_regulators,
.num_regulator = ARRAY_SIZE(ab8505_regulators),
};
static void ab8500_modify_reg_init(int id, u8 mask, u8 value)
{
int i;
if (cpu_is_u8520()) {
for (i = ARRAY_SIZE(ab8505_reg_init) - 1; i >= 0; i--) {
if (ab8505_reg_init[i].id == id) {
u8 initval = ab8505_reg_init[i].value;
initval = (initval & ~mask) | (value & mask);
ab8505_reg_init[i].value = initval;
BUG_ON(mask & ~ab8505_reg_init[i].mask);
return;
}
}
} else {
for (i = ARRAY_SIZE(ab8500_reg_init) - 1; i >= 0; i--) {
if (ab8500_reg_init[i].id == id) {
u8 initval = ab8500_reg_init[i].value;
initval = (initval & ~mask) | (value & mask);
ab8500_reg_init[i].value = initval;
BUG_ON(mask & ~ab8500_reg_init[i].mask);
return;
}
}
}
BUG_ON(1);
}
void mop500_regulator_init(void)
{
struct regulator_init_data *regulator;
/*
* Temporarily turn on Vaux2 on 8520 machine
*/
if (cpu_is_u8520()) {
/* Vaux2 initialized to be on */
ab8500_modify_reg_init(AB8505_VAUX12REGU, 0x0f, 0x05);
}
/*
* Handle AB8500_EXT_SUPPLY2 on HREFP_V20_V50 boards (do it for
* all HREFP_V20 boards)
*/
if (cpu_is_u8500v20()) {
/* VextSupply2RequestCtrl = HP/OFF depending on VxRequest */
ab8500_modify_reg_init(AB8500_REGUREQUESTCTRL3, 0x01, 0x01);
/* VextSupply2SysClkReq1HPValid = SysClkReq1 controlled */
ab8500_modify_reg_init(AB8500_REGUSYSCLKREQ1HPVALID2,
0x20, 0x20);
/* VextSupply2 = force HP at initialization */
ab8500_modify_reg_init(AB8500_EXTSUPPLYREGU, 0x0c, 0x04);
/* enable VextSupply2 during platform active */
regulator = &ab8500_ext_regulators[AB8500_EXT_SUPPLY2];
regulator->constraints.always_on = 1;
/* disable VextSupply2 in suspend */
regulator = &ab8500_ext_regulators[AB8500_EXT_SUPPLY2];
regulator->constraints.state_mem.disabled = 1;
regulator->constraints.state_standby.disabled = 1;
/* enable VextSupply2 HW control (used in suspend) */
regulator->driver_data = (void *)&ab8500_ext_supply2;
}
}
/*
* Copyright (C) ST-Ericsson SA 2010
*
* License Terms: GNU General Public License v2
*
* Author: Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson
*
* MOP500 board specific initialization for regulators
*/
#ifndef __BOARD_MOP500_REGULATORS_H
#define __BOARD_MOP500_REGULATORS_H
#include <linux/regulator/machine.h>
#include <linux/regulator/ab8500.h>
extern struct ab8500_regulator_platform_data ab8500_regulator_plat_data;
extern struct ab8500_regulator_platform_data ab8505_regulator_plat_data;
extern struct regulator_init_data tps61052_regulator;
extern struct regulator_init_data gpio_en_3v3_regulator;
void mop500_regulator_init(void);
#endif
/*
* Copyright (C) ST-Ericsson SA 2011
*
* License terms: GNU General Public License (GPL) version 2
*/
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <asm/outercache.h>
#include <asm/hardware/cache-l2x0.h>
#include "db8500-regs.h"
#include "id.h"
static int __init ux500_l2x0_unlock(void)
{
int i;
struct device_node *np;
void __iomem *l2x0_base;
np = of_find_compatible_node(NULL, NULL, "arm,pl310-cache");
l2x0_base = of_iomap(np, 0);
of_node_put(np);
if (!l2x0_base)
return -ENODEV;
/*
* Unlock Data and Instruction Lock if locked. Ux500 U-Boot versions
* apparently locks both caches before jumping to the kernel. The
* l2x0 core will not touch the unlock registers if the l2x0 is
* already enabled, so we do it right here instead. The PL310 has
* 8 sets of registers, one per possible CPU.
*/
for (i = 0; i < 8; i++) {
writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_D_BASE +
i * L2X0_LOCKDOWN_STRIDE);
writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_I_BASE +
i * L2X0_LOCKDOWN_STRIDE);
}
iounmap(l2x0_base);
return 0;
}
static void ux500_l2c310_write_sec(unsigned long val, unsigned reg)
{
/*
* We can't write to secure registers as we are in non-secure
* mode, until we have some SMI service available.
*/
}
static int __init ux500_l2x0_init(void)
{
/* Multiplatform guard */
if (!((cpu_is_u8500_family() || cpu_is_ux540_family())))
return -ENODEV;
/* Unlock before init */
ux500_l2x0_unlock();
outer_cache.write_sec = ux500_l2c310_write_sec;
l2x0_of_init(0, ~0);
return 0;
}
early_initcall(ux500_l2x0_init);
...@@ -12,41 +12,107 @@ ...@@ -12,41 +12,107 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/amba/bus.h> #include <linux/amba/bus.h>
#include <linux/init.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/irqchip.h>
#include <linux/irqchip/arm-gic.h>
#include <linux/mfd/dbx500-prcmu.h>
#include <linux/platform_data/arm-ux500-pm.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/mfd/abx500/ab8500.h>
#include <linux/mfd/dbx500-prcmu.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/perf/arm_pmu.h> #include <linux/perf/arm_pmu.h>
#include <linux/regulator/machine.h> #include <linux/regulator/machine.h>
#include <linux/random.h>
#include <asm/outercache.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/mach/map.h> #include <asm/mach/map.h>
#include <asm/mach/arch.h>
#include "setup.h" #include "setup.h"
#include "board-mop500-regulators.h"
#include "board-mop500.h" #include "board-mop500.h"
#include "db8500-regs.h" #include "db8500-regs.h"
#include "id.h"
static struct ab8500_platform_data ab8500_platdata = { static int __init ux500_l2x0_unlock(void)
.regulator = &ab8500_regulator_plat_data, {
}; int i;
struct device_node *np;
void __iomem *l2x0_base;
static struct prcmu_pdata db8500_prcmu_pdata = { np = of_find_compatible_node(NULL, NULL, "arm,pl310-cache");
.ab_platdata = &ab8500_platdata, l2x0_base = of_iomap(np, 0);
.version_offset = DB8500_PRCMU_FW_VERSION_OFFSET, of_node_put(np);
.legacy_offset = DB8500_PRCMU_LEGACY_OFFSET, if (!l2x0_base)
}; return -ENODEV;
/*
* Unlock Data and Instruction Lock if locked. Ux500 U-Boot versions
* apparently locks both caches before jumping to the kernel. The
* l2x0 core will not touch the unlock registers if the l2x0 is
* already enabled, so we do it right here instead. The PL310 has
* 8 sets of registers, one per possible CPU.
*/
for (i = 0; i < 8; i++) {
writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_D_BASE +
i * L2X0_LOCKDOWN_STRIDE);
writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_I_BASE +
i * L2X0_LOCKDOWN_STRIDE);
}
iounmap(l2x0_base);
return 0;
}
static void ux500_l2c310_write_sec(unsigned long val, unsigned reg)
{
/*
* We can't write to secure registers as we are in non-secure
* mode, until we have some SMI service available.
*/
}
static void __init u8500_map_io(void) /*
* FIXME: Should we set up the GPIO domain here?
*
* The problem is that we cannot put the interrupt resources into the platform
* device until the irqdomain has been added. Right now, we set the GIC interrupt
* domain from init_irq(), then load the gpio driver from
* core_initcall(nmk_gpio_init) and add the platform devices from
* arch_initcall(customize_machine).
*
* This feels fragile because it depends on the gpio device getting probed
* _before_ any device uses the gpio interrupts.
*/
static void __init ux500_init_irq(void)
{
struct device_node *np;
struct resource r;
irqchip_init();
np = of_find_compatible_node(NULL, NULL, "stericsson,db8500-prcmu");
of_address_to_resource(np, 0, &r);
of_node_put(np);
if (!r.start) {
pr_err("could not find PRCMU base resource\n");
return;
}
prcmu_early_init(r.start, r.end-r.start);
ux500_pm_init(r.start, r.end-r.start);
/* Unlock before init */
ux500_l2x0_unlock();
outer_cache.write_sec = ux500_l2c310_write_sec;
}
static void ux500_restart(enum reboot_mode mode, const char *cmd)
{ {
debug_ll_io_init(); local_irq_disable();
ux500_setup_id(); local_fiq_disable();
prcmu_system_reset(0);
} }
/* /*
...@@ -73,31 +139,6 @@ static struct arm_pmu_platdata db8500_pmu_platdata = { ...@@ -73,31 +139,6 @@ static struct arm_pmu_platdata db8500_pmu_platdata = {
.handle_irq = db8500_pmu_handler, .handle_irq = db8500_pmu_handler,
}; };
static const char *db8500_read_soc_id(void)
{
void __iomem *uid;
const char *retstr;
uid = ioremap(U8500_BB_UID_BASE, 0x20);
if (!uid)
return NULL;
/* Throw these device-specific numbers into the entropy pool */
add_device_randomness(uid, 0x14);
retstr = kasprintf(GFP_KERNEL, "%08x%08x%08x%08x%08x",
readl((u32 *)uid+0),
readl((u32 *)uid+1), readl((u32 *)uid+2),
readl((u32 *)uid+3), readl((u32 *)uid+4));
iounmap(uid);
return retstr;
}
static struct device * __init db8500_soc_device_init(void)
{
const char *soc_id = db8500_read_soc_id();
return ux500_soc_device_init(soc_id);
}
static struct of_dev_auxdata u8500_auxdata_lookup[] __initdata = { static struct of_dev_auxdata u8500_auxdata_lookup[] __initdata = {
/* Requires call-back bindings. */ /* Requires call-back bindings. */
OF_DEV_AUXDATA("arm,cortex-a9-pmu", 0, "arm-pmu", &db8500_pmu_platdata), OF_DEV_AUXDATA("arm,cortex-a9-pmu", 0, "arm-pmu", &db8500_pmu_platdata),
...@@ -111,8 +152,7 @@ static struct of_dev_auxdata u8500_auxdata_lookup[] __initdata = { ...@@ -111,8 +152,7 @@ static struct of_dev_auxdata u8500_auxdata_lookup[] __initdata = {
OF_DEV_AUXDATA("stericsson,ux500-msp-i2s", 0x80125000, OF_DEV_AUXDATA("stericsson,ux500-msp-i2s", 0x80125000,
"ux500-msp-i2s.3", &msp3_platform_data), "ux500-msp-i2s.3", &msp3_platform_data),
/* Requires non-DT:able platform data. */ /* Requires non-DT:able platform data. */
OF_DEV_AUXDATA("stericsson,db8500-prcmu", 0x80157000, "db8500-prcmu", OF_DEV_AUXDATA("stericsson,db8500-prcmu", 0x80157000, "db8500-prcmu", NULL),
&db8500_prcmu_pdata),
OF_DEV_AUXDATA("stericsson,ux500-cryp", 0xa03cb000, "cryp1", NULL), OF_DEV_AUXDATA("stericsson,ux500-cryp", 0xa03cb000, "cryp1", NULL),
OF_DEV_AUXDATA("stericsson,ux500-hash", 0xa03c2000, "hash1", NULL), OF_DEV_AUXDATA("stericsson,ux500-hash", 0xa03c2000, "hash1", NULL),
OF_DEV_AUXDATA("stericsson,snd-soc-mop500", 0, "snd-soc-mop500.0", OF_DEV_AUXDATA("stericsson,snd-soc-mop500", 0, "snd-soc-mop500.0",
...@@ -121,8 +161,7 @@ static struct of_dev_auxdata u8500_auxdata_lookup[] __initdata = { ...@@ -121,8 +161,7 @@ static struct of_dev_auxdata u8500_auxdata_lookup[] __initdata = {
}; };
static struct of_dev_auxdata u8540_auxdata_lookup[] __initdata = { static struct of_dev_auxdata u8540_auxdata_lookup[] __initdata = {
OF_DEV_AUXDATA("stericsson,db8500-prcmu", 0x80157000, "db8500-prcmu", OF_DEV_AUXDATA("stericsson,db8500-prcmu", 0x80157000, "db8500-prcmu", NULL),
&db8500_prcmu_pdata),
{}, {},
}; };
...@@ -136,15 +175,13 @@ static const struct of_device_id u8500_local_bus_nodes[] = { ...@@ -136,15 +175,13 @@ static const struct of_device_id u8500_local_bus_nodes[] = {
static void __init u8500_init_machine(void) static void __init u8500_init_machine(void)
{ {
struct device *parent = db8500_soc_device_init();
/* automatically probe child nodes of dbx5x0 devices */ /* automatically probe child nodes of dbx5x0 devices */
if (of_machine_is_compatible("st-ericsson,u8540")) if (of_machine_is_compatible("st-ericsson,u8540"))
of_platform_populate(NULL, u8500_local_bus_nodes, of_platform_populate(NULL, u8500_local_bus_nodes,
u8540_auxdata_lookup, parent); u8540_auxdata_lookup, NULL);
else else
of_platform_populate(NULL, u8500_local_bus_nodes, of_platform_populate(NULL, u8500_local_bus_nodes,
u8500_auxdata_lookup, parent); u8500_auxdata_lookup, NULL);
} }
static const char * stericsson_dt_platform_compat[] = { static const char * stericsson_dt_platform_compat[] = {
...@@ -156,10 +193,10 @@ static const char * stericsson_dt_platform_compat[] = { ...@@ -156,10 +193,10 @@ static const char * stericsson_dt_platform_compat[] = {
}; };
DT_MACHINE_START(U8500_DT, "ST-Ericsson Ux5x0 platform (Device Tree Support)") DT_MACHINE_START(U8500_DT, "ST-Ericsson Ux5x0 platform (Device Tree Support)")
.map_io = u8500_map_io, .l2c_aux_val = 0,
.l2c_aux_mask = ~0,
.init_irq = ux500_init_irq, .init_irq = ux500_init_irq,
.init_machine = u8500_init_machine, .init_machine = u8500_init_machine,
.init_late = NULL,
.dt_compat = stericsson_dt_platform_compat, .dt_compat = stericsson_dt_platform_compat,
.restart = ux500_restart, .restart = ux500_restart,
MACHINE_END MACHINE_END
/*
* Copyright (C) ST-Ericsson SA 2010
*
* Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
* Author: Lee Jones <lee.jones@linaro.org> for ST-Ericsson
* License terms: GNU General Public License (GPL) version 2
*/
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/mfd/dbx500-prcmu.h>
#include <linux/sys_soc.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/stat.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/irq.h>
#include <linux/irqchip.h>
#include <linux/irqchip/arm-gic.h>
#include <linux/platform_data/clk-ux500.h>
#include <linux/platform_data/arm-ux500-pm.h>
#include <asm/mach/map.h>
#include "setup.h"
#include "board-mop500.h"
#include "db8500-regs.h"
#include "id.h"
void ux500_restart(enum reboot_mode mode, const char *cmd)
{
local_irq_disable();
local_fiq_disable();
prcmu_system_reset(0);
}
/*
* FIXME: Should we set up the GPIO domain here?
*
* The problem is that we cannot put the interrupt resources into the platform
* device until the irqdomain has been added. Right now, we set the GIC interrupt
* domain from init_irq(), then load the gpio driver from
* core_initcall(nmk_gpio_init) and add the platform devices from
* arch_initcall(customize_machine).
*
* This feels fragile because it depends on the gpio device getting probed
* _before_ any device uses the gpio interrupts.
*/
void __init ux500_init_irq(void)
{
struct device_node *np;
struct resource r;
irqchip_init();
np = of_find_compatible_node(NULL, NULL, "stericsson,db8500-prcmu");
of_address_to_resource(np, 0, &r);
of_node_put(np);
if (!r.start) {
pr_err("could not find PRCMU base resource\n");
return;
}
prcmu_early_init(r.start, r.end-r.start);
ux500_pm_init(r.start, r.end-r.start);
/*
* Init clocks here so that they are available for system timer
* initialization.
*/
if (cpu_is_u8500_family())
u8500_clk_init();
else if (cpu_is_u9540())
u9540_clk_init();
else if (cpu_is_u8540())
u8540_clk_init();
}
static const char * __init ux500_get_machine(void)
{
return kasprintf(GFP_KERNEL, "DB%4x", dbx500_partnumber());
}
static const char * __init ux500_get_family(void)
{
return kasprintf(GFP_KERNEL, "ux500");
}
static const char * __init ux500_get_revision(void)
{
unsigned int rev = dbx500_revision();
if (rev == 0x01)
return kasprintf(GFP_KERNEL, "%s", "ED");
else if (rev >= 0xA0)
return kasprintf(GFP_KERNEL, "%d.%d",
(rev >> 4) - 0xA + 1, rev & 0xf);
return kasprintf(GFP_KERNEL, "%s", "Unknown");
}
static ssize_t ux500_get_process(struct device *dev,
struct device_attribute *attr,
char *buf)
{
if (dbx500_id.process == 0x00)
return sprintf(buf, "Standard\n");
return sprintf(buf, "%02xnm\n", dbx500_id.process);
}
static void __init soc_info_populate(struct soc_device_attribute *soc_dev_attr,
const char *soc_id)
{
soc_dev_attr->soc_id = soc_id;
soc_dev_attr->machine = ux500_get_machine();
soc_dev_attr->family = ux500_get_family();
soc_dev_attr->revision = ux500_get_revision();
}
static const struct device_attribute ux500_soc_attr =
__ATTR(process, S_IRUGO, ux500_get_process, NULL);
struct device * __init ux500_soc_device_init(const char *soc_id)
{
struct device *parent;
struct soc_device *soc_dev;
struct soc_device_attribute *soc_dev_attr;
soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
if (!soc_dev_attr)
return ERR_PTR(-ENOMEM);
soc_info_populate(soc_dev_attr, soc_id);
soc_dev = soc_device_register(soc_dev_attr);
if (IS_ERR(soc_dev)) {
kfree(soc_dev_attr);
return NULL;
}
parent = soc_device_to_device(soc_dev);
device_create_file(parent, &ux500_soc_attr);
return parent;
}
/*
* Copyright (C) ST-Ericsson SA 2010
*
* Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
* License terms: GNU General Public License (GPL) version 2
*/
#ifndef __MACH_UX500_ID
#define __MACH_UX500_ID
/**
* struct dbx500_asic_id - fields of the ASIC ID
* @process: the manufacturing process, 0x40 is 40 nm 0x00 is "standard"
* @partnumber: hithereto 0x8500 for DB8500
* @revision: version code in the series
*/
struct dbx500_asic_id {
u16 partnumber;
u8 revision;
u8 process;
};
extern struct dbx500_asic_id dbx500_id;
static inline unsigned int __attribute_const__ dbx500_partnumber(void)
{
return dbx500_id.partnumber;
}
static inline unsigned int __attribute_const__ dbx500_revision(void)
{
return dbx500_id.revision;
}
/*
* SOCs
*/
static inline bool __attribute_const__ cpu_is_u8500(void)
{
return dbx500_partnumber() == 0x8500;
}
static inline bool __attribute_const__ cpu_is_u8520(void)
{
return dbx500_partnumber() == 0x8520;
}
static inline bool cpu_is_u8500_family(void)
{
return cpu_is_u8500() || cpu_is_u8520();
}
static inline bool __attribute_const__ cpu_is_u9540(void)
{
return dbx500_partnumber() == 0x9540;
}
static inline bool __attribute_const__ cpu_is_u8540(void)
{
return dbx500_partnumber() == 0x8540;
}
static inline bool __attribute_const__ cpu_is_u8580(void)
{
return dbx500_partnumber() == 0x8580;
}
static inline bool cpu_is_ux540_family(void)
{
return cpu_is_u9540() || cpu_is_u8540() || cpu_is_u8580();
}
/*
* 8500 revisions
*/
static inline bool __attribute_const__ cpu_is_u8500ed(void)
{
return cpu_is_u8500() && dbx500_revision() == 0x00;
}
static inline bool __attribute_const__ cpu_is_u8500v1(void)
{
return cpu_is_u8500() && (dbx500_revision() & 0xf0) == 0xA0;
}
static inline bool __attribute_const__ cpu_is_u8500v10(void)
{
return cpu_is_u8500() && dbx500_revision() == 0xA0;
}
static inline bool __attribute_const__ cpu_is_u8500v11(void)
{
return cpu_is_u8500() && dbx500_revision() == 0xA1;
}
static inline bool __attribute_const__ cpu_is_u8500v2(void)
{
return cpu_is_u8500() && ((dbx500_revision() & 0xf0) == 0xB0);
}
static inline bool cpu_is_u8500v20(void)
{
return cpu_is_u8500() && (dbx500_revision() == 0xB0);
}
static inline bool cpu_is_u8500v21(void)
{
return cpu_is_u8500() && (dbx500_revision() == 0xB1);
}
static inline bool cpu_is_u8500v22(void)
{
return cpu_is_u8500() && (dbx500_revision() == 0xB2);
}
static inline bool cpu_is_u8500v20_or_later(void)
{
return (cpu_is_u8500() && !cpu_is_u8500v10() && !cpu_is_u8500v11());
}
/*
* 8540 revisions
*/
static inline bool __attribute_const__ cpu_is_u8540v10(void)
{
return cpu_is_u8540() && dbx500_revision() == 0xA0;
}
static inline bool __attribute_const__ cpu_is_u8580v10(void)
{
return cpu_is_u8580() && dbx500_revision() == 0xA0;
}
static inline bool ux500_is_svp(void)
{
return false;
}
#define ux500_unknown_soc() BUG()
#endif
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
#include "setup.h" #include "setup.h"
#include "db8500-regs.h" #include "db8500-regs.h"
#include "id.h"
/* Magic triggers in backup RAM */ /* Magic triggers in backup RAM */
#define UX500_CPU1_JUMPADDR_OFFSET 0x1FF4 #define UX500_CPU1_JUMPADDR_OFFSET 0x1FF4
......
...@@ -11,18 +11,6 @@ ...@@ -11,18 +11,6 @@
#ifndef __ASM_ARCH_SETUP_H #ifndef __ASM_ARCH_SETUP_H
#define __ASM_ARCH_SETUP_H #define __ASM_ARCH_SETUP_H
#include <asm/mach/arch.h>
#include <linux/init.h>
#include <linux/mfd/abx500/ab8500.h>
void ux500_restart(enum reboot_mode mode, const char *cmd);
void __init ux500_setup_id(void);
extern void __init ux500_init_irq(void);
extern struct device *ux500_soc_device_init(const char *soc_id);
extern void ux500_cpu_die(unsigned int cpu); extern void ux500_cpu_die(unsigned int cpu);
#endif /* __ASM_ARCH_SETUP_H */ #endif /* __ASM_ARCH_SETUP_H */
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
*/ */
#include <dt-bindings/interrupt-controller/arm-gic.h> #include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/reset/hisi,hi6220-resets.h>
#include <dt-bindings/clock/hi6220-clock.h> #include <dt-bindings/clock/hi6220-clock.h>
#include <dt-bindings/pinctrl/hisi.h> #include <dt-bindings/pinctrl/hisi.h>
#include <dt-bindings/thermal/thermal.h> #include <dt-bindings/thermal/thermal.h>
...@@ -252,6 +253,7 @@ ...@@ -252,6 +253,7 @@
compatible = "hisilicon,hi6220-mediactrl", "syscon"; compatible = "hisilicon,hi6220-mediactrl", "syscon";
reg = <0x0 0xf4410000 0x0 0x1000>; reg = <0x0 0xf4410000 0x0 0x1000>;
#clock-cells = <1>; #clock-cells = <1>;
#reset-cells = <1>;
}; };
pm_ctrl: pm_ctrl@f7032000 { pm_ctrl: pm_ctrl@f7032000 {
......
...@@ -132,6 +132,19 @@ config SUNXI_RSB ...@@ -132,6 +132,19 @@ config SUNXI_RSB
with various RSB based devices, such as AXP223, AXP8XX PMICs, with various RSB based devices, such as AXP223, AXP8XX PMICs,
and AC100/AC200 ICs. and AC100/AC200 ICs.
# TODO: This uses pm_clk_*() symbols that aren't exported in v4.7 and hence
# the driver will fail to build as a module. However there are patches to
# address that queued for v4.8, so this can be turned into a tristate symbol
# after v4.8-rc1.
config TEGRA_ACONNECT
bool "Tegra ACONNECT Bus Driver"
depends on ARCH_TEGRA_210_SOC
depends on OF && PM
select PM_CLK
help
Driver for the Tegra ACONNECT bus which is used to interface with
the devices inside the Audio Processing Engine (APE) for Tegra210.
config UNIPHIER_SYSTEM_BUS config UNIPHIER_SYSTEM_BUS
tristate "UniPhier System Bus driver" tristate "UniPhier System Bus driver"
depends on ARCH_UNIPHIER && OF depends on ARCH_UNIPHIER && OF
......
...@@ -17,5 +17,6 @@ obj-$(CONFIG_OMAP_INTERCONNECT) += omap_l3_smx.o omap_l3_noc.o ...@@ -17,5 +17,6 @@ obj-$(CONFIG_OMAP_INTERCONNECT) += omap_l3_smx.o omap_l3_noc.o
obj-$(CONFIG_OMAP_OCP2SCP) += omap-ocp2scp.o obj-$(CONFIG_OMAP_OCP2SCP) += omap-ocp2scp.o
obj-$(CONFIG_SUNXI_RSB) += sunxi-rsb.o obj-$(CONFIG_SUNXI_RSB) += sunxi-rsb.o
obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o
obj-$(CONFIG_TEGRA_ACONNECT) += tegra-aconnect.o
obj-$(CONFIG_UNIPHIER_SYSTEM_BUS) += uniphier-system-bus.o obj-$(CONFIG_UNIPHIER_SYSTEM_BUS) += uniphier-system-bus.o
obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o
/*
* Tegra ACONNECT Bus Driver
*
* Copyright (C) 2016, NVIDIA CORPORATION. All rights reserved.
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm_clock.h>
#include <linux/pm_runtime.h>
static int tegra_aconnect_add_clock(struct device *dev, char *name)
{
struct clk *clk;
int ret;
clk = clk_get(dev, name);
if (IS_ERR(clk)) {
dev_err(dev, "%s clock not found\n", name);
return PTR_ERR(clk);
}
ret = pm_clk_add_clk(dev, clk);
if (ret)
clk_put(clk);
return ret;
}
static int tegra_aconnect_probe(struct platform_device *pdev)
{
int ret;
if (!pdev->dev.of_node)
return -EINVAL;
ret = pm_clk_create(&pdev->dev);
if (ret)
return ret;
ret = tegra_aconnect_add_clock(&pdev->dev, "ape");
if (ret)
goto clk_destroy;
ret = tegra_aconnect_add_clock(&pdev->dev, "apb2ape");
if (ret)
goto clk_destroy;
pm_runtime_enable(&pdev->dev);
of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
dev_info(&pdev->dev, "Tegra ACONNECT bus registered\n");
return 0;
clk_destroy:
pm_clk_destroy(&pdev->dev);
return ret;
}
static int tegra_aconnect_remove(struct platform_device *pdev)
{
pm_runtime_disable(&pdev->dev);
pm_clk_destroy(&pdev->dev);
return 0;
}
static int tegra_aconnect_runtime_resume(struct device *dev)
{
return pm_clk_resume(dev);
}
static int tegra_aconnect_runtime_suspend(struct device *dev)
{
return pm_clk_suspend(dev);
}
static const struct dev_pm_ops tegra_aconnect_pm_ops = {
SET_RUNTIME_PM_OPS(tegra_aconnect_runtime_suspend,
tegra_aconnect_runtime_resume, NULL)
};
static const struct of_device_id tegra_aconnect_of_match[] = {
{ .compatible = "nvidia,tegra210-aconnect", },
{ }
};
MODULE_DEVICE_TABLE(of, tegra_aconnect_of_match);
static struct platform_driver tegra_aconnect_driver = {
.probe = tegra_aconnect_probe,
.remove = tegra_aconnect_remove,
.driver = {
.name = "tegra-aconnect",
.of_match_table = tegra_aconnect_of_match,
.pm = &tegra_aconnect_pm_ops,
},
};
module_platform_driver(tegra_aconnect_driver);
MODULE_DESCRIPTION("NVIDIA Tegra ACONNECT Bus Driver");
MODULE_AUTHOR("Jon Hunter <jonathanh@nvidia.com>");
MODULE_LICENSE("GPL v2");
...@@ -184,5 +184,5 @@ static void __init clps711x_clk_init_dt(struct device_node *np) ...@@ -184,5 +184,5 @@ static void __init clps711x_clk_init_dt(struct device_node *np)
of_clk_add_provider(np, of_clk_src_onecell_get, of_clk_add_provider(np, of_clk_src_onecell_get,
&clps711x_clk->clk_data); &clps711x_clk->clk_data);
} }
CLK_OF_DECLARE(clps711x, "cirrus,clps711x-clk", clps711x_clk_init_dt); CLK_OF_DECLARE(clps711x, "cirrus,ep7209-clk", clps711x_clk_init_dt);
#endif #endif
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/mfd/dbx500-prcmu.h> #include <linux/mfd/dbx500-prcmu.h>
#include <linux/platform_data/clk-ux500.h>
#include "clk.h" #include "clk.h"
#define PRCC_NUM_PERIPH_CLUSTERS 6 #define PRCC_NUM_PERIPH_CLUSTERS 6
...@@ -48,11 +47,6 @@ static struct clk *ux500_twocell_get(struct of_phandle_args *clkspec, ...@@ -48,11 +47,6 @@ static struct clk *ux500_twocell_get(struct of_phandle_args *clkspec,
return PRCC_SHOW(clk_data, base, bit); return PRCC_SHOW(clk_data, base, bit);
} }
static const struct of_device_id u8500_clk_of_match[] = {
{ .compatible = "stericsson,u8500-clks", },
{ },
};
/* CLKRST4 is missing making it hard to index things */ /* CLKRST4 is missing making it hard to index things */
enum clkrst_index { enum clkrst_index {
CLKRST1_INDEX = 0, CLKRST1_INDEX = 0,
...@@ -63,22 +57,15 @@ enum clkrst_index { ...@@ -63,22 +57,15 @@ enum clkrst_index {
CLKRST_MAX, CLKRST_MAX,
}; };
void u8500_clk_init(void) static void u8500_clk_init(struct device_node *np)
{ {
struct prcmu_fw_version *fw_version; struct prcmu_fw_version *fw_version;
struct device_node *np = NULL;
struct device_node *child = NULL; struct device_node *child = NULL;
const char *sgaclk_parent = NULL; const char *sgaclk_parent = NULL;
struct clk *clk, *rtc_clk, *twd_clk; struct clk *clk, *rtc_clk, *twd_clk;
u32 bases[CLKRST_MAX]; u32 bases[CLKRST_MAX];
int i; int i;
if (of_have_populated_dt())
np = of_find_matching_node(NULL, u8500_clk_of_match);
if (!np) {
pr_err("Either DT or U8500 Clock node not found\n");
return;
}
for (i = 0; i < ARRAY_SIZE(bases); i++) { for (i = 0; i < ARRAY_SIZE(bases); i++) {
struct resource r; struct resource r;
...@@ -573,3 +560,4 @@ void u8500_clk_init(void) ...@@ -573,3 +560,4 @@ void u8500_clk_init(void)
of_clk_add_provider(child, of_clk_src_simple_get, twd_clk); of_clk_add_provider(child, of_clk_src_simple_get, twd_clk);
} }
} }
CLK_OF_DECLARE(u8500_clks, "stericsson,u8500-clks", u8500_clk_init);
...@@ -12,14 +12,8 @@ ...@@ -12,14 +12,8 @@
#include <linux/clkdev.h> #include <linux/clkdev.h>
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/mfd/dbx500-prcmu.h> #include <linux/mfd/dbx500-prcmu.h>
#include <linux/platform_data/clk-ux500.h>
#include "clk.h" #include "clk.h"
static const struct of_device_id u8540_clk_of_match[] = {
{ .compatible = "stericsson,u8540-clks", },
{ }
};
/* CLKRST4 is missing making it hard to index things */ /* CLKRST4 is missing making it hard to index things */
enum clkrst_index { enum clkrst_index {
CLKRST1_INDEX = 0, CLKRST1_INDEX = 0,
...@@ -30,19 +24,12 @@ enum clkrst_index { ...@@ -30,19 +24,12 @@ enum clkrst_index {
CLKRST_MAX, CLKRST_MAX,
}; };
void u8540_clk_init(void) static void u8540_clk_init(struct device_node *np)
{ {
struct clk *clk; struct clk *clk;
struct device_node *np = NULL;
u32 bases[CLKRST_MAX]; u32 bases[CLKRST_MAX];
int i; int i;
if (of_have_populated_dt())
np = of_find_matching_node(NULL, u8540_clk_of_match);
if (!np) {
pr_err("Either DT or U8540 Clock node not found\n");
return;
}
for (i = 0; i < ARRAY_SIZE(bases); i++) { for (i = 0; i < ARRAY_SIZE(bases); i++) {
struct resource r; struct resource r;
...@@ -607,3 +594,4 @@ void u8540_clk_init(void) ...@@ -607,3 +594,4 @@ void u8540_clk_init(void)
bases[CLKRST6_INDEX], BIT(0), CLK_SET_RATE_GATE); bases[CLKRST6_INDEX], BIT(0), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "rng"); clk_register_clkdev(clk, NULL, "rng");
} }
CLK_OF_DECLARE(u8540_clks, "stericsson,u8540-clks", u8540_clk_init);
...@@ -9,10 +9,10 @@ ...@@ -9,10 +9,10 @@
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/mfd/dbx500-prcmu.h> #include <linux/mfd/dbx500-prcmu.h>
#include <linux/platform_data/clk-ux500.h>
#include "clk.h" #include "clk.h"
void u9540_clk_init(void) static void u9540_clk_init(struct device_node *np)
{ {
/* register clocks here */ /* register clocks here */
} }
CLK_OF_DECLARE(u9540_clks, "stericsson,u9540-clks", u9540_clk_init);
...@@ -119,5 +119,5 @@ static int __init clps711x_timer_init(struct device_node *np) ...@@ -119,5 +119,5 @@ static int __init clps711x_timer_init(struct device_node *np)
return -EINVAL; return -EINVAL;
} }
} }
CLOCKSOURCE_OF_DECLARE(clps711x, "cirrus,clps711x-timer", clps711x_timer_init); CLOCKSOURCE_OF_DECLARE(clps711x, "cirrus,ep7209-timer", clps711x_timer_init);
#endif #endif
...@@ -220,7 +220,7 @@ static void s5pv210_set_refresh(enum s5pv210_dmc_port ch, unsigned long freq) ...@@ -220,7 +220,7 @@ static void s5pv210_set_refresh(enum s5pv210_dmc_port ch, unsigned long freq)
tmp1 /= tmp; tmp1 /= tmp;
__raw_writel(tmp1, reg); writel_relaxed(tmp1, reg);
} }
static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index) static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index)
...@@ -296,29 +296,29 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index) ...@@ -296,29 +296,29 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index)
* 1. Temporary Change divider for MFC and G3D * 1. Temporary Change divider for MFC and G3D
* SCLKA2M(200/1=200)->(200/4=50)Mhz * SCLKA2M(200/1=200)->(200/4=50)Mhz
*/ */
reg = __raw_readl(S5P_CLK_DIV2); reg = readl_relaxed(S5P_CLK_DIV2);
reg &= ~(S5P_CLKDIV2_G3D_MASK | S5P_CLKDIV2_MFC_MASK); reg &= ~(S5P_CLKDIV2_G3D_MASK | S5P_CLKDIV2_MFC_MASK);
reg |= (3 << S5P_CLKDIV2_G3D_SHIFT) | reg |= (3 << S5P_CLKDIV2_G3D_SHIFT) |
(3 << S5P_CLKDIV2_MFC_SHIFT); (3 << S5P_CLKDIV2_MFC_SHIFT);
__raw_writel(reg, S5P_CLK_DIV2); writel_relaxed(reg, S5P_CLK_DIV2);
/* For MFC, G3D dividing */ /* For MFC, G3D dividing */
do { do {
reg = __raw_readl(S5P_CLKDIV_STAT0); reg = readl_relaxed(S5P_CLKDIV_STAT0);
} while (reg & ((1 << 16) | (1 << 17))); } while (reg & ((1 << 16) | (1 << 17)));
/* /*
* 2. Change SCLKA2M(200Mhz)to SCLKMPLL in MFC_MUX, G3D MUX * 2. Change SCLKA2M(200Mhz)to SCLKMPLL in MFC_MUX, G3D MUX
* (200/4=50)->(667/4=166)Mhz * (200/4=50)->(667/4=166)Mhz
*/ */
reg = __raw_readl(S5P_CLK_SRC2); reg = readl_relaxed(S5P_CLK_SRC2);
reg &= ~(S5P_CLKSRC2_G3D_MASK | S5P_CLKSRC2_MFC_MASK); reg &= ~(S5P_CLKSRC2_G3D_MASK | S5P_CLKSRC2_MFC_MASK);
reg |= (1 << S5P_CLKSRC2_G3D_SHIFT) | reg |= (1 << S5P_CLKSRC2_G3D_SHIFT) |
(1 << S5P_CLKSRC2_MFC_SHIFT); (1 << S5P_CLKSRC2_MFC_SHIFT);
__raw_writel(reg, S5P_CLK_SRC2); writel_relaxed(reg, S5P_CLK_SRC2);
do { do {
reg = __raw_readl(S5P_CLKMUX_STAT1); reg = readl_relaxed(S5P_CLKMUX_STAT1);
} while (reg & ((1 << 7) | (1 << 3))); } while (reg & ((1 << 7) | (1 << 3)));
/* /*
...@@ -330,19 +330,19 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index) ...@@ -330,19 +330,19 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index)
s5pv210_set_refresh(DMC1, 133000); s5pv210_set_refresh(DMC1, 133000);
/* 4. SCLKAPLL -> SCLKMPLL */ /* 4. SCLKAPLL -> SCLKMPLL */
reg = __raw_readl(S5P_CLK_SRC0); reg = readl_relaxed(S5P_CLK_SRC0);
reg &= ~(S5P_CLKSRC0_MUX200_MASK); reg &= ~(S5P_CLKSRC0_MUX200_MASK);
reg |= (0x1 << S5P_CLKSRC0_MUX200_SHIFT); reg |= (0x1 << S5P_CLKSRC0_MUX200_SHIFT);
__raw_writel(reg, S5P_CLK_SRC0); writel_relaxed(reg, S5P_CLK_SRC0);
do { do {
reg = __raw_readl(S5P_CLKMUX_STAT0); reg = readl_relaxed(S5P_CLKMUX_STAT0);
} while (reg & (0x1 << 18)); } while (reg & (0x1 << 18));
} }
/* Change divider */ /* Change divider */
reg = __raw_readl(S5P_CLK_DIV0); reg = readl_relaxed(S5P_CLK_DIV0);
reg &= ~(S5P_CLKDIV0_APLL_MASK | S5P_CLKDIV0_A2M_MASK | reg &= ~(S5P_CLKDIV0_APLL_MASK | S5P_CLKDIV0_A2M_MASK |
S5P_CLKDIV0_HCLK200_MASK | S5P_CLKDIV0_PCLK100_MASK | S5P_CLKDIV0_HCLK200_MASK | S5P_CLKDIV0_PCLK100_MASK |
...@@ -358,25 +358,25 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index) ...@@ -358,25 +358,25 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index)
(clkdiv_val[index][6] << S5P_CLKDIV0_HCLK133_SHIFT) | (clkdiv_val[index][6] << S5P_CLKDIV0_HCLK133_SHIFT) |
(clkdiv_val[index][7] << S5P_CLKDIV0_PCLK66_SHIFT)); (clkdiv_val[index][7] << S5P_CLKDIV0_PCLK66_SHIFT));
__raw_writel(reg, S5P_CLK_DIV0); writel_relaxed(reg, S5P_CLK_DIV0);
do { do {
reg = __raw_readl(S5P_CLKDIV_STAT0); reg = readl_relaxed(S5P_CLKDIV_STAT0);
} while (reg & 0xff); } while (reg & 0xff);
/* ARM MCS value changed */ /* ARM MCS value changed */
reg = __raw_readl(S5P_ARM_MCS_CON); reg = readl_relaxed(S5P_ARM_MCS_CON);
reg &= ~0x3; reg &= ~0x3;
if (index >= L3) if (index >= L3)
reg |= 0x3; reg |= 0x3;
else else
reg |= 0x1; reg |= 0x1;
__raw_writel(reg, S5P_ARM_MCS_CON); writel_relaxed(reg, S5P_ARM_MCS_CON);
if (pll_changing) { if (pll_changing) {
/* 5. Set Lock time = 30us*24Mhz = 0x2cf */ /* 5. Set Lock time = 30us*24Mhz = 0x2cf */
__raw_writel(0x2cf, S5P_APLL_LOCK); writel_relaxed(0x2cf, S5P_APLL_LOCK);
/* /*
* 6. Turn on APLL * 6. Turn on APLL
...@@ -384,12 +384,12 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index) ...@@ -384,12 +384,12 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index)
* 6-2. Wait untile the PLL is locked * 6-2. Wait untile the PLL is locked
*/ */
if (index == L0) if (index == L0)
__raw_writel(APLL_VAL_1000, S5P_APLL_CON); writel_relaxed(APLL_VAL_1000, S5P_APLL_CON);
else else
__raw_writel(APLL_VAL_800, S5P_APLL_CON); writel_relaxed(APLL_VAL_800, S5P_APLL_CON);
do { do {
reg = __raw_readl(S5P_APLL_CON); reg = readl_relaxed(S5P_APLL_CON);
} while (!(reg & (0x1 << 29))); } while (!(reg & (0x1 << 29)));
/* /*
...@@ -397,39 +397,39 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index) ...@@ -397,39 +397,39 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index)
* to SCLKA2M(200Mhz) in MFC_MUX and G3D MUX * to SCLKA2M(200Mhz) in MFC_MUX and G3D MUX
* (667/4=166)->(200/4=50)Mhz * (667/4=166)->(200/4=50)Mhz
*/ */
reg = __raw_readl(S5P_CLK_SRC2); reg = readl_relaxed(S5P_CLK_SRC2);
reg &= ~(S5P_CLKSRC2_G3D_MASK | S5P_CLKSRC2_MFC_MASK); reg &= ~(S5P_CLKSRC2_G3D_MASK | S5P_CLKSRC2_MFC_MASK);
reg |= (0 << S5P_CLKSRC2_G3D_SHIFT) | reg |= (0 << S5P_CLKSRC2_G3D_SHIFT) |
(0 << S5P_CLKSRC2_MFC_SHIFT); (0 << S5P_CLKSRC2_MFC_SHIFT);
__raw_writel(reg, S5P_CLK_SRC2); writel_relaxed(reg, S5P_CLK_SRC2);
do { do {
reg = __raw_readl(S5P_CLKMUX_STAT1); reg = readl_relaxed(S5P_CLKMUX_STAT1);
} while (reg & ((1 << 7) | (1 << 3))); } while (reg & ((1 << 7) | (1 << 3)));
/* /*
* 8. Change divider for MFC and G3D * 8. Change divider for MFC and G3D
* (200/4=50)->(200/1=200)Mhz * (200/4=50)->(200/1=200)Mhz
*/ */
reg = __raw_readl(S5P_CLK_DIV2); reg = readl_relaxed(S5P_CLK_DIV2);
reg &= ~(S5P_CLKDIV2_G3D_MASK | S5P_CLKDIV2_MFC_MASK); reg &= ~(S5P_CLKDIV2_G3D_MASK | S5P_CLKDIV2_MFC_MASK);
reg |= (clkdiv_val[index][10] << S5P_CLKDIV2_G3D_SHIFT) | reg |= (clkdiv_val[index][10] << S5P_CLKDIV2_G3D_SHIFT) |
(clkdiv_val[index][9] << S5P_CLKDIV2_MFC_SHIFT); (clkdiv_val[index][9] << S5P_CLKDIV2_MFC_SHIFT);
__raw_writel(reg, S5P_CLK_DIV2); writel_relaxed(reg, S5P_CLK_DIV2);
/* For MFC, G3D dividing */ /* For MFC, G3D dividing */
do { do {
reg = __raw_readl(S5P_CLKDIV_STAT0); reg = readl_relaxed(S5P_CLKDIV_STAT0);
} while (reg & ((1 << 16) | (1 << 17))); } while (reg & ((1 << 16) | (1 << 17)));
/* 9. Change MPLL to APLL in MSYS_MUX */ /* 9. Change MPLL to APLL in MSYS_MUX */
reg = __raw_readl(S5P_CLK_SRC0); reg = readl_relaxed(S5P_CLK_SRC0);
reg &= ~(S5P_CLKSRC0_MUX200_MASK); reg &= ~(S5P_CLKSRC0_MUX200_MASK);
reg |= (0x0 << S5P_CLKSRC0_MUX200_SHIFT); reg |= (0x0 << S5P_CLKSRC0_MUX200_SHIFT);
__raw_writel(reg, S5P_CLK_SRC0); writel_relaxed(reg, S5P_CLK_SRC0);
do { do {
reg = __raw_readl(S5P_CLKMUX_STAT0); reg = readl_relaxed(S5P_CLKMUX_STAT0);
} while (reg & (0x1 << 18)); } while (reg & (0x1 << 18));
/* /*
...@@ -446,13 +446,13 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index) ...@@ -446,13 +446,13 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index)
* and memory refresh parameter should be changed * and memory refresh parameter should be changed
*/ */
if (bus_speed_changing) { if (bus_speed_changing) {
reg = __raw_readl(S5P_CLK_DIV6); reg = readl_relaxed(S5P_CLK_DIV6);
reg &= ~S5P_CLKDIV6_ONEDRAM_MASK; reg &= ~S5P_CLKDIV6_ONEDRAM_MASK;
reg |= (clkdiv_val[index][8] << S5P_CLKDIV6_ONEDRAM_SHIFT); reg |= (clkdiv_val[index][8] << S5P_CLKDIV6_ONEDRAM_SHIFT);
__raw_writel(reg, S5P_CLK_DIV6); writel_relaxed(reg, S5P_CLK_DIV6);
do { do {
reg = __raw_readl(S5P_CLKDIV_STAT1); reg = readl_relaxed(S5P_CLKDIV_STAT1);
} while (reg & (1 << 15)); } while (reg & (1 << 15));
/* Reconfigure DRAM refresh counter value */ /* Reconfigure DRAM refresh counter value */
...@@ -492,7 +492,7 @@ static int check_mem_type(void __iomem *dmc_reg) ...@@ -492,7 +492,7 @@ static int check_mem_type(void __iomem *dmc_reg)
{ {
unsigned long val; unsigned long val;
val = __raw_readl(dmc_reg + 0x4); val = readl_relaxed(dmc_reg + 0x4);
val = (val & (0xf << 8)); val = (val & (0xf << 8));
return val >> 8; return val >> 8;
...@@ -537,10 +537,10 @@ static int s5pv210_cpu_init(struct cpufreq_policy *policy) ...@@ -537,10 +537,10 @@ static int s5pv210_cpu_init(struct cpufreq_policy *policy)
} }
/* Find current refresh counter and frequency each DMC */ /* Find current refresh counter and frequency each DMC */
s5pv210_dram_conf[0].refresh = (__raw_readl(dmc_base[0] + 0x30) * 1000); s5pv210_dram_conf[0].refresh = (readl_relaxed(dmc_base[0] + 0x30) * 1000);
s5pv210_dram_conf[0].freq = clk_get_rate(dmc0_clk); s5pv210_dram_conf[0].freq = clk_get_rate(dmc0_clk);
s5pv210_dram_conf[1].refresh = (__raw_readl(dmc_base[1] + 0x30) * 1000); s5pv210_dram_conf[1].refresh = (readl_relaxed(dmc_base[1] + 0x30) * 1000);
s5pv210_dram_conf[1].freq = clk_get_rate(dmc1_clk); s5pv210_dram_conf[1].freq = clk_get_rate(dmc1_clk);
policy->suspend_freq = SLEEP_FREQ; policy->suspend_freq = SLEEP_FREQ;
......
...@@ -10,7 +10,7 @@ config ARM_PSCI_FW ...@@ -10,7 +10,7 @@ config ARM_PSCI_FW
config ARM_SCPI_PROTOCOL config ARM_SCPI_PROTOCOL
tristate "ARM System Control and Power Interface (SCPI) Message Protocol" tristate "ARM System Control and Power Interface (SCPI) Message Protocol"
depends on ARM_MHU depends on MAILBOX
help help
System Control and Power Interface (SCPI) Message Protocol is System Control and Power Interface (SCPI) Message Protocol is
defined for the purpose of communication between the Application defined for the purpose of communication between the Application
...@@ -27,6 +27,15 @@ config ARM_SCPI_PROTOCOL ...@@ -27,6 +27,15 @@ config ARM_SCPI_PROTOCOL
This protocol library provides interface for all the client drivers This protocol library provides interface for all the client drivers
making use of the features offered by the SCP. making use of the features offered by the SCP.
config ARM_SCPI_POWER_DOMAIN
tristate "SCPI power domain driver"
depends on ARM_SCPI_PROTOCOL || (COMPILE_TEST && OF)
default y
select PM_GENERIC_DOMAINS if PM
help
This enables support for the SCPI power domains which can be
enabled or disabled via the SCP firmware
config EDD config EDD
tristate "BIOS Enhanced Disk Drive calls determine boot disk" tristate "BIOS Enhanced Disk Drive calls determine boot disk"
depends on X86 depends on X86
...@@ -184,6 +193,7 @@ config FW_CFG_SYSFS_CMDLINE ...@@ -184,6 +193,7 @@ config FW_CFG_SYSFS_CMDLINE
config QCOM_SCM config QCOM_SCM
bool bool
depends on ARM || ARM64 depends on ARM || ARM64
select RESET_CONTROLLER
config QCOM_SCM_32 config QCOM_SCM_32
def_bool y def_bool y
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
# #
obj-$(CONFIG_ARM_PSCI_FW) += psci.o obj-$(CONFIG_ARM_PSCI_FW) += psci.o
obj-$(CONFIG_ARM_SCPI_PROTOCOL) += arm_scpi.o obj-$(CONFIG_ARM_SCPI_PROTOCOL) += arm_scpi.o
obj-$(CONFIG_ARM_SCPI_POWER_DOMAIN) += scpi_pm_domain.o
obj-$(CONFIG_DMI) += dmi_scan.o obj-$(CONFIG_DMI) += dmi_scan.o
obj-$(CONFIG_DMI_SYSFS) += dmi-sysfs.o obj-$(CONFIG_DMI_SYSFS) += dmi-sysfs.o
obj-$(CONFIG_EDD) += edd.o obj-$(CONFIG_EDD) += edd.o
......
...@@ -210,10 +210,6 @@ struct dvfs_info { ...@@ -210,10 +210,6 @@ struct dvfs_info {
} opps[MAX_DVFS_OPPS]; } opps[MAX_DVFS_OPPS];
} __packed; } __packed;
struct dvfs_get {
u8 index;
} __packed;
struct dvfs_set { struct dvfs_set {
u8 domain; u8 domain;
u8 index; u8 index;
...@@ -235,6 +231,11 @@ struct sensor_value { ...@@ -235,6 +231,11 @@ struct sensor_value {
__le32 hi_val; __le32 hi_val;
} __packed; } __packed;
struct dev_pstate_set {
u16 dev_id;
u8 pstate;
} __packed;
static struct scpi_drvinfo *scpi_info; static struct scpi_drvinfo *scpi_info;
static int scpi_linux_errmap[SCPI_ERR_MAX] = { static int scpi_linux_errmap[SCPI_ERR_MAX] = {
...@@ -431,11 +432,11 @@ static int scpi_clk_set_val(u16 clk_id, unsigned long rate) ...@@ -431,11 +432,11 @@ static int scpi_clk_set_val(u16 clk_id, unsigned long rate)
static int scpi_dvfs_get_idx(u8 domain) static int scpi_dvfs_get_idx(u8 domain)
{ {
int ret; int ret;
struct dvfs_get dvfs; u8 dvfs_idx;
ret = scpi_send_message(SCPI_CMD_GET_DVFS, &domain, sizeof(domain), ret = scpi_send_message(SCPI_CMD_GET_DVFS, &domain, sizeof(domain),
&dvfs, sizeof(dvfs)); &dvfs_idx, sizeof(dvfs_idx));
return ret ? ret : dvfs.index; return ret ? ret : dvfs_idx;
} }
static int scpi_dvfs_set_idx(u8 domain, u8 index) static int scpi_dvfs_set_idx(u8 domain, u8 index)
...@@ -526,7 +527,7 @@ static int scpi_sensor_get_info(u16 sensor_id, struct scpi_sensor_info *info) ...@@ -526,7 +527,7 @@ static int scpi_sensor_get_info(u16 sensor_id, struct scpi_sensor_info *info)
return ret; return ret;
} }
int scpi_sensor_get_value(u16 sensor, u64 *val) static int scpi_sensor_get_value(u16 sensor, u64 *val)
{ {
__le16 id = cpu_to_le16(sensor); __le16 id = cpu_to_le16(sensor);
struct sensor_value buf; struct sensor_value buf;
...@@ -541,6 +542,29 @@ int scpi_sensor_get_value(u16 sensor, u64 *val) ...@@ -541,6 +542,29 @@ int scpi_sensor_get_value(u16 sensor, u64 *val)
return ret; return ret;
} }
static int scpi_device_get_power_state(u16 dev_id)
{
int ret;
u8 pstate;
__le16 id = cpu_to_le16(dev_id);
ret = scpi_send_message(SCPI_CMD_GET_DEVICE_PWR_STATE, &id,
sizeof(id), &pstate, sizeof(pstate));
return ret ? ret : pstate;
}
static int scpi_device_set_power_state(u16 dev_id, u8 pstate)
{
int stat;
struct dev_pstate_set dev_set = {
.dev_id = cpu_to_le16(dev_id),
.pstate = pstate,
};
return scpi_send_message(SCPI_CMD_SET_DEVICE_PWR_STATE, &dev_set,
sizeof(dev_set), &stat, sizeof(stat));
}
static struct scpi_ops scpi_ops = { static struct scpi_ops scpi_ops = {
.get_version = scpi_get_version, .get_version = scpi_get_version,
.clk_get_range = scpi_clk_get_range, .clk_get_range = scpi_clk_get_range,
...@@ -552,6 +576,8 @@ static struct scpi_ops scpi_ops = { ...@@ -552,6 +576,8 @@ static struct scpi_ops scpi_ops = {
.sensor_get_capability = scpi_sensor_get_capability, .sensor_get_capability = scpi_sensor_get_capability,
.sensor_get_info = scpi_sensor_get_info, .sensor_get_info = scpi_sensor_get_info,
.sensor_get_value = scpi_sensor_get_value, .sensor_get_value = scpi_sensor_get_value,
.device_get_power_state = scpi_device_get_power_state,
.device_set_power_state = scpi_device_set_power_state,
}; };
struct scpi_ops *get_scpi_ops(void) struct scpi_ops *get_scpi_ops(void)
......
...@@ -23,8 +23,7 @@ ...@@ -23,8 +23,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/qcom_scm.h> #include <linux/qcom_scm.h>
#include <linux/dma-mapping.h>
#include <asm/cacheflush.h>
#include "qcom_scm.h" #include "qcom_scm.h"
...@@ -96,44 +95,6 @@ struct qcom_scm_response { ...@@ -96,44 +95,6 @@ struct qcom_scm_response {
__le32 is_complete; __le32 is_complete;
}; };
/**
* alloc_qcom_scm_command() - Allocate an SCM command
* @cmd_size: size of the command buffer
* @resp_size: size of the response buffer
*
* Allocate an SCM command, including enough room for the command
* and response headers as well as the command and response buffers.
*
* Returns a valid &qcom_scm_command on success or %NULL if the allocation fails.
*/
static struct qcom_scm_command *alloc_qcom_scm_command(size_t cmd_size, size_t resp_size)
{
struct qcom_scm_command *cmd;
size_t len = sizeof(*cmd) + sizeof(struct qcom_scm_response) + cmd_size +
resp_size;
u32 offset;
cmd = kzalloc(PAGE_ALIGN(len), GFP_KERNEL);
if (cmd) {
cmd->len = cpu_to_le32(len);
offset = offsetof(struct qcom_scm_command, buf);
cmd->buf_offset = cpu_to_le32(offset);
cmd->resp_hdr_offset = cpu_to_le32(offset + cmd_size);
}
return cmd;
}
/**
* free_qcom_scm_command() - Free an SCM command
* @cmd: command to free
*
* Free an SCM command.
*/
static inline void free_qcom_scm_command(struct qcom_scm_command *cmd)
{
kfree(cmd);
}
/** /**
* qcom_scm_command_to_response() - Get a pointer to a qcom_scm_response * qcom_scm_command_to_response() - Get a pointer to a qcom_scm_response
* @cmd: command * @cmd: command
...@@ -168,23 +129,6 @@ static inline void *qcom_scm_get_response_buffer(const struct qcom_scm_response ...@@ -168,23 +129,6 @@ static inline void *qcom_scm_get_response_buffer(const struct qcom_scm_response
return (void *)rsp + le32_to_cpu(rsp->buf_offset); return (void *)rsp + le32_to_cpu(rsp->buf_offset);
} }
static int qcom_scm_remap_error(int err)
{
pr_err("qcom_scm_call failed with error code %d\n", err);
switch (err) {
case QCOM_SCM_ERROR:
return -EIO;
case QCOM_SCM_EINVAL_ADDR:
case QCOM_SCM_EINVAL_ARG:
return -EINVAL;
case QCOM_SCM_EOPNOTSUPP:
return -EOPNOTSUPP;
case QCOM_SCM_ENOMEM:
return -ENOMEM;
}
return -EINVAL;
}
static u32 smc(u32 cmd_addr) static u32 smc(u32 cmd_addr)
{ {
int context_id; int context_id;
...@@ -209,45 +153,9 @@ static u32 smc(u32 cmd_addr) ...@@ -209,45 +153,9 @@ static u32 smc(u32 cmd_addr)
return r0; return r0;
} }
static int __qcom_scm_call(const struct qcom_scm_command *cmd)
{
int ret;
u32 cmd_addr = virt_to_phys(cmd);
/*
* Flush the command buffer so that the secure world sees
* the correct data.
*/
secure_flush_area(cmd, cmd->len);
ret = smc(cmd_addr);
if (ret < 0)
ret = qcom_scm_remap_error(ret);
return ret;
}
static void qcom_scm_inv_range(unsigned long start, unsigned long end)
{
u32 cacheline_size, ctr;
asm volatile("mrc p15, 0, %0, c0, c0, 1" : "=r" (ctr));
cacheline_size = 4 << ((ctr >> 16) & 0xf);
start = round_down(start, cacheline_size);
end = round_up(end, cacheline_size);
outer_inv_range(start, end);
while (start < end) {
asm ("mcr p15, 0, %0, c7, c6, 1" : : "r" (start)
: "memory");
start += cacheline_size;
}
dsb();
isb();
}
/** /**
* qcom_scm_call() - Send an SCM command * qcom_scm_call() - Send an SCM command
* @dev: struct device
* @svc_id: service identifier * @svc_id: service identifier
* @cmd_id: command identifier * @cmd_id: command identifier
* @cmd_buf: command buffer * @cmd_buf: command buffer
...@@ -264,42 +172,59 @@ static void qcom_scm_inv_range(unsigned long start, unsigned long end) ...@@ -264,42 +172,59 @@ static void qcom_scm_inv_range(unsigned long start, unsigned long end)
* and response buffers is taken care of by qcom_scm_call; however, callers are * and response buffers is taken care of by qcom_scm_call; however, callers are
* responsible for any other cached buffers passed over to the secure world. * responsible for any other cached buffers passed over to the secure world.
*/ */
static int qcom_scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, static int qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id,
size_t cmd_len, void *resp_buf, size_t resp_len) const void *cmd_buf, size_t cmd_len, void *resp_buf,
size_t resp_len)
{ {
int ret; int ret;
struct qcom_scm_command *cmd; struct qcom_scm_command *cmd;
struct qcom_scm_response *rsp; struct qcom_scm_response *rsp;
unsigned long start, end; size_t alloc_len = sizeof(*cmd) + cmd_len + sizeof(*rsp) + resp_len;
dma_addr_t cmd_phys;
cmd = alloc_qcom_scm_command(cmd_len, resp_len); cmd = kzalloc(PAGE_ALIGN(alloc_len), GFP_KERNEL);
if (!cmd) if (!cmd)
return -ENOMEM; return -ENOMEM;
cmd->len = cpu_to_le32(alloc_len);
cmd->buf_offset = cpu_to_le32(sizeof(*cmd));
cmd->resp_hdr_offset = cpu_to_le32(sizeof(*cmd) + cmd_len);
cmd->id = cpu_to_le32((svc_id << 10) | cmd_id); cmd->id = cpu_to_le32((svc_id << 10) | cmd_id);
if (cmd_buf) if (cmd_buf)
memcpy(qcom_scm_get_command_buffer(cmd), cmd_buf, cmd_len); memcpy(qcom_scm_get_command_buffer(cmd), cmd_buf, cmd_len);
rsp = qcom_scm_command_to_response(cmd);
cmd_phys = dma_map_single(dev, cmd, alloc_len, DMA_TO_DEVICE);
if (dma_mapping_error(dev, cmd_phys)) {
kfree(cmd);
return -ENOMEM;
}
mutex_lock(&qcom_scm_lock); mutex_lock(&qcom_scm_lock);
ret = __qcom_scm_call(cmd); ret = smc(cmd_phys);
if (ret < 0)
ret = qcom_scm_remap_error(ret);
mutex_unlock(&qcom_scm_lock); mutex_unlock(&qcom_scm_lock);
if (ret) if (ret)
goto out; goto out;
rsp = qcom_scm_command_to_response(cmd);
start = (unsigned long)rsp;
do { do {
qcom_scm_inv_range(start, start + sizeof(*rsp)); dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len,
sizeof(*rsp), DMA_FROM_DEVICE);
} while (!rsp->is_complete); } while (!rsp->is_complete);
end = (unsigned long)qcom_scm_get_response_buffer(rsp) + resp_len; if (resp_buf) {
qcom_scm_inv_range(start, end); dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len +
le32_to_cpu(rsp->buf_offset),
if (resp_buf) resp_len, DMA_FROM_DEVICE);
memcpy(resp_buf, qcom_scm_get_response_buffer(rsp), resp_len); memcpy(resp_buf, qcom_scm_get_response_buffer(rsp),
resp_len);
}
out: out:
free_qcom_scm_command(cmd); dma_unmap_single(dev, cmd_phys, alloc_len, DMA_TO_DEVICE);
kfree(cmd);
return ret; return ret;
} }
...@@ -342,6 +267,41 @@ static s32 qcom_scm_call_atomic1(u32 svc, u32 cmd, u32 arg1) ...@@ -342,6 +267,41 @@ static s32 qcom_scm_call_atomic1(u32 svc, u32 cmd, u32 arg1)
return r0; return r0;
} }
/**
* qcom_scm_call_atomic2() - Send an atomic SCM command with two arguments
* @svc_id: service identifier
* @cmd_id: command identifier
* @arg1: first argument
* @arg2: second argument
*
* This shall only be used with commands that are guaranteed to be
* uninterruptable, atomic and SMP safe.
*/
static s32 qcom_scm_call_atomic2(u32 svc, u32 cmd, u32 arg1, u32 arg2)
{
int context_id;
register u32 r0 asm("r0") = SCM_ATOMIC(svc, cmd, 2);
register u32 r1 asm("r1") = (u32)&context_id;
register u32 r2 asm("r2") = arg1;
register u32 r3 asm("r3") = arg2;
asm volatile(
__asmeq("%0", "r0")
__asmeq("%1", "r0")
__asmeq("%2", "r1")
__asmeq("%3", "r2")
__asmeq("%4", "r3")
#ifdef REQUIRES_SEC
".arch_extension sec\n"
#endif
"smc #0 @ switch to secure world\n"
: "=r" (r0)
: "r" (r0), "r" (r1), "r" (r2), "r" (r3)
);
return r0;
}
u32 qcom_scm_get_version(void) u32 qcom_scm_get_version(void)
{ {
int context_id; int context_id;
...@@ -378,22 +338,6 @@ u32 qcom_scm_get_version(void) ...@@ -378,22 +338,6 @@ u32 qcom_scm_get_version(void)
} }
EXPORT_SYMBOL(qcom_scm_get_version); EXPORT_SYMBOL(qcom_scm_get_version);
/*
* Set the cold/warm boot address for one of the CPU cores.
*/
static int qcom_scm_set_boot_addr(u32 addr, int flags)
{
struct {
__le32 flags;
__le32 addr;
} cmd;
cmd.addr = cpu_to_le32(addr);
cmd.flags = cpu_to_le32(flags);
return qcom_scm_call(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_ADDR,
&cmd, sizeof(cmd), NULL, 0);
}
/** /**
* qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus
* @entry: Entry point function for the cpus * @entry: Entry point function for the cpus
...@@ -423,7 +367,8 @@ int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus) ...@@ -423,7 +367,8 @@ int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
set_cpu_present(cpu, false); set_cpu_present(cpu, false);
} }
return qcom_scm_set_boot_addr(virt_to_phys(entry), flags); return qcom_scm_call_atomic2(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_ADDR,
flags, virt_to_phys(entry));
} }
/** /**
...@@ -434,11 +379,16 @@ int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus) ...@@ -434,11 +379,16 @@ int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
* Set the Linux entry point for the SCM to transfer control to when coming * Set the Linux entry point for the SCM to transfer control to when coming
* out of a power down. CPU power down may be executed on cpuidle or hotplug. * out of a power down. CPU power down may be executed on cpuidle or hotplug.
*/ */
int __qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus) int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry,
const cpumask_t *cpus)
{ {
int ret; int ret;
int flags = 0; int flags = 0;
int cpu; int cpu;
struct {
__le32 flags;
__le32 addr;
} cmd;
/* /*
* Reassign only if we are switching from hotplug entry point * Reassign only if we are switching from hotplug entry point
...@@ -454,7 +404,10 @@ int __qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus) ...@@ -454,7 +404,10 @@ int __qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus)
if (!flags) if (!flags)
return 0; return 0;
ret = qcom_scm_set_boot_addr(virt_to_phys(entry), flags); cmd.addr = cpu_to_le32(virt_to_phys(entry));
cmd.flags = cpu_to_le32(flags);
ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_ADDR,
&cmd, sizeof(cmd), NULL, 0);
if (!ret) { if (!ret) {
for_each_cpu(cpu, cpus) for_each_cpu(cpu, cpus)
qcom_scm_wb[cpu].entry = entry; qcom_scm_wb[cpu].entry = entry;
...@@ -477,25 +430,133 @@ void __qcom_scm_cpu_power_down(u32 flags) ...@@ -477,25 +430,133 @@ void __qcom_scm_cpu_power_down(u32 flags)
flags & QCOM_SCM_FLUSH_FLAG_MASK); flags & QCOM_SCM_FLUSH_FLAG_MASK);
} }
int __qcom_scm_is_call_available(u32 svc_id, u32 cmd_id) int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
{ {
int ret; int ret;
__le32 svc_cmd = cpu_to_le32((svc_id << 10) | cmd_id); __le32 svc_cmd = cpu_to_le32((svc_id << 10) | cmd_id);
__le32 ret_val = 0; __le32 ret_val = 0;
ret = qcom_scm_call(QCOM_SCM_SVC_INFO, QCOM_IS_CALL_AVAIL_CMD, &svc_cmd, ret = qcom_scm_call(dev, QCOM_SCM_SVC_INFO, QCOM_IS_CALL_AVAIL_CMD,
sizeof(svc_cmd), &ret_val, sizeof(ret_val)); &svc_cmd, sizeof(svc_cmd), &ret_val,
sizeof(ret_val));
if (ret) if (ret)
return ret; return ret;
return le32_to_cpu(ret_val); return le32_to_cpu(ret_val);
} }
int __qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp) int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,
u32 req_cnt, u32 *resp)
{ {
if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT) if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT)
return -ERANGE; return -ERANGE;
return qcom_scm_call(QCOM_SCM_SVC_HDCP, QCOM_SCM_CMD_HDCP, return qcom_scm_call(dev, QCOM_SCM_SVC_HDCP, QCOM_SCM_CMD_HDCP,
req, req_cnt * sizeof(*req), resp, sizeof(*resp)); req, req_cnt * sizeof(*req), resp, sizeof(*resp));
} }
void __qcom_scm_init(void)
{
}
bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral)
{
__le32 out;
__le32 in;
int ret;
in = cpu_to_le32(peripheral);
ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
QCOM_SCM_PAS_IS_SUPPORTED_CMD,
&in, sizeof(in),
&out, sizeof(out));
return ret ? false : !!out;
}
int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral,
dma_addr_t metadata_phys)
{
__le32 scm_ret;
int ret;
struct {
__le32 proc;
__le32 image_addr;
} request;
request.proc = cpu_to_le32(peripheral);
request.image_addr = cpu_to_le32(metadata_phys);
ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
QCOM_SCM_PAS_INIT_IMAGE_CMD,
&request, sizeof(request),
&scm_ret, sizeof(scm_ret));
return ret ? : le32_to_cpu(scm_ret);
}
int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral,
phys_addr_t addr, phys_addr_t size)
{
__le32 scm_ret;
int ret;
struct {
__le32 proc;
__le32 addr;
__le32 len;
} request;
request.proc = cpu_to_le32(peripheral);
request.addr = cpu_to_le32(addr);
request.len = cpu_to_le32(size);
ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
QCOM_SCM_PAS_MEM_SETUP_CMD,
&request, sizeof(request),
&scm_ret, sizeof(scm_ret));
return ret ? : le32_to_cpu(scm_ret);
}
int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral)
{
__le32 out;
__le32 in;
int ret;
in = cpu_to_le32(peripheral);
ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
QCOM_SCM_PAS_AUTH_AND_RESET_CMD,
&in, sizeof(in),
&out, sizeof(out));
return ret ? : le32_to_cpu(out);
}
int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral)
{
__le32 out;
__le32 in;
int ret;
in = cpu_to_le32(peripheral);
ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
QCOM_SCM_PAS_SHUTDOWN_CMD,
&in, sizeof(in),
&out, sizeof(out));
return ret ? : le32_to_cpu(out);
}
int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
{
__le32 out;
__le32 in = cpu_to_le32(reset);
int ret;
ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_MSS_RESET,
&in, sizeof(in),
&out, sizeof(out));
return ret ? : le32_to_cpu(out);
}
...@@ -12,7 +12,150 @@ ...@@ -12,7 +12,150 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/qcom_scm.h> #include <linux/qcom_scm.h>
#include <linux/arm-smccc.h>
#include <linux/dma-mapping.h>
#include "qcom_scm.h"
#define QCOM_SCM_FNID(s, c) ((((s) & 0xFF) << 8) | ((c) & 0xFF))
#define MAX_QCOM_SCM_ARGS 10
#define MAX_QCOM_SCM_RETS 3
enum qcom_scm_arg_types {
QCOM_SCM_VAL,
QCOM_SCM_RO,
QCOM_SCM_RW,
QCOM_SCM_BUFVAL,
};
#define QCOM_SCM_ARGS_IMPL(num, a, b, c, d, e, f, g, h, i, j, ...) (\
(((a) & 0x3) << 4) | \
(((b) & 0x3) << 6) | \
(((c) & 0x3) << 8) | \
(((d) & 0x3) << 10) | \
(((e) & 0x3) << 12) | \
(((f) & 0x3) << 14) | \
(((g) & 0x3) << 16) | \
(((h) & 0x3) << 18) | \
(((i) & 0x3) << 20) | \
(((j) & 0x3) << 22) | \
((num) & 0xf))
#define QCOM_SCM_ARGS(...) QCOM_SCM_ARGS_IMPL(__VA_ARGS__, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
/**
* struct qcom_scm_desc
* @arginfo: Metadata describing the arguments in args[]
* @args: The array of arguments for the secure syscall
* @res: The values returned by the secure syscall
*/
struct qcom_scm_desc {
u32 arginfo;
u64 args[MAX_QCOM_SCM_ARGS];
};
static u64 qcom_smccc_convention = -1;
static DEFINE_MUTEX(qcom_scm_lock);
#define QCOM_SCM_EBUSY_WAIT_MS 30
#define QCOM_SCM_EBUSY_MAX_RETRY 20
#define N_EXT_QCOM_SCM_ARGS 7
#define FIRST_EXT_ARG_IDX 3
#define N_REGISTER_ARGS (MAX_QCOM_SCM_ARGS - N_EXT_QCOM_SCM_ARGS + 1)
/**
* qcom_scm_call() - Invoke a syscall in the secure world
* @dev: device
* @svc_id: service identifier
* @cmd_id: command identifier
* @desc: Descriptor structure containing arguments and return values
*
* Sends a command to the SCM and waits for the command to finish processing.
* This should *only* be called in pre-emptible context.
*/
static int qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id,
const struct qcom_scm_desc *desc,
struct arm_smccc_res *res)
{
int arglen = desc->arginfo & 0xf;
int retry_count = 0, i;
u32 fn_id = QCOM_SCM_FNID(svc_id, cmd_id);
u64 cmd, x5 = desc->args[FIRST_EXT_ARG_IDX];
dma_addr_t args_phys = 0;
void *args_virt = NULL;
size_t alloc_len;
if (unlikely(arglen > N_REGISTER_ARGS)) {
alloc_len = N_EXT_QCOM_SCM_ARGS * sizeof(u64);
args_virt = kzalloc(PAGE_ALIGN(alloc_len), GFP_KERNEL);
if (!args_virt)
return -ENOMEM;
if (qcom_smccc_convention == ARM_SMCCC_SMC_32) {
__le32 *args = args_virt;
for (i = 0; i < N_EXT_QCOM_SCM_ARGS; i++)
args[i] = cpu_to_le32(desc->args[i +
FIRST_EXT_ARG_IDX]);
} else {
__le64 *args = args_virt;
for (i = 0; i < N_EXT_QCOM_SCM_ARGS; i++)
args[i] = cpu_to_le64(desc->args[i +
FIRST_EXT_ARG_IDX]);
}
args_phys = dma_map_single(dev, args_virt, alloc_len,
DMA_TO_DEVICE);
if (dma_mapping_error(dev, args_phys)) {
kfree(args_virt);
return -ENOMEM;
}
x5 = args_phys;
}
do {
mutex_lock(&qcom_scm_lock);
cmd = ARM_SMCCC_CALL_VAL(ARM_SMCCC_STD_CALL,
qcom_smccc_convention,
ARM_SMCCC_OWNER_SIP, fn_id);
do {
arm_smccc_smc(cmd, desc->arginfo, desc->args[0],
desc->args[1], desc->args[2], x5, 0, 0,
res);
} while (res->a0 == QCOM_SCM_INTERRUPTED);
mutex_unlock(&qcom_scm_lock);
if (res->a0 == QCOM_SCM_V2_EBUSY) {
if (retry_count++ > QCOM_SCM_EBUSY_MAX_RETRY)
break;
msleep(QCOM_SCM_EBUSY_WAIT_MS);
}
} while (res->a0 == QCOM_SCM_V2_EBUSY);
if (args_virt) {
dma_unmap_single(dev, args_phys, alloc_len, DMA_TO_DEVICE);
kfree(args_virt);
}
if (res->a0 < 0)
return qcom_scm_remap_error(res->a0);
return 0;
}
/** /**
* qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus
...@@ -29,13 +172,15 @@ int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus) ...@@ -29,13 +172,15 @@ int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
/** /**
* qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus * qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus
* @dev: Device pointer
* @entry: Entry point function for the cpus * @entry: Entry point function for the cpus
* @cpus: The cpumask of cpus that will use the entry point * @cpus: The cpumask of cpus that will use the entry point
* *
* Set the Linux entry point for the SCM to transfer control to when coming * Set the Linux entry point for the SCM to transfer control to when coming
* out of a power down. CPU power down may be executed on cpuidle or hotplug. * out of a power down. CPU power down may be executed on cpuidle or hotplug.
*/ */
int __qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus) int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry,
const cpumask_t *cpus)
{ {
return -ENOTSUPP; return -ENOTSUPP;
} }
...@@ -52,12 +197,164 @@ void __qcom_scm_cpu_power_down(u32 flags) ...@@ -52,12 +197,164 @@ void __qcom_scm_cpu_power_down(u32 flags)
{ {
} }
int __qcom_scm_is_call_available(u32 svc_id, u32 cmd_id) int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
{ {
return -ENOTSUPP; int ret;
struct qcom_scm_desc desc = {0};
struct arm_smccc_res res;
desc.arginfo = QCOM_SCM_ARGS(1);
desc.args[0] = QCOM_SCM_FNID(svc_id, cmd_id) |
(ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT);
ret = qcom_scm_call(dev, QCOM_SCM_SVC_INFO, QCOM_IS_CALL_AVAIL_CMD,
&desc, &res);
return ret ? : res.a1;
} }
int __qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp) int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,
u32 req_cnt, u32 *resp)
{ {
return -ENOTSUPP; int ret;
struct qcom_scm_desc desc = {0};
struct arm_smccc_res res;
if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT)
return -ERANGE;
desc.args[0] = req[0].addr;
desc.args[1] = req[0].val;
desc.args[2] = req[1].addr;
desc.args[3] = req[1].val;
desc.args[4] = req[2].addr;
desc.args[5] = req[2].val;
desc.args[6] = req[3].addr;
desc.args[7] = req[3].val;
desc.args[8] = req[4].addr;
desc.args[9] = req[4].val;
desc.arginfo = QCOM_SCM_ARGS(10);
ret = qcom_scm_call(dev, QCOM_SCM_SVC_HDCP, QCOM_SCM_CMD_HDCP, &desc,
&res);
*resp = res.a1;
return ret;
}
void __qcom_scm_init(void)
{
u64 cmd;
struct arm_smccc_res res;
u32 function = QCOM_SCM_FNID(QCOM_SCM_SVC_INFO, QCOM_IS_CALL_AVAIL_CMD);
/* First try a SMC64 call */
cmd = ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64,
ARM_SMCCC_OWNER_SIP, function);
arm_smccc_smc(cmd, QCOM_SCM_ARGS(1), cmd & (~BIT(ARM_SMCCC_TYPE_SHIFT)),
0, 0, 0, 0, 0, &res);
if (!res.a0 && res.a1)
qcom_smccc_convention = ARM_SMCCC_SMC_64;
else
qcom_smccc_convention = ARM_SMCCC_SMC_32;
}
bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral)
{
int ret;
struct qcom_scm_desc desc = {0};
struct arm_smccc_res res;
desc.args[0] = peripheral;
desc.arginfo = QCOM_SCM_ARGS(1);
ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
QCOM_SCM_PAS_IS_SUPPORTED_CMD,
&desc, &res);
return ret ? false : !!res.a1;
}
int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral,
dma_addr_t metadata_phys)
{
int ret;
struct qcom_scm_desc desc = {0};
struct arm_smccc_res res;
desc.args[0] = peripheral;
desc.args[1] = metadata_phys;
desc.arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW);
ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_INIT_IMAGE_CMD,
&desc, &res);
return ret ? : res.a1;
}
int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral,
phys_addr_t addr, phys_addr_t size)
{
int ret;
struct qcom_scm_desc desc = {0};
struct arm_smccc_res res;
desc.args[0] = peripheral;
desc.args[1] = addr;
desc.args[2] = size;
desc.arginfo = QCOM_SCM_ARGS(3);
ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_MEM_SETUP_CMD,
&desc, &res);
return ret ? : res.a1;
}
int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral)
{
int ret;
struct qcom_scm_desc desc = {0};
struct arm_smccc_res res;
desc.args[0] = peripheral;
desc.arginfo = QCOM_SCM_ARGS(1);
ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
QCOM_SCM_PAS_AUTH_AND_RESET_CMD,
&desc, &res);
return ret ? : res.a1;
}
int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral)
{
int ret;
struct qcom_scm_desc desc = {0};
struct arm_smccc_res res;
desc.args[0] = peripheral;
desc.arginfo = QCOM_SCM_ARGS(1);
ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_SHUTDOWN_CMD,
&desc, &res);
return ret ? : res.a1;
}
int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
{
struct qcom_scm_desc desc = {0};
struct arm_smccc_res res;
int ret;
desc.args[0] = reset;
desc.args[1] = 0;
desc.arginfo = QCOM_SCM_ARGS(2);
ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_MSS_RESET, &desc,
&res);
return ret ? : res.a1;
} }
...@@ -10,19 +10,64 @@ ...@@ -10,19 +10,64 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/ */
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/cpumask.h> #include <linux/cpumask.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/dma-mapping.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/qcom_scm.h> #include <linux/qcom_scm.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/clk.h>
#include <linux/reset-controller.h>
#include "qcom_scm.h" #include "qcom_scm.h"
struct qcom_scm {
struct device *dev;
struct clk *core_clk;
struct clk *iface_clk;
struct clk *bus_clk;
struct reset_controller_dev reset;
};
static struct qcom_scm *__scm;
static int qcom_scm_clk_enable(void)
{
int ret;
ret = clk_prepare_enable(__scm->core_clk);
if (ret)
goto bail;
ret = clk_prepare_enable(__scm->iface_clk);
if (ret)
goto disable_core;
ret = clk_prepare_enable(__scm->bus_clk);
if (ret)
goto disable_iface;
return 0;
disable_iface:
clk_disable_unprepare(__scm->iface_clk);
disable_core:
clk_disable_unprepare(__scm->core_clk);
bail:
return ret;
}
static void qcom_scm_clk_disable(void)
{
clk_disable_unprepare(__scm->core_clk);
clk_disable_unprepare(__scm->iface_clk);
clk_disable_unprepare(__scm->bus_clk);
}
/** /**
* qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus
* @entry: Entry point function for the cpus * @entry: Entry point function for the cpus
...@@ -47,7 +92,7 @@ EXPORT_SYMBOL(qcom_scm_set_cold_boot_addr); ...@@ -47,7 +92,7 @@ EXPORT_SYMBOL(qcom_scm_set_cold_boot_addr);
*/ */
int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus) int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus)
{ {
return __qcom_scm_set_warm_boot_addr(entry, cpus); return __qcom_scm_set_warm_boot_addr(__scm->dev, entry, cpus);
} }
EXPORT_SYMBOL(qcom_scm_set_warm_boot_addr); EXPORT_SYMBOL(qcom_scm_set_warm_boot_addr);
...@@ -72,12 +117,17 @@ EXPORT_SYMBOL(qcom_scm_cpu_power_down); ...@@ -72,12 +117,17 @@ EXPORT_SYMBOL(qcom_scm_cpu_power_down);
*/ */
bool qcom_scm_hdcp_available(void) bool qcom_scm_hdcp_available(void)
{ {
int ret; int ret = qcom_scm_clk_enable();
ret = __qcom_scm_is_call_available(QCOM_SCM_SVC_HDCP, if (ret)
QCOM_SCM_CMD_HDCP); return ret;
return (ret > 0) ? true : false; ret = __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_HDCP,
QCOM_SCM_CMD_HDCP);
qcom_scm_clk_disable();
return ret > 0 ? true : false;
} }
EXPORT_SYMBOL(qcom_scm_hdcp_available); EXPORT_SYMBOL(qcom_scm_hdcp_available);
...@@ -91,6 +141,287 @@ EXPORT_SYMBOL(qcom_scm_hdcp_available); ...@@ -91,6 +141,287 @@ EXPORT_SYMBOL(qcom_scm_hdcp_available);
*/ */
int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp) int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp)
{ {
return __qcom_scm_hdcp_req(req, req_cnt, resp); int ret = qcom_scm_clk_enable();
if (ret)
return ret;
ret = __qcom_scm_hdcp_req(__scm->dev, req, req_cnt, resp);
qcom_scm_clk_disable();
return ret;
} }
EXPORT_SYMBOL(qcom_scm_hdcp_req); EXPORT_SYMBOL(qcom_scm_hdcp_req);
/**
* qcom_scm_pas_supported() - Check if the peripheral authentication service is
* available for the given peripherial
* @peripheral: peripheral id
*
* Returns true if PAS is supported for this peripheral, otherwise false.
*/
bool qcom_scm_pas_supported(u32 peripheral)
{
int ret;
ret = __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL,
QCOM_SCM_PAS_IS_SUPPORTED_CMD);
if (ret <= 0)
return false;
return __qcom_scm_pas_supported(__scm->dev, peripheral);
}
EXPORT_SYMBOL(qcom_scm_pas_supported);
/**
* qcom_scm_pas_init_image() - Initialize peripheral authentication service
* state machine for a given peripheral, using the
* metadata
* @peripheral: peripheral id
* @metadata: pointer to memory containing ELF header, program header table
* and optional blob of data used for authenticating the metadata
* and the rest of the firmware
* @size: size of the metadata
*
* Returns 0 on success.
*/
int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size)
{
dma_addr_t mdata_phys;
void *mdata_buf;
int ret;
/*
* During the scm call memory protection will be enabled for the meta
* data blob, so make sure it's physically contiguous, 4K aligned and
* non-cachable to avoid XPU violations.
*/
mdata_buf = dma_alloc_coherent(__scm->dev, size, &mdata_phys,
GFP_KERNEL);
if (!mdata_buf) {
dev_err(__scm->dev, "Allocation of metadata buffer failed.\n");
return -ENOMEM;
}
memcpy(mdata_buf, metadata, size);
ret = qcom_scm_clk_enable();
if (ret)
goto free_metadata;
ret = __qcom_scm_pas_init_image(__scm->dev, peripheral, mdata_phys);
qcom_scm_clk_disable();
free_metadata:
dma_free_coherent(__scm->dev, size, mdata_buf, mdata_phys);
return ret;
}
EXPORT_SYMBOL(qcom_scm_pas_init_image);
/**
* qcom_scm_pas_mem_setup() - Prepare the memory related to a given peripheral
* for firmware loading
* @peripheral: peripheral id
* @addr: start address of memory area to prepare
* @size: size of the memory area to prepare
*
* Returns 0 on success.
*/
int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size)
{
int ret;
ret = qcom_scm_clk_enable();
if (ret)
return ret;
ret = __qcom_scm_pas_mem_setup(__scm->dev, peripheral, addr, size);
qcom_scm_clk_disable();
return ret;
}
EXPORT_SYMBOL(qcom_scm_pas_mem_setup);
/**
* qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware
* and reset the remote processor
* @peripheral: peripheral id
*
* Return 0 on success.
*/
int qcom_scm_pas_auth_and_reset(u32 peripheral)
{
int ret;
ret = qcom_scm_clk_enable();
if (ret)
return ret;
ret = __qcom_scm_pas_auth_and_reset(__scm->dev, peripheral);
qcom_scm_clk_disable();
return ret;
}
EXPORT_SYMBOL(qcom_scm_pas_auth_and_reset);
/**
* qcom_scm_pas_shutdown() - Shut down the remote processor
* @peripheral: peripheral id
*
* Returns 0 on success.
*/
int qcom_scm_pas_shutdown(u32 peripheral)
{
int ret;
ret = qcom_scm_clk_enable();
if (ret)
return ret;
ret = __qcom_scm_pas_shutdown(__scm->dev, peripheral);
qcom_scm_clk_disable();
return ret;
}
EXPORT_SYMBOL(qcom_scm_pas_shutdown);
static int qcom_scm_pas_reset_assert(struct reset_controller_dev *rcdev,
unsigned long idx)
{
if (idx != 0)
return -EINVAL;
return __qcom_scm_pas_mss_reset(__scm->dev, 1);
}
static int qcom_scm_pas_reset_deassert(struct reset_controller_dev *rcdev,
unsigned long idx)
{
if (idx != 0)
return -EINVAL;
return __qcom_scm_pas_mss_reset(__scm->dev, 0);
}
static const struct reset_control_ops qcom_scm_pas_reset_ops = {
.assert = qcom_scm_pas_reset_assert,
.deassert = qcom_scm_pas_reset_deassert,
};
/**
* qcom_scm_is_available() - Checks if SCM is available
*/
bool qcom_scm_is_available(void)
{
return !!__scm;
}
EXPORT_SYMBOL(qcom_scm_is_available);
static int qcom_scm_probe(struct platform_device *pdev)
{
struct qcom_scm *scm;
int ret;
scm = devm_kzalloc(&pdev->dev, sizeof(*scm), GFP_KERNEL);
if (!scm)
return -ENOMEM;
scm->core_clk = devm_clk_get(&pdev->dev, "core");
if (IS_ERR(scm->core_clk)) {
if (PTR_ERR(scm->core_clk) == -EPROBE_DEFER)
return PTR_ERR(scm->core_clk);
scm->core_clk = NULL;
}
if (of_device_is_compatible(pdev->dev.of_node, "qcom,scm")) {
scm->iface_clk = devm_clk_get(&pdev->dev, "iface");
if (IS_ERR(scm->iface_clk)) {
if (PTR_ERR(scm->iface_clk) != -EPROBE_DEFER)
dev_err(&pdev->dev, "failed to acquire iface clk\n");
return PTR_ERR(scm->iface_clk);
}
scm->bus_clk = devm_clk_get(&pdev->dev, "bus");
if (IS_ERR(scm->bus_clk)) {
if (PTR_ERR(scm->bus_clk) != -EPROBE_DEFER)
dev_err(&pdev->dev, "failed to acquire bus clk\n");
return PTR_ERR(scm->bus_clk);
}
}
scm->reset.ops = &qcom_scm_pas_reset_ops;
scm->reset.nr_resets = 1;
scm->reset.of_node = pdev->dev.of_node;
reset_controller_register(&scm->reset);
/* vote for max clk rate for highest performance */
ret = clk_set_rate(scm->core_clk, INT_MAX);
if (ret)
return ret;
__scm = scm;
__scm->dev = &pdev->dev;
__qcom_scm_init();
return 0;
}
static const struct of_device_id qcom_scm_dt_match[] = {
{ .compatible = "qcom,scm-apq8064",},
{ .compatible = "qcom,scm-msm8660",},
{ .compatible = "qcom,scm-msm8960",},
{ .compatible = "qcom,scm",},
{}
};
MODULE_DEVICE_TABLE(of, qcom_scm_dt_match);
static struct platform_driver qcom_scm_driver = {
.driver = {
.name = "qcom_scm",
.of_match_table = qcom_scm_dt_match,
},
.probe = qcom_scm_probe,
};
static int __init qcom_scm_init(void)
{
struct device_node *np, *fw_np;
int ret;
fw_np = of_find_node_by_name(NULL, "firmware");
if (!fw_np)
return -ENODEV;
np = of_find_matching_node(fw_np, qcom_scm_dt_match);
if (!np) {
of_node_put(fw_np);
return -ENODEV;
}
of_node_put(np);
ret = of_platform_populate(fw_np, qcom_scm_dt_match, NULL, NULL);
of_node_put(fw_np);
if (ret)
return ret;
return platform_driver_register(&qcom_scm_driver);
}
subsys_initcall(qcom_scm_init);
static void __exit qcom_scm_exit(void)
{
platform_driver_unregister(&qcom_scm_driver);
}
module_exit(qcom_scm_exit);
MODULE_DESCRIPTION("Qualcomm SCM driver");
MODULE_LICENSE("GPL v2");
...@@ -19,7 +19,8 @@ ...@@ -19,7 +19,8 @@
#define QCOM_SCM_FLAG_HLOS 0x01 #define QCOM_SCM_FLAG_HLOS 0x01
#define QCOM_SCM_FLAG_COLDBOOT_MC 0x02 #define QCOM_SCM_FLAG_COLDBOOT_MC 0x02
#define QCOM_SCM_FLAG_WARMBOOT_MC 0x04 #define QCOM_SCM_FLAG_WARMBOOT_MC 0x04
extern int __qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus); extern int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry,
const cpumask_t *cpus);
extern int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus); extern int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus);
#define QCOM_SCM_CMD_TERMINATE_PC 0x2 #define QCOM_SCM_CMD_TERMINATE_PC 0x2
...@@ -29,14 +30,34 @@ extern void __qcom_scm_cpu_power_down(u32 flags); ...@@ -29,14 +30,34 @@ extern void __qcom_scm_cpu_power_down(u32 flags);
#define QCOM_SCM_SVC_INFO 0x6 #define QCOM_SCM_SVC_INFO 0x6
#define QCOM_IS_CALL_AVAIL_CMD 0x1 #define QCOM_IS_CALL_AVAIL_CMD 0x1
extern int __qcom_scm_is_call_available(u32 svc_id, u32 cmd_id); extern int __qcom_scm_is_call_available(struct device *dev, u32 svc_id,
u32 cmd_id);
#define QCOM_SCM_SVC_HDCP 0x11 #define QCOM_SCM_SVC_HDCP 0x11
#define QCOM_SCM_CMD_HDCP 0x01 #define QCOM_SCM_CMD_HDCP 0x01
extern int __qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, extern int __qcom_scm_hdcp_req(struct device *dev,
u32 *resp); struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp);
extern void __qcom_scm_init(void);
#define QCOM_SCM_SVC_PIL 0x2
#define QCOM_SCM_PAS_INIT_IMAGE_CMD 0x1
#define QCOM_SCM_PAS_MEM_SETUP_CMD 0x2
#define QCOM_SCM_PAS_AUTH_AND_RESET_CMD 0x5
#define QCOM_SCM_PAS_SHUTDOWN_CMD 0x6
#define QCOM_SCM_PAS_IS_SUPPORTED_CMD 0x7
#define QCOM_SCM_PAS_MSS_RESET 0xa
extern bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral);
extern int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral,
dma_addr_t metadata_phys);
extern int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral,
phys_addr_t addr, phys_addr_t size);
extern int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral);
extern int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral);
extern int __qcom_scm_pas_mss_reset(struct device *dev, bool reset);
/* common error codes */ /* common error codes */
#define QCOM_SCM_V2_EBUSY -12
#define QCOM_SCM_ENOMEM -5 #define QCOM_SCM_ENOMEM -5
#define QCOM_SCM_EOPNOTSUPP -4 #define QCOM_SCM_EOPNOTSUPP -4
#define QCOM_SCM_EINVAL_ADDR -3 #define QCOM_SCM_EINVAL_ADDR -3
...@@ -44,4 +65,22 @@ extern int __qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, ...@@ -44,4 +65,22 @@ extern int __qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
#define QCOM_SCM_ERROR -1 #define QCOM_SCM_ERROR -1
#define QCOM_SCM_INTERRUPTED 1 #define QCOM_SCM_INTERRUPTED 1
static inline int qcom_scm_remap_error(int err)
{
switch (err) {
case QCOM_SCM_ERROR:
return -EIO;
case QCOM_SCM_EINVAL_ADDR:
case QCOM_SCM_EINVAL_ARG:
return -EINVAL;
case QCOM_SCM_EOPNOTSUPP:
return -EOPNOTSUPP;
case QCOM_SCM_ENOMEM:
return -ENOMEM;
case QCOM_SCM_V2_EBUSY:
return -EBUSY;
}
return -EINVAL;
}
#endif #endif
/*
* SCPI Generic power domain support.
*
* Copyright (C) 2016 ARM Ltd.
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/pm_domain.h>
#include <linux/scpi_protocol.h>
struct scpi_pm_domain {
struct generic_pm_domain genpd;
struct scpi_ops *ops;
u32 domain;
char name[30];
};
/*
* These device power state values are not well-defined in the specification.
* In case, different implementations use different values, we can make these
* specific to compatibles rather than getting these values from device tree.
*/
enum scpi_power_domain_state {
SCPI_PD_STATE_ON = 0,
SCPI_PD_STATE_OFF = 3,
};
#define to_scpi_pd(gpd) container_of(gpd, struct scpi_pm_domain, genpd)
static int scpi_pd_power(struct scpi_pm_domain *pd, bool power_on)
{
int ret;
enum scpi_power_domain_state state;
if (power_on)
state = SCPI_PD_STATE_ON;
else
state = SCPI_PD_STATE_OFF;
ret = pd->ops->device_set_power_state(pd->domain, state);
if (ret)
return ret;
return !(state == pd->ops->device_get_power_state(pd->domain));
}
static int scpi_pd_power_on(struct generic_pm_domain *domain)
{
struct scpi_pm_domain *pd = to_scpi_pd(domain);
return scpi_pd_power(pd, true);
}
static int scpi_pd_power_off(struct generic_pm_domain *domain)
{
struct scpi_pm_domain *pd = to_scpi_pd(domain);
return scpi_pd_power(pd, false);
}
static int scpi_pm_domain_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct scpi_pm_domain *scpi_pd;
struct genpd_onecell_data *scpi_pd_data;
struct generic_pm_domain **domains;
struct scpi_ops *scpi_ops;
int ret, num_domains, i;
scpi_ops = get_scpi_ops();
if (!scpi_ops)
return -EPROBE_DEFER;
if (!np) {
dev_err(dev, "device tree node not found\n");
return -ENODEV;
}
if (!scpi_ops->device_set_power_state ||
!scpi_ops->device_get_power_state) {
dev_err(dev, "power domains not supported in the firmware\n");
return -ENODEV;
}
ret = of_property_read_u32(np, "num-domains", &num_domains);
if (ret) {
dev_err(dev, "number of domains not found\n");
return -EINVAL;
}
scpi_pd = devm_kcalloc(dev, num_domains, sizeof(*scpi_pd), GFP_KERNEL);
if (!scpi_pd)
return -ENOMEM;
scpi_pd_data = devm_kzalloc(dev, sizeof(*scpi_pd_data), GFP_KERNEL);
if (!scpi_pd_data)
return -ENOMEM;
domains = devm_kcalloc(dev, num_domains, sizeof(*domains), GFP_KERNEL);
if (!domains)
return -ENOMEM;
for (i = 0; i < num_domains; i++, scpi_pd++) {
domains[i] = &scpi_pd->genpd;
scpi_pd->domain = i;
scpi_pd->ops = scpi_ops;
sprintf(scpi_pd->name, "%s.%d", np->name, i);
scpi_pd->genpd.name = scpi_pd->name;
scpi_pd->genpd.power_off = scpi_pd_power_off;
scpi_pd->genpd.power_on = scpi_pd_power_on;
/*
* Treat all power domains as off at boot.
*
* The SCP firmware itself may have switched on some domains,
* but for reference counting purpose, keep it this way.
*/
pm_genpd_init(&scpi_pd->genpd, NULL, true);
}
scpi_pd_data->domains = domains;
scpi_pd_data->num_domains = num_domains;
of_genpd_add_provider_onecell(np, scpi_pd_data);
return 0;
}
static const struct of_device_id scpi_power_domain_ids[] = {
{ .compatible = "arm,scpi-power-domains", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, scpi_power_domain_ids);
static struct platform_driver scpi_power_domain_driver = {
.driver = {
.name = "scpi_power_domain",
.of_match_table = scpi_power_domain_ids,
},
.probe = scpi_pm_domain_probe,
};
module_platform_driver(scpi_power_domain_driver);
MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
MODULE_DESCRIPTION("ARM SCPI power domain driver");
MODULE_LICENSE("GPL v2");
...@@ -101,7 +101,7 @@ static int clps711x_keypad_probe(struct platform_device *pdev) ...@@ -101,7 +101,7 @@ static int clps711x_keypad_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
priv->syscon = priv->syscon =
syscon_regmap_lookup_by_compatible("cirrus,clps711x-syscon1"); syscon_regmap_lookup_by_compatible("cirrus,ep7209-syscon1");
if (IS_ERR(priv->syscon)) if (IS_ERR(priv->syscon))
return PTR_ERR(priv->syscon); return PTR_ERR(priv->syscon);
...@@ -181,7 +181,7 @@ static int clps711x_keypad_remove(struct platform_device *pdev) ...@@ -181,7 +181,7 @@ static int clps711x_keypad_remove(struct platform_device *pdev)
} }
static const struct of_device_id clps711x_keypad_of_match[] = { static const struct of_device_id clps711x_keypad_of_match[] = {
{ .compatible = "cirrus,clps711x-keypad", }, { .compatible = "cirrus,ep7209-keypad", },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, clps711x_keypad_of_match); MODULE_DEVICE_TABLE(of, clps711x_keypad_of_match);
......
...@@ -234,5 +234,5 @@ static int __init clps711x_intc_init_dt(struct device_node *np, ...@@ -234,5 +234,5 @@ static int __init clps711x_intc_init_dt(struct device_node *np,
return _clps711x_intc_init(np, res.start, resource_size(&res)); return _clps711x_intc_init(np, res.start, resource_size(&res));
} }
IRQCHIP_DECLARE(clps711x, "cirrus,clps711x-intc", clps711x_intc_init_dt); IRQCHIP_DECLARE(clps711x, "cirrus,ep7209-intc", clps711x_intc_init_dt);
#endif #endif
...@@ -336,7 +336,7 @@ config IR_TTUSBIR ...@@ -336,7 +336,7 @@ config IR_TTUSBIR
config IR_RX51 config IR_RX51
tristate "Nokia N900 IR transmitter diode" tristate "Nokia N900 IR transmitter diode"
depends on OMAP_DM_TIMER && ARCH_OMAP2PLUS && LIRC && !ARCH_MULTIPLATFORM depends on OMAP_DM_TIMER && PWM_OMAP_DMTIMER && ARCH_OMAP2PLUS && LIRC
---help--- ---help---
Say Y or M here if you want to enable support for the IR Say Y or M here if you want to enable support for the IR
transmitter diode built in the Nokia N900 (RX51) device. transmitter diode built in the Nokia N900 (RX51) device.
......
...@@ -12,22 +12,17 @@ ...@@ -12,22 +12,17 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/ */
#include <linux/clk.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/pwm.h>
#include <plat/dmtimer.h> #include <linux/of.h>
#include <plat/clock.h> #include <linux/hrtimer.h>
#include <media/lirc.h> #include <media/lirc.h>
#include <media/lirc_dev.h> #include <media/lirc_dev.h>
...@@ -41,100 +36,51 @@ ...@@ -41,100 +36,51 @@
#define WBUF_LEN 256 #define WBUF_LEN 256
#define TIMER_MAX_VALUE 0xffffffff
struct lirc_rx51 { struct lirc_rx51 {
struct omap_dm_timer *pwm_timer; struct pwm_device *pwm;
struct omap_dm_timer *pulse_timer; struct hrtimer timer;
struct device *dev; struct device *dev;
struct lirc_rx51_platform_data *pdata; struct lirc_rx51_platform_data *pdata;
wait_queue_head_t wqueue; wait_queue_head_t wqueue;
unsigned long fclk_khz;
unsigned int freq; /* carrier frequency */ unsigned int freq; /* carrier frequency */
unsigned int duty_cycle; /* carrier duty cycle */ unsigned int duty_cycle; /* carrier duty cycle */
unsigned int irq_num;
unsigned int match;
int wbuf[WBUF_LEN]; int wbuf[WBUF_LEN];
int wbuf_index; int wbuf_index;
unsigned long device_is_open; unsigned long device_is_open;
int pwm_timer_num;
}; };
static void lirc_rx51_on(struct lirc_rx51 *lirc_rx51) static inline void lirc_rx51_on(struct lirc_rx51 *lirc_rx51)
{ {
omap_dm_timer_set_pwm(lirc_rx51->pwm_timer, 0, 1, pwm_enable(lirc_rx51->pwm);
OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE);
} }
static void lirc_rx51_off(struct lirc_rx51 *lirc_rx51) static inline void lirc_rx51_off(struct lirc_rx51 *lirc_rx51)
{ {
omap_dm_timer_set_pwm(lirc_rx51->pwm_timer, 0, 1, pwm_disable(lirc_rx51->pwm);
OMAP_TIMER_TRIGGER_NONE);
} }
static int init_timing_params(struct lirc_rx51 *lirc_rx51) static int init_timing_params(struct lirc_rx51 *lirc_rx51)
{ {
u32 load, match; struct pwm_device *pwm = lirc_rx51->pwm;
int duty, period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, lirc_rx51->freq);
load = -(lirc_rx51->fclk_khz * 1000 / lirc_rx51->freq); duty = DIV_ROUND_CLOSEST(lirc_rx51->duty_cycle * period, 100);
match = -(lirc_rx51->duty_cycle * -load / 100);
omap_dm_timer_set_load(lirc_rx51->pwm_timer, 1, load);
omap_dm_timer_set_match(lirc_rx51->pwm_timer, 1, match);
omap_dm_timer_write_counter(lirc_rx51->pwm_timer, TIMER_MAX_VALUE - 2);
omap_dm_timer_start(lirc_rx51->pwm_timer);
omap_dm_timer_set_int_enable(lirc_rx51->pulse_timer, 0);
omap_dm_timer_start(lirc_rx51->pulse_timer);
lirc_rx51->match = 0; pwm_config(pwm, duty, period);
return 0; return 0;
} }
#define tics_after(a, b) ((long)(b) - (long)(a) < 0) static enum hrtimer_restart lirc_rx51_timer_cb(struct hrtimer *timer)
static int pulse_timer_set_timeout(struct lirc_rx51 *lirc_rx51, int usec)
{ {
int counter; struct lirc_rx51 *lirc_rx51 =
container_of(timer, struct lirc_rx51, timer);
BUG_ON(usec < 0); ktime_t now;
if (lirc_rx51->match == 0)
counter = omap_dm_timer_read_counter(lirc_rx51->pulse_timer);
else
counter = lirc_rx51->match;
counter += (u32)(lirc_rx51->fclk_khz * usec / (1000));
omap_dm_timer_set_match(lirc_rx51->pulse_timer, 1, counter);
omap_dm_timer_set_int_enable(lirc_rx51->pulse_timer,
OMAP_TIMER_INT_MATCH);
if (tics_after(omap_dm_timer_read_counter(lirc_rx51->pulse_timer),
counter)) {
return 1;
}
return 0;
}
static irqreturn_t lirc_rx51_interrupt_handler(int irq, void *ptr)
{
unsigned int retval;
struct lirc_rx51 *lirc_rx51 = ptr;
retval = omap_dm_timer_read_status(lirc_rx51->pulse_timer);
if (!retval)
return IRQ_NONE;
if (retval & ~OMAP_TIMER_INT_MATCH)
dev_err_ratelimited(lirc_rx51->dev,
": Unexpected interrupt source: %x\n", retval);
omap_dm_timer_write_status(lirc_rx51->pulse_timer,
OMAP_TIMER_INT_MATCH |
OMAP_TIMER_INT_OVERFLOW |
OMAP_TIMER_INT_CAPTURE);
if (lirc_rx51->wbuf_index < 0) { if (lirc_rx51->wbuf_index < 0) {
dev_err_ratelimited(lirc_rx51->dev, dev_err_ratelimited(lirc_rx51->dev,
": BUG wbuf_index has value of %i\n", "BUG wbuf_index has value of %i\n",
lirc_rx51->wbuf_index); lirc_rx51->wbuf_index);
goto end; goto end;
} }
...@@ -144,6 +90,8 @@ static irqreturn_t lirc_rx51_interrupt_handler(int irq, void *ptr) ...@@ -144,6 +90,8 @@ static irqreturn_t lirc_rx51_interrupt_handler(int irq, void *ptr)
* pulses until we catch up. * pulses until we catch up.
*/ */
do { do {
u64 ns;
if (lirc_rx51->wbuf_index >= WBUF_LEN) if (lirc_rx51->wbuf_index >= WBUF_LEN)
goto end; goto end;
if (lirc_rx51->wbuf[lirc_rx51->wbuf_index] == -1) if (lirc_rx51->wbuf[lirc_rx51->wbuf_index] == -1)
...@@ -154,84 +102,24 @@ static irqreturn_t lirc_rx51_interrupt_handler(int irq, void *ptr) ...@@ -154,84 +102,24 @@ static irqreturn_t lirc_rx51_interrupt_handler(int irq, void *ptr)
else else
lirc_rx51_on(lirc_rx51); lirc_rx51_on(lirc_rx51);
retval = pulse_timer_set_timeout(lirc_rx51, ns = 1000 * lirc_rx51->wbuf[lirc_rx51->wbuf_index];
lirc_rx51->wbuf[lirc_rx51->wbuf_index]); hrtimer_add_expires_ns(timer, ns);
lirc_rx51->wbuf_index++; lirc_rx51->wbuf_index++;
} while (retval); now = timer->base->get_time();
} while (hrtimer_get_expires_tv64(timer) < now.tv64);
return IRQ_HANDLED; return HRTIMER_RESTART;
end: end:
/* Stop TX here */ /* Stop TX here */
lirc_rx51_off(lirc_rx51); lirc_rx51_off(lirc_rx51);
lirc_rx51->wbuf_index = -1; lirc_rx51->wbuf_index = -1;
omap_dm_timer_stop(lirc_rx51->pwm_timer);
omap_dm_timer_stop(lirc_rx51->pulse_timer);
omap_dm_timer_set_int_enable(lirc_rx51->pulse_timer, 0);
wake_up_interruptible(&lirc_rx51->wqueue);
return IRQ_HANDLED;
}
static int lirc_rx51_init_port(struct lirc_rx51 *lirc_rx51)
{
struct clk *clk_fclk;
int retval, pwm_timer = lirc_rx51->pwm_timer_num;
lirc_rx51->pwm_timer = omap_dm_timer_request_specific(pwm_timer);
if (lirc_rx51->pwm_timer == NULL) {
dev_err(lirc_rx51->dev, ": Error requesting GPT%d timer\n",
pwm_timer);
return -EBUSY;
}
lirc_rx51->pulse_timer = omap_dm_timer_request();
if (lirc_rx51->pulse_timer == NULL) {
dev_err(lirc_rx51->dev, ": Error requesting pulse timer\n");
retval = -EBUSY;
goto err1;
}
omap_dm_timer_set_source(lirc_rx51->pwm_timer, OMAP_TIMER_SRC_SYS_CLK);
omap_dm_timer_set_source(lirc_rx51->pulse_timer,
OMAP_TIMER_SRC_SYS_CLK);
omap_dm_timer_enable(lirc_rx51->pwm_timer);
omap_dm_timer_enable(lirc_rx51->pulse_timer);
lirc_rx51->irq_num = omap_dm_timer_get_irq(lirc_rx51->pulse_timer);
retval = request_irq(lirc_rx51->irq_num, lirc_rx51_interrupt_handler,
IRQF_SHARED, "lirc_pulse_timer", lirc_rx51);
if (retval) {
dev_err(lirc_rx51->dev, ": Failed to request interrupt line\n");
goto err2;
}
clk_fclk = omap_dm_timer_get_fclk(lirc_rx51->pwm_timer);
lirc_rx51->fclk_khz = clk_fclk->rate / 1000;
return 0;
err2: wake_up_interruptible(&lirc_rx51->wqueue);
omap_dm_timer_free(lirc_rx51->pulse_timer);
err1:
omap_dm_timer_free(lirc_rx51->pwm_timer);
return retval;
}
static int lirc_rx51_free_port(struct lirc_rx51 *lirc_rx51)
{
omap_dm_timer_set_int_enable(lirc_rx51->pulse_timer, 0);
free_irq(lirc_rx51->irq_num, lirc_rx51);
lirc_rx51_off(lirc_rx51);
omap_dm_timer_disable(lirc_rx51->pwm_timer);
omap_dm_timer_disable(lirc_rx51->pulse_timer);
omap_dm_timer_free(lirc_rx51->pwm_timer);
omap_dm_timer_free(lirc_rx51->pulse_timer);
lirc_rx51->wbuf_index = -1;
return 0; return HRTIMER_NORESTART;
} }
static ssize_t lirc_rx51_write(struct file *file, const char *buf, static ssize_t lirc_rx51_write(struct file *file, const char *buf,
...@@ -270,8 +158,9 @@ static ssize_t lirc_rx51_write(struct file *file, const char *buf, ...@@ -270,8 +158,9 @@ static ssize_t lirc_rx51_write(struct file *file, const char *buf,
lirc_rx51_on(lirc_rx51); lirc_rx51_on(lirc_rx51);
lirc_rx51->wbuf_index = 1; lirc_rx51->wbuf_index = 1;
pulse_timer_set_timeout(lirc_rx51, lirc_rx51->wbuf[0]); hrtimer_start(&lirc_rx51->timer,
ns_to_ktime(1000 * lirc_rx51->wbuf[0]),
HRTIMER_MODE_REL);
/* /*
* Don't return back to the userspace until the transfer has * Don't return back to the userspace until the transfer has
* finished * finished
...@@ -371,14 +260,24 @@ static int lirc_rx51_open(struct inode *inode, struct file *file) ...@@ -371,14 +260,24 @@ static int lirc_rx51_open(struct inode *inode, struct file *file)
if (test_and_set_bit(1, &lirc_rx51->device_is_open)) if (test_and_set_bit(1, &lirc_rx51->device_is_open))
return -EBUSY; return -EBUSY;
return lirc_rx51_init_port(lirc_rx51); lirc_rx51->pwm = pwm_get(lirc_rx51->dev, NULL);
if (IS_ERR(lirc_rx51->pwm)) {
int res = PTR_ERR(lirc_rx51->pwm);
dev_err(lirc_rx51->dev, "pwm_get failed: %d\n", res);
return res;
}
return 0;
} }
static int lirc_rx51_release(struct inode *inode, struct file *file) static int lirc_rx51_release(struct inode *inode, struct file *file)
{ {
struct lirc_rx51 *lirc_rx51 = file->private_data; struct lirc_rx51 *lirc_rx51 = file->private_data;
lirc_rx51_free_port(lirc_rx51); hrtimer_cancel(&lirc_rx51->timer);
lirc_rx51_off(lirc_rx51);
pwm_put(lirc_rx51->pwm);
clear_bit(1, &lirc_rx51->device_is_open); clear_bit(1, &lirc_rx51->device_is_open);
...@@ -386,7 +285,6 @@ static int lirc_rx51_release(struct inode *inode, struct file *file) ...@@ -386,7 +285,6 @@ static int lirc_rx51_release(struct inode *inode, struct file *file)
} }
static struct lirc_rx51 lirc_rx51 = { static struct lirc_rx51 lirc_rx51 = {
.freq = 38000,
.duty_cycle = 50, .duty_cycle = 50,
.wbuf_index = -1, .wbuf_index = -1,
}; };
...@@ -444,9 +342,32 @@ static int lirc_rx51_resume(struct platform_device *dev) ...@@ -444,9 +342,32 @@ static int lirc_rx51_resume(struct platform_device *dev)
static int lirc_rx51_probe(struct platform_device *dev) static int lirc_rx51_probe(struct platform_device *dev)
{ {
struct pwm_device *pwm;
lirc_rx51_driver.features = LIRC_RX51_DRIVER_FEATURES; lirc_rx51_driver.features = LIRC_RX51_DRIVER_FEATURES;
lirc_rx51.pdata = dev->dev.platform_data; lirc_rx51.pdata = dev->dev.platform_data;
lirc_rx51.pwm_timer_num = lirc_rx51.pdata->pwm_timer;
if (!lirc_rx51.pdata) {
dev_err(&dev->dev, "Platform Data is missing\n");
return -ENXIO;
}
pwm = pwm_get(&dev->dev, NULL);
if (IS_ERR(pwm)) {
int err = PTR_ERR(pwm);
if (err != -EPROBE_DEFER)
dev_err(&dev->dev, "pwm_get failed: %d\n", err);
return err;
}
/* Use default, in case userspace does not set the carrier */
lirc_rx51.freq = DIV_ROUND_CLOSEST(pwm_get_period(pwm), NSEC_PER_SEC);
pwm_put(pwm);
hrtimer_init(&lirc_rx51.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
lirc_rx51.timer.function = lirc_rx51_timer_cb;
lirc_rx51.dev = &dev->dev; lirc_rx51.dev = &dev->dev;
lirc_rx51_driver.dev = &dev->dev; lirc_rx51_driver.dev = &dev->dev;
lirc_rx51_driver.minor = lirc_register_driver(&lirc_rx51_driver); lirc_rx51_driver.minor = lirc_register_driver(&lirc_rx51_driver);
...@@ -457,8 +378,6 @@ static int lirc_rx51_probe(struct platform_device *dev) ...@@ -457,8 +378,6 @@ static int lirc_rx51_probe(struct platform_device *dev)
lirc_rx51_driver.minor); lirc_rx51_driver.minor);
return lirc_rx51_driver.minor; return lirc_rx51_driver.minor;
} }
dev_info(lirc_rx51.dev, "registration ok, minor: %d, pwm: %d\n",
lirc_rx51_driver.minor, lirc_rx51.pwm_timer_num);
return 0; return 0;
} }
...@@ -468,6 +387,14 @@ static int lirc_rx51_remove(struct platform_device *dev) ...@@ -468,6 +387,14 @@ static int lirc_rx51_remove(struct platform_device *dev)
return lirc_unregister_driver(lirc_rx51_driver.minor); return lirc_unregister_driver(lirc_rx51_driver.minor);
} }
static const struct of_device_id lirc_rx51_match[] = {
{
.compatible = "nokia,n900-ir",
},
{},
};
MODULE_DEVICE_TABLE(of, lirc_rx51_match);
struct platform_driver lirc_rx51_platform_driver = { struct platform_driver lirc_rx51_platform_driver = {
.probe = lirc_rx51_probe, .probe = lirc_rx51_probe,
.remove = lirc_rx51_remove, .remove = lirc_rx51_remove,
...@@ -475,7 +402,7 @@ struct platform_driver lirc_rx51_platform_driver = { ...@@ -475,7 +402,7 @@ struct platform_driver lirc_rx51_platform_driver = {
.resume = lirc_rx51_resume, .resume = lirc_rx51_resume,
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.owner = THIS_MODULE, .of_match_table = of_match_ptr(lirc_rx51_match),
}, },
}; };
module_platform_driver(lirc_rx51_platform_driver); module_platform_driver(lirc_rx51_platform_driver);
......
...@@ -25,6 +25,17 @@ config ATMEL_SDRAMC ...@@ -25,6 +25,17 @@ config ATMEL_SDRAMC
Starting with the at91sam9g45, this controller supports SDR, DDR and Starting with the at91sam9g45, this controller supports SDR, DDR and
LP-DDR memories. LP-DDR memories.
config ATMEL_EBI
bool "Atmel EBI driver"
default y
depends on ARCH_AT91 && OF
select MFD_SYSCON
help
Driver for Atmel EBI controller.
Used to configure the EBI (external bus interface) when the device-
tree is used. This bus supports NANDs, external ethernet controller,
SRAMs, ATA devices, etc.
config TI_AEMIF config TI_AEMIF
tristate "Texas Instruments AEMIF driver" tristate "Texas Instruments AEMIF driver"
depends on (ARCH_DAVINCI || ARCH_KEYSTONE) && OF depends on (ARCH_DAVINCI || ARCH_KEYSTONE) && OF
......
...@@ -7,6 +7,7 @@ obj-$(CONFIG_OF) += of_memory.o ...@@ -7,6 +7,7 @@ obj-$(CONFIG_OF) += of_memory.o
endif endif
obj-$(CONFIG_ARM_PL172_MPMC) += pl172.o obj-$(CONFIG_ARM_PL172_MPMC) += pl172.o
obj-$(CONFIG_ATMEL_SDRAMC) += atmel-sdramc.o obj-$(CONFIG_ATMEL_SDRAMC) += atmel-sdramc.o
obj-$(CONFIG_ATMEL_EBI) += atmel-ebi.o
obj-$(CONFIG_TI_AEMIF) += ti-aemif.o obj-$(CONFIG_TI_AEMIF) += ti-aemif.o
obj-$(CONFIG_TI_EMIF) += emif.o obj-$(CONFIG_TI_EMIF) += emif.o
obj-$(CONFIG_OMAP_GPMC) += omap-gpmc.o obj-$(CONFIG_OMAP_GPMC) += omap-gpmc.o
......
/*
* EBI driver for Atmel chips
* inspired by the fsl weim bus driver
*
* Copyright (C) 2013 Jean-Jacques Hiblot <jjhiblot@traphandler.com>
*
* 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 <linux/clk.h>
#include <linux/io.h>
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/atmel-matrix.h>
#include <linux/mfd/syscon/atmel-smc.h>
#include <linux/init.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
struct at91sam9_smc_timings {
u32 ncs_rd_setup_ns;
u32 nrd_setup_ns;
u32 ncs_wr_setup_ns;
u32 nwe_setup_ns;
u32 ncs_rd_pulse_ns;
u32 nrd_pulse_ns;
u32 ncs_wr_pulse_ns;
u32 nwe_pulse_ns;
u32 nrd_cycle_ns;
u32 nwe_cycle_ns;
u32 tdf_ns;
};
struct at91sam9_smc_generic_fields {
struct regmap_field *setup;
struct regmap_field *pulse;
struct regmap_field *cycle;
struct regmap_field *mode;
};
struct at91sam9_ebi_dev_config {
struct at91sam9_smc_timings timings;
u32 mode;
};
struct at91_ebi_dev_config {
int cs;
union {
struct at91sam9_ebi_dev_config sam9;
};
};
struct at91_ebi;
struct at91_ebi_dev {
struct list_head node;
struct at91_ebi *ebi;
u32 mode;
int numcs;
struct at91_ebi_dev_config configs[];
};
struct at91_ebi_caps {
unsigned int available_cs;
const struct reg_field *ebi_csa;
void (*get_config)(struct at91_ebi_dev *ebid,
struct at91_ebi_dev_config *conf);
int (*xlate_config)(struct at91_ebi_dev *ebid,
struct device_node *configs_np,
struct at91_ebi_dev_config *conf);
int (*apply_config)(struct at91_ebi_dev *ebid,
struct at91_ebi_dev_config *conf);
int (*init)(struct at91_ebi *ebi);
};
struct at91_ebi {
struct clk *clk;
struct regmap *smc;
struct regmap *matrix;
struct regmap_field *ebi_csa;
struct device *dev;
const struct at91_ebi_caps *caps;
struct list_head devs;
union {
struct at91sam9_smc_generic_fields sam9;
};
};
static void at91sam9_ebi_get_config(struct at91_ebi_dev *ebid,
struct at91_ebi_dev_config *conf)
{
struct at91sam9_smc_generic_fields *fields = &ebid->ebi->sam9;
unsigned int clk_rate = clk_get_rate(ebid->ebi->clk);
struct at91sam9_ebi_dev_config *config = &conf->sam9;
struct at91sam9_smc_timings *timings = &config->timings;
unsigned int val;
regmap_fields_read(fields->mode, conf->cs, &val);
config->mode = val & ~AT91_SMC_TDF;
val = (val & AT91_SMC_TDF) >> 16;
timings->tdf_ns = clk_rate * val;
regmap_fields_read(fields->setup, conf->cs, &val);
timings->ncs_rd_setup_ns = (val >> 24) & 0x1f;
timings->ncs_rd_setup_ns += ((val >> 29) & 0x1) * 128;
timings->ncs_rd_setup_ns *= clk_rate;
timings->nrd_setup_ns = (val >> 16) & 0x1f;
timings->nrd_setup_ns += ((val >> 21) & 0x1) * 128;
timings->nrd_setup_ns *= clk_rate;
timings->ncs_wr_setup_ns = (val >> 8) & 0x1f;
timings->ncs_wr_setup_ns += ((val >> 13) & 0x1) * 128;
timings->ncs_wr_setup_ns *= clk_rate;
timings->nwe_setup_ns = val & 0x1f;
timings->nwe_setup_ns += ((val >> 5) & 0x1) * 128;
timings->nwe_setup_ns *= clk_rate;
regmap_fields_read(fields->pulse, conf->cs, &val);
timings->ncs_rd_pulse_ns = (val >> 24) & 0x3f;
timings->ncs_rd_pulse_ns += ((val >> 30) & 0x1) * 256;
timings->ncs_rd_pulse_ns *= clk_rate;
timings->nrd_pulse_ns = (val >> 16) & 0x3f;
timings->nrd_pulse_ns += ((val >> 22) & 0x1) * 256;
timings->nrd_pulse_ns *= clk_rate;
timings->ncs_wr_pulse_ns = (val >> 8) & 0x3f;
timings->ncs_wr_pulse_ns += ((val >> 14) & 0x1) * 256;
timings->ncs_wr_pulse_ns *= clk_rate;
timings->nwe_pulse_ns = val & 0x3f;
timings->nwe_pulse_ns += ((val >> 6) & 0x1) * 256;
timings->nwe_pulse_ns *= clk_rate;
regmap_fields_read(fields->cycle, conf->cs, &val);
timings->nrd_cycle_ns = (val >> 16) & 0x7f;
timings->nrd_cycle_ns += ((val >> 23) & 0x3) * 256;
timings->nrd_cycle_ns *= clk_rate;
timings->nwe_cycle_ns = val & 0x7f;
timings->nwe_cycle_ns += ((val >> 7) & 0x3) * 256;
timings->nwe_cycle_ns *= clk_rate;
}
static int at91_xlate_timing(struct device_node *np, const char *prop,
u32 *val, bool *required)
{
if (!of_property_read_u32(np, prop, val)) {
*required = true;
return 0;
}
if (*required)
return -EINVAL;
return 0;
}
static int at91sam9_smc_xslate_timings(struct at91_ebi_dev *ebid,
struct device_node *np,
struct at91sam9_smc_timings *timings,
bool *required)
{
int ret;
ret = at91_xlate_timing(np, "atmel,smc-ncs-rd-setup-ns",
&timings->ncs_rd_setup_ns, required);
if (ret)
goto out;
ret = at91_xlate_timing(np, "atmel,smc-nrd-setup-ns",
&timings->nrd_setup_ns, required);
if (ret)
goto out;
ret = at91_xlate_timing(np, "atmel,smc-ncs-wr-setup-ns",
&timings->ncs_wr_setup_ns, required);
if (ret)
goto out;
ret = at91_xlate_timing(np, "atmel,smc-nwe-setup-ns",
&timings->nwe_setup_ns, required);
if (ret)
goto out;
ret = at91_xlate_timing(np, "atmel,smc-ncs-rd-pulse-ns",
&timings->ncs_rd_pulse_ns, required);
if (ret)
goto out;
ret = at91_xlate_timing(np, "atmel,smc-nrd-pulse-ns",
&timings->nrd_pulse_ns, required);
if (ret)
goto out;
ret = at91_xlate_timing(np, "atmel,smc-ncs-wr-pulse-ns",
&timings->ncs_wr_pulse_ns, required);
if (ret)
goto out;
ret = at91_xlate_timing(np, "atmel,smc-nwe-pulse-ns",
&timings->nwe_pulse_ns, required);
if (ret)
goto out;
ret = at91_xlate_timing(np, "atmel,smc-nwe-cycle-ns",
&timings->nwe_cycle_ns, required);
if (ret)
goto out;
ret = at91_xlate_timing(np, "atmel,smc-nrd-cycle-ns",
&timings->nrd_cycle_ns, required);
if (ret)
goto out;
ret = at91_xlate_timing(np, "atmel,smc-tdf-ns",
&timings->tdf_ns, required);
out:
if (ret)
dev_err(ebid->ebi->dev,
"missing or invalid timings definition in %s",
np->full_name);
return ret;
}
static int at91sam9_ebi_xslate_config(struct at91_ebi_dev *ebid,
struct device_node *np,
struct at91_ebi_dev_config *conf)
{
struct at91sam9_ebi_dev_config *config = &conf->sam9;
bool required = false;
const char *tmp_str;
u32 tmp;
int ret;
ret = of_property_read_u32(np, "atmel,smc-bus-width", &tmp);
if (!ret) {
switch (tmp) {
case 8:
config->mode |= AT91_SMC_DBW_8;
break;
case 16:
config->mode |= AT91_SMC_DBW_16;
break;
case 32:
config->mode |= AT91_SMC_DBW_32;
break;
default:
return -EINVAL;
}
required = true;
}
if (of_property_read_bool(np, "atmel,smc-tdf-optimized")) {
config->mode |= AT91_SMC_TDFMODE_OPTIMIZED;
required = true;
}
tmp_str = NULL;
of_property_read_string(np, "atmel,smc-byte-access-type", &tmp_str);
if (tmp_str && !strcmp(tmp_str, "write")) {
config->mode |= AT91_SMC_BAT_WRITE;
required = true;
}
tmp_str = NULL;
of_property_read_string(np, "atmel,smc-read-mode", &tmp_str);
if (tmp_str && !strcmp(tmp_str, "nrd")) {
config->mode |= AT91_SMC_READMODE_NRD;
required = true;
}
tmp_str = NULL;
of_property_read_string(np, "atmel,smc-write-mode", &tmp_str);
if (tmp_str && !strcmp(tmp_str, "nwe")) {
config->mode |= AT91_SMC_WRITEMODE_NWE;
required = true;
}
tmp_str = NULL;
of_property_read_string(np, "atmel,smc-exnw-mode", &tmp_str);
if (tmp_str) {
if (!strcmp(tmp_str, "frozen"))
config->mode |= AT91_SMC_EXNWMODE_FROZEN;
else if (!strcmp(tmp_str, "ready"))
config->mode |= AT91_SMC_EXNWMODE_READY;
else if (strcmp(tmp_str, "disabled"))
return -EINVAL;
required = true;
}
ret = of_property_read_u32(np, "atmel,smc-page-mode", &tmp);
if (!ret) {
switch (tmp) {
case 4:
config->mode |= AT91_SMC_PS_4;
break;
case 8:
config->mode |= AT91_SMC_PS_8;
break;
case 16:
config->mode |= AT91_SMC_PS_16;
break;
case 32:
config->mode |= AT91_SMC_PS_32;
break;
default:
return -EINVAL;
}
config->mode |= AT91_SMC_PMEN;
required = true;
}
ret = at91sam9_smc_xslate_timings(ebid, np, &config->timings,
&required);
if (ret)
return ret;
return required;
}
static int at91sam9_ebi_apply_config(struct at91_ebi_dev *ebid,
struct at91_ebi_dev_config *conf)
{
unsigned int clk_rate = clk_get_rate(ebid->ebi->clk);
struct at91sam9_ebi_dev_config *config = &conf->sam9;
struct at91sam9_smc_timings *timings = &config->timings;
struct at91sam9_smc_generic_fields *fields = &ebid->ebi->sam9;
u32 coded_val;
u32 val;
coded_val = at91sam9_smc_setup_ns_to_cycles(clk_rate,
timings->ncs_rd_setup_ns);
val = AT91SAM9_SMC_NCS_NRDSETUP(coded_val);
coded_val = at91sam9_smc_setup_ns_to_cycles(clk_rate,
timings->nrd_setup_ns);
val |= AT91SAM9_SMC_NRDSETUP(coded_val);
coded_val = at91sam9_smc_setup_ns_to_cycles(clk_rate,
timings->ncs_wr_setup_ns);
val |= AT91SAM9_SMC_NCS_WRSETUP(coded_val);
coded_val = at91sam9_smc_setup_ns_to_cycles(clk_rate,
timings->nwe_setup_ns);
val |= AT91SAM9_SMC_NWESETUP(coded_val);
regmap_fields_write(fields->setup, conf->cs, val);
coded_val = at91sam9_smc_pulse_ns_to_cycles(clk_rate,
timings->ncs_rd_pulse_ns);
val = AT91SAM9_SMC_NCS_NRDPULSE(coded_val);
coded_val = at91sam9_smc_pulse_ns_to_cycles(clk_rate,
timings->nrd_pulse_ns);
val |= AT91SAM9_SMC_NRDPULSE(coded_val);
coded_val = at91sam9_smc_pulse_ns_to_cycles(clk_rate,
timings->ncs_wr_pulse_ns);
val |= AT91SAM9_SMC_NCS_WRPULSE(coded_val);
coded_val = at91sam9_smc_pulse_ns_to_cycles(clk_rate,
timings->nwe_pulse_ns);
val |= AT91SAM9_SMC_NWEPULSE(coded_val);
regmap_fields_write(fields->pulse, conf->cs, val);
coded_val = at91sam9_smc_cycle_ns_to_cycles(clk_rate,
timings->nrd_cycle_ns);
val = AT91SAM9_SMC_NRDCYCLE(coded_val);
coded_val = at91sam9_smc_cycle_ns_to_cycles(clk_rate,
timings->nwe_cycle_ns);
val |= AT91SAM9_SMC_NWECYCLE(coded_val);
regmap_fields_write(fields->cycle, conf->cs, val);
val = DIV_ROUND_UP(timings->tdf_ns, clk_rate);
if (val > AT91_SMC_TDF_MAX)
val = AT91_SMC_TDF_MAX;
regmap_fields_write(fields->mode, conf->cs,
config->mode | AT91_SMC_TDF_(val));
return 0;
}
static int at91sam9_ebi_init(struct at91_ebi *ebi)
{
struct at91sam9_smc_generic_fields *fields = &ebi->sam9;
struct reg_field field = REG_FIELD(0, 0, 31);
field.id_size = fls(ebi->caps->available_cs);
field.id_offset = AT91SAM9_SMC_GENERIC_BLK_SZ;
field.reg = AT91SAM9_SMC_SETUP(AT91SAM9_SMC_GENERIC);
fields->setup = devm_regmap_field_alloc(ebi->dev, ebi->smc, field);
if (IS_ERR(fields->setup))
return PTR_ERR(fields->setup);
field.reg = AT91SAM9_SMC_PULSE(AT91SAM9_SMC_GENERIC);
fields->pulse = devm_regmap_field_alloc(ebi->dev, ebi->smc, field);
if (IS_ERR(fields->pulse))
return PTR_ERR(fields->pulse);
field.reg = AT91SAM9_SMC_CYCLE(AT91SAM9_SMC_GENERIC);
fields->cycle = devm_regmap_field_alloc(ebi->dev, ebi->smc, field);
if (IS_ERR(fields->cycle))
return PTR_ERR(fields->cycle);
field.reg = AT91SAM9_SMC_MODE(AT91SAM9_SMC_GENERIC);
fields->mode = devm_regmap_field_alloc(ebi->dev, ebi->smc, field);
if (IS_ERR(fields->mode))
return PTR_ERR(fields->mode);
return 0;
}
static int sama5d3_ebi_init(struct at91_ebi *ebi)
{
struct at91sam9_smc_generic_fields *fields = &ebi->sam9;
struct reg_field field = REG_FIELD(0, 0, 31);
field.id_size = fls(ebi->caps->available_cs);
field.id_offset = SAMA5_SMC_GENERIC_BLK_SZ;
field.reg = AT91SAM9_SMC_SETUP(SAMA5_SMC_GENERIC);
fields->setup = devm_regmap_field_alloc(ebi->dev, ebi->smc, field);
if (IS_ERR(fields->setup))
return PTR_ERR(fields->setup);
field.reg = AT91SAM9_SMC_PULSE(SAMA5_SMC_GENERIC);
fields->pulse = devm_regmap_field_alloc(ebi->dev, ebi->smc, field);
if (IS_ERR(fields->pulse))
return PTR_ERR(fields->pulse);
field.reg = AT91SAM9_SMC_CYCLE(SAMA5_SMC_GENERIC);
fields->cycle = devm_regmap_field_alloc(ebi->dev, ebi->smc, field);
if (IS_ERR(fields->cycle))
return PTR_ERR(fields->cycle);
field.reg = SAMA5_SMC_MODE(SAMA5_SMC_GENERIC);
fields->mode = devm_regmap_field_alloc(ebi->dev, ebi->smc, field);
if (IS_ERR(fields->mode))
return PTR_ERR(fields->mode);
return 0;
}
static int at91_ebi_dev_setup(struct at91_ebi *ebi, struct device_node *np,
int reg_cells)
{
const struct at91_ebi_caps *caps = ebi->caps;
struct at91_ebi_dev_config conf = { };
struct device *dev = ebi->dev;
struct at91_ebi_dev *ebid;
int ret, numcs = 0, i;
bool apply = false;
numcs = of_property_count_elems_of_size(np, "reg",
reg_cells * sizeof(u32));
if (numcs <= 0) {
dev_err(dev, "invalid reg property in %s\n", np->full_name);
return -EINVAL;
}
ebid = devm_kzalloc(ebi->dev,
sizeof(*ebid) + (numcs * sizeof(*ebid->configs)),
GFP_KERNEL);
if (!ebid)
return -ENOMEM;
ebid->ebi = ebi;
ret = caps->xlate_config(ebid, np, &conf);
if (ret < 0)
return ret;
else if (ret)
apply = true;
for (i = 0; i < numcs; i++) {
u32 cs;
ret = of_property_read_u32_index(np, "reg", i * reg_cells,
&cs);
if (ret)
return ret;
if (cs > AT91_MATRIX_EBI_NUM_CS ||
!(ebi->caps->available_cs & BIT(cs))) {
dev_err(dev, "invalid reg property in %s\n",
np->full_name);
return -EINVAL;
}
ebid->configs[i].cs = cs;
if (apply) {
conf.cs = cs;
ret = caps->apply_config(ebid, &conf);
if (ret)
return ret;
}
caps->get_config(ebid, &ebid->configs[i]);
/*
* Attach the EBI device to the generic SMC logic if at least
* one "atmel,smc-" property is present.
*/
if (ebi->ebi_csa && ret)
regmap_field_update_bits(ebi->ebi_csa,
BIT(cs), 0);
}
list_add_tail(&ebid->node, &ebi->devs);
return 0;
}
static const struct reg_field at91sam9260_ebi_csa =
REG_FIELD(AT91SAM9260_MATRIX_EBICSA, 0,
AT91_MATRIX_EBI_NUM_CS - 1);
static const struct at91_ebi_caps at91sam9260_ebi_caps = {
.available_cs = 0xff,
.ebi_csa = &at91sam9260_ebi_csa,
.get_config = at91sam9_ebi_get_config,
.xlate_config = at91sam9_ebi_xslate_config,
.apply_config = at91sam9_ebi_apply_config,
.init = at91sam9_ebi_init,
};
static const struct reg_field at91sam9261_ebi_csa =
REG_FIELD(AT91SAM9261_MATRIX_EBICSA, 0,
AT91_MATRIX_EBI_NUM_CS - 1);
static const struct at91_ebi_caps at91sam9261_ebi_caps = {
.available_cs = 0xff,
.ebi_csa = &at91sam9261_ebi_csa,
.get_config = at91sam9_ebi_get_config,
.xlate_config = at91sam9_ebi_xslate_config,
.apply_config = at91sam9_ebi_apply_config,
.init = at91sam9_ebi_init,
};
static const struct reg_field at91sam9263_ebi0_csa =
REG_FIELD(AT91SAM9263_MATRIX_EBI0CSA, 0,
AT91_MATRIX_EBI_NUM_CS - 1);
static const struct at91_ebi_caps at91sam9263_ebi0_caps = {
.available_cs = 0x3f,
.ebi_csa = &at91sam9263_ebi0_csa,
.get_config = at91sam9_ebi_get_config,
.xlate_config = at91sam9_ebi_xslate_config,
.apply_config = at91sam9_ebi_apply_config,
.init = at91sam9_ebi_init,
};
static const struct reg_field at91sam9263_ebi1_csa =
REG_FIELD(AT91SAM9263_MATRIX_EBI1CSA, 0,
AT91_MATRIX_EBI_NUM_CS - 1);
static const struct at91_ebi_caps at91sam9263_ebi1_caps = {
.available_cs = 0x7,
.ebi_csa = &at91sam9263_ebi1_csa,
.get_config = at91sam9_ebi_get_config,
.xlate_config = at91sam9_ebi_xslate_config,
.apply_config = at91sam9_ebi_apply_config,
.init = at91sam9_ebi_init,
};
static const struct reg_field at91sam9rl_ebi_csa =
REG_FIELD(AT91SAM9RL_MATRIX_EBICSA, 0,
AT91_MATRIX_EBI_NUM_CS - 1);
static const struct at91_ebi_caps at91sam9rl_ebi_caps = {
.available_cs = 0x3f,
.ebi_csa = &at91sam9rl_ebi_csa,
.get_config = at91sam9_ebi_get_config,
.xlate_config = at91sam9_ebi_xslate_config,
.apply_config = at91sam9_ebi_apply_config,
.init = at91sam9_ebi_init,
};
static const struct reg_field at91sam9g45_ebi_csa =
REG_FIELD(AT91SAM9G45_MATRIX_EBICSA, 0,
AT91_MATRIX_EBI_NUM_CS - 1);
static const struct at91_ebi_caps at91sam9g45_ebi_caps = {
.available_cs = 0x3f,
.ebi_csa = &at91sam9g45_ebi_csa,
.get_config = at91sam9_ebi_get_config,
.xlate_config = at91sam9_ebi_xslate_config,
.apply_config = at91sam9_ebi_apply_config,
.init = at91sam9_ebi_init,
};
static const struct at91_ebi_caps at91sam9x5_ebi_caps = {
.available_cs = 0x3f,
.ebi_csa = &at91sam9263_ebi0_csa,
.get_config = at91sam9_ebi_get_config,
.xlate_config = at91sam9_ebi_xslate_config,
.apply_config = at91sam9_ebi_apply_config,
.init = at91sam9_ebi_init,
};
static const struct at91_ebi_caps sama5d3_ebi_caps = {
.available_cs = 0xf,
.get_config = at91sam9_ebi_get_config,
.xlate_config = at91sam9_ebi_xslate_config,
.apply_config = at91sam9_ebi_apply_config,
.init = sama5d3_ebi_init,
};
static const struct of_device_id at91_ebi_id_table[] = {
{
.compatible = "atmel,at91sam9260-ebi",
.data = &at91sam9260_ebi_caps,
},
{
.compatible = "atmel,at91sam9261-ebi",
.data = &at91sam9261_ebi_caps,
},
{
.compatible = "atmel,at91sam9263-ebi0",
.data = &at91sam9263_ebi0_caps,
},
{
.compatible = "atmel,at91sam9263-ebi1",
.data = &at91sam9263_ebi1_caps,
},
{
.compatible = "atmel,at91sam9rl-ebi",
.data = &at91sam9rl_ebi_caps,
},
{
.compatible = "atmel,at91sam9g45-ebi",
.data = &at91sam9g45_ebi_caps,
},
{
.compatible = "atmel,at91sam9x5-ebi",
.data = &at91sam9x5_ebi_caps,
},
{
.compatible = "atmel,sama5d3-ebi",
.data = &sama5d3_ebi_caps,
},
{ /* sentinel */ }
};
static int at91_ebi_dev_disable(struct at91_ebi *ebi, struct device_node *np)
{
struct device *dev = ebi->dev;
struct property *newprop;
newprop = devm_kzalloc(dev, sizeof(*newprop), GFP_KERNEL);
if (!newprop)
return -ENOMEM;
newprop->name = devm_kstrdup(dev, "status", GFP_KERNEL);
if (!newprop->name)
return -ENOMEM;
newprop->value = devm_kstrdup(dev, "disabled", GFP_KERNEL);
if (!newprop->name)
return -ENOMEM;
newprop->length = sizeof("disabled");
return of_update_property(np, newprop);
}
static int at91_ebi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *child, *np = dev->of_node;
const struct of_device_id *match;
struct at91_ebi *ebi;
int ret, reg_cells;
struct clk *clk;
u32 val;
match = of_match_device(at91_ebi_id_table, dev);
if (!match || !match->data)
return -EINVAL;
ebi = devm_kzalloc(dev, sizeof(*ebi), GFP_KERNEL);
if (!ebi)
return -ENOMEM;
INIT_LIST_HEAD(&ebi->devs);
ebi->caps = match->data;
ebi->dev = dev;
clk = devm_clk_get(dev, NULL);
if (IS_ERR(clk))
return PTR_ERR(clk);
ebi->clk = clk;
ebi->smc = syscon_regmap_lookup_by_phandle(np, "atmel,smc");
if (IS_ERR(ebi->smc))
return PTR_ERR(ebi->smc);
/*
* The sama5d3 does not provide an EBICSA register and thus does need
* to access the matrix registers.
*/
if (ebi->caps->ebi_csa) {
ebi->matrix =
syscon_regmap_lookup_by_phandle(np, "atmel,matrix");
if (IS_ERR(ebi->matrix))
return PTR_ERR(ebi->matrix);
ebi->ebi_csa = regmap_field_alloc(ebi->matrix,
*ebi->caps->ebi_csa);
if (IS_ERR(ebi->ebi_csa))
return PTR_ERR(ebi->ebi_csa);
}
ret = ebi->caps->init(ebi);
if (ret)
return ret;
ret = of_property_read_u32(np, "#address-cells", &val);
if (ret) {
dev_err(dev, "missing #address-cells property\n");
return ret;
}
reg_cells = val;
ret = of_property_read_u32(np, "#size-cells", &val);
if (ret) {
dev_err(dev, "missing #address-cells property\n");
return ret;
}
reg_cells += val;
for_each_available_child_of_node(np, child) {
if (!of_find_property(child, "reg", NULL))
continue;
ret = at91_ebi_dev_setup(ebi, child, reg_cells);
if (ret) {
dev_err(dev, "failed to configure EBI bus for %s, disabling the device",
child->full_name);
ret = at91_ebi_dev_disable(ebi, child);
if (ret)
return ret;
}
}
return of_platform_populate(np, NULL, NULL, dev);
}
static struct platform_driver at91_ebi_driver = {
.driver = {
.name = "atmel-ebi",
.of_match_table = at91_ebi_id_table,
},
};
builtin_platform_driver_probe(at91_ebi_driver, at91_ebi_probe);
/* /*
* Atmel (Multi-port DDR-)SDRAM Controller driver * Atmel (Multi-port DDR-)SDRAM Controller driver
* *
* Author: Alexandre Belloni <alexandre.belloni@free-electrons.com>
*
* Copyright (C) 2014 Atmel * Copyright (C) 2014 Atmel
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
...@@ -20,7 +22,7 @@ ...@@ -20,7 +22,7 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/init.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
...@@ -48,7 +50,6 @@ static const struct of_device_id atmel_ramc_of_match[] = { ...@@ -48,7 +50,6 @@ static const struct of_device_id atmel_ramc_of_match[] = {
{ .compatible = "atmel,sama5d3-ddramc", .data = &sama5d3_caps, }, { .compatible = "atmel,sama5d3-ddramc", .data = &sama5d3_caps, },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, atmel_ramc_of_match);
static int atmel_ramc_probe(struct platform_device *pdev) static int atmel_ramc_probe(struct platform_device *pdev)
{ {
...@@ -90,8 +91,4 @@ static int __init atmel_ramc_init(void) ...@@ -90,8 +91,4 @@ static int __init atmel_ramc_init(void)
{ {
return platform_driver_register(&atmel_ramc_driver); return platform_driver_register(&atmel_ramc_driver);
} }
module_init(atmel_ramc_init); device_initcall(atmel_ramc_init);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@free-electrons.com>");
MODULE_DESCRIPTION("Atmel (Multi-port DDR-)SDRAM Controller");
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/module.h>
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/irqdomain.h> #include <linux/irqdomain.h>
...@@ -1807,7 +1806,6 @@ static const struct of_device_id gpmc_dt_ids[] = { ...@@ -1807,7 +1806,6 @@ static const struct of_device_id gpmc_dt_ids[] = {
{ .compatible = "ti,am3352-gpmc" }, /* am335x devices */ { .compatible = "ti,am3352-gpmc" }, /* am335x devices */
{ } { }
}; };
MODULE_DEVICE_TABLE(of, gpmc_dt_ids);
/** /**
* gpmc_read_settings_dt - read gpmc settings from device-tree * gpmc_read_settings_dt - read gpmc settings from device-tree
...@@ -2154,68 +2152,6 @@ static int gpmc_probe_generic_child(struct platform_device *pdev, ...@@ -2154,68 +2152,6 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
return ret; return ret;
} }
static int gpmc_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
{
return 1; /* we're input only */
}
static int gpmc_gpio_direction_input(struct gpio_chip *chip,
unsigned int offset)
{
return 0; /* we're input only */
}
static int gpmc_gpio_direction_output(struct gpio_chip *chip,
unsigned int offset, int value)
{
return -EINVAL; /* we're input only */
}
static void gpmc_gpio_set(struct gpio_chip *chip, unsigned int offset,
int value)
{
}
static int gpmc_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
u32 reg;
offset += 8;
reg = gpmc_read_reg(GPMC_STATUS) & BIT(offset);
return !!reg;
}
static int gpmc_gpio_init(struct gpmc_device *gpmc)
{
int ret;
gpmc->gpio_chip.parent = gpmc->dev;
gpmc->gpio_chip.owner = THIS_MODULE;
gpmc->gpio_chip.label = DEVICE_NAME;
gpmc->gpio_chip.ngpio = gpmc_nr_waitpins;
gpmc->gpio_chip.get_direction = gpmc_gpio_get_direction;
gpmc->gpio_chip.direction_input = gpmc_gpio_direction_input;
gpmc->gpio_chip.direction_output = gpmc_gpio_direction_output;
gpmc->gpio_chip.set = gpmc_gpio_set;
gpmc->gpio_chip.get = gpmc_gpio_get;
gpmc->gpio_chip.base = -1;
ret = gpiochip_add(&gpmc->gpio_chip);
if (ret < 0) {
dev_err(gpmc->dev, "could not register gpio chip: %d\n", ret);
return ret;
}
return 0;
}
static void gpmc_gpio_exit(struct gpmc_device *gpmc)
{
gpiochip_remove(&gpmc->gpio_chip);
}
static int gpmc_probe_dt(struct platform_device *pdev) static int gpmc_probe_dt(struct platform_device *pdev)
{ {
int ret; int ret;
...@@ -2280,7 +2216,69 @@ static int gpmc_probe_dt_children(struct platform_device *pdev) ...@@ -2280,7 +2216,69 @@ static int gpmc_probe_dt_children(struct platform_device *pdev)
{ {
return 0; return 0;
} }
#endif #endif /* CONFIG_OF */
static int gpmc_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
{
return 1; /* we're input only */
}
static int gpmc_gpio_direction_input(struct gpio_chip *chip,
unsigned int offset)
{
return 0; /* we're input only */
}
static int gpmc_gpio_direction_output(struct gpio_chip *chip,
unsigned int offset, int value)
{
return -EINVAL; /* we're input only */
}
static void gpmc_gpio_set(struct gpio_chip *chip, unsigned int offset,
int value)
{
}
static int gpmc_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
u32 reg;
offset += 8;
reg = gpmc_read_reg(GPMC_STATUS) & BIT(offset);
return !!reg;
}
static int gpmc_gpio_init(struct gpmc_device *gpmc)
{
int ret;
gpmc->gpio_chip.parent = gpmc->dev;
gpmc->gpio_chip.owner = THIS_MODULE;
gpmc->gpio_chip.label = DEVICE_NAME;
gpmc->gpio_chip.ngpio = gpmc_nr_waitpins;
gpmc->gpio_chip.get_direction = gpmc_gpio_get_direction;
gpmc->gpio_chip.direction_input = gpmc_gpio_direction_input;
gpmc->gpio_chip.direction_output = gpmc_gpio_direction_output;
gpmc->gpio_chip.set = gpmc_gpio_set;
gpmc->gpio_chip.get = gpmc_gpio_get;
gpmc->gpio_chip.base = -1;
ret = gpiochip_add(&gpmc->gpio_chip);
if (ret < 0) {
dev_err(gpmc->dev, "could not register gpio chip: %d\n", ret);
return ret;
}
return 0;
}
static void gpmc_gpio_exit(struct gpmc_device *gpmc)
{
gpiochip_remove(&gpmc->gpio_chip);
}
static int gpmc_probe(struct platform_device *pdev) static int gpmc_probe(struct platform_device *pdev)
{ {
...@@ -2436,15 +2434,7 @@ static __init int gpmc_init(void) ...@@ -2436,15 +2434,7 @@ static __init int gpmc_init(void)
{ {
return platform_driver_register(&gpmc_driver); return platform_driver_register(&gpmc_driver);
} }
static __exit void gpmc_exit(void)
{
platform_driver_unregister(&gpmc_driver);
}
postcore_initcall(gpmc_init); postcore_initcall(gpmc_init);
module_exit(gpmc_exit);
static struct omap3_gpmc_regs gpmc_context; static struct omap3_gpmc_regs gpmc_context;
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
*/ */
#include <linux/io.h> #include <linux/io.h>
#include <linux/module.h> #include <linux/init.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
...@@ -91,17 +91,17 @@ static int exynos_srom_configure_bank(struct exynos_srom *srom, ...@@ -91,17 +91,17 @@ static int exynos_srom_configure_bank(struct exynos_srom *srom,
if (width == 2) if (width == 2)
cs |= 1 << EXYNOS_SROM_BW__DATAWIDTH__SHIFT; cs |= 1 << EXYNOS_SROM_BW__DATAWIDTH__SHIFT;
bw = __raw_readl(srom->reg_base + EXYNOS_SROM_BW); bw = readl_relaxed(srom->reg_base + EXYNOS_SROM_BW);
bw = (bw & ~(EXYNOS_SROM_BW__CS_MASK << bank)) | (cs << bank); bw = (bw & ~(EXYNOS_SROM_BW__CS_MASK << bank)) | (cs << bank);
__raw_writel(bw, srom->reg_base + EXYNOS_SROM_BW); writel_relaxed(bw, srom->reg_base + EXYNOS_SROM_BW);
__raw_writel(pmc | (timing[0] << EXYNOS_SROM_BCX__TACP__SHIFT) | writel_relaxed(pmc | (timing[0] << EXYNOS_SROM_BCX__TACP__SHIFT) |
(timing[1] << EXYNOS_SROM_BCX__TCAH__SHIFT) | (timing[1] << EXYNOS_SROM_BCX__TCAH__SHIFT) |
(timing[2] << EXYNOS_SROM_BCX__TCOH__SHIFT) | (timing[2] << EXYNOS_SROM_BCX__TCOH__SHIFT) |
(timing[3] << EXYNOS_SROM_BCX__TACC__SHIFT) | (timing[3] << EXYNOS_SROM_BCX__TACC__SHIFT) |
(timing[4] << EXYNOS_SROM_BCX__TCOS__SHIFT) | (timing[4] << EXYNOS_SROM_BCX__TCOS__SHIFT) |
(timing[5] << EXYNOS_SROM_BCX__TACS__SHIFT), (timing[5] << EXYNOS_SROM_BCX__TACS__SHIFT),
srom->reg_base + EXYNOS_SROM_BC0 + bank); srom->reg_base + EXYNOS_SROM_BC0 + bank);
return 0; return 0;
} }
...@@ -134,7 +134,7 @@ static int exynos_srom_probe(struct platform_device *pdev) ...@@ -134,7 +134,7 @@ static int exynos_srom_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, srom); platform_set_drvdata(pdev, srom);
srom->reg_offset = exynos_srom_alloc_reg_dump(exynos_srom_offsets, srom->reg_offset = exynos_srom_alloc_reg_dump(exynos_srom_offsets,
sizeof(exynos_srom_offsets)); ARRAY_SIZE(exynos_srom_offsets));
if (!srom->reg_offset) { if (!srom->reg_offset) {
iounmap(srom->reg_base); iounmap(srom->reg_base);
return -ENOMEM; return -ENOMEM;
...@@ -159,16 +159,6 @@ static int exynos_srom_probe(struct platform_device *pdev) ...@@ -159,16 +159,6 @@ static int exynos_srom_probe(struct platform_device *pdev)
return of_platform_populate(np, NULL, NULL, dev); return of_platform_populate(np, NULL, NULL, dev);
} }
static int exynos_srom_remove(struct platform_device *pdev)
{
struct exynos_srom *srom = platform_get_drvdata(pdev);
kfree(srom->reg_offset);
iounmap(srom->reg_base);
return 0;
}
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
static void exynos_srom_save(void __iomem *base, static void exynos_srom_save(void __iomem *base,
struct exynos_srom_reg_dump *rd, struct exynos_srom_reg_dump *rd,
...@@ -211,21 +201,16 @@ static const struct of_device_id of_exynos_srom_ids[] = { ...@@ -211,21 +201,16 @@ static const struct of_device_id of_exynos_srom_ids[] = {
}, },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, of_exynos_srom_ids);
static SIMPLE_DEV_PM_OPS(exynos_srom_pm_ops, exynos_srom_suspend, exynos_srom_resume); static SIMPLE_DEV_PM_OPS(exynos_srom_pm_ops, exynos_srom_suspend, exynos_srom_resume);
static struct platform_driver exynos_srom_driver = { static struct platform_driver exynos_srom_driver = {
.probe = exynos_srom_probe, .probe = exynos_srom_probe,
.remove = exynos_srom_remove,
.driver = { .driver = {
.name = "exynos-srom", .name = "exynos-srom",
.of_match_table = of_exynos_srom_ids, .of_match_table = of_exynos_srom_ids,
.pm = &exynos_srom_pm_ops, .pm = &exynos_srom_pm_ops,
.suppress_bind_attrs = true,
}, },
}; };
module_platform_driver(exynos_srom_driver); builtin_platform_driver(exynos_srom_driver);
MODULE_AUTHOR("Pankaj Dubey <pankaj.dubey@samsung.com>");
MODULE_DESCRIPTION("Exynos SROM Controller Driver");
MODULE_LICENSE("GPL");
...@@ -186,8 +186,10 @@ static int load_timings(struct tegra_mc *mc, struct device_node *node) ...@@ -186,8 +186,10 @@ static int load_timings(struct tegra_mc *mc, struct device_node *node)
timing = &mc->timings[i++]; timing = &mc->timings[i++];
err = load_one_timing(mc, timing, child); err = load_one_timing(mc, timing, child);
if (err) if (err) {
of_node_put(child);
return err; return err;
}
} }
return 0; return 0;
...@@ -206,15 +208,13 @@ static int tegra_mc_setup_timings(struct tegra_mc *mc) ...@@ -206,15 +208,13 @@ static int tegra_mc_setup_timings(struct tegra_mc *mc)
for_each_child_of_node(mc->dev->of_node, node) { for_each_child_of_node(mc->dev->of_node, node) {
err = of_property_read_u32(node, "nvidia,ram-code", err = of_property_read_u32(node, "nvidia,ram-code",
&node_ram_code); &node_ram_code);
if (err || (node_ram_code != ram_code)) { if (err || (node_ram_code != ram_code))
of_node_put(node);
continue; continue;
}
err = load_timings(mc, node); err = load_timings(mc, node);
of_node_put(node);
if (err) if (err)
return err; return err;
of_node_put(node);
break; break;
} }
......
...@@ -970,8 +970,10 @@ static int tegra_emc_load_timings_from_dt(struct tegra_emc *emc, ...@@ -970,8 +970,10 @@ static int tegra_emc_load_timings_from_dt(struct tegra_emc *emc,
timing = &emc->timings[i++]; timing = &emc->timings[i++];
err = load_one_timing_from_dt(emc, timing, child); err = load_one_timing_from_dt(emc, timing, child);
if (err) if (err) {
of_node_put(child);
return err; return err;
}
} }
sort(emc->timings, emc->num_timings, sizeof(*timing), cmp_timings, sort(emc->timings, emc->num_timings, sizeof(*timing), cmp_timings,
...@@ -995,10 +997,8 @@ tegra_emc_find_node_by_ram_code(struct device_node *node, u32 ram_code) ...@@ -995,10 +997,8 @@ tegra_emc_find_node_by_ram_code(struct device_node *node, u32 ram_code)
u32 value; u32 value;
err = of_property_read_u32(np, "nvidia,ram-code", &value); err = of_property_read_u32(np, "nvidia,ram-code", &value);
if (err || (value != ram_code)) { if (err || (value != ram_code))
of_node_put(np);
continue; continue;
}
return np; return np;
} }
......
...@@ -1087,7 +1087,6 @@ static int ab8500_probe(struct platform_device *pdev) ...@@ -1087,7 +1087,6 @@ static int ab8500_probe(struct platform_device *pdev)
"Vbus Detect (USB)", "Vbus Detect (USB)",
"USB ID Detect", "USB ID Detect",
"UART Factory Mode Detect"}; "UART Factory Mode Detect"};
struct ab8500_platform_data *plat = dev_get_platdata(&pdev->dev);
const struct platform_device_id *platid = platform_get_device_id(pdev); const struct platform_device_id *platid = platform_get_device_id(pdev);
enum ab8500_version version = AB8500_VERSION_UNDEFINED; enum ab8500_version version = AB8500_VERSION_UNDEFINED;
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
...@@ -1219,9 +1218,6 @@ static int ab8500_probe(struct platform_device *pdev) ...@@ -1219,9 +1218,6 @@ static int ab8500_probe(struct platform_device *pdev)
pr_cont("None\n"); pr_cont("None\n");
} }
if (plat && plat->init)
plat->init(ab8500);
if (is_ab9540(ab8500)) { if (is_ab9540(ab8500)) {
ret = get_register_interruptible(ab8500, AB8500_CHARGER, ret = get_register_interruptible(ab8500, AB8500_CHARGER,
AB8500_CH_USBCH_STAT1_REG, &value); AB8500_CH_USBCH_STAT1_REG, &value);
......
...@@ -127,45 +127,11 @@ EXPORT_SYMBOL(ab8500_sysctrl_write); ...@@ -127,45 +127,11 @@ EXPORT_SYMBOL(ab8500_sysctrl_write);
static int ab8500_sysctrl_probe(struct platform_device *pdev) static int ab8500_sysctrl_probe(struct platform_device *pdev)
{ {
struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
struct ab8500_platform_data *plat;
struct ab8500_sysctrl_platform_data *pdata;
plat = dev_get_platdata(pdev->dev.parent);
if (!plat)
return -EINVAL;
sysctrl_dev = &pdev->dev; sysctrl_dev = &pdev->dev;
if (!pm_power_off) if (!pm_power_off)
pm_power_off = ab8500_power_off; pm_power_off = ab8500_power_off;
pdata = plat->sysctrl;
if (pdata) {
int last, ret, i, j;
if (is_ab8505(ab8500))
last = AB8500_SYSCLKREQ4RFCLKBUF;
else
last = AB8500_SYSCLKREQ8RFCLKBUF;
for (i = AB8500_SYSCLKREQ1RFCLKBUF; i <= last; i++) {
j = i - AB8500_SYSCLKREQ1RFCLKBUF;
ret = ab8500_sysctrl_write(i, 0xff,
pdata->initial_req_buf_config[j]);
dev_dbg(&pdev->dev,
"Setting SysClkReq%dRfClkBuf 0x%X\n",
j + 1,
pdata->initial_req_buf_config[j]);
if (ret < 0) {
dev_err(&pdev->dev,
"Can't set sysClkReq%dRfClkBuf: %d\n",
j + 1, ret);
}
}
}
return 0; return 0;
} }
......
...@@ -3094,8 +3094,7 @@ static void db8500_prcmu_update_cpufreq(void) ...@@ -3094,8 +3094,7 @@ static void db8500_prcmu_update_cpufreq(void)
} }
} }
static int db8500_prcmu_register_ab8500(struct device *parent, static int db8500_prcmu_register_ab8500(struct device *parent)
struct ab8500_platform_data *pdata)
{ {
struct device_node *np; struct device_node *np;
struct resource ab8500_resource; struct resource ab8500_resource;
...@@ -3103,8 +3102,6 @@ static int db8500_prcmu_register_ab8500(struct device *parent, ...@@ -3103,8 +3102,6 @@ static int db8500_prcmu_register_ab8500(struct device *parent,
.name = "ab8500-core", .name = "ab8500-core",
.of_compatible = "stericsson,ab8500", .of_compatible = "stericsson,ab8500",
.id = AB8500_VERSION_AB8500, .id = AB8500_VERSION_AB8500,
.platform_data = pdata,
.pdata_size = sizeof(struct ab8500_platform_data),
.resources = &ab8500_resource, .resources = &ab8500_resource,
.num_resources = 1, .num_resources = 1,
}; };
...@@ -3133,7 +3130,6 @@ static int db8500_prcmu_register_ab8500(struct device *parent, ...@@ -3133,7 +3130,6 @@ static int db8500_prcmu_register_ab8500(struct device *parent,
static int db8500_prcmu_probe(struct platform_device *pdev) static int db8500_prcmu_probe(struct platform_device *pdev)
{ {
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
struct prcmu_pdata *pdata = dev_get_platdata(&pdev->dev);
int irq = 0, err = 0; int irq = 0, err = 0;
struct resource *res; struct resource *res;
...@@ -3149,7 +3145,7 @@ static int db8500_prcmu_probe(struct platform_device *pdev) ...@@ -3149,7 +3145,7 @@ static int db8500_prcmu_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
} }
init_prcm_registers(); init_prcm_registers();
dbx500_fw_version_init(pdev, pdata->version_offset); dbx500_fw_version_init(pdev, DB8500_PRCMU_FW_VERSION_OFFSET);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "prcmu-tcdm"); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "prcmu-tcdm");
if (!res) { if (!res) {
dev_err(&pdev->dev, "no prcmu tcdm region provided\n"); dev_err(&pdev->dev, "no prcmu tcdm region provided\n");
...@@ -3204,7 +3200,7 @@ static int db8500_prcmu_probe(struct platform_device *pdev) ...@@ -3204,7 +3200,7 @@ static int db8500_prcmu_probe(struct platform_device *pdev)
} }
} }
err = db8500_prcmu_register_ab8500(&pdev->dev, pdata->ab_platdata); err = db8500_prcmu_register_ab8500(&pdev->dev);
if (err) { if (err) {
mfd_remove_devices(&pdev->dev); mfd_remove_devices(&pdev->dev);
pr_err("prcmu: Failed to add ab8500 subdevice\n"); pr_err("prcmu: Failed to add ab8500 subdevice\n");
......
...@@ -46,6 +46,16 @@ config POWER_RESET_AXXIA ...@@ -46,6 +46,16 @@ config POWER_RESET_AXXIA
Say Y if you have an Axxia family SoC. Say Y if you have an Axxia family SoC.
config POWER_RESET_BRCMKONA
bool "Broadcom Kona reset driver"
depends on ARM || COMPILE_TEST
default ARCH_BCM_MOBILE
help
This driver provides restart support for Broadcom Kona chips.
Say Y here if you have a Broadcom Kona-based board and you wish
to have restart support.
config POWER_RESET_BRCMSTB config POWER_RESET_BRCMSTB
bool "Broadcom STB reset driver" bool "Broadcom STB reset driver"
depends on ARM || MIPS || COMPILE_TEST depends on ARM || MIPS || COMPILE_TEST
......
...@@ -3,6 +3,7 @@ obj-$(CONFIG_POWER_RESET_AT91_POWEROFF) += at91-poweroff.o ...@@ -3,6 +3,7 @@ obj-$(CONFIG_POWER_RESET_AT91_POWEROFF) += at91-poweroff.o
obj-$(CONFIG_POWER_RESET_AT91_RESET) += at91-reset.o obj-$(CONFIG_POWER_RESET_AT91_RESET) += at91-reset.o
obj-$(CONFIG_POWER_RESET_AT91_SAMA5D2_SHDWC) += at91-sama5d2_shdwc.o obj-$(CONFIG_POWER_RESET_AT91_SAMA5D2_SHDWC) += at91-sama5d2_shdwc.o
obj-$(CONFIG_POWER_RESET_AXXIA) += axxia-reset.o obj-$(CONFIG_POWER_RESET_AXXIA) += axxia-reset.o
obj-$(CONFIG_POWER_RESET_BRCMKONA) += brcm-kona-reset.o
obj-$(CONFIG_POWER_RESET_BRCMSTB) += brcmstb-reboot.o obj-$(CONFIG_POWER_RESET_BRCMSTB) += brcmstb-reboot.o
obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o
obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o
......
/*
* Copyright (C) 2016 Broadcom
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/io.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/reboot.h>
#define RSTMGR_REG_WR_ACCESS_OFFSET 0
#define RSTMGR_REG_CHIP_SOFT_RST_OFFSET 4
#define RSTMGR_WR_PASSWORD 0xa5a5
#define RSTMGR_WR_PASSWORD_SHIFT 8
#define RSTMGR_WR_ACCESS_ENABLE 1
static void __iomem *kona_reset_base;
static int kona_reset_handler(struct notifier_block *this,
unsigned long mode, void *cmd)
{
/*
* A soft reset is triggered by writing a 0 to bit 0 of the soft reset
* register. To write to that register we must first write the password
* and the enable bit in the write access enable register.
*/
writel((RSTMGR_WR_PASSWORD << RSTMGR_WR_PASSWORD_SHIFT) |
RSTMGR_WR_ACCESS_ENABLE,
kona_reset_base + RSTMGR_REG_WR_ACCESS_OFFSET);
writel(0, kona_reset_base + RSTMGR_REG_CHIP_SOFT_RST_OFFSET);
return NOTIFY_DONE;
}
static struct notifier_block kona_reset_nb = {
.notifier_call = kona_reset_handler,
.priority = 128,
};
static int kona_reset_probe(struct platform_device *pdev)
{
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
kona_reset_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(kona_reset_base))
return PTR_ERR(kona_reset_base);
return register_restart_handler(&kona_reset_nb);
}
static const struct of_device_id of_match[] = {
{ .compatible = "brcm,bcm21664-resetmgr" },
{},
};
static struct platform_driver bcm_kona_reset_driver = {
.probe = kona_reset_probe,
.driver = {
.name = "brcm-kona-reset",
.of_match_table = of_match,
},
};
builtin_platform_driver(bcm_kona_reset_driver);
...@@ -155,7 +155,7 @@ static int clps711x_pwm_remove(struct platform_device *pdev) ...@@ -155,7 +155,7 @@ static int clps711x_pwm_remove(struct platform_device *pdev)
} }
static const struct of_device_id __maybe_unused clps711x_pwm_dt_ids[] = { static const struct of_device_id __maybe_unused clps711x_pwm_dt_ids[] = {
{ .compatible = "cirrus,clps711x-pwm", }, { .compatible = "cirrus,ep7209-pwm", },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, clps711x_pwm_dt_ids); MODULE_DEVICE_TABLE(of, clps711x_pwm_dt_ids);
......
...@@ -245,7 +245,7 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev) ...@@ -245,7 +245,7 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
struct pwm_omap_dmtimer_chip *omap; struct pwm_omap_dmtimer_chip *omap;
struct pwm_omap_dmtimer_pdata *pdata; struct pwm_omap_dmtimer_pdata *pdata;
pwm_omap_dmtimer *dm_timer; pwm_omap_dmtimer *dm_timer;
u32 prescaler; u32 v;
int status; int status;
pdata = dev_get_platdata(&pdev->dev); pdata = dev_get_platdata(&pdev->dev);
...@@ -306,10 +306,12 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev) ...@@ -306,10 +306,12 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
if (pm_runtime_active(&omap->dm_timer_pdev->dev)) if (pm_runtime_active(&omap->dm_timer_pdev->dev))
omap->pdata->stop(omap->dm_timer); omap->pdata->stop(omap->dm_timer);
/* setup dmtimer prescaler */ if (!of_property_read_u32(pdev->dev.of_node, "ti,prescaler", &v))
if (!of_property_read_u32(pdev->dev.of_node, "ti,prescaler", omap->pdata->set_prescaler(omap->dm_timer, v);
&prescaler))
omap->pdata->set_prescaler(omap->dm_timer, prescaler); /* setup dmtimer clock source */
if (!of_property_read_u32(pdev->dev.of_node, "ti,clock-source", &v))
omap->pdata->set_source(omap->dm_timer, v);
omap->chip.dev = &pdev->dev; omap->chip.dev = &pdev->dev;
omap->chip.ops = &pwm_omap_dmtimer_ops; omap->chip.ops = &pwm_omap_dmtimer_ops;
......
...@@ -25,6 +25,456 @@ ...@@ -25,6 +25,456 @@
#include <linux/mfd/abx500/ab8500.h> #include <linux/mfd/abx500/ab8500.h>
#include <linux/regulator/ab8500.h> #include <linux/regulator/ab8500.h>
static struct regulator_consumer_supply ab8500_vaux1_consumers[] = {
/* Main display, u8500 R3 uib */
REGULATOR_SUPPLY("vddi", "mcde_disp_sony_acx424akp.0"),
/* Main display, u8500 uib and ST uib */
REGULATOR_SUPPLY("vdd1", "samsung_s6d16d0.0"),
/* Secondary display, ST uib */
REGULATOR_SUPPLY("vdd1", "samsung_s6d16d0.1"),
/* SFH7741 proximity sensor */
REGULATOR_SUPPLY("vcc", "gpio-keys.0"),
/* BH1780GLS ambient light sensor */
REGULATOR_SUPPLY("vcc", "2-0029"),
/* lsm303dlh accelerometer */
REGULATOR_SUPPLY("vdd", "2-0018"),
/* lsm303dlhc accelerometer */
REGULATOR_SUPPLY("vdd", "2-0019"),
/* lsm303dlh magnetometer */
REGULATOR_SUPPLY("vdd", "2-001e"),
/* Rohm BU21013 Touchscreen devices */
REGULATOR_SUPPLY("avdd", "3-005c"),
REGULATOR_SUPPLY("avdd", "3-005d"),
/* Synaptics RMI4 Touchscreen device */
REGULATOR_SUPPLY("vdd", "3-004b"),
/* L3G4200D Gyroscope device */
REGULATOR_SUPPLY("vdd", "2-0068"),
/* Ambient light sensor device */
REGULATOR_SUPPLY("vdd", "3-0029"),
/* Pressure sensor device */
REGULATOR_SUPPLY("vdd", "2-005c"),
/* Cypress TrueTouch Touchscreen device */
REGULATOR_SUPPLY("vcpin", "spi8.0"),
/* Camera device */
REGULATOR_SUPPLY("vaux12v5", "mmio_camera"),
};
static struct regulator_consumer_supply ab8500_vaux2_consumers[] = {
/* On-board eMMC power */
REGULATOR_SUPPLY("vmmc", "sdi4"),
/* AB8500 audio codec */
REGULATOR_SUPPLY("vcc-N2158", "ab8500-codec.0"),
/* AB8500 accessory detect 1 */
REGULATOR_SUPPLY("vcc-N2158", "ab8500-acc-det.0"),
/* AB8500 Tv-out device */
REGULATOR_SUPPLY("vcc-N2158", "mcde_tv_ab8500.4"),
/* AV8100 HDMI device */
REGULATOR_SUPPLY("vcc-N2158", "av8100_hdmi.3"),
};
static struct regulator_consumer_supply ab8500_vaux3_consumers[] = {
REGULATOR_SUPPLY("v-SD-STM", "stm"),
/* External MMC slot power */
REGULATOR_SUPPLY("vmmc", "sdi0"),
};
static struct regulator_consumer_supply ab8500_vtvout_consumers[] = {
/* TV-out DENC supply */
REGULATOR_SUPPLY("vtvout", "ab8500-denc.0"),
/* Internal general-purpose ADC */
REGULATOR_SUPPLY("vddadc", "ab8500-gpadc.0"),
/* ADC for charger */
REGULATOR_SUPPLY("vddadc", "ab8500-charger.0"),
/* AB8500 Tv-out device */
REGULATOR_SUPPLY("vtvout", "mcde_tv_ab8500.4"),
};
static struct regulator_consumer_supply ab8500_vaud_consumers[] = {
/* AB8500 audio-codec main supply */
REGULATOR_SUPPLY("vaud", "ab8500-codec.0"),
};
static struct regulator_consumer_supply ab8500_vamic1_consumers[] = {
/* AB8500 audio-codec Mic1 supply */
REGULATOR_SUPPLY("vamic1", "ab8500-codec.0"),
};
static struct regulator_consumer_supply ab8500_vamic2_consumers[] = {
/* AB8500 audio-codec Mic2 supply */
REGULATOR_SUPPLY("vamic2", "ab8500-codec.0"),
};
static struct regulator_consumer_supply ab8500_vdmic_consumers[] = {
/* AB8500 audio-codec DMic supply */
REGULATOR_SUPPLY("vdmic", "ab8500-codec.0"),
};
static struct regulator_consumer_supply ab8500_vintcore_consumers[] = {
/* SoC core supply, no device */
REGULATOR_SUPPLY("v-intcore", NULL),
/* USB Transceiver */
REGULATOR_SUPPLY("vddulpivio18", "ab8500-usb.0"),
/* Handled by abx500 clk driver */
REGULATOR_SUPPLY("v-intcore", "abx500-clk.0"),
};
static struct regulator_consumer_supply ab8500_vana_consumers[] = {
/* DB8500 DSI */
REGULATOR_SUPPLY("vdddsi1v2", "mcde"),
REGULATOR_SUPPLY("vdddsi1v2", "b2r2_core"),
REGULATOR_SUPPLY("vdddsi1v2", "b2r2_1_core"),
REGULATOR_SUPPLY("vdddsi1v2", "dsilink.0"),
REGULATOR_SUPPLY("vdddsi1v2", "dsilink.1"),
REGULATOR_SUPPLY("vdddsi1v2", "dsilink.2"),
/* DB8500 CSI */
REGULATOR_SUPPLY("vddcsi1v2", "mmio_camera"),
};
/* ab8500 regulator register initialization */
static struct ab8500_regulator_reg_init ab8500_reg_init[] = {
/*
* VanaRequestCtrl = HP/LP depending on VxRequest
* VextSupply1RequestCtrl = HP/LP depending on VxRequest
*/
INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL2, 0xf0, 0x00),
/*
* VextSupply2RequestCtrl = HP/LP depending on VxRequest
* VextSupply3RequestCtrl = HP/LP depending on VxRequest
* Vaux1RequestCtrl = HP/LP depending on VxRequest
* Vaux2RequestCtrl = HP/LP depending on VxRequest
*/
INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL3, 0xff, 0x00),
/*
* Vaux3RequestCtrl = HP/LP depending on VxRequest
* SwHPReq = Control through SWValid disabled
*/
INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL4, 0x07, 0x00),
/*
* VanaSysClkReq1HPValid = disabled
* Vaux1SysClkReq1HPValid = disabled
* Vaux2SysClkReq1HPValid = disabled
* Vaux3SysClkReq1HPValid = disabled
*/
INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQ1HPVALID1, 0xe8, 0x00),
/*
* VextSupply1SysClkReq1HPValid = disabled
* VextSupply2SysClkReq1HPValid = disabled
* VextSupply3SysClkReq1HPValid = SysClkReq1 controlled
*/
INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQ1HPVALID2, 0x70, 0x40),
/*
* VanaHwHPReq1Valid = disabled
* Vaux1HwHPreq1Valid = disabled
* Vaux2HwHPReq1Valid = disabled
* Vaux3HwHPReqValid = disabled
*/
INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ1VALID1, 0xe8, 0x00),
/*
* VextSupply1HwHPReq1Valid = disabled
* VextSupply2HwHPReq1Valid = disabled
* VextSupply3HwHPReq1Valid = disabled
*/
INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ1VALID2, 0x07, 0x00),
/*
* VanaHwHPReq2Valid = disabled
* Vaux1HwHPReq2Valid = disabled
* Vaux2HwHPReq2Valid = disabled
* Vaux3HwHPReq2Valid = disabled
*/
INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ2VALID1, 0xe8, 0x00),
/*
* VextSupply1HwHPReq2Valid = disabled
* VextSupply2HwHPReq2Valid = disabled
* VextSupply3HwHPReq2Valid = HWReq2 controlled
*/
INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ2VALID2, 0x07, 0x04),
/*
* VanaSwHPReqValid = disabled
* Vaux1SwHPReqValid = disabled
*/
INIT_REGULATOR_REGISTER(AB8500_REGUSWHPREQVALID1, 0xa0, 0x00),
/*
* Vaux2SwHPReqValid = disabled
* Vaux3SwHPReqValid = disabled
* VextSupply1SwHPReqValid = disabled
* VextSupply2SwHPReqValid = disabled
* VextSupply3SwHPReqValid = disabled
*/
INIT_REGULATOR_REGISTER(AB8500_REGUSWHPREQVALID2, 0x1f, 0x00),
/*
* SysClkReq2Valid1 = SysClkReq2 controlled
* SysClkReq3Valid1 = disabled
* SysClkReq4Valid1 = SysClkReq4 controlled
* SysClkReq5Valid1 = disabled
* SysClkReq6Valid1 = SysClkReq6 controlled
* SysClkReq7Valid1 = disabled
* SysClkReq8Valid1 = disabled
*/
INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQVALID1, 0xfe, 0x2a),
/*
* SysClkReq2Valid2 = disabled
* SysClkReq3Valid2 = disabled
* SysClkReq4Valid2 = disabled
* SysClkReq5Valid2 = disabled
* SysClkReq6Valid2 = SysClkReq6 controlled
* SysClkReq7Valid2 = disabled
* SysClkReq8Valid2 = disabled
*/
INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQVALID2, 0xfe, 0x20),
/*
* VTVoutEna = disabled
* Vintcore12Ena = disabled
* Vintcore12Sel = 1.25 V
* Vintcore12LP = inactive (HP)
* VTVoutLP = inactive (HP)
*/
INIT_REGULATOR_REGISTER(AB8500_REGUMISC1, 0xfe, 0x10),
/*
* VaudioEna = disabled
* VdmicEna = disabled
* Vamic1Ena = disabled
* Vamic2Ena = disabled
*/
INIT_REGULATOR_REGISTER(AB8500_VAUDIOSUPPLY, 0x1e, 0x00),
/*
* Vamic1_dzout = high-Z when Vamic1 is disabled
* Vamic2_dzout = high-Z when Vamic2 is disabled
*/
INIT_REGULATOR_REGISTER(AB8500_REGUCTRL1VAMIC, 0x03, 0x00),
/*
* VPll = Hw controlled (NOTE! PRCMU bits)
* VanaRegu = force off
*/
INIT_REGULATOR_REGISTER(AB8500_VPLLVANAREGU, 0x0f, 0x02),
/*
* VrefDDREna = disabled
* VrefDDRSleepMode = inactive (no pulldown)
*/
INIT_REGULATOR_REGISTER(AB8500_VREFDDR, 0x03, 0x00),
/*
* VextSupply1Regu = force LP
* VextSupply2Regu = force OFF
* VextSupply3Regu = force HP (-> STBB2=LP and TPS=LP)
* ExtSupply2Bypass = ExtSupply12LPn ball is 0 when Ena is 0
* ExtSupply3Bypass = ExtSupply3LPn ball is 0 when Ena is 0
*/
INIT_REGULATOR_REGISTER(AB8500_EXTSUPPLYREGU, 0xff, 0x13),
/*
* Vaux1Regu = force HP
* Vaux2Regu = force off
*/
INIT_REGULATOR_REGISTER(AB8500_VAUX12REGU, 0x0f, 0x01),
/*
* Vaux3Regu = force off
*/
INIT_REGULATOR_REGISTER(AB8500_VRF1VAUX3REGU, 0x03, 0x00),
/*
* Vaux1Sel = 2.8 V
*/
INIT_REGULATOR_REGISTER(AB8500_VAUX1SEL, 0x0f, 0x0C),
/*
* Vaux2Sel = 2.9 V
*/
INIT_REGULATOR_REGISTER(AB8500_VAUX2SEL, 0x0f, 0x0d),
/*
* Vaux3Sel = 2.91 V
*/
INIT_REGULATOR_REGISTER(AB8500_VRF1VAUX3SEL, 0x07, 0x07),
/*
* VextSupply12LP = disabled (no LP)
*/
INIT_REGULATOR_REGISTER(AB8500_REGUCTRL2SPARE, 0x01, 0x00),
/*
* Vaux1Disch = short discharge time
* Vaux2Disch = short discharge time
* Vaux3Disch = short discharge time
* Vintcore12Disch = short discharge time
* VTVoutDisch = short discharge time
* VaudioDisch = short discharge time
*/
INIT_REGULATOR_REGISTER(AB8500_REGUCTRLDISCH, 0xfc, 0x00),
/*
* VanaDisch = short discharge time
* VdmicPullDownEna = pulldown disabled when Vdmic is disabled
* VdmicDisch = short discharge time
*/
INIT_REGULATOR_REGISTER(AB8500_REGUCTRLDISCH2, 0x16, 0x00),
};
/* AB8500 regulators */
static struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS] = {
/* supplies to the display/camera */
[AB8500_LDO_AUX1] = {
.supply_regulator = "ab8500-ext-supply3",
.constraints = {
.name = "V-DISPLAY",
.min_uV = 2800000,
.max_uV = 3300000,
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
REGULATOR_CHANGE_STATUS,
.boot_on = 1, /* display is on at boot */
},
.num_consumer_supplies = ARRAY_SIZE(ab8500_vaux1_consumers),
.consumer_supplies = ab8500_vaux1_consumers,
},
/* supplies to the on-board eMMC */
[AB8500_LDO_AUX2] = {
.supply_regulator = "ab8500-ext-supply3",
.constraints = {
.name = "V-eMMC1",
.min_uV = 1100000,
.max_uV = 3300000,
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
REGULATOR_CHANGE_STATUS |
REGULATOR_CHANGE_MODE,
.valid_modes_mask = REGULATOR_MODE_NORMAL |
REGULATOR_MODE_IDLE,
},
.num_consumer_supplies = ARRAY_SIZE(ab8500_vaux2_consumers),
.consumer_supplies = ab8500_vaux2_consumers,
},
/* supply for VAUX3, supplies to SDcard slots */
[AB8500_LDO_AUX3] = {
.supply_regulator = "ab8500-ext-supply3",
.constraints = {
.name = "V-MMC-SD",
.min_uV = 1100000,
.max_uV = 3300000,
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
REGULATOR_CHANGE_STATUS |
REGULATOR_CHANGE_MODE,
.valid_modes_mask = REGULATOR_MODE_NORMAL |
REGULATOR_MODE_IDLE,
},
.num_consumer_supplies = ARRAY_SIZE(ab8500_vaux3_consumers),
.consumer_supplies = ab8500_vaux3_consumers,
},
/* supply for tvout, gpadc, TVOUT LDO */
[AB8500_LDO_TVOUT] = {
.constraints = {
.name = "V-TVOUT",
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = ARRAY_SIZE(ab8500_vtvout_consumers),
.consumer_supplies = ab8500_vtvout_consumers,
},
/* supply for ab8500-vaudio, VAUDIO LDO */
[AB8500_LDO_AUDIO] = {
.constraints = {
.name = "V-AUD",
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = ARRAY_SIZE(ab8500_vaud_consumers),
.consumer_supplies = ab8500_vaud_consumers,
},
/* supply for v-anamic1 VAMic1-LDO */
[AB8500_LDO_ANAMIC1] = {
.constraints = {
.name = "V-AMIC1",
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = ARRAY_SIZE(ab8500_vamic1_consumers),
.consumer_supplies = ab8500_vamic1_consumers,
},
/* supply for v-amic2, VAMIC2 LDO, reuse constants for AMIC1 */
[AB8500_LDO_ANAMIC2] = {
.constraints = {
.name = "V-AMIC2",
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = ARRAY_SIZE(ab8500_vamic2_consumers),
.consumer_supplies = ab8500_vamic2_consumers,
},
/* supply for v-dmic, VDMIC LDO */
[AB8500_LDO_DMIC] = {
.constraints = {
.name = "V-DMIC",
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = ARRAY_SIZE(ab8500_vdmic_consumers),
.consumer_supplies = ab8500_vdmic_consumers,
},
/* supply for v-intcore12, VINTCORE12 LDO */
[AB8500_LDO_INTCORE] = {
.constraints = {
.name = "V-INTCORE",
.min_uV = 1250000,
.max_uV = 1350000,
.input_uV = 1800000,
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
REGULATOR_CHANGE_STATUS |
REGULATOR_CHANGE_MODE |
REGULATOR_CHANGE_DRMS,
.valid_modes_mask = REGULATOR_MODE_NORMAL |
REGULATOR_MODE_IDLE,
},
.num_consumer_supplies = ARRAY_SIZE(ab8500_vintcore_consumers),
.consumer_supplies = ab8500_vintcore_consumers,
},
/* supply for U8500 CSI-DSI, VANA LDO */
[AB8500_LDO_ANA] = {
.constraints = {
.name = "V-CSI-DSI",
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = ARRAY_SIZE(ab8500_vana_consumers),
.consumer_supplies = ab8500_vana_consumers,
},
};
/* supply for VextSupply3 */
static struct regulator_consumer_supply ab8500_ext_supply3_consumers[] = {
/* SIM supply for 3 V SIM cards */
REGULATOR_SUPPLY("vinvsim", "sim-detect.0"),
};
/*
* AB8500 external regulators
*/
static struct regulator_init_data ab8500_ext_regulators[] = {
/* fixed Vbat supplies VSMPS1_EXT_1V8 */
[AB8500_EXT_SUPPLY1] = {
.constraints = {
.name = "ab8500-ext-supply1",
.min_uV = 1800000,
.max_uV = 1800000,
.initial_mode = REGULATOR_MODE_IDLE,
.boot_on = 1,
.always_on = 1,
},
},
/* fixed Vbat supplies VSMPS2_EXT_1V36 and VSMPS5_EXT_1V15 */
[AB8500_EXT_SUPPLY2] = {
.constraints = {
.name = "ab8500-ext-supply2",
.min_uV = 1360000,
.max_uV = 1360000,
},
},
/* fixed Vbat supplies VSMPS3_EXT_3V4 and VSMPS4_EXT_3V4 */
[AB8500_EXT_SUPPLY3] = {
.constraints = {
.name = "ab8500-ext-supply3",
.min_uV = 3400000,
.max_uV = 3400000,
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
.boot_on = 1,
},
.num_consumer_supplies =
ARRAY_SIZE(ab8500_ext_supply3_consumers),
.consumer_supplies = ab8500_ext_supply3_consumers,
},
};
static struct ab8500_regulator_platform_data ab8500_regulator_plat_data = {
.reg_init = ab8500_reg_init,
.num_reg_init = ARRAY_SIZE(ab8500_reg_init),
.regulator = ab8500_regulators,
.num_regulator = ARRAY_SIZE(ab8500_regulators),
.ext_regulator = ab8500_ext_regulators,
.num_ext_regulator = ARRAY_SIZE(ab8500_ext_regulators),
};
/** /**
* struct ab8500_ext_regulator_info - ab8500 regulator information * struct ab8500_ext_regulator_info - ab8500 regulator information
* @dev: device pointer * @dev: device pointer
...@@ -344,8 +794,7 @@ static struct of_regulator_match ab8500_ext_regulator_match[] = { ...@@ -344,8 +794,7 @@ static struct of_regulator_match ab8500_ext_regulator_match[] = {
static int ab8500_ext_regulator_probe(struct platform_device *pdev) static int ab8500_ext_regulator_probe(struct platform_device *pdev)
{ {
struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent); struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
struct ab8500_platform_data *ppdata; struct ab8500_regulator_platform_data *pdata = &ab8500_regulator_plat_data;
struct ab8500_regulator_platform_data *pdata;
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
struct regulator_config config = { }; struct regulator_config config = { };
int i, err; int i, err;
...@@ -366,18 +815,6 @@ static int ab8500_ext_regulator_probe(struct platform_device *pdev) ...@@ -366,18 +815,6 @@ static int ab8500_ext_regulator_probe(struct platform_device *pdev)
return -EINVAL; return -EINVAL;
} }
ppdata = dev_get_platdata(ab8500->dev);
if (!ppdata) {
dev_err(&pdev->dev, "null parent pdata\n");
return -EINVAL;
}
pdata = ppdata->regulator;
if (!pdata) {
dev_err(&pdev->dev, "null pdata\n");
return -EINVAL;
}
/* make sure the platform data has the correct size */ /* make sure the platform data has the correct size */
if (pdata->num_ext_regulator != ARRAY_SIZE(ab8500_ext_regulator_info)) { if (pdata->num_ext_regulator != ARRAY_SIZE(ab8500_ext_regulator_info)) {
dev_err(&pdev->dev, "Configuration error: size mismatch.\n"); dev_err(&pdev->dev, "Configuration error: size mismatch.\n");
......
...@@ -12,8 +12,22 @@ menuconfig RESET_CONTROLLER ...@@ -12,8 +12,22 @@ menuconfig RESET_CONTROLLER
If unsure, say no. If unsure, say no.
if RESET_CONTROLLER
config RESET_OXNAS config RESET_OXNAS
bool bool
config TI_SYSCON_RESET
tristate "TI SYSCON Reset Driver"
depends on HAS_IOMEM
select MFD_SYSCON
help
This enables the reset driver support for TI devices with
memory-mapped reset registers as part of a syscon device node. If
you wish to use the reset framework for such memory-mapped devices,
say Y here. Otherwise, say N.
source "drivers/reset/sti/Kconfig" source "drivers/reset/sti/Kconfig"
source "drivers/reset/hisilicon/Kconfig" source "drivers/reset/hisilicon/Kconfig"
endif
...@@ -3,9 +3,11 @@ obj-$(CONFIG_ARCH_LPC18XX) += reset-lpc18xx.o ...@@ -3,9 +3,11 @@ obj-$(CONFIG_ARCH_LPC18XX) += reset-lpc18xx.o
obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o
obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o
obj-$(CONFIG_MACH_PISTACHIO) += reset-pistachio.o obj-$(CONFIG_MACH_PISTACHIO) += reset-pistachio.o
obj-$(CONFIG_ARCH_MESON) += reset-meson.o
obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o
obj-$(CONFIG_ARCH_STI) += sti/ obj-$(CONFIG_ARCH_STI) += sti/
obj-$(CONFIG_ARCH_HISI) += hisilicon/ obj-$(CONFIG_ARCH_HISI) += hisilicon/
obj-$(CONFIG_ARCH_ZYNQ) += reset-zynq.o obj-$(CONFIG_ARCH_ZYNQ) += reset-zynq.o
obj-$(CONFIG_ATH79) += reset-ath79.o obj-$(CONFIG_ATH79) += reset-ath79.o
obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o
obj-$(CONFIG_TI_SYSCON_RESET) += reset-ti-syscon.o
...@@ -93,6 +93,43 @@ void reset_controller_unregister(struct reset_controller_dev *rcdev) ...@@ -93,6 +93,43 @@ void reset_controller_unregister(struct reset_controller_dev *rcdev)
} }
EXPORT_SYMBOL_GPL(reset_controller_unregister); EXPORT_SYMBOL_GPL(reset_controller_unregister);
static void devm_reset_controller_release(struct device *dev, void *res)
{
reset_controller_unregister(*(struct reset_controller_dev **)res);
}
/**
* devm_reset_controller_register - resource managed reset_controller_register()
* @dev: device that is registering this reset controller
* @rcdev: a pointer to the initialized reset controller device
*
* Managed reset_controller_register(). For reset controllers registered by
* this function, reset_controller_unregister() is automatically called on
* driver detach. See reset_controller_register() for more information.
*/
int devm_reset_controller_register(struct device *dev,
struct reset_controller_dev *rcdev)
{
struct reset_controller_dev **rcdevp;
int ret;
rcdevp = devres_alloc(devm_reset_controller_release, sizeof(*rcdevp),
GFP_KERNEL);
if (!rcdevp)
return -ENOMEM;
ret = reset_controller_register(rcdev);
if (!ret) {
*rcdevp = rcdev;
devres_add(dev, rcdevp);
} else {
devres_free(rcdevp);
}
return ret;
}
EXPORT_SYMBOL_GPL(devm_reset_controller_register);
/** /**
* reset_control_reset - reset the controlled device * reset_control_reset - reset the controlled device
* @rstc: reset controller * @rstc: reset controller
......
/* /*
* Hisilicon Hi6220 reset controller driver * Hisilicon Hi6220 reset controller driver
* *
* Copyright (c) 2015 Hisilicon Limited. * Copyright (c) 2016 Linaro Limited.
* Copyright (c) 2015-2016 Hisilicon Limited.
* *
* Author: Feng Chen <puck.chen@hisilicon.com> * Author: Feng Chen <puck.chen@hisilicon.com>
* *
...@@ -15,81 +16,130 @@ ...@@ -15,81 +16,130 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
#include <linux/reset-controller.h> #include <linux/reset-controller.h>
#include <linux/reset.h> #include <linux/reset.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#define ASSERT_OFFSET 0x300 #define PERIPH_ASSERT_OFFSET 0x300
#define DEASSERT_OFFSET 0x304 #define PERIPH_DEASSERT_OFFSET 0x304
#define MAX_INDEX 0x509 #define PERIPH_MAX_INDEX 0x509
#define SC_MEDIA_RSTEN 0x052C
#define SC_MEDIA_RSTDIS 0x0530
#define MEDIA_MAX_INDEX 8
#define to_reset_data(x) container_of(x, struct hi6220_reset_data, rc_dev) #define to_reset_data(x) container_of(x, struct hi6220_reset_data, rc_dev)
enum hi6220_reset_ctrl_type {
PERIPHERAL,
MEDIA,
};
struct hi6220_reset_data { struct hi6220_reset_data {
void __iomem *assert_base; struct reset_controller_dev rc_dev;
void __iomem *deassert_base; struct regmap *regmap;
struct reset_controller_dev rc_dev;
}; };
static int hi6220_reset_assert(struct reset_controller_dev *rc_dev, static int hi6220_peripheral_assert(struct reset_controller_dev *rc_dev,
unsigned long idx) unsigned long idx)
{ {
struct hi6220_reset_data *data = to_reset_data(rc_dev); struct hi6220_reset_data *data = to_reset_data(rc_dev);
struct regmap *regmap = data->regmap;
u32 bank = idx >> 8;
u32 offset = idx & 0xff;
u32 reg = PERIPH_ASSERT_OFFSET + bank * 0x10;
int bank = idx >> 8; return regmap_write(regmap, reg, BIT(offset));
int offset = idx & 0xff; }
writel(BIT(offset), data->assert_base + (bank * 0x10)); static int hi6220_peripheral_deassert(struct reset_controller_dev *rc_dev,
unsigned long idx)
{
struct hi6220_reset_data *data = to_reset_data(rc_dev);
struct regmap *regmap = data->regmap;
u32 bank = idx >> 8;
u32 offset = idx & 0xff;
u32 reg = PERIPH_DEASSERT_OFFSET + bank * 0x10;
return 0; return regmap_write(regmap, reg, BIT(offset));
} }
static int hi6220_reset_deassert(struct reset_controller_dev *rc_dev, static const struct reset_control_ops hi6220_peripheral_reset_ops = {
unsigned long idx) .assert = hi6220_peripheral_assert,
.deassert = hi6220_peripheral_deassert,
};
static int hi6220_media_assert(struct reset_controller_dev *rc_dev,
unsigned long idx)
{ {
struct hi6220_reset_data *data = to_reset_data(rc_dev); struct hi6220_reset_data *data = to_reset_data(rc_dev);
struct regmap *regmap = data->regmap;
int bank = idx >> 8; return regmap_write(regmap, SC_MEDIA_RSTEN, BIT(idx));
int offset = idx & 0xff; }
writel(BIT(offset), data->deassert_base + (bank * 0x10)); static int hi6220_media_deassert(struct reset_controller_dev *rc_dev,
unsigned long idx)
{
struct hi6220_reset_data *data = to_reset_data(rc_dev);
struct regmap *regmap = data->regmap;
return 0; return regmap_write(regmap, SC_MEDIA_RSTDIS, BIT(idx));
} }
static const struct reset_control_ops hi6220_reset_ops = { static const struct reset_control_ops hi6220_media_reset_ops = {
.assert = hi6220_reset_assert, .assert = hi6220_media_assert,
.deassert = hi6220_reset_deassert, .deassert = hi6220_media_deassert,
}; };
static int hi6220_reset_probe(struct platform_device *pdev) static int hi6220_reset_probe(struct platform_device *pdev)
{ {
struct device_node *np = pdev->dev.of_node;
struct device *dev = &pdev->dev;
enum hi6220_reset_ctrl_type type;
struct hi6220_reset_data *data; struct hi6220_reset_data *data;
struct resource *res; struct regmap *regmap;
void __iomem *src_base;
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data) if (!data)
return -ENOMEM; return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); type = (enum hi6220_reset_ctrl_type)of_device_get_match_data(dev);
src_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(src_base)) regmap = syscon_node_to_regmap(np);
return PTR_ERR(src_base); if (IS_ERR(regmap)) {
dev_err(dev, "failed to get reset controller regmap\n");
return PTR_ERR(regmap);
}
data->assert_base = src_base + ASSERT_OFFSET; data->regmap = regmap;
data->deassert_base = src_base + DEASSERT_OFFSET; data->rc_dev.of_node = np;
data->rc_dev.nr_resets = MAX_INDEX; if (type == MEDIA) {
data->rc_dev.ops = &hi6220_reset_ops; data->rc_dev.ops = &hi6220_media_reset_ops;
data->rc_dev.of_node = pdev->dev.of_node; data->rc_dev.nr_resets = MEDIA_MAX_INDEX;
} else {
data->rc_dev.ops = &hi6220_peripheral_reset_ops;
data->rc_dev.nr_resets = PERIPH_MAX_INDEX;
}
return reset_controller_register(&data->rc_dev); return reset_controller_register(&data->rc_dev);
} }
static const struct of_device_id hi6220_reset_match[] = { static const struct of_device_id hi6220_reset_match[] = {
{ .compatible = "hisilicon,hi6220-sysctrl" }, {
{ }, .compatible = "hisilicon,hi6220-sysctrl",
.data = (void *)PERIPHERAL,
},
{
.compatible = "hisilicon,hi6220-mediactrl",
.data = (void *)MEDIA,
},
{ /* sentinel */ },
}; };
MODULE_DEVICE_TABLE(of, hi6220_reset_match);
static struct platform_driver hi6220_reset_driver = { static struct platform_driver hi6220_reset_driver = {
.probe = hi6220_reset_probe, .probe = hi6220_reset_probe,
......
...@@ -112,7 +112,7 @@ static int ath79_reset_probe(struct platform_device *pdev) ...@@ -112,7 +112,7 @@ static int ath79_reset_probe(struct platform_device *pdev)
ath79_reset->rcdev.of_reset_n_cells = 1; ath79_reset->rcdev.of_reset_n_cells = 1;
ath79_reset->rcdev.nr_resets = 32; ath79_reset->rcdev.nr_resets = 32;
err = reset_controller_register(&ath79_reset->rcdev); err = devm_reset_controller_register(&pdev->dev, &ath79_reset->rcdev);
if (err) if (err)
return err; return err;
...@@ -131,7 +131,6 @@ static int ath79_reset_remove(struct platform_device *pdev) ...@@ -131,7 +131,6 @@ static int ath79_reset_remove(struct platform_device *pdev)
struct ath79_reset *ath79_reset = platform_get_drvdata(pdev); struct ath79_reset *ath79_reset = platform_get_drvdata(pdev);
unregister_restart_handler(&ath79_reset->restart_nb); unregister_restart_handler(&ath79_reset->restart_nb);
reset_controller_unregister(&ath79_reset->rcdev);
return 0; return 0;
} }
......
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* GPL LICENSE SUMMARY
*
* Copyright (c) 2016 BayLibre, SAS.
* Author: Neil Armstrong <narmstrong@baylibre.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
* BSD LICENSE
*
* Copyright (c) 2016 BayLibre, SAS.
* Author: Neil Armstrong <narmstrong@baylibre.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <linux/err.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/reset-controller.h>
#include <linux/slab.h>
#include <linux/types.h>
#define REG_COUNT 8
#define BITS_PER_REG 32
struct meson_reset {
void __iomem *reg_base;
struct reset_controller_dev rcdev;
};
static int meson_reset_reset(struct reset_controller_dev *rcdev,
unsigned long id)
{
struct meson_reset *data =
container_of(rcdev, struct meson_reset, rcdev);
unsigned int bank = id / BITS_PER_REG;
unsigned int offset = id % BITS_PER_REG;
void __iomem *reg_addr = data->reg_base + (bank << 2);
if (bank >= REG_COUNT)
return -EINVAL;
writel(BIT(offset), reg_addr);
return 0;
}
static const struct reset_control_ops meson_reset_ops = {
.reset = meson_reset_reset,
};
static const struct of_device_id meson_reset_dt_ids[] = {
{ .compatible = "amlogic,meson8b-reset", },
{ .compatible = "amlogic,meson-gxbb-reset", },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, meson_reset_dt_ids);
static int meson_reset_probe(struct platform_device *pdev)
{
struct meson_reset *data;
struct resource *res;
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
data->reg_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(data->reg_base))
return PTR_ERR(data->reg_base);
platform_set_drvdata(pdev, data);
data->rcdev.owner = THIS_MODULE;
data->rcdev.nr_resets = REG_COUNT * BITS_PER_REG;
data->rcdev.ops = &meson_reset_ops;
data->rcdev.of_node = pdev->dev.of_node;
return devm_reset_controller_register(&pdev->dev, &data->rcdev);
}
static struct platform_driver meson_reset_driver = {
.probe = meson_reset_probe,
.driver = {
.name = "meson_reset",
.of_match_table = meson_reset_dt_ids,
},
};
module_platform_driver(meson_reset_driver);
MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
MODULE_DESCRIPTION("Amlogic Meson Reset Controller driver");
MODULE_LICENSE("Dual BSD/GPL");
...@@ -112,21 +112,11 @@ static int oxnas_reset_probe(struct platform_device *pdev) ...@@ -112,21 +112,11 @@ static int oxnas_reset_probe(struct platform_device *pdev)
data->rcdev.ops = &oxnas_reset_ops; data->rcdev.ops = &oxnas_reset_ops;
data->rcdev.of_node = pdev->dev.of_node; data->rcdev.of_node = pdev->dev.of_node;
return reset_controller_register(&data->rcdev); return devm_reset_controller_register(&pdev->dev, &data->rcdev);
}
static int oxnas_reset_remove(struct platform_device *pdev)
{
struct oxnas_reset *data = platform_get_drvdata(pdev);
reset_controller_unregister(&data->rcdev);
return 0;
} }
static struct platform_driver oxnas_reset_driver = { static struct platform_driver oxnas_reset_driver = {
.probe = oxnas_reset_probe, .probe = oxnas_reset_probe,
.remove = oxnas_reset_remove,
.driver = { .driver = {
.name = "oxnas-reset", .name = "oxnas-reset",
.of_match_table = oxnas_reset_dt_ids, .of_match_table = oxnas_reset_dt_ids,
......
...@@ -121,16 +121,7 @@ static int pistachio_reset_probe(struct platform_device *pdev) ...@@ -121,16 +121,7 @@ static int pistachio_reset_probe(struct platform_device *pdev)
rd->rcdev.ops = &pistachio_reset_ops; rd->rcdev.ops = &pistachio_reset_ops;
rd->rcdev.of_node = np; rd->rcdev.of_node = np;
return reset_controller_register(&rd->rcdev); return devm_reset_controller_register(dev, &rd->rcdev);
}
static int pistachio_reset_remove(struct platform_device *pdev)
{
struct pistachio_reset_data *data = platform_get_drvdata(pdev);
reset_controller_unregister(&data->rcdev);
return 0;
} }
static const struct of_device_id pistachio_reset_dt_ids[] = { static const struct of_device_id pistachio_reset_dt_ids[] = {
...@@ -141,7 +132,6 @@ MODULE_DEVICE_TABLE(of, pistachio_reset_dt_ids); ...@@ -141,7 +132,6 @@ MODULE_DEVICE_TABLE(of, pistachio_reset_dt_ids);
static struct platform_driver pistachio_reset_driver = { static struct platform_driver pistachio_reset_driver = {
.probe = pistachio_reset_probe, .probe = pistachio_reset_probe,
.remove = pistachio_reset_remove,
.driver = { .driver = {
.name = "pistachio-reset", .name = "pistachio-reset",
.of_match_table = pistachio_reset_dt_ids, .of_match_table = pistachio_reset_dt_ids,
......
...@@ -134,16 +134,7 @@ static int socfpga_reset_probe(struct platform_device *pdev) ...@@ -134,16 +134,7 @@ static int socfpga_reset_probe(struct platform_device *pdev)
data->rcdev.ops = &socfpga_reset_ops; data->rcdev.ops = &socfpga_reset_ops;
data->rcdev.of_node = pdev->dev.of_node; data->rcdev.of_node = pdev->dev.of_node;
return reset_controller_register(&data->rcdev); return devm_reset_controller_register(dev, &data->rcdev);
}
static int socfpga_reset_remove(struct platform_device *pdev)
{
struct socfpga_reset_data *data = platform_get_drvdata(pdev);
reset_controller_unregister(&data->rcdev);
return 0;
} }
static const struct of_device_id socfpga_reset_dt_ids[] = { static const struct of_device_id socfpga_reset_dt_ids[] = {
...@@ -153,7 +144,6 @@ static const struct of_device_id socfpga_reset_dt_ids[] = { ...@@ -153,7 +144,6 @@ static const struct of_device_id socfpga_reset_dt_ids[] = {
static struct platform_driver socfpga_reset_driver = { static struct platform_driver socfpga_reset_driver = {
.probe = socfpga_reset_probe, .probe = socfpga_reset_probe,
.remove = socfpga_reset_remove,
.driver = { .driver = {
.name = "socfpga-reset", .name = "socfpga-reset",
.of_match_table = socfpga_reset_dt_ids, .of_match_table = socfpga_reset_dt_ids,
......
...@@ -165,21 +165,11 @@ static int sunxi_reset_probe(struct platform_device *pdev) ...@@ -165,21 +165,11 @@ static int sunxi_reset_probe(struct platform_device *pdev)
data->rcdev.ops = &sunxi_reset_ops; data->rcdev.ops = &sunxi_reset_ops;
data->rcdev.of_node = pdev->dev.of_node; data->rcdev.of_node = pdev->dev.of_node;
return reset_controller_register(&data->rcdev); return devm_reset_controller_register(&pdev->dev, &data->rcdev);
}
static int sunxi_reset_remove(struct platform_device *pdev)
{
struct sunxi_reset_data *data = platform_get_drvdata(pdev);
reset_controller_unregister(&data->rcdev);
return 0;
} }
static struct platform_driver sunxi_reset_driver = { static struct platform_driver sunxi_reset_driver = {
.probe = sunxi_reset_probe, .probe = sunxi_reset_probe,
.remove = sunxi_reset_remove,
.driver = { .driver = {
.name = "sunxi-reset", .name = "sunxi-reset",
.of_match_table = sunxi_reset_dt_ids, .of_match_table = sunxi_reset_dt_ids,
......
/*
* TI SYSCON regmap reset driver
*
* Copyright (C) 2015-2016 Texas Instruments Incorporated - http://www.ti.com/
* Andrew F. Davis <afd@ti.com>
* Suman Anna <afd@ti.com>
*
* 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.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/reset-controller.h>
#include <dt-bindings/reset/ti-syscon.h>
/**
* struct ti_syscon_reset_control - reset control structure
* @assert_offset: reset assert control register offset from syscon base
* @assert_bit: reset assert bit in the reset assert control register
* @deassert_offset: reset deassert control register offset from syscon base
* @deassert_bit: reset deassert bit in the reset deassert control register
* @status_offset: reset status register offset from syscon base
* @status_bit: reset status bit in the reset status register
* @flags: reset flag indicating how the (de)assert and status are handled
*/
struct ti_syscon_reset_control {
unsigned int assert_offset;
unsigned int assert_bit;
unsigned int deassert_offset;
unsigned int deassert_bit;
unsigned int status_offset;
unsigned int status_bit;
u32 flags;
};
/**
* struct ti_syscon_reset_data - reset controller information structure
* @rcdev: reset controller entity
* @regmap: regmap handle containing the memory-mapped reset registers
* @controls: array of reset controls
* @nr_controls: number of controls in control array
*/
struct ti_syscon_reset_data {
struct reset_controller_dev rcdev;
struct regmap *regmap;
struct ti_syscon_reset_control *controls;
unsigned int nr_controls;
};
#define to_ti_syscon_reset_data(rcdev) \
container_of(rcdev, struct ti_syscon_reset_data, rcdev)
/**
* ti_syscon_reset_assert() - assert device reset
* @rcdev: reset controller entity
* @id: ID of the reset to be asserted
*
* This function implements the reset driver op to assert a device's reset.
* This asserts the reset in a manner prescribed by the reset flags.
*
* Return: 0 for successful request, else a corresponding error value
*/
static int ti_syscon_reset_assert(struct reset_controller_dev *rcdev,
unsigned long id)
{
struct ti_syscon_reset_data *data = to_ti_syscon_reset_data(rcdev);
struct ti_syscon_reset_control *control;
unsigned int mask, value;
if (id >= data->nr_controls)
return -EINVAL;
control = &data->controls[id];
if (control->flags & ASSERT_NONE)
return -ENOTSUPP; /* assert not supported for this reset */
mask = BIT(control->assert_bit);
value = (control->flags & ASSERT_SET) ? mask : 0x0;
return regmap_update_bits(data->regmap, control->assert_offset, mask, value);
}
/**
* ti_syscon_reset_deassert() - deassert device reset
* @rcdev: reset controller entity
* @id: ID of reset to be deasserted
*
* This function implements the reset driver op to deassert a device's reset.
* This deasserts the reset in a manner prescribed by the reset flags.
*
* Return: 0 for successful request, else a corresponding error value
*/
static int ti_syscon_reset_deassert(struct reset_controller_dev *rcdev,
unsigned long id)
{
struct ti_syscon_reset_data *data = to_ti_syscon_reset_data(rcdev);
struct ti_syscon_reset_control *control;
unsigned int mask, value;
if (id >= data->nr_controls)
return -EINVAL;
control = &data->controls[id];
if (control->flags & DEASSERT_NONE)
return -ENOTSUPP; /* deassert not supported for this reset */
mask = BIT(control->deassert_bit);
value = (control->flags & DEASSERT_SET) ? mask : 0x0;
return regmap_update_bits(data->regmap, control->deassert_offset, mask, value);
}
/**
* ti_syscon_reset_status() - check device reset status
* @rcdev: reset controller entity
* @id: ID of the reset for which the status is being requested
*
* This function implements the reset driver op to return the status of a
* device's reset.
*
* Return: 0 if reset is deasserted, true if reset is asserted, else a
* corresponding error value
*/
static int ti_syscon_reset_status(struct reset_controller_dev *rcdev,
unsigned long id)
{
struct ti_syscon_reset_data *data = to_ti_syscon_reset_data(rcdev);
struct ti_syscon_reset_control *control;
unsigned int reset_state;
int ret;
if (id >= data->nr_controls)
return -EINVAL;
control = &data->controls[id];
if (control->flags & STATUS_NONE)
return -ENOTSUPP; /* status not supported for this reset */
ret = regmap_read(data->regmap, control->status_offset, &reset_state);
if (ret)
return ret;
return (reset_state & BIT(control->status_bit)) &&
(control->flags & STATUS_SET);
}
static struct reset_control_ops ti_syscon_reset_ops = {
.assert = ti_syscon_reset_assert,
.deassert = ti_syscon_reset_deassert,
.status = ti_syscon_reset_status,
};
static int ti_syscon_reset_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct ti_syscon_reset_data *data;
struct regmap *regmap;
const __be32 *list;
struct ti_syscon_reset_control *controls;
int size, nr_controls, i;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
regmap = syscon_node_to_regmap(np->parent);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
list = of_get_property(np, "ti,reset-bits", &size);
if (!list || (size / sizeof(*list)) % 7 != 0) {
dev_err(dev, "invalid DT reset description\n");
return -EINVAL;
}
nr_controls = (size / sizeof(*list)) / 7;
controls = devm_kzalloc(dev, nr_controls * sizeof(*controls), GFP_KERNEL);
if (!controls)
return -ENOMEM;
for (i = 0; i < nr_controls; i++) {
controls[i].assert_offset = be32_to_cpup(list++);
controls[i].assert_bit = be32_to_cpup(list++);
controls[i].deassert_offset = be32_to_cpup(list++);
controls[i].deassert_bit = be32_to_cpup(list++);
controls[i].status_offset = be32_to_cpup(list++);
controls[i].status_bit = be32_to_cpup(list++);
controls[i].flags = be32_to_cpup(list++);
}
data->rcdev.ops = &ti_syscon_reset_ops;
data->rcdev.owner = THIS_MODULE;
data->rcdev.of_node = np;
data->rcdev.nr_resets = nr_controls;
data->regmap = regmap;
data->controls = controls;
data->nr_controls = nr_controls;
platform_set_drvdata(pdev, data);
return devm_reset_controller_register(dev, &data->rcdev);
}
static const struct of_device_id ti_syscon_reset_of_match[] = {
{ .compatible = "ti,syscon-reset", },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, ti_syscon_reset_of_match);
static struct platform_driver ti_syscon_reset_driver = {
.probe = ti_syscon_reset_probe,
.driver = {
.name = "ti-syscon-reset",
.of_match_table = ti_syscon_reset_of_match,
},
};
module_platform_driver(ti_syscon_reset_driver);
MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
MODULE_AUTHOR("Suman Anna <s-anna@ti.com>");
MODULE_DESCRIPTION("TI SYSCON Regmap Reset Driver");
MODULE_LICENSE("GPL v2");
...@@ -122,16 +122,7 @@ static int zynq_reset_probe(struct platform_device *pdev) ...@@ -122,16 +122,7 @@ static int zynq_reset_probe(struct platform_device *pdev)
priv->rcdev.ops = &zynq_reset_ops; priv->rcdev.ops = &zynq_reset_ops;
priv->rcdev.of_node = pdev->dev.of_node; priv->rcdev.of_node = pdev->dev.of_node;
return reset_controller_register(&priv->rcdev); return devm_reset_controller_register(&pdev->dev, &priv->rcdev);
}
static int zynq_reset_remove(struct platform_device *pdev)
{
struct zynq_reset_data *priv = platform_get_drvdata(pdev);
reset_controller_unregister(&priv->rcdev);
return 0;
} }
static const struct of_device_id zynq_reset_dt_ids[] = { static const struct of_device_id zynq_reset_dt_ids[] = {
...@@ -141,7 +132,6 @@ static const struct of_device_id zynq_reset_dt_ids[] = { ...@@ -141,7 +132,6 @@ static const struct of_device_id zynq_reset_dt_ids[] = {
static struct platform_driver zynq_reset_driver = { static struct platform_driver zynq_reset_driver = {
.probe = zynq_reset_probe, .probe = zynq_reset_probe,
.remove = zynq_reset_remove,
.driver = { .driver = {
.name = KBUILD_MODNAME, .name = KBUILD_MODNAME,
.of_match_table = zynq_reset_dt_ids, .of_match_table = zynq_reset_dt_ids,
......
...@@ -2,7 +2,6 @@ if ARCH_STI ...@@ -2,7 +2,6 @@ if ARCH_STI
config STI_RESET_SYSCFG config STI_RESET_SYSCFG
bool bool
select RESET_CONTROLLER
config STIH415_RESET config STIH415_RESET
bool bool
......
menu "SOC (System On Chip) specific Drivers" menu "SOC (System On Chip) specific Drivers"
source "drivers/soc/bcm/Kconfig" source "drivers/soc/bcm/Kconfig"
source "drivers/soc/brcmstb/Kconfig"
source "drivers/soc/fsl/qe/Kconfig" source "drivers/soc/fsl/qe/Kconfig"
source "drivers/soc/mediatek/Kconfig" source "drivers/soc/mediatek/Kconfig"
source "drivers/soc/qcom/Kconfig" source "drivers/soc/qcom/Kconfig"
...@@ -10,6 +9,7 @@ source "drivers/soc/samsung/Kconfig" ...@@ -10,6 +9,7 @@ source "drivers/soc/samsung/Kconfig"
source "drivers/soc/sunxi/Kconfig" source "drivers/soc/sunxi/Kconfig"
source "drivers/soc/tegra/Kconfig" source "drivers/soc/tegra/Kconfig"
source "drivers/soc/ti/Kconfig" source "drivers/soc/ti/Kconfig"
source "drivers/soc/ux500/Kconfig"
source "drivers/soc/versatile/Kconfig" source "drivers/soc/versatile/Kconfig"
endmenu endmenu
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
# #
obj-y += bcm/ obj-y += bcm/
obj-$(CONFIG_SOC_BRCMSTB) += brcmstb/
obj-$(CONFIG_ARCH_DOVE) += dove/ obj-$(CONFIG_ARCH_DOVE) += dove/
obj-$(CONFIG_MACH_DOVE) += dove/ obj-$(CONFIG_MACH_DOVE) += dove/
obj-y += fsl/ obj-y += fsl/
...@@ -15,4 +14,5 @@ obj-$(CONFIG_SOC_SAMSUNG) += samsung/ ...@@ -15,4 +14,5 @@ obj-$(CONFIG_SOC_SAMSUNG) += samsung/
obj-$(CONFIG_ARCH_SUNXI) += sunxi/ obj-$(CONFIG_ARCH_SUNXI) += sunxi/
obj-$(CONFIG_ARCH_TEGRA) += tegra/ obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-$(CONFIG_SOC_TI) += ti/ obj-$(CONFIG_SOC_TI) += ti/
obj-$(CONFIG_ARCH_U8500) += ux500/
obj-$(CONFIG_PLAT_VERSATILE) += versatile/ obj-$(CONFIG_PLAT_VERSATILE) += versatile/
menu "Broadcom SoC drivers"
config RASPBERRYPI_POWER config RASPBERRYPI_POWER
bool "Raspberry Pi power domain driver" bool "Raspberry Pi power domain driver"
depends on ARCH_BCM2835 || COMPILE_TEST depends on ARCH_BCM2835 || (COMPILE_TEST && OF)
depends on RASPBERRYPI_FIRMWARE=y depends on RASPBERRYPI_FIRMWARE=y
select PM_GENERIC_DOMAINS if PM select PM_GENERIC_DOMAINS if PM
select PM_GENERIC_DOMAINS_OF if PM
help help
This enables support for the RPi power domains which can be enabled This enables support for the RPi power domains which can be enabled
or disabled via the RPi firmware. or disabled via the RPi firmware.
config SOC_BRCMSTB
bool "Broadcom STB SoC drivers"
depends on ARM
select SOC_BUS
help
Enables drivers for the Broadcom Set-Top Box (STB) series of chips.
This option alone enables only some support code, while the drivers
can be enabled individually within this menu.
If unsure, say N.
endmenu
obj-$(CONFIG_RASPBERRYPI_POWER) += raspberrypi-power.o obj-$(CONFIG_RASPBERRYPI_POWER) += raspberrypi-power.o
obj-$(CONFIG_SOC_BRCMSTB) += brcmstb/
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/syscore_ops.h> #include <linux/syscore_ops.h>
#include <linux/soc/brcmstb/brcmstb.h>
#define CPU_CREDIT_REG_OFFSET 0x184 #define CPU_CREDIT_REG_OFFSET 0x184
#define CPU_CREDIT_REG_MCPx_WR_PAIRING_EN_MASK 0x70000000 #define CPU_CREDIT_REG_MCPx_WR_PAIRING_EN_MASK 0x70000000
......
menuconfig SOC_BRCMSTB
bool "Broadcom STB SoC drivers"
depends on ARM
select SOC_BUS
help
Enables drivers for the Broadcom Set-Top Box (STB) series of chips.
This option alone enables only some support code, while the drivers
can be enabled individually within this menu.
If unsure, say N.
...@@ -104,26 +104,26 @@ struct qcom_smem_state *qcom_smem_state_get(struct device *dev, ...@@ -104,26 +104,26 @@ struct qcom_smem_state *qcom_smem_state_get(struct device *dev,
if (con_id) { if (con_id) {
index = of_property_match_string(dev->of_node, index = of_property_match_string(dev->of_node,
"qcom,state-names", "qcom,smem-state-names",
con_id); con_id);
if (index < 0) { if (index < 0) {
dev_err(dev, "missing qcom,state-names\n"); dev_err(dev, "missing qcom,smem-state-names\n");
return ERR_PTR(index); return ERR_PTR(index);
} }
} }
ret = of_parse_phandle_with_args(dev->of_node, ret = of_parse_phandle_with_args(dev->of_node,
"qcom,state", "qcom,smem-states",
"#qcom,state-cells", "#qcom,smem-state-cells",
index, index,
&args); &args);
if (ret) { if (ret) {
dev_err(dev, "failed to parse qcom,state property\n"); dev_err(dev, "failed to parse qcom,smem-states property\n");
return ERR_PTR(ret); return ERR_PTR(ret);
} }
if (args.args_count != 1) { if (args.args_count != 1) {
dev_err(dev, "invalid #qcom,state-cells\n"); dev_err(dev, "invalid #qcom,smem-state-cells\n");
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
......
...@@ -196,7 +196,7 @@ static irqreturn_t qcom_smp2p_intr(int irq, void *data) ...@@ -196,7 +196,7 @@ static irqreturn_t qcom_smp2p_intr(int irq, void *data)
/* Match newly created entries */ /* Match newly created entries */
for (i = smp2p->valid_entries; i < in->valid_entries; i++) { for (i = smp2p->valid_entries; i < in->valid_entries; i++) {
list_for_each_entry(entry, &smp2p->inbound, node) { list_for_each_entry(entry, &smp2p->inbound, node) {
memcpy_fromio(buf, in->entries[i].name, sizeof(buf)); memcpy(buf, in->entries[i].name, sizeof(buf));
if (!strcmp(buf, entry->name)) { if (!strcmp(buf, entry->name)) {
entry->value = &in->entries[i].value; entry->value = &in->entries[i].value;
break; break;
...@@ -343,12 +343,13 @@ static int qcom_smp2p_outbound_entry(struct qcom_smp2p *smp2p, ...@@ -343,12 +343,13 @@ static int qcom_smp2p_outbound_entry(struct qcom_smp2p *smp2p,
/* Allocate an entry from the smem item */ /* Allocate an entry from the smem item */
strlcpy(buf, entry->name, SMP2P_MAX_ENTRY_NAME); strlcpy(buf, entry->name, SMP2P_MAX_ENTRY_NAME);
memcpy_toio(out->entries[out->valid_entries].name, buf, SMP2P_MAX_ENTRY_NAME); memcpy(out->entries[out->valid_entries].name, buf, SMP2P_MAX_ENTRY_NAME);
out->valid_entries++;
/* Make the logical entry reference the physical value */ /* Make the logical entry reference the physical value */
entry->value = &out->entries[out->valid_entries].value; entry->value = &out->entries[out->valid_entries].value;
out->valid_entries++;
entry->state = qcom_smem_state_register(node, &smp2p_state_ops, entry); entry->state = qcom_smem_state_register(node, &smp2p_state_ops, entry);
if (IS_ERR(entry->state)) { if (IS_ERR(entry->state)) {
dev_err(smp2p->dev, "failed to register qcom_smem_state\n"); dev_err(smp2p->dev, "failed to register qcom_smem_state\n");
......
...@@ -495,7 +495,7 @@ static int qcom_smsm_probe(struct platform_device *pdev) ...@@ -495,7 +495,7 @@ static int qcom_smsm_probe(struct platform_device *pdev)
if (!smsm->hosts) if (!smsm->hosts)
return -ENOMEM; return -ENOMEM;
local_node = of_find_node_with_property(pdev->dev.of_node, "#qcom,state-cells"); local_node = of_find_node_with_property(pdev->dev.of_node, "#qcom,smem-state-cells");
if (!local_node) { if (!local_node) {
dev_err(&pdev->dev, "no state entry\n"); dev_err(&pdev->dev, "no state entry\n");
return -EINVAL; return -EINVAL;
......
/* /*
* Copyright (c) 2016, Linaro Ltd.
* Copyright (c) 2015, Sony Mobile Communications Inc. * Copyright (c) 2015, Sony Mobile Communications Inc.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -14,8 +15,16 @@ ...@@ -14,8 +15,16 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/soc/qcom/smd.h> #include <linux/soc/qcom/smd.h>
#include <linux/io.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/soc/qcom/wcnss_ctrl.h>
#define WCNSS_REQUEST_TIMEOUT (5 * HZ) #define WCNSS_REQUEST_TIMEOUT (5 * HZ)
#define WCNSS_CBC_TIMEOUT (10 * HZ)
#define WCNSS_ACK_DONE_BOOTING 1
#define WCNSS_ACK_COLD_BOOTING 2
#define NV_FRAGMENT_SIZE 3072 #define NV_FRAGMENT_SIZE 3072
#define NVBIN_FILE "wlan/prima/WCNSS_qcom_wlan_nv.bin" #define NVBIN_FILE "wlan/prima/WCNSS_qcom_wlan_nv.bin"
...@@ -25,17 +34,19 @@ ...@@ -25,17 +34,19 @@
* @dev: device handle * @dev: device handle
* @channel: SMD channel handle * @channel: SMD channel handle
* @ack: completion for outstanding requests * @ack: completion for outstanding requests
* @cbc: completion for cbc complete indication
* @ack_status: status of the outstanding request * @ack_status: status of the outstanding request
* @download_nv_work: worker for uploading nv binary * @probe_work: worker for uploading nv binary
*/ */
struct wcnss_ctrl { struct wcnss_ctrl {
struct device *dev; struct device *dev;
struct qcom_smd_channel *channel; struct qcom_smd_channel *channel;
struct completion ack; struct completion ack;
struct completion cbc;
int ack_status; int ack_status;
struct work_struct download_nv_work; struct work_struct probe_work;
}; };
/* message types */ /* message types */
...@@ -48,6 +59,11 @@ enum { ...@@ -48,6 +59,11 @@ enum {
WCNSS_UPLOAD_CAL_RESP, WCNSS_UPLOAD_CAL_RESP,
WCNSS_DOWNLOAD_CAL_REQ, WCNSS_DOWNLOAD_CAL_REQ,
WCNSS_DOWNLOAD_CAL_RESP, WCNSS_DOWNLOAD_CAL_RESP,
WCNSS_VBAT_LEVEL_IND,
WCNSS_BUILD_VERSION_REQ,
WCNSS_BUILD_VERSION_RESP,
WCNSS_PM_CONFIG_REQ,
WCNSS_CBC_COMPLETE_IND,
}; };
/** /**
...@@ -128,7 +144,7 @@ static int wcnss_ctrl_smd_callback(struct qcom_smd_channel *channel, ...@@ -128,7 +144,7 @@ static int wcnss_ctrl_smd_callback(struct qcom_smd_channel *channel,
version->major, version->minor, version->major, version->minor,
version->version, version->revision); version->version, version->revision);
schedule_work(&wcnss->download_nv_work); complete(&wcnss->ack);
break; break;
case WCNSS_DOWNLOAD_NV_RESP: case WCNSS_DOWNLOAD_NV_RESP:
if (count != sizeof(*nvresp)) { if (count != sizeof(*nvresp)) {
...@@ -141,6 +157,10 @@ static int wcnss_ctrl_smd_callback(struct qcom_smd_channel *channel, ...@@ -141,6 +157,10 @@ static int wcnss_ctrl_smd_callback(struct qcom_smd_channel *channel,
wcnss->ack_status = nvresp->status; wcnss->ack_status = nvresp->status;
complete(&wcnss->ack); complete(&wcnss->ack);
break; break;
case WCNSS_CBC_COMPLETE_IND:
dev_dbg(wcnss->dev, "cold boot complete\n");
complete(&wcnss->cbc);
break;
default: default:
dev_info(wcnss->dev, "unknown message type %d\n", hdr->type); dev_info(wcnss->dev, "unknown message type %d\n", hdr->type);
break; break;
...@@ -156,20 +176,32 @@ static int wcnss_ctrl_smd_callback(struct qcom_smd_channel *channel, ...@@ -156,20 +176,32 @@ static int wcnss_ctrl_smd_callback(struct qcom_smd_channel *channel,
static int wcnss_request_version(struct wcnss_ctrl *wcnss) static int wcnss_request_version(struct wcnss_ctrl *wcnss)
{ {
struct wcnss_msg_hdr msg; struct wcnss_msg_hdr msg;
int ret;
msg.type = WCNSS_VERSION_REQ; msg.type = WCNSS_VERSION_REQ;
msg.len = sizeof(msg); msg.len = sizeof(msg);
ret = qcom_smd_send(wcnss->channel, &msg, sizeof(msg));
if (ret < 0)
return ret;
ret = wait_for_completion_timeout(&wcnss->ack, WCNSS_CBC_TIMEOUT);
if (!ret) {
dev_err(wcnss->dev, "timeout waiting for version response\n");
return -ETIMEDOUT;
}
return qcom_smd_send(wcnss->channel, &msg, sizeof(msg)); return 0;
} }
/** /**
* wcnss_download_nv() - send nv binary to WCNSS * wcnss_download_nv() - send nv binary to WCNSS
* @work: work struct to acquire wcnss context * @wcnss: wcnss_ctrl state handle
* @expect_cbc: indicator to caller that an cbc event is expected
*
* Returns 0 on success. Negative errno on failure.
*/ */
static void wcnss_download_nv(struct work_struct *work) static int wcnss_download_nv(struct wcnss_ctrl *wcnss, bool *expect_cbc)
{ {
struct wcnss_ctrl *wcnss = container_of(work, struct wcnss_ctrl, download_nv_work);
struct wcnss_download_nv_req *req; struct wcnss_download_nv_req *req;
const struct firmware *fw; const struct firmware *fw;
const void *data; const void *data;
...@@ -178,10 +210,10 @@ static void wcnss_download_nv(struct work_struct *work) ...@@ -178,10 +210,10 @@ static void wcnss_download_nv(struct work_struct *work)
req = kzalloc(sizeof(*req) + NV_FRAGMENT_SIZE, GFP_KERNEL); req = kzalloc(sizeof(*req) + NV_FRAGMENT_SIZE, GFP_KERNEL);
if (!req) if (!req)
return; return -ENOMEM;
ret = request_firmware(&fw, NVBIN_FILE, wcnss->dev); ret = request_firmware(&fw, NVBIN_FILE, wcnss->dev);
if (ret) { if (ret < 0) {
dev_err(wcnss->dev, "Failed to load nv file %s: %d\n", dev_err(wcnss->dev, "Failed to load nv file %s: %d\n",
NVBIN_FILE, ret); NVBIN_FILE, ret);
goto free_req; goto free_req;
...@@ -207,7 +239,7 @@ static void wcnss_download_nv(struct work_struct *work) ...@@ -207,7 +239,7 @@ static void wcnss_download_nv(struct work_struct *work)
memcpy(req->fragment, data, req->frag_size); memcpy(req->fragment, data, req->frag_size);
ret = qcom_smd_send(wcnss->channel, req, req->hdr.len); ret = qcom_smd_send(wcnss->channel, req, req->hdr.len);
if (ret) { if (ret < 0) {
dev_err(wcnss->dev, "failed to send smd packet\n"); dev_err(wcnss->dev, "failed to send smd packet\n");
goto release_fw; goto release_fw;
} }
...@@ -220,16 +252,58 @@ static void wcnss_download_nv(struct work_struct *work) ...@@ -220,16 +252,58 @@ static void wcnss_download_nv(struct work_struct *work)
} while (left > 0); } while (left > 0);
ret = wait_for_completion_timeout(&wcnss->ack, WCNSS_REQUEST_TIMEOUT); ret = wait_for_completion_timeout(&wcnss->ack, WCNSS_REQUEST_TIMEOUT);
if (!ret) if (!ret) {
dev_err(wcnss->dev, "timeout waiting for nv upload ack\n"); dev_err(wcnss->dev, "timeout waiting for nv upload ack\n");
else if (wcnss->ack_status != 1) ret = -ETIMEDOUT;
dev_err(wcnss->dev, "nv upload response failed err: %d\n", } else {
wcnss->ack_status); *expect_cbc = wcnss->ack_status == WCNSS_ACK_COLD_BOOTING;
ret = 0;
}
release_fw: release_fw:
release_firmware(fw); release_firmware(fw);
free_req: free_req:
kfree(req); kfree(req);
return ret;
}
/**
* qcom_wcnss_open_channel() - open additional SMD channel to WCNSS
* @wcnss: wcnss handle, retrieved from drvdata
* @name: SMD channel name
* @cb: callback to handle incoming data on the channel
*/
struct qcom_smd_channel *qcom_wcnss_open_channel(void *wcnss, const char *name, qcom_smd_cb_t cb)
{
struct wcnss_ctrl *_wcnss = wcnss;
return qcom_smd_open_channel(_wcnss->channel, name, cb);
}
EXPORT_SYMBOL(qcom_wcnss_open_channel);
static void wcnss_async_probe(struct work_struct *work)
{
struct wcnss_ctrl *wcnss = container_of(work, struct wcnss_ctrl, probe_work);
bool expect_cbc;
int ret;
ret = wcnss_request_version(wcnss);
if (ret < 0)
return;
ret = wcnss_download_nv(wcnss, &expect_cbc);
if (ret < 0)
return;
/* Wait for pending cold boot completion if indicated by the nv downloader */
if (expect_cbc) {
ret = wait_for_completion_timeout(&wcnss->cbc, WCNSS_REQUEST_TIMEOUT);
if (!ret)
dev_err(wcnss->dev, "expected cold boot completion\n");
}
of_platform_populate(wcnss->dev->of_node, NULL, NULL, wcnss->dev);
} }
static int wcnss_ctrl_probe(struct qcom_smd_device *sdev) static int wcnss_ctrl_probe(struct qcom_smd_device *sdev)
...@@ -244,25 +318,38 @@ static int wcnss_ctrl_probe(struct qcom_smd_device *sdev) ...@@ -244,25 +318,38 @@ static int wcnss_ctrl_probe(struct qcom_smd_device *sdev)
wcnss->channel = sdev->channel; wcnss->channel = sdev->channel;
init_completion(&wcnss->ack); init_completion(&wcnss->ack);
INIT_WORK(&wcnss->download_nv_work, wcnss_download_nv); init_completion(&wcnss->cbc);
INIT_WORK(&wcnss->probe_work, wcnss_async_probe);
qcom_smd_set_drvdata(sdev->channel, wcnss); qcom_smd_set_drvdata(sdev->channel, wcnss);
dev_set_drvdata(&sdev->dev, wcnss);
schedule_work(&wcnss->probe_work);
return 0;
}
static void wcnss_ctrl_remove(struct qcom_smd_device *sdev)
{
struct wcnss_ctrl *wcnss = qcom_smd_get_drvdata(sdev->channel);
return wcnss_request_version(wcnss); cancel_work_sync(&wcnss->probe_work);
of_platform_depopulate(&sdev->dev);
} }
static const struct qcom_smd_id wcnss_ctrl_smd_match[] = { static const struct of_device_id wcnss_ctrl_of_match[] = {
{ .name = "WCNSS_CTRL" }, { .compatible = "qcom,wcnss", },
{} {}
}; };
static struct qcom_smd_driver wcnss_ctrl_driver = { static struct qcom_smd_driver wcnss_ctrl_driver = {
.probe = wcnss_ctrl_probe, .probe = wcnss_ctrl_probe,
.remove = wcnss_ctrl_remove,
.callback = wcnss_ctrl_smd_callback, .callback = wcnss_ctrl_smd_callback,
.smd_match_table = wcnss_ctrl_smd_match,
.driver = { .driver = {
.name = "qcom_wcnss_ctrl", .name = "qcom_wcnss_ctrl",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = wcnss_ctrl_of_match,
}, },
}; };
......
...@@ -10,4 +10,8 @@ config EXYNOS_PMU ...@@ -10,4 +10,8 @@ config EXYNOS_PMU
bool "Exynos PMU controller driver" if COMPILE_TEST bool "Exynos PMU controller driver" if COMPILE_TEST
depends on (ARM && ARCH_EXYNOS) || ((ARM || ARM64) && COMPILE_TEST) depends on (ARM && ARCH_EXYNOS) || ((ARM || ARM64) && COMPILE_TEST)
config EXYNOS_PM_DOMAINS
bool "Exynos PM domains" if COMPILE_TEST
depends on PM_GENERIC_DOMAINS || COMPILE_TEST
endif endif
obj-$(CONFIG_EXYNOS_PMU) += exynos-pmu.o exynos3250-pmu.o exynos4-pmu.o \ obj-$(CONFIG_EXYNOS_PMU) += exynos-pmu.o exynos3250-pmu.o exynos4-pmu.o \
exynos5250-pmu.o exynos5420-pmu.o exynos5250-pmu.o exynos5420-pmu.o
obj-$(CONFIG_EXYNOS_PM_DOMAINS) += pm_domains.o
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
#include "exynos-pmu.h" #include "exynos-pmu.h"
static struct exynos_pmu_conf exynos3250_pmu_config[] = { static const struct exynos_pmu_conf exynos3250_pmu_config[] = {
/* { .offset = offset, .val = { AFTR, W-AFTR, SLEEP } */ /* { .offset = offset, .val = { AFTR, W-AFTR, SLEEP } */
{ EXYNOS3_ARM_CORE0_SYS_PWR_REG, { 0x0, 0x0, 0x2} }, { EXYNOS3_ARM_CORE0_SYS_PWR_REG, { 0x0, 0x0, 0x2} },
{ EXYNOS3_DIS_IRQ_ARM_CORE0_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, { EXYNOS3_DIS_IRQ_ARM_CORE0_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
#include "exynos-pmu.h" #include "exynos-pmu.h"
static struct exynos_pmu_conf exynos5420_pmu_config[] = { static const struct exynos_pmu_conf exynos5420_pmu_config[] = {
/* { .offset = offset, .val = { AFTR, LPA, SLEEP } */ /* { .offset = offset, .val = { AFTR, LPA, SLEEP } */
{ EXYNOS5_ARM_CORE0_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, { EXYNOS5_ARM_CORE0_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
{ EXYNOS5_DIS_IRQ_ARM_CORE0_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, { EXYNOS5_DIS_IRQ_ARM_CORE0_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
......
...@@ -23,9 +23,13 @@ ...@@ -23,9 +23,13 @@
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/sched.h> #include <linux/sched.h>
#define INT_LOCAL_PWR_EN 0x7
#define MAX_CLK_PER_DOMAIN 4 #define MAX_CLK_PER_DOMAIN 4
struct exynos_pm_domain_config {
/* Value for LOCAL_PWR_CFG and STATUS fields for each domain */
u32 local_pwr_cfg;
};
/* /*
* Exynos specific wrapper around the generic power domain * Exynos specific wrapper around the generic power domain
*/ */
...@@ -38,6 +42,7 @@ struct exynos_pm_domain { ...@@ -38,6 +42,7 @@ struct exynos_pm_domain {
struct clk *clk[MAX_CLK_PER_DOMAIN]; struct clk *clk[MAX_CLK_PER_DOMAIN];
struct clk *pclk[MAX_CLK_PER_DOMAIN]; struct clk *pclk[MAX_CLK_PER_DOMAIN];
struct clk *asb_clk[MAX_CLK_PER_DOMAIN]; struct clk *asb_clk[MAX_CLK_PER_DOMAIN];
u32 local_pwr_cfg;
}; };
static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on) static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on)
...@@ -69,13 +74,13 @@ static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on) ...@@ -69,13 +74,13 @@ static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on)
} }
} }
pwr = power_on ? INT_LOCAL_PWR_EN : 0; pwr = power_on ? pd->local_pwr_cfg : 0;
writel_relaxed(pwr, base); writel_relaxed(pwr, base);
/* Wait max 1ms */ /* Wait max 1ms */
timeout = 10; timeout = 10;
while ((readl_relaxed(base + 0x4) & INT_LOCAL_PWR_EN) != pwr) { while ((readl_relaxed(base + 0x4) & pd->local_pwr_cfg) != pwr) {
if (!timeout) { if (!timeout) {
op = (power_on) ? "enable" : "disable"; op = (power_on) ? "enable" : "disable";
pr_err("Power domain %s %s failed\n", domain->name, op); pr_err("Power domain %s %s failed\n", domain->name, op);
...@@ -119,14 +124,30 @@ static int exynos_pd_power_off(struct generic_pm_domain *domain) ...@@ -119,14 +124,30 @@ static int exynos_pd_power_off(struct generic_pm_domain *domain)
return exynos_pd_power(domain, false); return exynos_pd_power(domain, false);
} }
static const struct exynos_pm_domain_config exynos4210_cfg __initconst = {
.local_pwr_cfg = 0x7,
};
static const struct of_device_id exynos_pm_domain_of_match[] __initconst = {
{
.compatible = "samsung,exynos4210-pd",
.data = &exynos4210_cfg,
},
{ },
};
static __init int exynos4_pm_init_power_domain(void) static __init int exynos4_pm_init_power_domain(void)
{ {
struct device_node *np; struct device_node *np;
const struct of_device_id *match;
for_each_compatible_node(np, NULL, "samsung,exynos4210-pd") { for_each_matching_node_and_match(np, exynos_pm_domain_of_match, &match) {
const struct exynos_pm_domain_config *pm_domain_cfg;
struct exynos_pm_domain *pd; struct exynos_pm_domain *pd;
int on, i; int on, i;
pm_domain_cfg = match->data;
pd = kzalloc(sizeof(*pd), GFP_KERNEL); pd = kzalloc(sizeof(*pd), GFP_KERNEL);
if (!pd) { if (!pd) {
pr_err("%s: failed to allocate memory for domain\n", pr_err("%s: failed to allocate memory for domain\n",
...@@ -153,6 +174,7 @@ static __init int exynos4_pm_init_power_domain(void) ...@@ -153,6 +174,7 @@ static __init int exynos4_pm_init_power_domain(void)
pd->pd.power_off = exynos_pd_power_off; pd->pd.power_off = exynos_pd_power_off;
pd->pd.power_on = exynos_pd_power_on; pd->pd.power_on = exynos_pd_power_on;
pd->local_pwr_cfg = pm_domain_cfg->local_pwr_cfg;
for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) { for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) {
char clk_name[8]; char clk_name[8];
...@@ -185,14 +207,14 @@ static __init int exynos4_pm_init_power_domain(void) ...@@ -185,14 +207,14 @@ static __init int exynos4_pm_init_power_domain(void)
clk_put(pd->oscclk); clk_put(pd->oscclk);
no_clk: no_clk:
on = readl_relaxed(pd->base + 0x4) & INT_LOCAL_PWR_EN; on = readl_relaxed(pd->base + 0x4) & pd->local_pwr_cfg;
pm_genpd_init(&pd->pd, NULL, !on); pm_genpd_init(&pd->pd, NULL, !on);
of_genpd_add_provider_simple(np, &pd->pd); of_genpd_add_provider_simple(np, &pd->pd);
} }
/* Assign the child power domains to their parents */ /* Assign the child power domains to their parents */
for_each_compatible_node(np, NULL, "samsung,exynos4210-pd") { for_each_matching_node(np, exynos_pm_domain_of_match) {
struct generic_pm_domain *child_domain, *parent_domain; struct generic_pm_domain *child_domain, *parent_domain;
struct of_phandle_args args; struct of_phandle_args args;
......
...@@ -51,6 +51,7 @@ ...@@ -51,6 +51,7 @@
#define PMC_CNTRL_CPU_PWRREQ_POLARITY (1 << 15) /* CPU pwr req polarity */ #define PMC_CNTRL_CPU_PWRREQ_POLARITY (1 << 15) /* CPU pwr req polarity */
#define PMC_CNTRL_CPU_PWRREQ_OE (1 << 16) /* CPU pwr req enable */ #define PMC_CNTRL_CPU_PWRREQ_OE (1 << 16) /* CPU pwr req enable */
#define PMC_CNTRL_INTR_POLARITY (1 << 17) /* inverts INTR polarity */ #define PMC_CNTRL_INTR_POLARITY (1 << 17) /* inverts INTR polarity */
#define PMC_CNTRL_MAIN_RST (1 << 4)
#define DPD_SAMPLE 0x020 #define DPD_SAMPLE 0x020
#define DPD_SAMPLE_ENABLE (1 << 0) #define DPD_SAMPLE_ENABLE (1 << 0)
...@@ -80,6 +81,14 @@ ...@@ -80,6 +81,14 @@
#define PMC_SENSOR_CTRL_SCRATCH_WRITE (1 << 2) #define PMC_SENSOR_CTRL_SCRATCH_WRITE (1 << 2)
#define PMC_SENSOR_CTRL_ENABLE_RST (1 << 1) #define PMC_SENSOR_CTRL_ENABLE_RST (1 << 1)
#define PMC_RST_STATUS 0x1b4
#define PMC_RST_STATUS_POR 0
#define PMC_RST_STATUS_WATCHDOG 1
#define PMC_RST_STATUS_SENSOR 2
#define PMC_RST_STATUS_SW_MAIN 3
#define PMC_RST_STATUS_LP0 4
#define PMC_RST_STATUS_AOTAG 5
#define IO_DPD_REQ 0x1b8 #define IO_DPD_REQ 0x1b8
#define IO_DPD_REQ_CODE_IDLE (0 << 30) #define IO_DPD_REQ_CODE_IDLE (0 << 30)
#define IO_DPD_REQ_CODE_OFF (1 << 30) #define IO_DPD_REQ_CODE_OFF (1 << 30)
...@@ -399,6 +408,7 @@ static int tegra_powergate_power_up(struct tegra_powergate *pg, ...@@ -399,6 +408,7 @@ static int tegra_powergate_power_up(struct tegra_powergate *pg,
disable_clks: disable_clks:
tegra_powergate_disable_clocks(pg); tegra_powergate_disable_clocks(pg);
usleep_range(10, 20); usleep_range(10, 20);
powergate_off: powergate_off:
tegra_powergate_set(pg->id, false); tegra_powergate_set(pg->id, false);
...@@ -436,6 +446,7 @@ static int tegra_powergate_power_down(struct tegra_powergate *pg) ...@@ -436,6 +446,7 @@ static int tegra_powergate_power_down(struct tegra_powergate *pg)
usleep_range(10, 20); usleep_range(10, 20);
tegra_powergate_reset_deassert(pg); tegra_powergate_reset_deassert(pg);
usleep_range(10, 20); usleep_range(10, 20);
disable_clks: disable_clks:
tegra_powergate_disable_clocks(pg); tegra_powergate_disable_clocks(pg);
...@@ -540,6 +551,9 @@ int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk, ...@@ -540,6 +551,9 @@ int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk,
struct tegra_powergate pg; struct tegra_powergate pg;
int err; int err;
if (!tegra_powergate_is_available(id))
return -EINVAL;
pg.id = id; pg.id = id;
pg.clks = &clk; pg.clks = &clk;
pg.num_clks = 1; pg.num_clks = 1;
...@@ -638,9 +652,10 @@ static int tegra_pmc_restart_notify(struct notifier_block *this, ...@@ -638,9 +652,10 @@ static int tegra_pmc_restart_notify(struct notifier_block *this,
tegra_pmc_writel(value, PMC_SCRATCH0); tegra_pmc_writel(value, PMC_SCRATCH0);
value = tegra_pmc_readl(0); /* reset everything but PMC_SCRATCH0 and PMC_RST_STATUS */
value |= 0x10; value = tegra_pmc_readl(PMC_CNTRL);
tegra_pmc_writel(value, 0); value |= PMC_CNTRL_MAIN_RST;
tegra_pmc_writel(value, PMC_CNTRL);
return NOTIFY_DONE; return NOTIFY_DONE;
} }
...@@ -722,13 +737,14 @@ static int tegra_powergate_of_get_clks(struct tegra_powergate *pg, ...@@ -722,13 +737,14 @@ static int tegra_powergate_of_get_clks(struct tegra_powergate *pg,
err: err:
while (i--) while (i--)
clk_put(pg->clks[i]); clk_put(pg->clks[i]);
kfree(pg->clks); kfree(pg->clks);
return err; return err;
} }
static int tegra_powergate_of_get_resets(struct tegra_powergate *pg, static int tegra_powergate_of_get_resets(struct tegra_powergate *pg,
struct device_node *np) struct device_node *np, bool off)
{ {
struct reset_control *rst; struct reset_control *rst;
unsigned int i, count; unsigned int i, count;
...@@ -748,6 +764,16 @@ static int tegra_powergate_of_get_resets(struct tegra_powergate *pg, ...@@ -748,6 +764,16 @@ static int tegra_powergate_of_get_resets(struct tegra_powergate *pg,
err = PTR_ERR(pg->resets[i]); err = PTR_ERR(pg->resets[i]);
goto error; goto error;
} }
if (off)
err = reset_control_assert(pg->resets[i]);
else
err = reset_control_deassert(pg->resets[i]);
if (err) {
reset_control_put(pg->resets[i]);
goto error;
}
} }
pg->num_resets = count; pg->num_resets = count;
...@@ -757,6 +783,7 @@ static int tegra_powergate_of_get_resets(struct tegra_powergate *pg, ...@@ -757,6 +783,7 @@ static int tegra_powergate_of_get_resets(struct tegra_powergate *pg,
error: error:
while (i--) while (i--)
reset_control_put(pg->resets[i]); reset_control_put(pg->resets[i]);
kfree(pg->resets); kfree(pg->resets);
return err; return err;
...@@ -765,16 +792,19 @@ static int tegra_powergate_of_get_resets(struct tegra_powergate *pg, ...@@ -765,16 +792,19 @@ static int tegra_powergate_of_get_resets(struct tegra_powergate *pg,
static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
{ {
struct tegra_powergate *pg; struct tegra_powergate *pg;
int id, err;
bool off; bool off;
int id;
pg = kzalloc(sizeof(*pg), GFP_KERNEL); pg = kzalloc(sizeof(*pg), GFP_KERNEL);
if (!pg) if (!pg)
goto error; return;
id = tegra_powergate_lookup(pmc, np->name); id = tegra_powergate_lookup(pmc, np->name);
if (id < 0) if (id < 0) {
dev_err(pmc->dev, "powergate lookup failed for %s: %d\n",
np->name, id);
goto free_mem; goto free_mem;
}
/* /*
* Clear the bit for this powergate so it cannot be managed * Clear the bit for this powergate so it cannot be managed
...@@ -788,31 +818,64 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) ...@@ -788,31 +818,64 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
pg->genpd.power_on = tegra_genpd_power_on; pg->genpd.power_on = tegra_genpd_power_on;
pg->pmc = pmc; pg->pmc = pmc;
if (tegra_powergate_of_get_clks(pg, np)) off = !tegra_powergate_is_powered(pg->id);
err = tegra_powergate_of_get_clks(pg, np);
if (err < 0) {
dev_err(pmc->dev, "failed to get clocks for %s: %d\n",
np->name, err);
goto set_available; goto set_available;
}
if (tegra_powergate_of_get_resets(pg, np)) err = tegra_powergate_of_get_resets(pg, np, off);
if (err < 0) {
dev_err(pmc->dev, "failed to get resets for %s: %d\n",
np->name, err);
goto remove_clks; goto remove_clks;
}
off = !tegra_powergate_is_powered(pg->id); if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS))
goto power_on_cleanup;
/*
* FIXME: If XHCI is enabled for Tegra, then power-up the XUSB
* host and super-speed partitions. Once the XHCI driver
* manages the partitions itself this code can be removed. Note
* that we don't register these partitions with the genpd core
* to avoid it from powering down the partitions as they appear
* to be unused.
*/
if (IS_ENABLED(CONFIG_USB_XHCI_TEGRA) &&
(id == TEGRA_POWERGATE_XUSBA || id == TEGRA_POWERGATE_XUSBC))
goto power_on_cleanup;
pm_genpd_init(&pg->genpd, NULL, off); pm_genpd_init(&pg->genpd, NULL, off);
if (of_genpd_add_provider_simple(np, &pg->genpd)) err = of_genpd_add_provider_simple(np, &pg->genpd);
if (err < 0) {
dev_err(pmc->dev, "failed to add genpd provider for %s: %d\n",
np->name, err);
goto remove_resets; goto remove_resets;
}
dev_dbg(pmc->dev, "added power domain %s\n", pg->genpd.name); dev_dbg(pmc->dev, "added power domain %s\n", pg->genpd.name);
return; return;
power_on_cleanup:
if (off)
WARN_ON(tegra_powergate_power_up(pg, true));
remove_resets: remove_resets:
while (pg->num_resets--) while (pg->num_resets--)
reset_control_put(pg->resets[pg->num_resets]); reset_control_put(pg->resets[pg->num_resets]);
kfree(pg->resets); kfree(pg->resets);
remove_clks: remove_clks:
while (pg->num_clks--) while (pg->num_clks--)
clk_put(pg->clks[pg->num_clks]); clk_put(pg->clks[pg->num_clks]);
kfree(pg->clks); kfree(pg->clks);
set_available: set_available:
...@@ -820,16 +883,20 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) ...@@ -820,16 +883,20 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
free_mem: free_mem:
kfree(pg); kfree(pg);
error:
dev_err(pmc->dev, "failed to create power domain for %s\n", np->name);
} }
static void tegra_powergate_init(struct tegra_pmc *pmc) static void tegra_powergate_init(struct tegra_pmc *pmc,
struct device_node *parent)
{ {
struct device_node *np, *child; struct device_node *np, *child;
unsigned int i;
/* Create a bitmap of the available and valid partitions */
for (i = 0; i < pmc->soc->num_powergates; i++)
if (pmc->soc->powergates[i])
set_bit(i, pmc->powergates_available);
np = of_get_child_by_name(pmc->dev->of_node, "powergates"); np = of_get_child_by_name(parent, "powergates");
if (!np) if (!np)
return; return;
...@@ -1205,6 +1272,14 @@ static int tegra_pmc_probe(struct platform_device *pdev) ...@@ -1205,6 +1272,14 @@ static int tegra_pmc_probe(struct platform_device *pdev)
struct resource *res; struct resource *res;
int err; int err;
/*
* Early initialisation should have configured an initial
* register mapping and setup the soc data pointer. If these
* are not valid then something went badly wrong!
*/
if (WARN_ON(!pmc->base || !pmc->soc))
return -ENODEV;
err = tegra_pmc_parse_dt(pmc, pdev->dev.of_node); err = tegra_pmc_parse_dt(pmc, pdev->dev.of_node);
if (err < 0) if (err < 0)
return err; return err;
...@@ -1242,8 +1317,6 @@ static int tegra_pmc_probe(struct platform_device *pdev) ...@@ -1242,8 +1317,6 @@ static int tegra_pmc_probe(struct platform_device *pdev)
return err; return err;
} }
tegra_powergate_init(pmc);
mutex_lock(&pmc->powergates_lock); mutex_lock(&pmc->powergates_lock);
iounmap(pmc->base); iounmap(pmc->base);
pmc->base = base; pmc->base = base;
...@@ -1477,10 +1550,11 @@ static int __init tegra_pmc_early_init(void) ...@@ -1477,10 +1550,11 @@ static int __init tegra_pmc_early_init(void)
const struct of_device_id *match; const struct of_device_id *match;
struct device_node *np; struct device_node *np;
struct resource regs; struct resource regs;
unsigned int i;
bool invert; bool invert;
u32 value; u32 value;
mutex_init(&pmc->powergates_lock);
np = of_find_matching_node_and_match(NULL, tegra_pmc_match, &match); np = of_find_matching_node_and_match(NULL, tegra_pmc_match, &match);
if (!np) { if (!np) {
/* /*
...@@ -1515,39 +1589,40 @@ static int __init tegra_pmc_early_init(void) ...@@ -1515,39 +1589,40 @@ static int __init tegra_pmc_early_init(void)
*/ */
if (of_address_to_resource(np, 0, &regs) < 0) { if (of_address_to_resource(np, 0, &regs) < 0) {
pr_err("failed to get PMC registers\n"); pr_err("failed to get PMC registers\n");
of_node_put(np);
return -ENXIO; return -ENXIO;
} }
pmc->soc = match->data;
} }
pmc->base = ioremap_nocache(regs.start, resource_size(&regs)); pmc->base = ioremap_nocache(regs.start, resource_size(&regs));
if (!pmc->base) { if (!pmc->base) {
pr_err("failed to map PMC registers\n"); pr_err("failed to map PMC registers\n");
of_node_put(np);
return -ENXIO; return -ENXIO;
} }
/* Create a bit-map of the available and valid partitions */ if (np) {
for (i = 0; i < pmc->soc->num_powergates; i++) pmc->soc = match->data;
if (pmc->soc->powergates[i])
set_bit(i, pmc->powergates_available);
mutex_init(&pmc->powergates_lock); tegra_powergate_init(pmc, np);
/* /*
* Invert the interrupt polarity if a PMC device tree node exists and * Invert the interrupt polarity if a PMC device tree node
* contains the nvidia,invert-interrupt property. * exists and contains the nvidia,invert-interrupt property.
*/ */
invert = of_property_read_bool(np, "nvidia,invert-interrupt"); invert = of_property_read_bool(np, "nvidia,invert-interrupt");
value = tegra_pmc_readl(PMC_CNTRL); value = tegra_pmc_readl(PMC_CNTRL);
if (invert) if (invert)
value |= PMC_CNTRL_INTR_POLARITY; value |= PMC_CNTRL_INTR_POLARITY;
else else
value &= ~PMC_CNTRL_INTR_POLARITY; value &= ~PMC_CNTRL_INTR_POLARITY;
tegra_pmc_writel(value, PMC_CNTRL); tegra_pmc_writel(value, PMC_CNTRL);
of_node_put(np);
}
return 0; return 0;
} }
......
config UX500_SOC_ID
bool "SoC bus for ST-Ericsson ux500"
depends on ARCH_U8500 || COMPILE_TEST
default ARCH_U8500
help
Include support for the SoC bus on the ARM RealView platforms
providing some sysfs information about the ASIC variant.
obj-$(CONFIG_UX500_SOC_ID) += ux500-soc-id.o
...@@ -8,43 +8,51 @@ ...@@ -8,43 +8,51 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/module.h>
#include <linux/random.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/sys_soc.h>
#include <asm/cputype.h> #include <asm/cputype.h>
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/mach/map.h> #include <asm/mach/map.h>
#include "setup.h" /**
* struct dbx500_asic_id - fields of the ASIC ID
#include "db8500-regs.h" * @process: the manufacturing process, 0x40 is 40 nm 0x00 is "standard"
#include "id.h" * @partnumber: hithereto 0x8500 for DB8500
* @revision: version code in the series
*/
struct dbx500_asic_id {
u16 partnumber;
u8 revision;
u8 process;
};
struct dbx500_asic_id dbx500_id; static struct dbx500_asic_id dbx500_id;
static unsigned int __init ux500_read_asicid(phys_addr_t addr) static unsigned int __init ux500_read_asicid(phys_addr_t addr)
{ {
phys_addr_t base = addr & ~0xfff; void __iomem *virt = ioremap(addr, 4);
struct map_desc desc = { unsigned int asicid;
.virtual = (unsigned long)UX500_VIRT_ROM,
.pfn = __phys_to_pfn(base),
.length = SZ_16K,
.type = MT_DEVICE,
};
iotable_init(&desc, 1); if (!virt)
return 0;
/* As in devicemaps_init() */ asicid = readl(virt);
local_flush_tlb_all(); iounmap(virt);
flush_cache_all();
return readl(UX500_VIRT_ROM + (addr & 0xfff)); return asicid;
} }
static void ux500_print_soc_info(unsigned int asicid) static void ux500_print_soc_info(unsigned int asicid)
{ {
unsigned int rev = dbx500_revision(); unsigned int rev = dbx500_id.revision;
pr_info("DB%4x ", dbx500_partnumber()); pr_info("DB%4x ", dbx500_id.partnumber);
if (rev == 0x01) if (rev == 0x01)
pr_cont("Early Drop"); pr_cont("Early Drop");
...@@ -72,7 +80,7 @@ static unsigned int partnumber(unsigned int asicid) ...@@ -72,7 +80,7 @@ static unsigned int partnumber(unsigned int asicid)
* DB9540 0x413fc090 0xFFFFDBF4 0x009540xx * DB9540 0x413fc090 0xFFFFDBF4 0x009540xx
*/ */
void __init ux500_setup_id(void) static void __init ux500_setup_id(void)
{ {
unsigned int cpuid = read_cpuid_id(); unsigned int cpuid = read_cpuid_id();
unsigned int asicid = 0; unsigned int asicid = 0;
...@@ -105,7 +113,7 @@ void __init ux500_setup_id(void) ...@@ -105,7 +113,7 @@ void __init ux500_setup_id(void)
if (!asicid) { if (!asicid) {
pr_err("Unable to identify SoC\n"); pr_err("Unable to identify SoC\n");
ux500_unknown_soc(); BUG();
} }
dbx500_id.process = asicid >> 24; dbx500_id.process = asicid >> 24;
...@@ -114,3 +122,101 @@ void __init ux500_setup_id(void) ...@@ -114,3 +122,101 @@ void __init ux500_setup_id(void)
ux500_print_soc_info(asicid); ux500_print_soc_info(asicid);
} }
static const char * __init ux500_get_machine(void)
{
return kasprintf(GFP_KERNEL, "DB%4x", dbx500_id.partnumber);
}
static const char * __init ux500_get_family(void)
{
return kasprintf(GFP_KERNEL, "ux500");
}
static const char * __init ux500_get_revision(void)
{
unsigned int rev = dbx500_id.revision;
if (rev == 0x01)
return kasprintf(GFP_KERNEL, "%s", "ED");
else if (rev >= 0xA0)
return kasprintf(GFP_KERNEL, "%d.%d",
(rev >> 4) - 0xA + 1, rev & 0xf);
return kasprintf(GFP_KERNEL, "%s", "Unknown");
}
static ssize_t ux500_get_process(struct device *dev,
struct device_attribute *attr,
char *buf)
{
if (dbx500_id.process == 0x00)
return sprintf(buf, "Standard\n");
return sprintf(buf, "%02xnm\n", dbx500_id.process);
}
static const char *db8500_read_soc_id(struct device_node *backupram)
{
void __iomem *base;
void __iomem *uid;
const char *retstr;
base = of_iomap(backupram, 0);
if (!base)
return NULL;
uid = base + 0x1fc0;
/* Throw these device-specific numbers into the entropy pool */
add_device_randomness(uid, 0x14);
retstr = kasprintf(GFP_KERNEL, "%08x%08x%08x%08x%08x",
readl((u32 *)uid+0),
readl((u32 *)uid+1), readl((u32 *)uid+2),
readl((u32 *)uid+3), readl((u32 *)uid+4));
iounmap(base);
return retstr;
}
static void __init soc_info_populate(struct soc_device_attribute *soc_dev_attr,
struct device_node *backupram)
{
soc_dev_attr->soc_id = db8500_read_soc_id(backupram);
soc_dev_attr->machine = ux500_get_machine();
soc_dev_attr->family = ux500_get_family();
soc_dev_attr->revision = ux500_get_revision();
}
static const struct device_attribute ux500_soc_attr =
__ATTR(process, S_IRUGO, ux500_get_process, NULL);
static int __init ux500_soc_device_init(void)
{
struct device *parent;
struct soc_device *soc_dev;
struct soc_device_attribute *soc_dev_attr;
struct device_node *backupram;
backupram = of_find_compatible_node(NULL, NULL, "ste,dbx500-backupram");
if (!backupram)
return 0;
ux500_setup_id();
soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
if (!soc_dev_attr)
return -ENOMEM;
soc_info_populate(soc_dev_attr, backupram);
soc_dev = soc_device_register(soc_dev_attr);
if (IS_ERR(soc_dev)) {
kfree(soc_dev_attr);
return PTR_ERR(soc_dev);
}
parent = soc_device_to_device(soc_dev);
device_create_file(parent, &ux500_soc_attr);
return 0;
}
subsys_initcall(ux500_soc_device_init);
...@@ -539,7 +539,7 @@ static int uart_clps711x_remove(struct platform_device *pdev) ...@@ -539,7 +539,7 @@ static int uart_clps711x_remove(struct platform_device *pdev)
} }
static const struct of_device_id __maybe_unused clps711x_uart_dt_ids[] = { static const struct of_device_id __maybe_unused clps711x_uart_dt_ids[] = {
{ .compatible = "cirrus,clps711x-uart", }, { .compatible = "cirrus,ep7209-uart", },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, clps711x_uart_dt_ids); MODULE_DEVICE_TABLE(of, clps711x_uart_dt_ids);
......
...@@ -273,7 +273,7 @@ static int clps711x_fb_probe(struct platform_device *pdev) ...@@ -273,7 +273,7 @@ static int clps711x_fb_probe(struct platform_device *pdev)
} }
cfb->syscon = cfb->syscon =
syscon_regmap_lookup_by_compatible("cirrus,clps711x-syscon1"); syscon_regmap_lookup_by_compatible("cirrus,ep7209-syscon1");
if (IS_ERR(cfb->syscon)) { if (IS_ERR(cfb->syscon)) {
ret = PTR_ERR(cfb->syscon); ret = PTR_ERR(cfb->syscon);
goto out_fb_release; goto out_fb_release;
...@@ -376,7 +376,7 @@ static int clps711x_fb_remove(struct platform_device *pdev) ...@@ -376,7 +376,7 @@ static int clps711x_fb_remove(struct platform_device *pdev)
} }
static const struct of_device_id clps711x_fb_dt_ids[] = { static const struct of_device_id clps711x_fb_dt_ids[] = {
{ .compatible = "cirrus,clps711x-fb", }, { .compatible = "cirrus,ep7209-fb", },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, clps711x_fb_dt_ids); MODULE_DEVICE_TABLE(of, clps711x_fb_dt_ids);
......
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* GPL LICENSE SUMMARY
*
* Copyright (c) 2016 BayLibre, SAS.
* Author: Neil Armstrong <narmstrong@baylibre.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
* BSD LICENSE
*
* Copyright (c) 2016 BayLibre, SAS.
* Author: Neil Armstrong <narmstrong@baylibre.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _DT_BINDINGS_AMLOGIC_MESON_GXBB_RESET_H
#define _DT_BINDINGS_AMLOGIC_MESON_GXBB_RESET_H
/* RESET0 */
#define RESET_HIU 0
/* 1 */
#define RESET_DOS_RESET 2
#define RESET_DDR_TOP 3
#define RESET_DCU_RESET 4
#define RESET_VIU 5
#define RESET_AIU 6
#define RESET_VID_PLL_DIV 7
/* 8 */
#define RESET_PMUX 9
#define RESET_VENC 10
#define RESET_ASSIST 11
#define RESET_AFIFO2 12
#define RESET_VCBUS 13
/* 14 */
/* 15 */
#define RESET_GIC 16
#define RESET_CAPB3_DECODE 17
#define RESET_NAND_CAPB3 18
#define RESET_HDMITX_CAPB3 19
#define RESET_MALI_CAPB3 20
#define RESET_DOS_CAPB3 21
#define RESET_SYS_CPU_CAPB3 22
#define RESET_CBUS_CAPB3 23
#define RESET_AHB_CNTL 24
#define RESET_AHB_DATA 25
#define RESET_VCBUS_CLK81 26
#define RESET_MMC 27
#define RESET_MIPI_0 28
#define RESET_MIPI_1 29
#define RESET_MIPI_2 30
#define RESET_MIPI_3 31
/* RESET1 */
#define RESET_CPPM 32
#define RESET_DEMUX 33
#define RESET_USB_OTG 34
#define RESET_DDR 35
#define RESET_AO_RESET 36
#define RESET_BT656 37
#define RESET_AHB_SRAM 38
/* 39 */
#define RESET_PARSER 40
#define RESET_BLKMV 41
#define RESET_ISA 42
#define RESET_ETHERNET 43
#define RESET_SD_EMMC_A 44
#define RESET_SD_EMMC_B 45
#define RESET_SD_EMMC_C 46
#define RESET_ROM_BOOT 47
#define RESET_SYS_CPU_0 48
#define RESET_SYS_CPU_1 49
#define RESET_SYS_CPU_2 50
#define RESET_SYS_CPU_3 51
#define RESET_SYS_CPU_CORE_0 52
#define RESET_SYS_CPU_CORE_1 53
#define RESET_SYS_CPU_CORE_2 54
#define RESET_SYS_CPU_CORE_3 55
#define RESET_SYS_PLL_DIV 56
#define RESET_SYS_CPU_AXI 57
#define RESET_SYS_CPU_L2 58
#define RESET_SYS_CPU_P 59
#define RESET_SYS_CPU_MBIST 60
/* 61 */
/* 62 */
/* 63 */
/* RESET2 */
#define RESET_VD_RMEM 64
#define RESET_AUDIN 65
#define RESET_HDMI_TX 66
/* 67 */
/* 68 */
/* 69 */
#define RESET_GE2D 70
#define RESET_PARSER_REG 71
#define RESET_PARSER_FETCH 72
#define RESET_PARSER_CTL 73
#define RESET_PARSER_TOP 74
/* 75 */
/* 76 */
#define RESET_AO_CPU_RESET 77
#define RESET_MALI 78
#define RESET_HDMI_SYSTEM_RESET 79
/* 80-95 */
/* RESET3 */
#define RESET_RING_OSCILLATOR 96
#define RESET_SYS_CPU 97
#define RESET_EFUSE 98
#define RESET_SYS_CPU_BVCI 99
#define RESET_AIFIFO 100
#define RESET_TVFE 101
#define RESET_AHB_BRIDGE_CNTL 102
/* 103 */
#define RESET_AUDIO_DAC 104
#define RESET_DEMUX_TOP 105
#define RESET_DEMUX_DES 106
#define RESET_DEMUX_S2P_0 107
#define RESET_DEMUX_S2P_1 108
#define RESET_DEMUX_RESET_0 109
#define RESET_DEMUX_RESET_1 110
#define RESET_DEMUX_RESET_2 111
/* 112-127 */
/* RESET4 */
/* 128 */
/* 129 */
/* 130 */
/* 131 */
#define RESET_DVIN_RESET 132
#define RESET_RDMA 133
#define RESET_VENCI 134
#define RESET_VENCP 135
/* 136 */
#define RESET_VDAC 137
#define RESET_RTC 138
/* 139 */
#define RESET_VDI6 140
#define RESET_VENCL 141
#define RESET_I2C_MASTER_2 142
#define RESET_I2C_MASTER_1 143
/* 144-159 */
/* RESET5 */
/* 160-191 */
/* RESET6 */
#define RESET_PERIPHS_GENERAL 192
#define RESET_PERIPHS_SPICC 193
#define RESET_PERIPHS_SMART_CARD 194
#define RESET_PERIPHS_SAR_ADC 195
#define RESET_PERIPHS_I2C_MASTER_0 196
#define RESET_SANA 197
/* 198 */
#define RESET_PERIPHS_STREAM_INTERFACE 199
#define RESET_PERIPHS_SDIO 200
#define RESET_PERIPHS_UART_0 201
#define RESET_PERIPHS_UART_1_2 202
#define RESET_PERIPHS_ASYNC_0 203
#define RESET_PERIPHS_ASYNC_1 204
#define RESET_PERIPHS_SPI_0 205
#define RESET_PERIPHS_SDHC 206
#define RESET_UART_SLIP 207
/* 208-223 */
/* RESET7 */
#define RESET_USB_DDR_0 224
#define RESET_USB_DDR_1 225
#define RESET_USB_DDR_2 226
#define RESET_USB_DDR_3 227
/* 228 */
#define RESET_DEVICE_MMC_ARB 229
/* 230 */
#define RESET_VID_LOCK 231
#define RESET_A9_DMC_PIPEL 232
/* 233-255 */
#endif
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* GPL LICENSE SUMMARY
*
* Copyright (c) 2016 BayLibre, SAS.
* Author: Neil Armstrong <narmstrong@baylibre.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
* BSD LICENSE
*
* Copyright (c) 2016 BayLibre, SAS.
* Author: Neil Armstrong <narmstrong@baylibre.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _DT_BINDINGS_AMLOGIC_MESON8B_RESET_H
#define _DT_BINDINGS_AMLOGIC_MESON8B_RESET_H
/* RESET0 */
#define RESET_HIU 0
#define RESET_VLD 1
#define RESET_IQIDCT 2
#define RESET_MC 3
/* 8 */
#define RESET_VIU 5
#define RESET_AIU 6
#define RESET_MCPU 7
#define RESET_CCPU 8
#define RESET_PMUX 9
#define RESET_VENC 10
#define RESET_ASSIST 11
#define RESET_AFIFO2 12
#define RESET_MDEC 13
#define RESET_VLD_PART 14
#define RESET_VIFIFO 15
/* 16-31 */
/* RESET1 */
/* 32 */
#define RESET_DEMUX 33
#define RESET_USB_OTG 34
#define RESET_DDR 35
#define RESET_VDAC_1 36
#define RESET_BT656 37
#define RESET_AHB_SRAM 38
#define RESET_AHB_BRIDGE 39
#define RESET_PARSER 40
#define RESET_BLKMV 41
#define RESET_ISA 42
#define RESET_ETHERNET 43
#define RESET_ABUF 44
#define RESET_AHB_DATA 45
#define RESET_AHB_CNTL 46
#define RESET_ROM_BOOT 47
/* 48-63 */
/* RESET2 */
#define RESET_VD_RMEM 64
#define RESET_AUDIN 65
#define RESET_DBLK 66
#define RESET_PIC_DC 66
#define RESET_PSC 66
#define RESET_NAND 66
#define RESET_GE2D 70
#define RESET_PARSER_REG 71
#define RESET_PARSER_FETCH 72
#define RESET_PARSER_CTL 73
#define RESET_PARSER_TOP 74
#define RESET_HDMI_APB 75
#define RESET_AUDIO_APB 76
#define RESET_MEDIA_CPU 77
#define RESET_MALI 78
#define RESET_HDMI_SYSTEM_RESET 79
/* 80-95 */
/* RESET3 */
#define RESET_RING_OSCILLATOR 96
#define RESET_SYS_CPU_0 97
#define RESET_EFUSE 98
#define RESET_SYS_CPU_BVCI 99
#define RESET_AIFIFO 100
#define RESET_AUDIO_PLL_MODULATOR 101
#define RESET_AHB_BRIDGE_CNTL 102
#define RESET_SYS_CPU_1 103
#define RESET_AUDIO_DAC 104
#define RESET_DEMUX_TOP 105
#define RESET_DEMUX_DES 106
#define RESET_DEMUX_S2P_0 107
#define RESET_DEMUX_S2P_1 108
#define RESET_DEMUX_RESET_0 109
#define RESET_DEMUX_RESET_1 110
#define RESET_DEMUX_RESET_2 111
/* 112-127 */
/* RESET4 */
#define RESET_PL310 128
#define RESET_A5_APB 129
#define RESET_A5_AXI 130
#define RESET_A5 131
#define RESET_DVIN 132
#define RESET_RDMA 133
#define RESET_VENCI 134
#define RESET_VENCP 135
#define RESET_VENCT 136
#define RESET_VDAC_4 137
#define RESET_RTC 138
#define RESET_A5_DEBUG 139
#define RESET_VDI6 140
#define RESET_VENCL 141
/* 142-159 */
/* RESET5 */
#define RESET_DDR_PLL 160
#define RESET_MISC_PLL 161
#define RESET_SYS_PLL 162
#define RESET_HPLL_PLL 163
#define RESET_AUDIO_PLL 164
#define RESET_VID2_PLL 165
/* 166-191 */
/* RESET6 */
#define RESET_PERIPHS_GENERAL 192
#define RESET_PERIPHS_IR_REMOTE 193
#define RESET_PERIPHS_SMART_CARD 194
#define RESET_PERIPHS_SAR_ADC 195
#define RESET_PERIPHS_I2C_MASTER_0 196
#define RESET_PERIPHS_I2C_MASTER_1 197
#define RESET_PERIPHS_I2C_SLAVE 198
#define RESET_PERIPHS_STREAM_INTERFACE 199
#define RESET_PERIPHS_SDIO 200
#define RESET_PERIPHS_UART_0 201
#define RESET_PERIPHS_UART_1 202
#define RESET_PERIPHS_ASYNC_0 203
#define RESET_PERIPHS_ASYNC_1 204
#define RESET_PERIPHS_SPI_0 205
#define RESET_PERIPHS_SPI_1 206
#define RESET_PERIPHS_LED_PWM 207
/* 208-223 */
/* RESET7 */
/* 224-255 */
#endif
...@@ -64,4 +64,12 @@ ...@@ -64,4 +64,12 @@
#define PERIPH_RSDIST9_CARM_SOCDBG 0x507 #define PERIPH_RSDIST9_CARM_SOCDBG 0x507
#define PERIPH_RSDIST9_CARM_ETM 0x508 #define PERIPH_RSDIST9_CARM_ETM 0x508
#define MEDIA_G3D 0
#define MEDIA_CODEC_VPU 2
#define MEDIA_CODEC_JPEG 3
#define MEDIA_ISP 4
#define MEDIA_ADE 5
#define MEDIA_MMU 6
#define MEDIA_XG2RAM1 7
#endif /*_DT_BINDINGS_RESET_CONTROLLER_HI6220*/ #endif /*_DT_BINDINGS_RESET_CONTROLLER_HI6220*/
/*
* TI Syscon Reset definitions
*
* Copyright (C) 2015-2016 Texas Instruments Incorporated - http://www.ti.com/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __DT_BINDINGS_RESET_TI_SYSCON_H__
#define __DT_BINDINGS_RESET_TI_SYSCON_H__
/*
* The reset does not support the feature and corresponding
* values are not valid
*/
#define ASSERT_NONE (1 << 0)
#define DEASSERT_NONE (1 << 1)
#define STATUS_NONE (1 << 2)
/* When set this function is activated by setting(vs clearing) this bit */
#define ASSERT_SET (1 << 3)
#define DEASSERT_SET (1 << 4)
#define STATUS_SET (1 << 5)
/* The following are the inverse of the above and are added for consistency */
#define ASSERT_CLEAR (0 << 3)
#define DEASSERT_CLEAR (0 << 4)
#define STATUS_CLEAR (0 << 5)
#endif
...@@ -37,12 +37,6 @@ static inline int ab8500_sysctrl_clear(u16 reg, u8 bits) ...@@ -37,12 +37,6 @@ static inline int ab8500_sysctrl_clear(u16 reg, u8 bits)
return ab8500_sysctrl_write(reg, bits, 0); return ab8500_sysctrl_write(reg, bits, 0);
} }
/* Configuration data for SysClkReq1RfClkBuf - SysClkReq8RfClkBuf */
struct ab8500_sysctrl_platform_data {
u8 initial_req_buf_config[8];
u16 (*reboot_reason_code)(const char *cmd);
};
/* Registers */ /* Registers */
#define AB8500_TURNONSTATUS 0x100 #define AB8500_TURNONSTATUS 0x100
#define AB8500_RESETSTATUS 0x101 #define AB8500_RESETSTATUS 0x101
......
...@@ -178,16 +178,6 @@ enum ddr_pwrst { ...@@ -178,16 +178,6 @@ enum ddr_pwrst {
#define DB8500_PRCMU_LEGACY_OFFSET 0xDD4 #define DB8500_PRCMU_LEGACY_OFFSET 0xDD4
struct prcmu_pdata
{
bool enable_set_ddr_opp;
bool enable_ape_opp_100_voltage;
struct ab8500_platform_data *ab_platdata;
u32 version_offset;
u32 legacy_offset;
u32 adt_offset;
};
#define PRCMU_FW_PROJECT_U8500 2 #define PRCMU_FW_PROJECT_U8500 2
#define PRCMU_FW_PROJECT_U8400 3 #define PRCMU_FW_PROJECT_U8400 3
#define PRCMU_FW_PROJECT_U9500 4 /* Customer specific */ #define PRCMU_FW_PROJECT_U9500 4 /* Customer specific */
......
/*
* Clock definitions for ux500 platforms
*
* Copyright (C) 2012 ST-Ericsson SA
* Author: Ulf Hansson <ulf.hansson@linaro.org>
*
* License terms: GNU General Public License (GPL) version 2
*/
#ifndef __CLK_UX500_H
#define __CLK_UX500_H
void u8500_clk_init(void);
void u9540_clk_init(void);
void u8540_clk_init(void);
#endif /* __CLK_UX500_H */
...@@ -2,10 +2,7 @@ ...@@ -2,10 +2,7 @@
#define _LIRC_RX51_H #define _LIRC_RX51_H
struct lirc_rx51_platform_data { struct lirc_rx51_platform_data {
int pwm_timer;
int(*set_max_mpu_wakeup_lat)(struct device *dev, long t); int(*set_max_mpu_wakeup_lat)(struct device *dev, long t);
struct pwm_omap_dmtimer_pdata *dmtimer;
}; };
#endif #endif
...@@ -29,6 +29,14 @@ extern bool qcom_scm_hdcp_available(void); ...@@ -29,6 +29,14 @@ extern bool qcom_scm_hdcp_available(void);
extern int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, extern int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
u32 *resp); u32 *resp);
extern bool qcom_scm_pas_supported(u32 peripheral);
extern int qcom_scm_pas_init_image(u32 peripheral, const void *metadata,
size_t size);
extern int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr,
phys_addr_t size);
extern int qcom_scm_pas_auth_and_reset(u32 peripheral);
extern int qcom_scm_pas_shutdown(u32 peripheral);
#define QCOM_SCM_CPU_PWR_DOWN_L2_ON 0x0 #define QCOM_SCM_CPU_PWR_DOWN_L2_ON 0x0
#define QCOM_SCM_CPU_PWR_DOWN_L2_OFF 0x1 #define QCOM_SCM_CPU_PWR_DOWN_L2_OFF 0x1
......
...@@ -53,4 +53,8 @@ struct reset_controller_dev { ...@@ -53,4 +53,8 @@ struct reset_controller_dev {
int reset_controller_register(struct reset_controller_dev *rcdev); int reset_controller_register(struct reset_controller_dev *rcdev);
void reset_controller_unregister(struct reset_controller_dev *rcdev); void reset_controller_unregister(struct reset_controller_dev *rcdev);
struct device;
int devm_reset_controller_register(struct device *dev,
struct reset_controller_dev *rcdev);
#endif #endif
...@@ -71,14 +71,14 @@ static inline struct reset_control *__of_reset_control_get( ...@@ -71,14 +71,14 @@ static inline struct reset_control *__of_reset_control_get(
struct device_node *node, struct device_node *node,
const char *id, int index, int shared) const char *id, int index, int shared)
{ {
return ERR_PTR(-EINVAL); return ERR_PTR(-ENOTSUPP);
} }
static inline struct reset_control *__devm_reset_control_get( static inline struct reset_control *__devm_reset_control_get(
struct device *dev, struct device *dev,
const char *id, int index, int shared) const char *id, int index, int shared)
{ {
return ERR_PTR(-EINVAL); return ERR_PTR(-ENOTSUPP);
} }
#endif /* CONFIG_RESET_CONTROLLER */ #endif /* CONFIG_RESET_CONTROLLER */
......
...@@ -70,6 +70,8 @@ struct scpi_ops { ...@@ -70,6 +70,8 @@ struct scpi_ops {
int (*sensor_get_capability)(u16 *sensors); int (*sensor_get_capability)(u16 *sensors);
int (*sensor_get_info)(u16 sensor_id, struct scpi_sensor_info *); int (*sensor_get_info)(u16 sensor_id, struct scpi_sensor_info *);
int (*sensor_get_value)(u16, u64 *); int (*sensor_get_value)(u16, u64 *);
int (*device_get_power_state)(u16);
int (*device_set_power_state)(u16, u8);
}; };
#if IS_REACHABLE(CONFIG_ARM_SCPI_PROTOCOL) #if IS_REACHABLE(CONFIG_ARM_SCPI_PROTOCOL)
......
#ifndef __WCNSS_CTRL_H__
#define __WCNSS_CTRL_H__
#include <linux/soc/qcom/smd.h>
struct qcom_smd_channel *qcom_wcnss_open_channel(void *wcnss, const char *name, qcom_smd_cb_t cb);
#endif
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
#ifndef __SOC_TEGRA_CPUIDLE_H__ #ifndef __SOC_TEGRA_CPUIDLE_H__
#define __SOC_TEGRA_CPUIDLE_H__ #define __SOC_TEGRA_CPUIDLE_H__
#ifdef CONFIG_CPU_IDLE #if defined(CONFIG_ARM) && defined(CONFIG_CPU_IDLE)
void tegra_cpuidle_pcie_irqs_in_use(void); void tegra_cpuidle_pcie_irqs_in_use(void);
#else #else
static inline void tegra_cpuidle_pcie_irqs_in_use(void) static inline void tegra_cpuidle_pcie_irqs_in_use(void)
......
...@@ -2464,45 +2464,20 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec) ...@@ -2464,45 +2464,20 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec)
struct device *dev = codec->dev; struct device *dev = codec->dev;
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(dev); struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(dev);
struct ab8500_platform_data *pdata; struct ab8500_codec_platform_data codec_pdata;
struct filter_control *fc; struct filter_control *fc;
int status; int status;
dev_dbg(dev, "%s: Enter.\n", __func__); dev_dbg(dev, "%s: Enter.\n", __func__);
/* Setup AB8500 according to board-settings */ ab8500_codec_of_probe(dev, np, &codec_pdata);
pdata = dev_get_platdata(dev->parent);
if (np) { status = ab8500_audio_setup_mics(codec, &codec_pdata.amics);
if (!pdata)
pdata = devm_kzalloc(dev,
sizeof(struct ab8500_platform_data),
GFP_KERNEL);
if (pdata && !pdata->codec)
pdata->codec
= devm_kzalloc(dev,
sizeof(struct ab8500_codec_platform_data),
GFP_KERNEL);
if (!(pdata && pdata->codec))
return -ENOMEM;
ab8500_codec_of_probe(dev, np, pdata->codec);
} else {
if (!(pdata && pdata->codec)) {
dev_err(dev, "No codec platform data or DT found\n");
return -EINVAL;
}
}
status = ab8500_audio_setup_mics(codec, &pdata->codec->amics);
if (status < 0) { if (status < 0) {
pr_err("%s: Failed to setup mics (%d)!\n", __func__, status); pr_err("%s: Failed to setup mics (%d)!\n", __func__, status);
return status; return status;
} }
status = ab8500_audio_set_ear_cmv(codec, pdata->codec->ear_cmv); status = ab8500_audio_set_ear_cmv(codec, codec_pdata.ear_cmv);
if (status < 0) { if (status < 0) {
pr_err("%s: Failed to set earpiece CM-voltage (%d)!\n", pr_err("%s: Failed to set earpiece CM-voltage (%d)!\n",
__func__, status); __func__, status);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册