MFD bits for the 3.7 merge window.
As usual we have a few new drivers: - TI LP8788 - TI OMAP USB TLL - Maxim MAX8907 - SMSC ECE1099 - Dialog Semiconductor DA9055 - A simpler syscon driver that allow us to get rid of the anatop one. Drivers are also gradually getting Device Tree and IRQ domain support. The following drivers got DT support: - palmas, 88pm860x, tc3589x and twl4030-audio And those ones now use the IRQ domain APIs: - 88pm860x, tc3589x, db8500_prcmu Also some other interesting changes: - Intel's ICH LPC now supports Lynx Point - TI's twl4030-audio added a GPO child - tps6527 enabled its backlight subdevice - The twl6030 pwm driver moved to the new PWM subsystem And finally a bunch of cleanup and casual fixes for mc13xxx, 88pm860x, palmas, ab8500, wm8994, wm5110, max8907 and the tps65xxx family. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQIcBAABAgAGBQJQbVq4AAoJEIqAPN1PVmxKXOsP/ifwoqYkaGUsZ7M8b8iTTxlk a0/SBU1O+FDG7LbIsOyJ6VZCpipj8R4WyVqNdS2CSPVoSdT8KnakrxFY9FAtcmpA c6O7r+9dymcT7HeQ6mBQYYeEyXcZQkTXj9Y298zuRT88gccH5PQIOX8DTj6gKVxN xhuDuAWtizvwAJWfof/57p7JLilCF96Hq0UdeISD10UWJPxPmXFJTzzYw6GbPPOl zk1N6yig3VpK6sfK+QdqZykHFKj23RX57SmceHOISTpEr66ayuKIkJEqWm/IydMO XWDTT2IN80ca+1PnbrQOyiMtXg3EKrZN5WDEp2AcUiKP0fnAoZBTeuZUkqyLc3rJ W8LowQe6x5154CeLwcJc4+kmeGUhbj09GHKCsI7x/lQpMWgJCaGHGvLxAUE1uRZi 4Bn9IUP7OqE465fNolLOd1fRxgzWJxe5rBYKQB7UcOrS0NThPhu0r0qV905zBrBO tyCZz+PexTiirpbv1K0dMTcpWeHVOmtYG5uJTmw9wTRv7jW7aUhkhkW5Q+E5BAdb 9Rj5/vYertqI3VzRQ1w2z1SavzBO3OykTURWGDkwjfFWYbJtEdPYGGjRSFiphVYG 8jvs5UzrDm2ICqkpkKzovVWi9lXyvNVVCgSwxHQeoPXfqb5dXLlbUZZBaCaQpRII XlItAJvIiUNIA8bXLoC8 =n6lp -----END PGP SIGNATURE----- Merge tag 'mfd-3.7-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6 Pull MFD changes from Samuel Ortiz: "MFD bits for the 3.7 merge window. As usual we have a few new drivers: - TI LP8788 - TI OMAP USB TLL - Maxim MAX8907 - SMSC ECE1099 - Dialog Semiconductor DA9055 - A simpler syscon driver that allow us to get rid of the anatop one. Drivers are also gradually getting Device Tree and IRQ domain support. The following drivers got DT support: - palmas, 88pm860x, tc3589x and twl4030-audio And those ones now use the IRQ domain APIs: - 88pm860x, tc3589x, db8500_prcmu Also some other interesting changes: - Intel's ICH LPC now supports Lynx Point - TI's twl4030-audio added a GPO child - tps6527 enabled its backlight subdevice - The twl6030 pwm driver moved to the new PWM subsystem And finally a bunch of cleanup and casual fixes for mc13xxx, 88pm860x, palmas, ab8500, wm8994, wm5110, max8907 and the tps65xxx family." Fix up various annoying conflicts: the DT and IRQ domain support came in twice and was already in 3.6. And then it was apparently rebased. Guys, DON'T REBASE! * tag 'mfd-3.7-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6: (89 commits) ARM: dts: Enable 88pm860x pmic mfd: 88pm860x: Move gpadc init into touch mfd: 88pm860x: Device tree support mfd: 88pm860x: Use irqdomain mfd: smsc: Add support for smsc gpio io/keypad driver backlight: tps65217_bl: Add missing platform_set_drvdata in tps65217_bl_probe mfd: DA9055 core driver mfd: tps65910: Add alarm interrupt of TPS65910 RTC to mfd device list mfd: wm5110: Add register patches for revision B mfd: wm5110: Disable control interface error report for WM5110 rev B mfd: max8907: Remove regulator-compatible from DT docs backlight: Add TPS65217 WLED driver mfd: Add backlight as subdevice to the tps65217 mfd: Provide the PRCMU with its own IRQ domain mfd: Fix max8907 sparse warning mfd: Add lp8788 mfd driver mfd: dbx500: Provide a more accurate smp_twd clock mfd: rc5t583: Fix warning messages regulator: palmas: Add DT support mfd: palmas: Change regulator defns to better suite DT ...
This commit is contained in:
commit
578f1ef91a
|
@ -0,0 +1,85 @@
|
|||
* Marvell 88PM860x Power Management IC
|
||||
|
||||
Required parent device properties:
|
||||
- compatible : "marvell,88pm860x"
|
||||
- reg : the I2C slave address for the 88pm860x chip
|
||||
- interrupts : IRQ line for the 88pm860x chip
|
||||
- interrupt-controller: describes the 88pm860x as an interrupt controller (has its own domain)
|
||||
- #interrupt-cells : should be 1.
|
||||
- The cell is the 88pm860x local IRQ number
|
||||
|
||||
Optional parent device properties:
|
||||
- marvell,88pm860x-irq-read-clr: inicates whether interrupt status is cleared by read
|
||||
- marvell,88pm860x-slave-addr: 88pm860x are two chips solution. <reg> stores the I2C address
|
||||
of one chip, and this property stores the I2C address of
|
||||
another chip.
|
||||
|
||||
88pm860x consists of a large and varied group of sub-devices:
|
||||
|
||||
Device Supply Names Description
|
||||
------ ------------ -----------
|
||||
88pm860x-onkey : : On key
|
||||
88pm860x-rtc : : RTC
|
||||
88pm8607 : : Regulators
|
||||
88pm860x-backlight : : Backlight
|
||||
88pm860x-led : : Led
|
||||
88pm860x-touch : : Touchscreen
|
||||
|
||||
Example:
|
||||
|
||||
pmic: 88pm860x@34 {
|
||||
compatible = "marvell,88pm860x";
|
||||
reg = <0x34>;
|
||||
interrupts = <4>;
|
||||
interrupt-parent = <&intc>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <1>;
|
||||
|
||||
marvell,88pm860x-irq-read-clr;
|
||||
marvell,88pm860x-slave-addr = <0x11>;
|
||||
|
||||
regulators {
|
||||
BUCK1 {
|
||||
regulator-min-microvolt = <1000000>;
|
||||
regulator-max-microvolt = <1500000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
LDO1 {
|
||||
regulator-min-microvolt = <1200000>;
|
||||
regulator-max-microvolt = <2800000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
};
|
||||
rtc {
|
||||
marvell,88pm860x-vrtc = <1>;
|
||||
};
|
||||
touch {
|
||||
marvell,88pm860x-gpadc-prebias = <1>;
|
||||
marvell,88pm860x-gpadc-slot-cycle = <1>;
|
||||
marvell,88pm860x-tsi-prebias = <6>;
|
||||
marvell,88pm860x-pen-prebias = <16>;
|
||||
marvell,88pm860x-pen-prechg = <2>;
|
||||
marvell,88pm860x-resistor-X = <300>;
|
||||
};
|
||||
backlights {
|
||||
backlight-0 {
|
||||
marvell,88pm860x-iset = <4>;
|
||||
marvell,88pm860x-pwm = <3>;
|
||||
};
|
||||
backlight-2 {
|
||||
};
|
||||
};
|
||||
leds {
|
||||
led0-red {
|
||||
marvell,88pm860x-iset = <12>;
|
||||
};
|
||||
led0-green {
|
||||
marvell,88pm860x-iset = <12>;
|
||||
};
|
||||
led0-blue {
|
||||
marvell,88pm860x-iset = <12>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -0,0 +1,20 @@
|
|||
* System Controller Registers R/W driver
|
||||
|
||||
System controller node represents a register region containing a set
|
||||
of miscellaneous registers. The registers are not cohesive enough to
|
||||
represent as any specific type of device. The typical use-case is for
|
||||
some other node's driver, or platform-specific code, to acquire a
|
||||
reference to the syscon node (e.g. by phandle, node path, or search
|
||||
using a specific compatible value), interrogate the node (or associated
|
||||
OS driver) to determine the location of the registers, and access the
|
||||
registers directly.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should contain "syscon".
|
||||
- reg: the register region can be accessed from syscon
|
||||
|
||||
Examples:
|
||||
gpr: iomuxc-gpr@020e0000 {
|
||||
compatible = "fsl,imx6q-iomuxc-gpr", "syscon";
|
||||
reg = <0x020e0000 0x38>;
|
||||
};
|
|
@ -59,6 +59,8 @@ Optional properties:
|
|||
in TPS6591X datasheet)
|
||||
- ti,en-gpio-sleep: enable sleep control for gpios
|
||||
There should be 9 entries here, one for each gpio.
|
||||
- ti,system-power-controller: Telling whether or not this pmic is controlling
|
||||
the system power.
|
||||
|
||||
Regulator Optional properties:
|
||||
- ti,regulator-ext-sleep-control: enable external sleep
|
||||
|
@ -79,6 +81,8 @@ Example:
|
|||
#interrupt-cells = <2>;
|
||||
interrupt-controller;
|
||||
|
||||
ti,system-power-controller;
|
||||
|
||||
ti,vmbch-threshold = 0;
|
||||
ti,vmbch2-threshold = 0;
|
||||
ti,en-ck32k-xtal;
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
Texas Instruments TWL family (twl4030) audio module
|
||||
|
||||
The audio module inside the TWL family consist of an audio codec and a vibra
|
||||
driver.
|
||||
|
||||
Required properties:
|
||||
- compatible : must be "ti,twl4030-audio"
|
||||
|
||||
Optional properties, nodes:
|
||||
|
||||
Audio functionality:
|
||||
- codec { }: Need to be present if the audio functionality is used. Within this
|
||||
section the following options can be used:
|
||||
- ti,digimic_delay: Delay need after enabling the digimic to reduce artifacts
|
||||
from the start of the recorded sample (in ms)
|
||||
-ti,ramp_delay_value: HS ramp delay configuration to reduce pop noise
|
||||
-ti,hs_extmute: Use external mute for HS pop reduction
|
||||
-ti,hs_extmute_gpio: Use external GPIO to control the external mute
|
||||
-ti,offset_cncl_path: Offset cancellation path selection, refer to TRM for the
|
||||
valid values.
|
||||
|
||||
Vibra functionality
|
||||
- ti,enable-vibra: Need to be set to <1> if the vibra functionality is used. if
|
||||
missing or it is 0, the vibra functionality is disabled.
|
||||
|
||||
Example:
|
||||
&i2c1 {
|
||||
clock-frequency = <2600000>;
|
||||
|
||||
twl: twl@48 {
|
||||
reg = <0x48>;
|
||||
interrupts = <7>; /* SYS_NIRQ cascaded to intc */
|
||||
interrupt-parent = <&intc>;
|
||||
|
||||
twl_audio: audio {
|
||||
compatible = "ti,twl4030-audio";
|
||||
|
||||
ti,enable-vibra = <1>;
|
||||
|
||||
codec {
|
||||
ti,ramp_delay_value = <3>;
|
||||
};
|
||||
|
||||
};
|
||||
};
|
||||
};
|
|
@ -1,7 +1,7 @@
|
|||
Texas Instruments TWL6040 family
|
||||
|
||||
The TWL6040s are 8-channel high quality low-power audio codecs providing audio
|
||||
and vibra functionality on OMAP4+ platforms.
|
||||
The TWL6040s are 8-channel high quality low-power audio codecs providing audio,
|
||||
vibra and GPO functionality on OMAP4+ platforms.
|
||||
They are connected ot the host processor via i2c for commands, McPDM for audio
|
||||
data and commands.
|
||||
|
||||
|
@ -10,6 +10,8 @@ Required properties:
|
|||
- reg: must be 0x4b for i2c address
|
||||
- interrupts: twl6040 has one interrupt line connecteded to the main SoC
|
||||
- interrupt-parent: The parent interrupt controller
|
||||
- gpio-controller:
|
||||
- #gpio-cells = <1>: twl6040 provides GPO lines.
|
||||
- twl6040,audpwron-gpio: Power on GPIO line for the twl6040
|
||||
|
||||
- vio-supply: Regulator for the twl6040 VIO supply
|
||||
|
@ -37,7 +39,6 @@ Example:
|
|||
&i2c1 {
|
||||
twl6040: twl@4b {
|
||||
compatible = "ti,twl6040";
|
||||
reg = <0x4b>;
|
||||
|
||||
interrupts = <0 119 4>;
|
||||
interrupt-parent = <&gic>;
|
||||
|
@ -60,3 +61,5 @@ Example:
|
|||
};
|
||||
};
|
||||
};
|
||||
|
||||
/include/ "twl6040.dtsi"
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
Marvell 88PM860x regulator
|
||||
|
||||
Required properties:
|
||||
- compatible: "marvell,88pm860x"
|
||||
- reg: I2C slave address
|
||||
- regulators: A node that houses a sub-node for each regulator within the
|
||||
device. Each sub-node is identified using the regulator-compatible
|
||||
property, with valid values listed below.
|
||||
|
||||
Example:
|
||||
|
||||
pmic: 88pm860x@34 {
|
||||
compatible = "marvell,88pm860x";
|
||||
reg = <0x34>;
|
||||
|
||||
regulators {
|
||||
BUCK1 {
|
||||
regulator-min-microvolt = <1000000>;
|
||||
regulator-max-microvolt = <1500000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
BUCK3 {
|
||||
regulator-min-microvolt = <1000000>;
|
||||
regulator-max-microvolt = <3000000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -0,0 +1,69 @@
|
|||
MAX8907 regulator
|
||||
|
||||
Required properties:
|
||||
- compatible: "maxim,max8907"
|
||||
- reg: I2C slave address
|
||||
- interrupts: The interrupt output of the controller
|
||||
- mbatt-supply: The input supply for MBATT, BBAT, SDBY, VRTC.
|
||||
- in-v1-supply: The input supply for SD1.
|
||||
- in-v2-supply: The input supply for SD2.
|
||||
- in-v3-supply: The input supply for SD3.
|
||||
- in1-supply: The input supply for LDO1.
|
||||
...
|
||||
- in20-supply: The input supply for LDO20.
|
||||
- regulators: A node that houses a sub-node for each regulator within the
|
||||
device. Each sub-node is identified using the node's name (or the deprecated
|
||||
regulator-compatible property if present), with valid values listed below.
|
||||
The content of each sub-node is defined by the standard binding for
|
||||
regulators; see regulator.txt.
|
||||
|
||||
Optional properties:
|
||||
- maxim,system-power-controller: Boolean property indicating that the PMIC
|
||||
controls the overall system power.
|
||||
|
||||
The valid names for regulators are:
|
||||
|
||||
sd1, sd2, sd3, ldo1, ldo2, ldo3, ldo4, ldo5, ldo6, ldo7, ldo8, ldo9, ldo10,
|
||||
ldo11, ldo12, ldo13, ldo14, ldo15, ldo16, ldo17, ldo18, ldo19, ldo20, out5v,
|
||||
out33v, bbat, sdby, vrtc.
|
||||
|
||||
Example:
|
||||
|
||||
max8907@3c {
|
||||
compatible = "maxim,max8907";
|
||||
reg = <0x3c>;
|
||||
interrupts = <0 86 0x4>;
|
||||
|
||||
maxim,system-power-controller;
|
||||
|
||||
mbatt-supply = <&some_reg>;
|
||||
in-v1-supply = <&mbatt_reg>;
|
||||
...
|
||||
in1-supply = <&mbatt_reg>;
|
||||
...
|
||||
|
||||
regulators {
|
||||
mbatt_reg: mbatt {
|
||||
regulator-name = "vbat_pmu";
|
||||
regulator-min-microvolt = <5000000>;
|
||||
regulator-max-microvolt = <5000000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
sd1 {
|
||||
regulator-name = "nvvdd_sv1,vdd_cpu_pmu";
|
||||
regulator-min-microvolt = <1000000>;
|
||||
regulator-max-microvolt = <1000000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
sd2 {
|
||||
regulator-name = "nvvdd_sv2,vdd_core";
|
||||
regulator-min-microvolt = <1200000>;
|
||||
regulator-max-microvolt = <1200000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
...
|
||||
};
|
||||
};
|
||||
};
|
|
@ -22,6 +22,10 @@ Required properties:
|
|||
- vinldo678-supply: The input supply for the LDO6, LDO7 and LDO8
|
||||
- vinldo9-supply: The input supply for the LDO9
|
||||
|
||||
Optional properties:
|
||||
- ti,system-power-controller: Telling whether or not this pmic is controlling
|
||||
the system power.
|
||||
|
||||
Each regulator is defined using the standard binding for regulators.
|
||||
|
||||
Note: LDO5 and LDO_RTC is supplied by SYS regulator internally and driver
|
||||
|
@ -37,6 +41,8 @@ Example:
|
|||
#gpio-cells = <2>;
|
||||
gpio-controller;
|
||||
|
||||
ti,system-power-controller;
|
||||
|
||||
sys-supply = <&some_reg>;
|
||||
vin-sm0-supply = <&some_reg>;
|
||||
vin-sm1-supply = <&some_reg>;
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
88pm860x-backlight bindings
|
||||
|
||||
Optional properties:
|
||||
- marvell,88pm860x-iset: Current supplies on backlight device.
|
||||
- marvell,88pm860x-pwm: PWM frequency on backlight device.
|
||||
|
||||
Example:
|
||||
|
||||
backlights {
|
||||
backlight-0 {
|
||||
marvell,88pm860x-iset = <4>;
|
||||
marvell,88pm860x-pwm = <3>;
|
||||
};
|
||||
backlight-2 {
|
||||
};
|
|
@ -0,0 +1,56 @@
|
|||
What is smsc-ece1099?
|
||||
----------------------
|
||||
|
||||
The ECE1099 is a 40-Pin 3.3V Keyboard Scan Expansion
|
||||
or GPIO Expansion device. The device supports a keyboard
|
||||
scan matrix of 23x8. The device is connected to a Master
|
||||
via the SMSC BC-Link interface or via the SMBus.
|
||||
Keypad scan Input(KSI) and Keypad Scan Output(KSO) signals
|
||||
are multiplexed with GPIOs.
|
||||
|
||||
Interrupt generation
|
||||
--------------------
|
||||
|
||||
Interrupts can be generated by an edge detection on a GPIO
|
||||
pin or an edge detection on one of the bus interface pins.
|
||||
Interrupts can also be detected on the keyboard scan interface.
|
||||
The bus interrupt pin (BC_INT# or SMBUS_INT#) is asserted if
|
||||
any bit in one of the Interrupt Status registers is 1 and
|
||||
the corresponding Interrupt Mask bit is also 1.
|
||||
|
||||
In order for software to determine which device is the source
|
||||
of an interrupt, it should first read the Group Interrupt Status Register
|
||||
to determine which Status register group is a source for the interrupt.
|
||||
Software should read both the Status register and the associated Mask register,
|
||||
then AND the two values together. Bits that are 1 in the result of the AND
|
||||
are active interrupts. Software clears an interrupt by writing a 1 to the
|
||||
corresponding bit in the Status register.
|
||||
|
||||
Communication Protocol
|
||||
----------------------
|
||||
|
||||
- SMbus slave Interface
|
||||
The host processor communicates with the ECE1099 device
|
||||
through a series of read/write registers via the SMBus
|
||||
interface. SMBus is a serial communication protocol between
|
||||
a computer host and its peripheral devices. The SMBus data
|
||||
rate is 10KHz minimum to 400 KHz maximum
|
||||
|
||||
- Slave Bus Interface
|
||||
The ECE1099 device SMBus implementation is a subset of the
|
||||
SMBus interface to the host. The device is a slave-only SMBus device.
|
||||
The implementation in the device is a subset of SMBus since it
|
||||
only supports four protocols.
|
||||
|
||||
The Write Byte, Read Byte, Send Byte, and Receive Byte protocols are the
|
||||
only valid SMBus protocols for the device.
|
||||
|
||||
- BC-LinkTM Interface
|
||||
The BC-Link is a proprietary bus that allows communication
|
||||
between a Master device and a Companion device. The Master
|
||||
device uses this serial bus to read and write registers
|
||||
located on the Companion device. The bus comprises three signals,
|
||||
BC_CLK, BC_DAT and BC_INT#. The Master device always provides the
|
||||
clock, BC_CLK, and the Companion device is the source for an
|
||||
independent asynchronous interrupt signal, BC_INT#. The ECE1099
|
||||
supports BC-Link speeds up to 24MHz.
|
|
@ -400,8 +400,8 @@
|
|||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
anatop@020c8000 {
|
||||
compatible = "fsl,imx6q-anatop";
|
||||
anatop: anatop@020c8000 {
|
||||
compatible = "fsl,imx6q-anatop", "syscon", "simple-bus";
|
||||
reg = <0x020c8000 0x1000>;
|
||||
interrupts = <0 49 0x04 0 54 0x04 0 127 0x04>;
|
||||
|
||||
|
@ -531,6 +531,11 @@
|
|||
interrupts = <0 89 0x04 0 90 0x04>;
|
||||
};
|
||||
|
||||
gpr: iomuxc-gpr@020e0000 {
|
||||
compatible = "fsl,imx6q-iomuxc-gpr", "syscon";
|
||||
reg = <0x020e0000 0x38>;
|
||||
};
|
||||
|
||||
iomuxc@020e0000 {
|
||||
compatible = "fsl,imx6q-iomuxc";
|
||||
reg = <0x020e0000 0x4000>;
|
||||
|
|
|
@ -29,6 +29,143 @@
|
|||
};
|
||||
twsi1: i2c@d4011000 {
|
||||
status = "okay";
|
||||
|
||||
pmic: 88pm860x@34 {
|
||||
compatible = "marvell,88pm860x";
|
||||
reg = <0x34>;
|
||||
interrupts = <4>;
|
||||
interrupt-parent = <&intc>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <1>;
|
||||
|
||||
marvell,88pm860x-irq-read-clr;
|
||||
marvell,88pm860x-slave-addr = <0x11>;
|
||||
|
||||
regulators {
|
||||
BUCK1 {
|
||||
regulator-min-microvolt = <1000000>;
|
||||
regulator-max-microvolt = <1500000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
BUCK2 {
|
||||
regulator-min-microvolt = <1000000>;
|
||||
regulator-max-microvolt = <1500000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
BUCK3 {
|
||||
regulator-min-microvolt = <1000000>;
|
||||
regulator-max-microvolt = <3000000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
LDO1 {
|
||||
regulator-min-microvolt = <1200000>;
|
||||
regulator-max-microvolt = <2800000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
LDO2 {
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
LDO3 {
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
LDO4 {
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
LDO5 {
|
||||
regulator-min-microvolt = <2900000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
LDO6 {
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
LDO7 {
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <2900000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
LDO8 {
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <2900000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
LDO9 {
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
LDO10 {
|
||||
regulator-min-microvolt = <1200000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
LDO12 {
|
||||
regulator-min-microvolt = <1200000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
LDO13 {
|
||||
regulator-min-microvolt = <1200000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
LDO14 {
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
};
|
||||
rtc {
|
||||
marvell,88pm860x-vrtc = <1>;
|
||||
};
|
||||
touch {
|
||||
marvell,88pm860x-gpadc-prebias = <1>;
|
||||
marvell,88pm860x-gpadc-slot-cycle = <1>;
|
||||
marvell,88pm860x-tsi-prebias = <6>;
|
||||
marvell,88pm860x-pen-prebias = <16>;
|
||||
marvell,88pm860x-pen-prechg = <2>;
|
||||
marvell,88pm860x-resistor-X = <300>;
|
||||
};
|
||||
backlights {
|
||||
backlight-0 {
|
||||
marvell,88pm860x-iset = <4>;
|
||||
marvell,88pm860x-pwm = <3>;
|
||||
};
|
||||
backlight-2 {
|
||||
};
|
||||
};
|
||||
leds {
|
||||
led0-red {
|
||||
marvell,88pm860x-iset = <12>;
|
||||
};
|
||||
led0-green {
|
||||
marvell,88pm860x-iset = <12>;
|
||||
};
|
||||
led0-blue {
|
||||
marvell,88pm860x-iset = <12>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
rtc: rtc@d4010000 {
|
||||
status = "okay";
|
||||
|
|
|
@ -120,6 +120,8 @@
|
|||
|
||||
twsi1: i2c@d4011000 {
|
||||
compatible = "mrvl,mmp-twsi";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0xd4011000 0x1000>;
|
||||
interrupts = <7>;
|
||||
mrvl,i2c-fast-mode;
|
||||
|
@ -128,6 +130,8 @@
|
|||
|
||||
twsi2: i2c@d4037000 {
|
||||
compatible = "mrvl,mmp-twsi";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0xd4037000 0x1000>;
|
||||
interrupts = <54>;
|
||||
status = "disabled";
|
||||
|
|
|
@ -758,7 +758,7 @@ config SOC_IMX6Q
|
|||
select HAVE_IMX_MMDC
|
||||
select HAVE_IMX_SRC
|
||||
select HAVE_SMP
|
||||
select MFD_ANATOP
|
||||
select MFD_SYSCON
|
||||
select PINCTRL
|
||||
select PINCTRL_IMX6Q
|
||||
|
||||
|
|
|
@ -23,8 +23,9 @@
|
|||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/micrel_phy.h>
|
||||
#include <linux/mfd/anatop.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <asm/cpuidle.h>
|
||||
#include <asm/smp_twd.h>
|
||||
#include <asm/hardware/cache-l2x0.h>
|
||||
|
@ -118,20 +119,7 @@ static void __init imx6q_sabrelite_init(void)
|
|||
|
||||
static void __init imx6q_usb_init(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
struct platform_device *pdev = NULL;
|
||||
struct anatop *adata = NULL;
|
||||
|
||||
np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop");
|
||||
if (np)
|
||||
pdev = of_find_device_by_node(np);
|
||||
if (pdev)
|
||||
adata = platform_get_drvdata(pdev);
|
||||
if (!adata) {
|
||||
if (np)
|
||||
of_node_put(np);
|
||||
return;
|
||||
}
|
||||
struct regmap *anatop;
|
||||
|
||||
#define HW_ANADIG_USB1_CHRG_DETECT 0x000001b0
|
||||
#define HW_ANADIG_USB2_CHRG_DETECT 0x00000210
|
||||
|
@ -139,20 +127,21 @@ static void __init imx6q_usb_init(void)
|
|||
#define BM_ANADIG_USB_CHRG_DETECT_EN_B 0x00100000
|
||||
#define BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B 0x00080000
|
||||
|
||||
/*
|
||||
* The external charger detector needs to be disabled,
|
||||
* or the signal at DP will be poor
|
||||
*/
|
||||
anatop_write_reg(adata, HW_ANADIG_USB1_CHRG_DETECT,
|
||||
BM_ANADIG_USB_CHRG_DETECT_EN_B
|
||||
| BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B,
|
||||
~0);
|
||||
anatop_write_reg(adata, HW_ANADIG_USB2_CHRG_DETECT,
|
||||
BM_ANADIG_USB_CHRG_DETECT_EN_B |
|
||||
BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B,
|
||||
~0);
|
||||
|
||||
of_node_put(np);
|
||||
anatop = syscon_regmap_lookup_by_compatible("fsl,imx6q-anatop");
|
||||
if (!IS_ERR(anatop)) {
|
||||
/*
|
||||
* The external charger detector needs to be disabled,
|
||||
* or the signal at DP will be poor
|
||||
*/
|
||||
regmap_write(anatop, HW_ANADIG_USB1_CHRG_DETECT,
|
||||
BM_ANADIG_USB_CHRG_DETECT_EN_B
|
||||
| BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B);
|
||||
regmap_write(anatop, HW_ANADIG_USB2_CHRG_DETECT,
|
||||
BM_ANADIG_USB_CHRG_DETECT_EN_B |
|
||||
BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B);
|
||||
} else {
|
||||
pr_warn("failed to find fsl,imx6q-anatop regmap\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void __init imx6q_init_machine(void)
|
||||
|
|
|
@ -33,10 +33,12 @@
|
|||
#ifdef CONFIG_MFD_OMAP_USB_HOST
|
||||
|
||||
#define OMAP_USBHS_DEVICE "usbhs_omap"
|
||||
#define OMAP_USBTLL_DEVICE "usbhs_tll"
|
||||
#define USBHS_UHH_HWMODNAME "usb_host_hs"
|
||||
#define USBHS_TLL_HWMODNAME "usb_tll_hs"
|
||||
|
||||
static struct usbhs_omap_platform_data usbhs_data;
|
||||
static struct usbtll_omap_platform_data usbtll_data;
|
||||
static struct ehci_hcd_omap_platform_data ehci_data;
|
||||
static struct ohci_hcd_omap_platform_data ohci_data;
|
||||
|
||||
|
@ -485,13 +487,14 @@ void __init setup_4430ohci_io_mux(const enum usbhs_omap_port_mode *port_mode)
|
|||
|
||||
void __init usbhs_init(const struct usbhs_omap_board_data *pdata)
|
||||
{
|
||||
struct omap_hwmod *oh[2];
|
||||
struct omap_hwmod *uhh_hwm, *tll_hwm;
|
||||
struct platform_device *pdev;
|
||||
int bus_id = -1;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < OMAP3_HS_USB_PORTS; i++) {
|
||||
usbhs_data.port_mode[i] = pdata->port_mode[i];
|
||||
usbtll_data.port_mode[i] = pdata->port_mode[i];
|
||||
ohci_data.port_mode[i] = pdata->port_mode[i];
|
||||
ehci_data.port_mode[i] = pdata->port_mode[i];
|
||||
ehci_data.reset_gpio_port[i] = pdata->reset_gpio_port[i];
|
||||
|
@ -510,25 +513,35 @@ void __init usbhs_init(const struct usbhs_omap_board_data *pdata)
|
|||
setup_4430ohci_io_mux(pdata->port_mode);
|
||||
}
|
||||
|
||||
oh[0] = omap_hwmod_lookup(USBHS_UHH_HWMODNAME);
|
||||
if (!oh[0]) {
|
||||
uhh_hwm = omap_hwmod_lookup(USBHS_UHH_HWMODNAME);
|
||||
if (!uhh_hwm) {
|
||||
pr_err("Could not look up %s\n", USBHS_UHH_HWMODNAME);
|
||||
return;
|
||||
}
|
||||
|
||||
oh[1] = omap_hwmod_lookup(USBHS_TLL_HWMODNAME);
|
||||
if (!oh[1]) {
|
||||
tll_hwm = omap_hwmod_lookup(USBHS_TLL_HWMODNAME);
|
||||
if (!tll_hwm) {
|
||||
pr_err("Could not look up %s\n", USBHS_TLL_HWMODNAME);
|
||||
return;
|
||||
}
|
||||
|
||||
pdev = omap_device_build_ss(OMAP_USBHS_DEVICE, bus_id, oh, 2,
|
||||
(void *)&usbhs_data, sizeof(usbhs_data),
|
||||
pdev = omap_device_build(OMAP_USBTLL_DEVICE, bus_id, tll_hwm,
|
||||
&usbtll_data, sizeof(usbtll_data),
|
||||
omap_uhhtll_latency,
|
||||
ARRAY_SIZE(omap_uhhtll_latency), false);
|
||||
if (IS_ERR(pdev)) {
|
||||
pr_err("Could not build hwmod devices %s,%s\n",
|
||||
USBHS_UHH_HWMODNAME, USBHS_TLL_HWMODNAME);
|
||||
pr_err("Could not build hwmod device %s\n",
|
||||
USBHS_TLL_HWMODNAME);
|
||||
return;
|
||||
}
|
||||
|
||||
pdev = omap_device_build(OMAP_USBHS_DEVICE, bus_id, uhh_hwm,
|
||||
&usbhs_data, sizeof(usbhs_data),
|
||||
omap_uhhtll_latency,
|
||||
ARRAY_SIZE(omap_uhhtll_latency), false);
|
||||
if (IS_ERR(pdev)) {
|
||||
pr_err("Could not build hwmod devices %s\n",
|
||||
USBHS_UHH_HWMODNAME);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mfd/abx500.h>
|
||||
#include <linux/mfd/ab3100.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/amba/bus.h>
|
||||
#include <mach/irqs.h>
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#define __ASM_ARCH_OMAP_USB_H
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/usb/musb.h>
|
||||
|
||||
#define OMAP3_HS_USB_PORTS 3
|
||||
|
@ -63,6 +64,10 @@ struct usbhs_omap_platform_data {
|
|||
struct ehci_hcd_omap_platform_data *ehci_data;
|
||||
struct ohci_hcd_omap_platform_data *ohci_data;
|
||||
};
|
||||
|
||||
struct usbtll_omap_platform_data {
|
||||
enum usbhs_omap_port_mode port_mode[OMAP3_HS_USB_PORTS];
|
||||
};
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
struct omap_musb_board_data {
|
||||
|
@ -81,6 +86,8 @@ enum musb_interface {MUSB_INTERFACE_ULPI, MUSB_INTERFACE_UTMI};
|
|||
extern void usb_musb_init(struct omap_musb_board_data *board_data);
|
||||
|
||||
extern void usbhs_init(const struct usbhs_omap_board_data *pdata);
|
||||
extern int omap_tll_enable(void);
|
||||
extern int omap_tll_disable(void);
|
||||
|
||||
extern int omap4430_phy_power(struct device *dev, int ID, int on);
|
||||
extern int omap4430_phy_set_clk(struct device *dev, int on);
|
||||
|
|
|
@ -409,6 +409,13 @@ config GPIO_TWL4030
|
|||
Say yes here to access the GPIO signals of various multi-function
|
||||
power management chips from Texas Instruments.
|
||||
|
||||
config GPIO_TWL6040
|
||||
tristate "TWL6040 GPO"
|
||||
depends on TWL6040_CORE
|
||||
help
|
||||
Say yes here to access the GPO signals of twl6040
|
||||
audio chip from Texas Instruments.
|
||||
|
||||
config GPIO_WM831X
|
||||
tristate "WM831x GPIOs"
|
||||
depends on MFD_WM831X
|
||||
|
|
|
@ -68,6 +68,7 @@ obj-$(CONFIG_GPIO_TPS6586X) += gpio-tps6586x.o
|
|||
obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o
|
||||
obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o
|
||||
obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o
|
||||
obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o
|
||||
obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o
|
||||
obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o
|
||||
obj-$(CONFIG_GPIO_VT8500) += gpio-vt8500.o
|
||||
|
|
|
@ -49,6 +49,10 @@ static const u8 ichx_regs[3][3] = {
|
|||
{0x0c, 0x38, 0x48}, /* LVL[1-3] offsets */
|
||||
};
|
||||
|
||||
static const u8 ichx_reglen[3] = {
|
||||
0x30, 0x10, 0x10,
|
||||
};
|
||||
|
||||
#define ICHX_WRITE(val, reg, base_res) outl(val, (reg) + (base_res)->start)
|
||||
#define ICHX_READ(reg, base_res) inl((reg) + (base_res)->start)
|
||||
|
||||
|
@ -75,6 +79,7 @@ static struct {
|
|||
struct resource *pm_base; /* Power Mangagment IO base */
|
||||
struct ichx_desc *desc; /* Pointer to chipset-specific description */
|
||||
u32 orig_gpio_ctrl; /* Orig CTRL value, used to restore on exit */
|
||||
u8 use_gpio; /* Which GPIO groups are usable */
|
||||
} ichx_priv;
|
||||
|
||||
static int modparam_gpiobase = -1; /* dynamic */
|
||||
|
@ -123,8 +128,16 @@ static int ichx_read_bit(int reg, unsigned nr)
|
|||
return data & (1 << bit) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int ichx_gpio_check_available(struct gpio_chip *gpio, unsigned nr)
|
||||
{
|
||||
return (ichx_priv.use_gpio & (1 << (nr / 32))) ? 0 : -ENXIO;
|
||||
}
|
||||
|
||||
static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
|
||||
{
|
||||
if (!ichx_gpio_check_available(gpio, nr))
|
||||
return -ENXIO;
|
||||
|
||||
/*
|
||||
* Try setting pin as an input and verify it worked since many pins
|
||||
* are output-only.
|
||||
|
@ -138,6 +151,9 @@ static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
|
|||
static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
|
||||
int val)
|
||||
{
|
||||
if (!ichx_gpio_check_available(gpio, nr))
|
||||
return -ENXIO;
|
||||
|
||||
/* Set GPIO output value. */
|
||||
ichx_write_bit(GPIO_LVL, nr, val, 0);
|
||||
|
||||
|
@ -153,6 +169,9 @@ static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
|
|||
|
||||
static int ichx_gpio_get(struct gpio_chip *chip, unsigned nr)
|
||||
{
|
||||
if (!ichx_gpio_check_available(chip, nr))
|
||||
return -ENXIO;
|
||||
|
||||
return ichx_read_bit(GPIO_LVL, nr);
|
||||
}
|
||||
|
||||
|
@ -161,6 +180,9 @@ static int ich6_gpio_get(struct gpio_chip *chip, unsigned nr)
|
|||
unsigned long flags;
|
||||
u32 data;
|
||||
|
||||
if (!ichx_gpio_check_available(chip, nr))
|
||||
return -ENXIO;
|
||||
|
||||
/*
|
||||
* GPI 0 - 15 need to be read from the power management registers on
|
||||
* a ICH6/3100 bridge.
|
||||
|
@ -291,6 +313,46 @@ static struct ichx_desc intel5_desc = {
|
|||
.ngpio = 76,
|
||||
};
|
||||
|
||||
static int __devinit ichx_gpio_request_regions(struct resource *res_base,
|
||||
const char *name, u8 use_gpio)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!res_base || !res_base->start || !res_base->end)
|
||||
return -ENODEV;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ichx_regs[0]); i++) {
|
||||
if (!(use_gpio & (1 << i)))
|
||||
continue;
|
||||
if (!request_region(res_base->start + ichx_regs[0][i],
|
||||
ichx_reglen[i], name))
|
||||
goto request_err;
|
||||
}
|
||||
return 0;
|
||||
|
||||
request_err:
|
||||
/* Clean up: release already requested regions, if any */
|
||||
for (i--; i >= 0; i--) {
|
||||
if (!(use_gpio & (1 << i)))
|
||||
continue;
|
||||
release_region(res_base->start + ichx_regs[0][i],
|
||||
ichx_reglen[i]);
|
||||
}
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
static void ichx_gpio_release_regions(struct resource *res_base, u8 use_gpio)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ichx_regs[0]); i++) {
|
||||
if (!(use_gpio & (1 << i)))
|
||||
continue;
|
||||
release_region(res_base->start + ichx_regs[0][i],
|
||||
ichx_reglen[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static int __devinit ichx_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res_base, *res_pm;
|
||||
|
@ -329,12 +391,11 @@ static int __devinit ichx_gpio_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
res_base = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_GPIO);
|
||||
if (!res_base || !res_base->start || !res_base->end)
|
||||
return -ENODEV;
|
||||
|
||||
if (!request_region(res_base->start, resource_size(res_base),
|
||||
pdev->name))
|
||||
return -EBUSY;
|
||||
ichx_priv.use_gpio = ich_info->use_gpio;
|
||||
err = ichx_gpio_request_regions(res_base, pdev->name,
|
||||
ichx_priv.use_gpio);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
ichx_priv.gpio_base = res_base;
|
||||
|
||||
|
@ -374,8 +435,7 @@ init:
|
|||
return 0;
|
||||
|
||||
add_err:
|
||||
release_region(ichx_priv.gpio_base->start,
|
||||
resource_size(ichx_priv.gpio_base));
|
||||
ichx_gpio_release_regions(ichx_priv.gpio_base, ichx_priv.use_gpio);
|
||||
if (ichx_priv.pm_base)
|
||||
release_region(ichx_priv.pm_base->start,
|
||||
resource_size(ichx_priv.pm_base));
|
||||
|
@ -393,8 +453,7 @@ static int __devexit ichx_gpio_remove(struct platform_device *pdev)
|
|||
return err;
|
||||
}
|
||||
|
||||
release_region(ichx_priv.gpio_base->start,
|
||||
resource_size(ichx_priv.gpio_base));
|
||||
ichx_gpio_release_regions(ichx_priv.gpio_base, ichx_priv.use_gpio);
|
||||
if (ichx_priv.pm_base)
|
||||
release_region(ichx_priv.pm_base->start,
|
||||
resource_size(ichx_priv.pm_base));
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* Access to GPOs on TWL6040 chip
|
||||
*
|
||||
* Copyright (C) 2012 Texas Instruments, Inc.
|
||||
*
|
||||
* Authors:
|
||||
* Sergio Aguirre <saaguirre@ti.com>
|
||||
* Peter Ujfalusi <peter.ujfalusi@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.
|
||||
*
|
||||
* 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/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include <linux/mfd/twl6040.h>
|
||||
|
||||
static struct gpio_chip twl6040gpo_chip;
|
||||
|
||||
static int twl6040gpo_get(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct twl6040 *twl6040 = dev_get_drvdata(chip->dev->parent);
|
||||
int ret = 0;
|
||||
|
||||
ret = twl6040_reg_read(twl6040, TWL6040_REG_GPOCTL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return (ret >> offset) & 1;
|
||||
}
|
||||
|
||||
static int twl6040gpo_direction_out(struct gpio_chip *chip, unsigned offset,
|
||||
int value)
|
||||
{
|
||||
/* This only drives GPOs, and can't change direction */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void twl6040gpo_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||
{
|
||||
struct twl6040 *twl6040 = dev_get_drvdata(chip->dev->parent);
|
||||
int ret;
|
||||
u8 gpoctl;
|
||||
|
||||
ret = twl6040_reg_read(twl6040, TWL6040_REG_GPOCTL);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
if (value)
|
||||
gpoctl = ret | (1 << offset);
|
||||
else
|
||||
gpoctl = ret & ~(1 << offset);
|
||||
|
||||
twl6040_reg_write(twl6040, TWL6040_REG_GPOCTL, gpoctl);
|
||||
}
|
||||
|
||||
static struct gpio_chip twl6040gpo_chip = {
|
||||
.label = "twl6040",
|
||||
.owner = THIS_MODULE,
|
||||
.get = twl6040gpo_get,
|
||||
.direction_output = twl6040gpo_direction_out,
|
||||
.set = twl6040gpo_set,
|
||||
.can_sleep = 1,
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
static int __devinit gpo_twl6040_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct twl6040_gpo_data *pdata = pdev->dev.platform_data;
|
||||
struct device *twl6040_core_dev = pdev->dev.parent;
|
||||
struct twl6040 *twl6040 = dev_get_drvdata(twl6040_core_dev);
|
||||
int ret;
|
||||
|
||||
if (pdata)
|
||||
twl6040gpo_chip.base = pdata->gpio_base;
|
||||
else
|
||||
twl6040gpo_chip.base = -1;
|
||||
|
||||
if (twl6040_get_revid(twl6040) < TWL6041_REV_ES2_0)
|
||||
twl6040gpo_chip.ngpio = 3; /* twl6040 have 3 GPO */
|
||||
else
|
||||
twl6040gpo_chip.ngpio = 1; /* twl6041 have 1 GPO */
|
||||
|
||||
twl6040gpo_chip.dev = &pdev->dev;
|
||||
#ifdef CONFIG_OF_GPIO
|
||||
twl6040gpo_chip.of_node = twl6040_core_dev->of_node;
|
||||
#endif
|
||||
|
||||
ret = gpiochip_add(&twl6040gpo_chip);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret);
|
||||
twl6040gpo_chip.ngpio = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit gpo_twl6040_remove(struct platform_device *pdev)
|
||||
{
|
||||
return gpiochip_remove(&twl6040gpo_chip);
|
||||
}
|
||||
|
||||
/* Note: this hardware lives inside an I2C-based multi-function device. */
|
||||
MODULE_ALIAS("platform:twl6040-gpo");
|
||||
|
||||
static struct platform_driver gpo_twl6040_driver = {
|
||||
.driver = {
|
||||
.name = "twl6040-gpo",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = gpo_twl6040_probe,
|
||||
.remove = gpo_twl6040_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(gpo_twl6040_driver);
|
||||
|
||||
MODULE_AUTHOR("Texas Instruments, Inc.");
|
||||
MODULE_DESCRIPTION("GPO interface for TWL6040");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -26,6 +26,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/i2c/twl.h>
|
||||
#include <linux/mfd/twl4030-audio.h>
|
||||
|
@ -194,13 +195,26 @@ static int twl4030_vibra_resume(struct device *dev)
|
|||
static SIMPLE_DEV_PM_OPS(twl4030_vibra_pm_ops,
|
||||
twl4030_vibra_suspend, twl4030_vibra_resume);
|
||||
|
||||
static bool twl4030_vibra_check_coexist(struct twl4030_vibra_data *pdata,
|
||||
struct device_node *node)
|
||||
{
|
||||
if (pdata && pdata->coexist)
|
||||
return true;
|
||||
|
||||
if (of_find_node_by_name(node, "codec"))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int __devinit twl4030_vibra_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct twl4030_vibra_data *pdata = pdev->dev.platform_data;
|
||||
struct device_node *twl4030_core_node = pdev->dev.parent->of_node;
|
||||
struct vibra_info *info;
|
||||
int ret;
|
||||
|
||||
if (!pdata) {
|
||||
if (!pdata && !twl4030_core_node) {
|
||||
dev_dbg(&pdev->dev, "platform_data not available\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -210,7 +224,7 @@ static int __devinit twl4030_vibra_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
|
||||
info->dev = &pdev->dev;
|
||||
info->coexist = pdata->coexist;
|
||||
info->coexist = twl4030_vibra_check_coexist(pdata, twl4030_core_node);
|
||||
INIT_WORK(&info->play_work, vibra_play_work);
|
||||
|
||||
info->input_dev = input_allocate_device();
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/input.h>
|
||||
|
@ -113,14 +114,69 @@ static void pm860x_touch_close(struct input_dev *dev)
|
|||
pm860x_set_bits(touch->i2c, MEAS_EN3, data, 0);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int __devinit pm860x_touch_dt_init(struct platform_device *pdev,
|
||||
struct pm860x_chip *chip,
|
||||
int *res_x)
|
||||
{
|
||||
struct device_node *np = pdev->dev.parent->of_node;
|
||||
struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \
|
||||
: chip->companion;
|
||||
int data, n, ret;
|
||||
if (!np)
|
||||
return -ENODEV;
|
||||
np = of_find_node_by_name(np, "touch");
|
||||
if (!np) {
|
||||
dev_err(&pdev->dev, "Can't find touch node\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
/* set GPADC MISC1 register */
|
||||
data = 0;
|
||||
if (!of_property_read_u32(np, "marvell,88pm860x-gpadc-prebias", &n))
|
||||
data |= (n << 1) & PM8607_GPADC_PREBIAS_MASK;
|
||||
if (!of_property_read_u32(np, "marvell,88pm860x-gpadc-slot-cycle", &n))
|
||||
data |= (n << 3) & PM8607_GPADC_SLOT_CYCLE_MASK;
|
||||
if (!of_property_read_u32(np, "marvell,88pm860x-gpadc-off-scale", &n))
|
||||
data |= (n << 5) & PM8607_GPADC_OFF_SCALE_MASK;
|
||||
if (!of_property_read_u32(np, "marvell,88pm860x-gpadc-sw-cal", &n))
|
||||
data |= (n << 7) & PM8607_GPADC_SW_CAL_MASK;
|
||||
if (data) {
|
||||
ret = pm860x_reg_write(i2c, PM8607_GPADC_MISC1, data);
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
/* set tsi prebias time */
|
||||
if (!of_property_read_u32(np, "marvell,88pm860x-tsi-prebias", &data)) {
|
||||
ret = pm860x_reg_write(i2c, PM8607_TSI_PREBIAS, data);
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
/* set prebias & prechg time of pen detect */
|
||||
data = 0;
|
||||
if (!of_property_read_u32(np, "marvell,88pm860x-pen-prebias", &n))
|
||||
data |= n & PM8607_PD_PREBIAS_MASK;
|
||||
if (!of_property_read_u32(np, "marvell,88pm860x-pen-prechg", &n))
|
||||
data |= n & PM8607_PD_PRECHG_MASK;
|
||||
if (data) {
|
||||
ret = pm860x_reg_write(i2c, PM8607_PD_PREBIAS, data);
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
of_property_read_u32(np, "marvell,88pm860x-resistor-X", res_x);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define pm860x_touch_dt_init(x, y, z) (-1)
|
||||
#endif
|
||||
|
||||
static int __devinit pm860x_touch_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
|
||||
struct pm860x_platform_data *pm860x_pdata = \
|
||||
pdev->dev.parent->platform_data;
|
||||
struct pm860x_touch_pdata *pdata = NULL;
|
||||
struct pm860x_touch_pdata *pdata = pdev->dev.platform_data;
|
||||
struct pm860x_touch *touch;
|
||||
int irq, ret;
|
||||
struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \
|
||||
: chip->companion;
|
||||
int irq, ret, res_x = 0, data = 0;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
|
@ -128,16 +184,55 @@ static int __devinit pm860x_touch_probe(struct platform_device *pdev)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!pm860x_pdata) {
|
||||
dev_err(&pdev->dev, "platform data is missing\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pdata = pm860x_pdata->touch;
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "touchscreen data is missing\n");
|
||||
return -EINVAL;
|
||||
if (pm860x_touch_dt_init(pdev, chip, &res_x)) {
|
||||
if (pdata) {
|
||||
/* set GPADC MISC1 register */
|
||||
data = 0;
|
||||
data |= (pdata->gpadc_prebias << 1)
|
||||
& PM8607_GPADC_PREBIAS_MASK;
|
||||
data |= (pdata->slot_cycle << 3)
|
||||
& PM8607_GPADC_SLOT_CYCLE_MASK;
|
||||
data |= (pdata->off_scale << 5)
|
||||
& PM8607_GPADC_OFF_SCALE_MASK;
|
||||
data |= (pdata->sw_cal << 7)
|
||||
& PM8607_GPADC_SW_CAL_MASK;
|
||||
if (data) {
|
||||
ret = pm860x_reg_write(i2c,
|
||||
PM8607_GPADC_MISC1, data);
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
/* set tsi prebias time */
|
||||
if (pdata->tsi_prebias) {
|
||||
data = pdata->tsi_prebias;
|
||||
ret = pm860x_reg_write(i2c,
|
||||
PM8607_TSI_PREBIAS, data);
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
/* set prebias & prechg time of pen detect */
|
||||
data = 0;
|
||||
data |= pdata->pen_prebias
|
||||
& PM8607_PD_PREBIAS_MASK;
|
||||
data |= (pdata->pen_prechg << 5)
|
||||
& PM8607_PD_PRECHG_MASK;
|
||||
if (data) {
|
||||
ret = pm860x_reg_write(i2c,
|
||||
PM8607_PD_PREBIAS, data);
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
res_x = pdata->res_x;
|
||||
} else {
|
||||
dev_err(&pdev->dev, "failed to get platform data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
/* enable GPADC */
|
||||
ret = pm860x_set_bits(i2c, PM8607_GPADC_MISC1, PM8607_GPADC_EN,
|
||||
PM8607_GPADC_EN);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
touch = kzalloc(sizeof(struct pm860x_touch), GFP_KERNEL);
|
||||
if (touch == NULL)
|
||||
|
@ -158,9 +253,9 @@ static int __devinit pm860x_touch_probe(struct platform_device *pdev)
|
|||
touch->idev->open = pm860x_touch_open;
|
||||
touch->idev->close = pm860x_touch_close;
|
||||
touch->chip = chip;
|
||||
touch->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
|
||||
touch->irq = irq + chip->irq_base;
|
||||
touch->res_x = pdata->res_x;
|
||||
touch->i2c = i2c;
|
||||
touch->irq = irq;
|
||||
touch->res_x = res_x;
|
||||
input_set_drvdata(touch->idev, touch);
|
||||
|
||||
ret = request_threaded_irq(touch->irq, NULL, pm860x_touch_handler,
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/leds.h>
|
||||
|
@ -20,18 +21,12 @@
|
|||
#include <linux/mfd/88pm860x.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#define LED_PWM_SHIFT (3)
|
||||
#define LED_PWM_MASK (0x1F)
|
||||
#define LED_CURRENT_MASK (0x07 << 5)
|
||||
|
||||
#define LED_BLINK_ON_MASK (0x07)
|
||||
#define LED_BLINK_MASK (0x7F)
|
||||
|
||||
#define LED_BLINK_ON(x) ((x & 0x7) * 66 + 66)
|
||||
#define LED_BLINK_ON_MIN LED_BLINK_ON(0)
|
||||
#define LED_BLINK_ON_MAX LED_BLINK_ON(0x7)
|
||||
#define LED_ON_CONTINUOUS (0x0F << 3)
|
||||
#define LED_TO_ON(x) ((x - 66) / 66)
|
||||
|
||||
#define LED1_BLINK_EN (1 << 1)
|
||||
#define LED2_BLINK_EN (1 << 2)
|
||||
|
@ -49,85 +44,25 @@ struct pm860x_led {
|
|||
unsigned char brightness;
|
||||
unsigned char current_brightness;
|
||||
|
||||
int blink_data;
|
||||
int blink_time;
|
||||
int blink_on;
|
||||
int blink_off;
|
||||
int reg_control;
|
||||
int reg_blink;
|
||||
int blink_mask;
|
||||
};
|
||||
|
||||
/* return offset of color register */
|
||||
static inline int __led_off(int port)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
|
||||
switch (port) {
|
||||
case PM8606_LED1_RED:
|
||||
case PM8606_LED1_GREEN:
|
||||
case PM8606_LED1_BLUE:
|
||||
ret = port - PM8606_LED1_RED + PM8606_RGB1B;
|
||||
break;
|
||||
case PM8606_LED2_RED:
|
||||
case PM8606_LED2_GREEN:
|
||||
case PM8606_LED2_BLUE:
|
||||
ret = port - PM8606_LED2_RED + PM8606_RGB2B;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* return offset of blink register */
|
||||
static inline int __blink_off(int port)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
|
||||
switch (port) {
|
||||
case PM8606_LED1_RED:
|
||||
case PM8606_LED1_GREEN:
|
||||
case PM8606_LED1_BLUE:
|
||||
ret = PM8606_RGB1A;
|
||||
break;
|
||||
case PM8606_LED2_RED:
|
||||
case PM8606_LED2_GREEN:
|
||||
case PM8606_LED2_BLUE:
|
||||
ret = PM8606_RGB2A;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int __blink_ctl_mask(int port)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
|
||||
switch (port) {
|
||||
case PM8606_LED1_RED:
|
||||
case PM8606_LED1_GREEN:
|
||||
case PM8606_LED1_BLUE:
|
||||
ret = LED1_BLINK_EN;
|
||||
break;
|
||||
case PM8606_LED2_RED:
|
||||
case PM8606_LED2_GREEN:
|
||||
case PM8606_LED2_BLUE:
|
||||
ret = LED2_BLINK_EN;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int led_power_set(struct pm860x_chip *chip, int port, int on)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
|
||||
switch (port) {
|
||||
case PM8606_LED1_RED:
|
||||
case PM8606_LED1_GREEN:
|
||||
case PM8606_LED1_BLUE:
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
ret = on ? pm8606_osc_enable(chip, RGB1_ENABLE) :
|
||||
pm8606_osc_disable(chip, RGB1_ENABLE);
|
||||
break;
|
||||
case PM8606_LED2_RED:
|
||||
case PM8606_LED2_GREEN:
|
||||
case PM8606_LED2_BLUE:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
ret = on ? pm8606_osc_enable(chip, RGB2_ENABLE) :
|
||||
pm8606_osc_disable(chip, RGB2_ENABLE);
|
||||
break;
|
||||
|
@ -141,7 +76,7 @@ static void pm860x_led_work(struct work_struct *work)
|
|||
struct pm860x_led *led;
|
||||
struct pm860x_chip *chip;
|
||||
unsigned char buf[3];
|
||||
int mask, ret;
|
||||
int ret;
|
||||
|
||||
led = container_of(work, struct pm860x_led, work);
|
||||
chip = led->chip;
|
||||
|
@ -149,34 +84,34 @@ static void pm860x_led_work(struct work_struct *work)
|
|||
if ((led->current_brightness == 0) && led->brightness) {
|
||||
led_power_set(chip, led->port, 1);
|
||||
if (led->iset) {
|
||||
pm860x_set_bits(led->i2c, __led_off(led->port),
|
||||
pm860x_set_bits(led->i2c, led->reg_control,
|
||||
LED_CURRENT_MASK, led->iset);
|
||||
}
|
||||
pm860x_set_bits(led->i2c, __blink_off(led->port),
|
||||
pm860x_set_bits(led->i2c, led->reg_blink,
|
||||
LED_BLINK_MASK, LED_ON_CONTINUOUS);
|
||||
mask = __blink_ctl_mask(led->port);
|
||||
pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, mask);
|
||||
pm860x_set_bits(led->i2c, PM8606_WLED3B, led->blink_mask,
|
||||
led->blink_mask);
|
||||
}
|
||||
pm860x_set_bits(led->i2c, __led_off(led->port), LED_PWM_MASK,
|
||||
pm860x_set_bits(led->i2c, led->reg_control, LED_PWM_MASK,
|
||||
led->brightness);
|
||||
|
||||
if (led->brightness == 0) {
|
||||
pm860x_bulk_read(led->i2c, __led_off(led->port), 3, buf);
|
||||
pm860x_bulk_read(led->i2c, led->reg_control, 3, buf);
|
||||
ret = buf[0] & LED_PWM_MASK;
|
||||
ret |= buf[1] & LED_PWM_MASK;
|
||||
ret |= buf[2] & LED_PWM_MASK;
|
||||
if (ret == 0) {
|
||||
/* unset current since no led is lighting */
|
||||
pm860x_set_bits(led->i2c, __led_off(led->port),
|
||||
pm860x_set_bits(led->i2c, led->reg_control,
|
||||
LED_CURRENT_MASK, 0);
|
||||
mask = __blink_ctl_mask(led->port);
|
||||
pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, 0);
|
||||
pm860x_set_bits(led->i2c, PM8606_WLED3B,
|
||||
led->blink_mask, 0);
|
||||
led_power_set(chip, led->port, 0);
|
||||
}
|
||||
}
|
||||
led->current_brightness = led->brightness;
|
||||
dev_dbg(chip->dev, "Update LED. (reg:%d, brightness:%d)\n",
|
||||
__led_off(led->port), led->brightness);
|
||||
led->reg_control, led->brightness);
|
||||
mutex_unlock(&led->lock);
|
||||
}
|
||||
|
||||
|
@ -189,39 +124,92 @@ static void pm860x_led_set(struct led_classdev *cdev,
|
|||
schedule_work(&data->work);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int pm860x_led_dt_init(struct platform_device *pdev,
|
||||
struct pm860x_led *data)
|
||||
{
|
||||
struct device_node *nproot = pdev->dev.parent->of_node, *np;
|
||||
int iset = 0;
|
||||
if (!nproot)
|
||||
return -ENODEV;
|
||||
nproot = of_find_node_by_name(nproot, "leds");
|
||||
if (!nproot) {
|
||||
dev_err(&pdev->dev, "failed to find leds node\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
for_each_child_of_node(nproot, np) {
|
||||
if (!of_node_cmp(np->name, data->name)) {
|
||||
of_property_read_u32(np, "marvell,88pm860x-iset",
|
||||
&iset);
|
||||
data->iset = PM8606_LED_CURRENT(iset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define pm860x_led_dt_init(x, y) (-1)
|
||||
#endif
|
||||
|
||||
static int pm860x_led_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
|
||||
struct pm860x_led_pdata *pdata;
|
||||
struct pm860x_led_pdata *pdata = pdev->dev.platform_data;
|
||||
struct pm860x_led *data;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
if (res == NULL) {
|
||||
dev_err(&pdev->dev, "No I/O resource!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
if (pdata == NULL) {
|
||||
dev_err(&pdev->dev, "No platform data!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
int ret = 0;
|
||||
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(struct pm860x_led), GFP_KERNEL);
|
||||
if (data == NULL)
|
||||
return -ENOMEM;
|
||||
strncpy(data->name, res->name, MFD_NAME_SIZE - 1);
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_REG, "control");
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "No REG resource for control\n");
|
||||
ret = -ENXIO;
|
||||
goto out;
|
||||
}
|
||||
data->reg_control = res->start;
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_REG, "blink");
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "No REG resource for blink\n");
|
||||
ret = -ENXIO;
|
||||
goto out;
|
||||
}
|
||||
data->reg_blink = res->start;
|
||||
memset(data->name, 0, MFD_NAME_SIZE);
|
||||
switch (pdev->id) {
|
||||
case 0:
|
||||
data->blink_mask = LED1_BLINK_EN;
|
||||
sprintf(data->name, "led0-red");
|
||||
break;
|
||||
case 1:
|
||||
data->blink_mask = LED1_BLINK_EN;
|
||||
sprintf(data->name, "led0-green");
|
||||
break;
|
||||
case 2:
|
||||
data->blink_mask = LED1_BLINK_EN;
|
||||
sprintf(data->name, "led0-blue");
|
||||
break;
|
||||
case 3:
|
||||
data->blink_mask = LED2_BLINK_EN;
|
||||
sprintf(data->name, "led1-red");
|
||||
break;
|
||||
case 4:
|
||||
data->blink_mask = LED2_BLINK_EN;
|
||||
sprintf(data->name, "led1-green");
|
||||
break;
|
||||
case 5:
|
||||
data->blink_mask = LED2_BLINK_EN;
|
||||
sprintf(data->name, "led1-blue");
|
||||
break;
|
||||
}
|
||||
dev_set_drvdata(&pdev->dev, data);
|
||||
data->chip = chip;
|
||||
data->i2c = (chip->id == CHIP_PM8606) ? chip->client : chip->companion;
|
||||
data->iset = pdata->iset;
|
||||
data->port = pdata->flags;
|
||||
if (data->port < 0) {
|
||||
dev_err(&pdev->dev, "check device failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
data->port = pdev->id;
|
||||
if (pm860x_led_dt_init(pdev, data))
|
||||
if (pdata)
|
||||
data->iset = pdata->iset;
|
||||
|
||||
data->current_brightness = 0;
|
||||
data->cdev.name = data->name;
|
||||
|
@ -236,6 +224,9 @@ static int pm860x_led_probe(struct platform_device *pdev)
|
|||
}
|
||||
pm860x_led_set(&data->cdev, 0);
|
||||
return 0;
|
||||
out:
|
||||
devm_kfree(&pdev->dev, data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pm860x_led_remove(struct platform_device *pdev)
|
||||
|
|
|
@ -11,50 +11,116 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/88pm860x.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
|
||||
#define INT_STATUS_NUM 3
|
||||
|
||||
static struct resource bk_resources[] __devinitdata = {
|
||||
{PM8606_BACKLIGHT1, PM8606_BACKLIGHT1, "backlight-0", IORESOURCE_IO,},
|
||||
{PM8606_BACKLIGHT2, PM8606_BACKLIGHT2, "backlight-1", IORESOURCE_IO,},
|
||||
{PM8606_BACKLIGHT3, PM8606_BACKLIGHT3, "backlight-2", IORESOURCE_IO,},
|
||||
static struct resource bk0_resources[] __devinitdata = {
|
||||
{2, 2, "duty cycle", IORESOURCE_REG, },
|
||||
{3, 3, "always on", IORESOURCE_REG, },
|
||||
{3, 3, "current", IORESOURCE_REG, },
|
||||
};
|
||||
static struct resource bk1_resources[] __devinitdata = {
|
||||
{4, 4, "duty cycle", IORESOURCE_REG, },
|
||||
{5, 5, "always on", IORESOURCE_REG, },
|
||||
{5, 5, "current", IORESOURCE_REG, },
|
||||
};
|
||||
static struct resource bk2_resources[] __devinitdata = {
|
||||
{6, 6, "duty cycle", IORESOURCE_REG, },
|
||||
{7, 7, "always on", IORESOURCE_REG, },
|
||||
{5, 5, "current", IORESOURCE_REG, },
|
||||
};
|
||||
|
||||
static struct resource led_resources[] __devinitdata = {
|
||||
{PM8606_LED1_RED, PM8606_LED1_RED, "led0-red", IORESOURCE_IO,},
|
||||
{PM8606_LED1_GREEN, PM8606_LED1_GREEN, "led0-green", IORESOURCE_IO,},
|
||||
{PM8606_LED1_BLUE, PM8606_LED1_BLUE, "led0-blue", IORESOURCE_IO,},
|
||||
{PM8606_LED2_RED, PM8606_LED2_RED, "led1-red", IORESOURCE_IO,},
|
||||
{PM8606_LED2_GREEN, PM8606_LED2_GREEN, "led1-green", IORESOURCE_IO,},
|
||||
{PM8606_LED2_BLUE, PM8606_LED2_BLUE, "led1-blue", IORESOURCE_IO,},
|
||||
static struct resource led0_resources[] __devinitdata = {
|
||||
/* RGB1 Red LED */
|
||||
{0xd, 0xd, "control", IORESOURCE_REG, },
|
||||
{0xc, 0xc, "blink", IORESOURCE_REG, },
|
||||
};
|
||||
static struct resource led1_resources[] __devinitdata = {
|
||||
/* RGB1 Green LED */
|
||||
{0xe, 0xe, "control", IORESOURCE_REG, },
|
||||
{0xc, 0xc, "blink", IORESOURCE_REG, },
|
||||
};
|
||||
static struct resource led2_resources[] __devinitdata = {
|
||||
/* RGB1 Blue LED */
|
||||
{0xf, 0xf, "control", IORESOURCE_REG, },
|
||||
{0xc, 0xc, "blink", IORESOURCE_REG, },
|
||||
};
|
||||
static struct resource led3_resources[] __devinitdata = {
|
||||
/* RGB2 Red LED */
|
||||
{0x9, 0x9, "control", IORESOURCE_REG, },
|
||||
{0x8, 0x8, "blink", IORESOURCE_REG, },
|
||||
};
|
||||
static struct resource led4_resources[] __devinitdata = {
|
||||
/* RGB2 Green LED */
|
||||
{0xa, 0xa, "control", IORESOURCE_REG, },
|
||||
{0x8, 0x8, "blink", IORESOURCE_REG, },
|
||||
};
|
||||
static struct resource led5_resources[] __devinitdata = {
|
||||
/* RGB2 Blue LED */
|
||||
{0xb, 0xb, "control", IORESOURCE_REG, },
|
||||
{0x8, 0x8, "blink", IORESOURCE_REG, },
|
||||
};
|
||||
|
||||
static struct resource regulator_resources[] __devinitdata = {
|
||||
{PM8607_ID_BUCK1, PM8607_ID_BUCK1, "buck-1", IORESOURCE_IO,},
|
||||
{PM8607_ID_BUCK2, PM8607_ID_BUCK2, "buck-2", IORESOURCE_IO,},
|
||||
{PM8607_ID_BUCK3, PM8607_ID_BUCK3, "buck-3", IORESOURCE_IO,},
|
||||
{PM8607_ID_LDO1, PM8607_ID_LDO1, "ldo-01", IORESOURCE_IO,},
|
||||
{PM8607_ID_LDO2, PM8607_ID_LDO2, "ldo-02", IORESOURCE_IO,},
|
||||
{PM8607_ID_LDO3, PM8607_ID_LDO3, "ldo-03", IORESOURCE_IO,},
|
||||
{PM8607_ID_LDO4, PM8607_ID_LDO4, "ldo-04", IORESOURCE_IO,},
|
||||
{PM8607_ID_LDO5, PM8607_ID_LDO5, "ldo-05", IORESOURCE_IO,},
|
||||
{PM8607_ID_LDO6, PM8607_ID_LDO6, "ldo-06", IORESOURCE_IO,},
|
||||
{PM8607_ID_LDO7, PM8607_ID_LDO7, "ldo-07", IORESOURCE_IO,},
|
||||
{PM8607_ID_LDO8, PM8607_ID_LDO8, "ldo-08", IORESOURCE_IO,},
|
||||
{PM8607_ID_LDO9, PM8607_ID_LDO9, "ldo-09", IORESOURCE_IO,},
|
||||
{PM8607_ID_LDO10, PM8607_ID_LDO10, "ldo-10", IORESOURCE_IO,},
|
||||
{PM8607_ID_LDO11, PM8607_ID_LDO11, "ldo-11", IORESOURCE_IO,},
|
||||
{PM8607_ID_LDO12, PM8607_ID_LDO12, "ldo-12", IORESOURCE_IO,},
|
||||
{PM8607_ID_LDO13, PM8607_ID_LDO13, "ldo-13", IORESOURCE_IO,},
|
||||
{PM8607_ID_LDO14, PM8607_ID_LDO14, "ldo-14", IORESOURCE_IO,},
|
||||
{PM8607_ID_LDO15, PM8607_ID_LDO15, "ldo-15", IORESOURCE_IO,},
|
||||
static struct resource buck1_resources[] __devinitdata = {
|
||||
{0x24, 0x24, "buck set", IORESOURCE_REG, },
|
||||
};
|
||||
static struct resource buck2_resources[] __devinitdata = {
|
||||
{0x25, 0x25, "buck set", IORESOURCE_REG, },
|
||||
};
|
||||
static struct resource buck3_resources[] __devinitdata = {
|
||||
{0x26, 0x26, "buck set", IORESOURCE_REG, },
|
||||
};
|
||||
static struct resource ldo1_resources[] __devinitdata = {
|
||||
{0x10, 0x10, "ldo set", IORESOURCE_REG, },
|
||||
};
|
||||
static struct resource ldo2_resources[] __devinitdata = {
|
||||
{0x11, 0x11, "ldo set", IORESOURCE_REG, },
|
||||
};
|
||||
static struct resource ldo3_resources[] __devinitdata = {
|
||||
{0x12, 0x12, "ldo set", IORESOURCE_REG, },
|
||||
};
|
||||
static struct resource ldo4_resources[] __devinitdata = {
|
||||
{0x13, 0x13, "ldo set", IORESOURCE_REG, },
|
||||
};
|
||||
static struct resource ldo5_resources[] __devinitdata = {
|
||||
{0x14, 0x14, "ldo set", IORESOURCE_REG, },
|
||||
};
|
||||
static struct resource ldo6_resources[] __devinitdata = {
|
||||
{0x15, 0x15, "ldo set", IORESOURCE_REG, },
|
||||
};
|
||||
static struct resource ldo7_resources[] __devinitdata = {
|
||||
{0x16, 0x16, "ldo set", IORESOURCE_REG, },
|
||||
};
|
||||
static struct resource ldo8_resources[] __devinitdata = {
|
||||
{0x17, 0x17, "ldo set", IORESOURCE_REG, },
|
||||
};
|
||||
static struct resource ldo9_resources[] __devinitdata = {
|
||||
{0x18, 0x18, "ldo set", IORESOURCE_REG, },
|
||||
};
|
||||
static struct resource ldo10_resources[] __devinitdata = {
|
||||
{0x19, 0x19, "ldo set", IORESOURCE_REG, },
|
||||
};
|
||||
static struct resource ldo12_resources[] __devinitdata = {
|
||||
{0x1a, 0x1a, "ldo set", IORESOURCE_REG, },
|
||||
};
|
||||
static struct resource ldo_vibrator_resources[] __devinitdata = {
|
||||
{0x28, 0x28, "ldo set", IORESOURCE_REG, },
|
||||
};
|
||||
static struct resource ldo14_resources[] __devinitdata = {
|
||||
{0x1b, 0x1b, "ldo set", IORESOURCE_REG, },
|
||||
};
|
||||
|
||||
static struct resource touch_resources[] __devinitdata = {
|
||||
|
@ -90,48 +156,145 @@ static struct resource charger_resources[] __devinitdata = {
|
|||
{PM8607_IRQ_VCHG, PM8607_IRQ_VCHG, "vchg voltage", IORESOURCE_IRQ,},
|
||||
};
|
||||
|
||||
static struct resource preg_resources[] __devinitdata = {
|
||||
{PM8606_ID_PREG, PM8606_ID_PREG, "preg", IORESOURCE_IO,},
|
||||
};
|
||||
|
||||
static struct resource rtc_resources[] __devinitdata = {
|
||||
{PM8607_IRQ_RTC, PM8607_IRQ_RTC, "rtc", IORESOURCE_IRQ,},
|
||||
};
|
||||
|
||||
static struct mfd_cell bk_devs[] = {
|
||||
{"88pm860x-backlight", 0,},
|
||||
{"88pm860x-backlight", 1,},
|
||||
{"88pm860x-backlight", 2,},
|
||||
static struct mfd_cell bk_devs[] __devinitdata = {
|
||||
{
|
||||
.name = "88pm860x-backlight",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(bk0_resources),
|
||||
.resources = bk0_resources,
|
||||
}, {
|
||||
.name = "88pm860x-backlight",
|
||||
.id = 1,
|
||||
.num_resources = ARRAY_SIZE(bk1_resources),
|
||||
.resources = bk1_resources,
|
||||
}, {
|
||||
.name = "88pm860x-backlight",
|
||||
.id = 2,
|
||||
.num_resources = ARRAY_SIZE(bk2_resources),
|
||||
.resources = bk2_resources,
|
||||
},
|
||||
};
|
||||
|
||||
static struct mfd_cell led_devs[] = {
|
||||
{"88pm860x-led", 0,},
|
||||
{"88pm860x-led", 1,},
|
||||
{"88pm860x-led", 2,},
|
||||
{"88pm860x-led", 3,},
|
||||
{"88pm860x-led", 4,},
|
||||
{"88pm860x-led", 5,},
|
||||
static struct mfd_cell led_devs[] __devinitdata = {
|
||||
{
|
||||
.name = "88pm860x-led",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(led0_resources),
|
||||
.resources = led0_resources,
|
||||
}, {
|
||||
.name = "88pm860x-led",
|
||||
.id = 1,
|
||||
.num_resources = ARRAY_SIZE(led1_resources),
|
||||
.resources = led1_resources,
|
||||
}, {
|
||||
.name = "88pm860x-led",
|
||||
.id = 2,
|
||||
.num_resources = ARRAY_SIZE(led2_resources),
|
||||
.resources = led2_resources,
|
||||
}, {
|
||||
.name = "88pm860x-led",
|
||||
.id = 3,
|
||||
.num_resources = ARRAY_SIZE(led3_resources),
|
||||
.resources = led3_resources,
|
||||
}, {
|
||||
.name = "88pm860x-led",
|
||||
.id = 4,
|
||||
.num_resources = ARRAY_SIZE(led4_resources),
|
||||
.resources = led4_resources,
|
||||
}, {
|
||||
.name = "88pm860x-led",
|
||||
.id = 5,
|
||||
.num_resources = ARRAY_SIZE(led5_resources),
|
||||
.resources = led5_resources,
|
||||
},
|
||||
};
|
||||
|
||||
static struct mfd_cell regulator_devs[] = {
|
||||
{"88pm860x-regulator", 0,},
|
||||
{"88pm860x-regulator", 1,},
|
||||
{"88pm860x-regulator", 2,},
|
||||
{"88pm860x-regulator", 3,},
|
||||
{"88pm860x-regulator", 4,},
|
||||
{"88pm860x-regulator", 5,},
|
||||
{"88pm860x-regulator", 6,},
|
||||
{"88pm860x-regulator", 7,},
|
||||
{"88pm860x-regulator", 8,},
|
||||
{"88pm860x-regulator", 9,},
|
||||
{"88pm860x-regulator", 10,},
|
||||
{"88pm860x-regulator", 11,},
|
||||
{"88pm860x-regulator", 12,},
|
||||
{"88pm860x-regulator", 13,},
|
||||
{"88pm860x-regulator", 14,},
|
||||
{"88pm860x-regulator", 15,},
|
||||
{"88pm860x-regulator", 16,},
|
||||
{"88pm860x-regulator", 17,},
|
||||
static struct mfd_cell reg_devs[] __devinitdata = {
|
||||
{
|
||||
.name = "88pm860x-regulator",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(buck1_resources),
|
||||
.resources = buck1_resources,
|
||||
}, {
|
||||
.name = "88pm860x-regulator",
|
||||
.id = 1,
|
||||
.num_resources = ARRAY_SIZE(buck2_resources),
|
||||
.resources = buck2_resources,
|
||||
}, {
|
||||
.name = "88pm860x-regulator",
|
||||
.id = 2,
|
||||
.num_resources = ARRAY_SIZE(buck3_resources),
|
||||
.resources = buck3_resources,
|
||||
}, {
|
||||
.name = "88pm860x-regulator",
|
||||
.id = 3,
|
||||
.num_resources = ARRAY_SIZE(ldo1_resources),
|
||||
.resources = ldo1_resources,
|
||||
}, {
|
||||
.name = "88pm860x-regulator",
|
||||
.id = 4,
|
||||
.num_resources = ARRAY_SIZE(ldo2_resources),
|
||||
.resources = ldo2_resources,
|
||||
}, {
|
||||
.name = "88pm860x-regulator",
|
||||
.id = 5,
|
||||
.num_resources = ARRAY_SIZE(ldo3_resources),
|
||||
.resources = ldo3_resources,
|
||||
}, {
|
||||
.name = "88pm860x-regulator",
|
||||
.id = 6,
|
||||
.num_resources = ARRAY_SIZE(ldo4_resources),
|
||||
.resources = ldo4_resources,
|
||||
}, {
|
||||
.name = "88pm860x-regulator",
|
||||
.id = 7,
|
||||
.num_resources = ARRAY_SIZE(ldo5_resources),
|
||||
.resources = ldo5_resources,
|
||||
}, {
|
||||
.name = "88pm860x-regulator",
|
||||
.id = 8,
|
||||
.num_resources = ARRAY_SIZE(ldo6_resources),
|
||||
.resources = ldo6_resources,
|
||||
}, {
|
||||
.name = "88pm860x-regulator",
|
||||
.id = 9,
|
||||
.num_resources = ARRAY_SIZE(ldo7_resources),
|
||||
.resources = ldo7_resources,
|
||||
}, {
|
||||
.name = "88pm860x-regulator",
|
||||
.id = 10,
|
||||
.num_resources = ARRAY_SIZE(ldo8_resources),
|
||||
.resources = ldo8_resources,
|
||||
}, {
|
||||
.name = "88pm860x-regulator",
|
||||
.id = 11,
|
||||
.num_resources = ARRAY_SIZE(ldo9_resources),
|
||||
.resources = ldo9_resources,
|
||||
}, {
|
||||
.name = "88pm860x-regulator",
|
||||
.id = 12,
|
||||
.num_resources = ARRAY_SIZE(ldo10_resources),
|
||||
.resources = ldo10_resources,
|
||||
}, {
|
||||
.name = "88pm860x-regulator",
|
||||
.id = 13,
|
||||
.num_resources = ARRAY_SIZE(ldo12_resources),
|
||||
.resources = ldo12_resources,
|
||||
}, {
|
||||
.name = "88pm860x-regulator",
|
||||
.id = 14,
|
||||
.num_resources = ARRAY_SIZE(ldo_vibrator_resources),
|
||||
.resources = ldo_vibrator_resources,
|
||||
}, {
|
||||
.name = "88pm860x-regulator",
|
||||
.id = 15,
|
||||
.num_resources = ARRAY_SIZE(ldo14_resources),
|
||||
.resources = ldo14_resources,
|
||||
},
|
||||
};
|
||||
|
||||
static struct mfd_cell touch_devs[] = {
|
||||
|
@ -360,15 +523,12 @@ static void pm860x_irq_sync_unlock(struct irq_data *data)
|
|||
|
||||
static void pm860x_irq_enable(struct irq_data *data)
|
||||
{
|
||||
struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
|
||||
pm860x_irqs[data->irq - chip->irq_base].enable
|
||||
= pm860x_irqs[data->irq - chip->irq_base].offs;
|
||||
pm860x_irqs[data->hwirq].enable = pm860x_irqs[data->hwirq].offs;
|
||||
}
|
||||
|
||||
static void pm860x_irq_disable(struct irq_data *data)
|
||||
{
|
||||
struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
|
||||
pm860x_irqs[data->irq - chip->irq_base].enable = 0;
|
||||
pm860x_irqs[data->hwirq].enable = 0;
|
||||
}
|
||||
|
||||
static struct irq_chip pm860x_irq_chip = {
|
||||
|
@ -379,53 +539,25 @@ static struct irq_chip pm860x_irq_chip = {
|
|||
.irq_disable = pm860x_irq_disable,
|
||||
};
|
||||
|
||||
static int __devinit device_gpadc_init(struct pm860x_chip *chip,
|
||||
struct pm860x_platform_data *pdata)
|
||||
static int pm860x_irq_domain_map(struct irq_domain *d, unsigned int virq,
|
||||
irq_hw_number_t hw)
|
||||
{
|
||||
struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \
|
||||
: chip->companion;
|
||||
int data;
|
||||
int ret;
|
||||
|
||||
/* initialize GPADC without activating it */
|
||||
|
||||
if (!pdata || !pdata->touch)
|
||||
return -EINVAL;
|
||||
|
||||
/* set GPADC MISC1 register */
|
||||
data = 0;
|
||||
data |= (pdata->touch->gpadc_prebias << 1) & PM8607_GPADC_PREBIAS_MASK;
|
||||
data |= (pdata->touch->slot_cycle << 3) & PM8607_GPADC_SLOT_CYCLE_MASK;
|
||||
data |= (pdata->touch->off_scale << 5) & PM8607_GPADC_OFF_SCALE_MASK;
|
||||
data |= (pdata->touch->sw_cal << 7) & PM8607_GPADC_SW_CAL_MASK;
|
||||
if (data) {
|
||||
ret = pm860x_reg_write(i2c, PM8607_GPADC_MISC1, data);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
/* set tsi prebias time */
|
||||
if (pdata->touch->tsi_prebias) {
|
||||
data = pdata->touch->tsi_prebias;
|
||||
ret = pm860x_reg_write(i2c, PM8607_TSI_PREBIAS, data);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
/* set prebias & prechg time of pen detect */
|
||||
data = 0;
|
||||
data |= pdata->touch->pen_prebias & PM8607_PD_PREBIAS_MASK;
|
||||
data |= (pdata->touch->pen_prechg << 5) & PM8607_PD_PRECHG_MASK;
|
||||
if (data) {
|
||||
ret = pm860x_reg_write(i2c, PM8607_PD_PREBIAS, data);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = pm860x_set_bits(i2c, PM8607_GPADC_MISC1,
|
||||
PM8607_GPADC_EN, PM8607_GPADC_EN);
|
||||
out:
|
||||
return ret;
|
||||
irq_set_chip_data(virq, d->host_data);
|
||||
irq_set_chip_and_handler(virq, &pm860x_irq_chip, handle_edge_irq);
|
||||
irq_set_nested_thread(virq, 1);
|
||||
#ifdef CONFIG_ARM
|
||||
set_irq_flags(virq, IRQF_VALID);
|
||||
#else
|
||||
irq_set_noprobe(virq);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct irq_domain_ops pm860x_irq_domain_ops = {
|
||||
.map = pm860x_irq_domain_map,
|
||||
.xlate = irq_domain_xlate_onetwocell,
|
||||
};
|
||||
|
||||
static int __devinit device_irq_init(struct pm860x_chip *chip,
|
||||
struct pm860x_platform_data *pdata)
|
||||
{
|
||||
|
@ -433,13 +565,9 @@ static int __devinit device_irq_init(struct pm860x_chip *chip,
|
|||
: chip->companion;
|
||||
unsigned char status_buf[INT_STATUS_NUM];
|
||||
unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
|
||||
int i, data, mask, ret = -EINVAL;
|
||||
int __irq;
|
||||
|
||||
if (!pdata || !pdata->irq_base) {
|
||||
dev_warn(chip->dev, "No interrupt support on IRQ base\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
int data, mask, ret = -EINVAL;
|
||||
int nr_irqs, irq_base = -1;
|
||||
struct device_node *node = i2c->dev.of_node;
|
||||
|
||||
mask = PM8607_B0_MISC1_INV_INT | PM8607_B0_MISC1_INT_CLEAR
|
||||
| PM8607_B0_MISC1_INT_MASK;
|
||||
|
@ -479,26 +607,24 @@ static int __devinit device_irq_init(struct pm860x_chip *chip,
|
|||
goto out;
|
||||
|
||||
mutex_init(&chip->irq_lock);
|
||||
chip->irq_base = pdata->irq_base;
|
||||
|
||||
if (pdata && pdata->irq_base)
|
||||
irq_base = pdata->irq_base;
|
||||
nr_irqs = ARRAY_SIZE(pm860x_irqs);
|
||||
chip->irq_base = irq_alloc_descs(irq_base, 0, nr_irqs, 0);
|
||||
if (chip->irq_base < 0) {
|
||||
dev_err(&i2c->dev, "Failed to allocate interrupts, ret:%d\n",
|
||||
chip->irq_base);
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
irq_domain_add_legacy(node, nr_irqs, chip->irq_base, 0,
|
||||
&pm860x_irq_domain_ops, chip);
|
||||
chip->core_irq = i2c->irq;
|
||||
if (!chip->core_irq)
|
||||
goto out;
|
||||
|
||||
/* register IRQ by genirq */
|
||||
for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) {
|
||||
__irq = i + chip->irq_base;
|
||||
irq_set_chip_data(__irq, chip);
|
||||
irq_set_chip_and_handler(__irq, &pm860x_irq_chip,
|
||||
handle_edge_irq);
|
||||
irq_set_nested_thread(__irq, 1);
|
||||
#ifdef CONFIG_ARM
|
||||
set_irq_flags(__irq, IRQF_VALID);
|
||||
#else
|
||||
irq_set_noprobe(__irq);
|
||||
#endif
|
||||
}
|
||||
|
||||
ret = request_threaded_irq(chip->core_irq, NULL, pm860x_irq, flags,
|
||||
ret = request_threaded_irq(chip->core_irq, NULL, pm860x_irq, flags | IRQF_ONESHOT,
|
||||
"88pm860x", chip);
|
||||
if (ret) {
|
||||
dev_err(chip->dev, "Failed to request IRQ: %d\n", ret);
|
||||
|
@ -615,108 +741,122 @@ static void __devinit device_osc_init(struct i2c_client *i2c)
|
|||
static void __devinit device_bk_init(struct pm860x_chip *chip,
|
||||
struct pm860x_platform_data *pdata)
|
||||
{
|
||||
int ret;
|
||||
int i, j, id;
|
||||
int ret, i;
|
||||
|
||||
if ((pdata == NULL) || (pdata->backlight == NULL))
|
||||
return;
|
||||
|
||||
if (pdata->num_backlights > ARRAY_SIZE(bk_devs))
|
||||
pdata->num_backlights = ARRAY_SIZE(bk_devs);
|
||||
|
||||
for (i = 0; i < pdata->num_backlights; i++) {
|
||||
bk_devs[i].platform_data = &pdata->backlight[i];
|
||||
bk_devs[i].pdata_size = sizeof(struct pm860x_backlight_pdata);
|
||||
|
||||
for (j = 0; j < ARRAY_SIZE(bk_devs); j++) {
|
||||
id = bk_resources[j].start;
|
||||
if (pdata->backlight[i].flags != id)
|
||||
continue;
|
||||
|
||||
bk_devs[i].num_resources = 1;
|
||||
bk_devs[i].resources = &bk_resources[j];
|
||||
ret = mfd_add_devices(chip->dev, 0,
|
||||
&bk_devs[i], 1,
|
||||
&bk_resources[j], 0, NULL);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "Failed to add "
|
||||
"backlight subdev\n");
|
||||
return;
|
||||
}
|
||||
if (pdata && pdata->backlight) {
|
||||
if (pdata->num_backlights > ARRAY_SIZE(bk_devs))
|
||||
pdata->num_backlights = ARRAY_SIZE(bk_devs);
|
||||
for (i = 0; i < pdata->num_backlights; i++) {
|
||||
bk_devs[i].platform_data = &pdata->backlight[i];
|
||||
bk_devs[i].pdata_size =
|
||||
sizeof(struct pm860x_backlight_pdata);
|
||||
}
|
||||
}
|
||||
ret = mfd_add_devices(chip->dev, 0, bk_devs,
|
||||
ARRAY_SIZE(bk_devs), NULL, 0, NULL);
|
||||
if (ret < 0)
|
||||
dev_err(chip->dev, "Failed to add backlight subdev\n");
|
||||
}
|
||||
|
||||
static void __devinit device_led_init(struct pm860x_chip *chip,
|
||||
struct pm860x_platform_data *pdata)
|
||||
{
|
||||
int ret;
|
||||
int i, j, id;
|
||||
int ret, i;
|
||||
|
||||
if ((pdata == NULL) || (pdata->led == NULL))
|
||||
return;
|
||||
|
||||
if (pdata->num_leds > ARRAY_SIZE(led_devs))
|
||||
pdata->num_leds = ARRAY_SIZE(led_devs);
|
||||
|
||||
for (i = 0; i < pdata->num_leds; i++) {
|
||||
led_devs[i].platform_data = &pdata->led[i];
|
||||
led_devs[i].pdata_size = sizeof(struct pm860x_led_pdata);
|
||||
|
||||
for (j = 0; j < ARRAY_SIZE(led_devs); j++) {
|
||||
id = led_resources[j].start;
|
||||
if (pdata->led[i].flags != id)
|
||||
continue;
|
||||
|
||||
led_devs[i].num_resources = 1;
|
||||
led_devs[i].resources = &led_resources[j],
|
||||
ret = mfd_add_devices(chip->dev, 0,
|
||||
&led_devs[i], 1,
|
||||
&led_resources[j], 0, NULL);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "Failed to add "
|
||||
"led subdev\n");
|
||||
return;
|
||||
}
|
||||
if (pdata && pdata->led) {
|
||||
if (pdata->num_leds > ARRAY_SIZE(led_devs))
|
||||
pdata->num_leds = ARRAY_SIZE(led_devs);
|
||||
for (i = 0; i < pdata->num_leds; i++) {
|
||||
led_devs[i].platform_data = &pdata->led[i];
|
||||
led_devs[i].pdata_size =
|
||||
sizeof(struct pm860x_led_pdata);
|
||||
}
|
||||
}
|
||||
ret = mfd_add_devices(chip->dev, 0, led_devs,
|
||||
ARRAY_SIZE(led_devs), NULL, 0, NULL);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "Failed to add led subdev\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void __devinit device_regulator_init(struct pm860x_chip *chip,
|
||||
struct pm860x_platform_data *pdata)
|
||||
{
|
||||
struct regulator_init_data *initdata;
|
||||
int ret;
|
||||
int i, seq;
|
||||
|
||||
if ((pdata == NULL) || (pdata->regulator == NULL))
|
||||
if (pdata == NULL)
|
||||
return;
|
||||
if (pdata->buck1) {
|
||||
reg_devs[0].platform_data = pdata->buck1;
|
||||
reg_devs[0].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->buck2) {
|
||||
reg_devs[1].platform_data = pdata->buck2;
|
||||
reg_devs[1].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->buck3) {
|
||||
reg_devs[2].platform_data = pdata->buck3;
|
||||
reg_devs[2].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->ldo1) {
|
||||
reg_devs[3].platform_data = pdata->ldo1;
|
||||
reg_devs[3].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->ldo2) {
|
||||
reg_devs[4].platform_data = pdata->ldo2;
|
||||
reg_devs[4].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->ldo3) {
|
||||
reg_devs[5].platform_data = pdata->ldo3;
|
||||
reg_devs[5].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->ldo4) {
|
||||
reg_devs[6].platform_data = pdata->ldo4;
|
||||
reg_devs[6].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->ldo5) {
|
||||
reg_devs[7].platform_data = pdata->ldo5;
|
||||
reg_devs[7].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->ldo6) {
|
||||
reg_devs[8].platform_data = pdata->ldo6;
|
||||
reg_devs[8].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->ldo7) {
|
||||
reg_devs[9].platform_data = pdata->ldo7;
|
||||
reg_devs[9].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->ldo8) {
|
||||
reg_devs[10].platform_data = pdata->ldo8;
|
||||
reg_devs[10].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->ldo9) {
|
||||
reg_devs[11].platform_data = pdata->ldo9;
|
||||
reg_devs[11].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->ldo10) {
|
||||
reg_devs[12].platform_data = pdata->ldo10;
|
||||
reg_devs[12].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->ldo12) {
|
||||
reg_devs[13].platform_data = pdata->ldo12;
|
||||
reg_devs[13].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->ldo_vibrator) {
|
||||
reg_devs[14].platform_data = pdata->ldo_vibrator;
|
||||
reg_devs[14].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->ldo14) {
|
||||
reg_devs[15].platform_data = pdata->ldo14;
|
||||
reg_devs[15].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
ret = mfd_add_devices(chip->dev, 0, reg_devs,
|
||||
ARRAY_SIZE(reg_devs), NULL, 0, NULL);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "Failed to add regulator subdev\n");
|
||||
return;
|
||||
|
||||
if (pdata->num_regulators > ARRAY_SIZE(regulator_devs))
|
||||
pdata->num_regulators = ARRAY_SIZE(regulator_devs);
|
||||
|
||||
for (i = 0, seq = -1; i < pdata->num_regulators; i++) {
|
||||
initdata = &pdata->regulator[i];
|
||||
seq = *(unsigned int *)initdata->driver_data;
|
||||
if ((seq < 0) || (seq > PM8607_ID_RG_MAX)) {
|
||||
dev_err(chip->dev, "Wrong ID(%d) on regulator(%s)\n",
|
||||
seq, initdata->constraints.name);
|
||||
goto out;
|
||||
}
|
||||
regulator_devs[i].platform_data = &pdata->regulator[i];
|
||||
regulator_devs[i].pdata_size = sizeof(struct regulator_init_data);
|
||||
regulator_devs[i].num_resources = 1;
|
||||
regulator_devs[i].resources = ®ulator_resources[seq];
|
||||
|
||||
ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[i], 1,
|
||||
®ulator_resources[seq], 0, NULL);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "Failed to add regulator subdev\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
out:
|
||||
return;
|
||||
}
|
||||
|
||||
static void __devinit device_rtc_init(struct pm860x_chip *chip,
|
||||
|
@ -785,10 +925,8 @@ static void __devinit device_power_init(struct pm860x_chip *chip,
|
|||
|
||||
power_devs[2].platform_data = &preg_init_data;
|
||||
power_devs[2].pdata_size = sizeof(struct regulator_init_data);
|
||||
power_devs[2].num_resources = ARRAY_SIZE(preg_resources);
|
||||
power_devs[2].resources = &preg_resources[0],
|
||||
ret = mfd_add_devices(chip->dev, 0, &power_devs[2], 1,
|
||||
&preg_resources[0], chip->irq_base, NULL);
|
||||
NULL, chip->irq_base, NULL);
|
||||
if (ret < 0)
|
||||
dev_err(chip->dev, "Failed to add preg subdev\n");
|
||||
}
|
||||
|
@ -868,10 +1006,6 @@ static void __devinit device_8607_init(struct pm860x_chip *chip,
|
|||
goto out;
|
||||
}
|
||||
|
||||
ret = device_gpadc_init(chip, pdata);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = device_irq_init(chip, pdata);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
@ -895,8 +1029,8 @@ static void __devinit device_8606_init(struct pm860x_chip *chip,
|
|||
device_led_init(chip, pdata);
|
||||
}
|
||||
|
||||
int __devinit pm860x_device_init(struct pm860x_chip *chip,
|
||||
struct pm860x_platform_data *pdata)
|
||||
static int __devinit pm860x_device_init(struct pm860x_chip *chip,
|
||||
struct pm860x_platform_data *pdata)
|
||||
{
|
||||
chip->core_irq = 0;
|
||||
|
||||
|
@ -923,12 +1057,207 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip,
|
|||
return 0;
|
||||
}
|
||||
|
||||
void __devexit pm860x_device_exit(struct pm860x_chip *chip)
|
||||
static void __devexit pm860x_device_exit(struct pm860x_chip *chip)
|
||||
{
|
||||
device_irq_exit(chip);
|
||||
mfd_remove_devices(chip->dev);
|
||||
}
|
||||
|
||||
static int verify_addr(struct i2c_client *i2c)
|
||||
{
|
||||
unsigned short addr_8607[] = {0x30, 0x34};
|
||||
unsigned short addr_8606[] = {0x10, 0x11};
|
||||
int size, i;
|
||||
|
||||
if (i2c == NULL)
|
||||
return 0;
|
||||
size = ARRAY_SIZE(addr_8606);
|
||||
for (i = 0; i < size; i++) {
|
||||
if (i2c->addr == *(addr_8606 + i))
|
||||
return CHIP_PM8606;
|
||||
}
|
||||
size = ARRAY_SIZE(addr_8607);
|
||||
for (i = 0; i < size; i++) {
|
||||
if (i2c->addr == *(addr_8607 + i))
|
||||
return CHIP_PM8607;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct regmap_config pm860x_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
};
|
||||
|
||||
static int __devinit pm860x_dt_init(struct device_node *np,
|
||||
struct device *dev,
|
||||
struct pm860x_platform_data *pdata)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (of_get_property(np, "marvell,88pm860x-irq-read-clr", NULL))
|
||||
pdata->irq_mode = 1;
|
||||
ret = of_property_read_u32(np, "marvell,88pm860x-slave-addr",
|
||||
&pdata->companion_addr);
|
||||
if (ret) {
|
||||
dev_err(dev, "Not found \"marvell,88pm860x-slave-addr\" "
|
||||
"property\n");
|
||||
pdata->companion_addr = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit pm860x_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct pm860x_platform_data *pdata = client->dev.platform_data;
|
||||
struct device_node *node = client->dev.of_node;
|
||||
struct pm860x_chip *chip;
|
||||
int ret;
|
||||
|
||||
if (node && !pdata) {
|
||||
/* parse DT to get platform data */
|
||||
pdata = devm_kzalloc(&client->dev,
|
||||
sizeof(struct pm860x_platform_data),
|
||||
GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return -ENOMEM;
|
||||
ret = pm860x_dt_init(node, &client->dev, pdata);
|
||||
if (ret)
|
||||
goto err;
|
||||
} else if (!pdata) {
|
||||
pr_info("No platform data in %s!\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL);
|
||||
if (chip == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
chip->id = verify_addr(client);
|
||||
chip->regmap = regmap_init_i2c(client, &pm860x_regmap_config);
|
||||
if (IS_ERR(chip->regmap)) {
|
||||
ret = PTR_ERR(chip->regmap);
|
||||
dev_err(&client->dev, "Failed to allocate register map: %d\n",
|
||||
ret);
|
||||
kfree(chip);
|
||||
return ret;
|
||||
}
|
||||
chip->client = client;
|
||||
i2c_set_clientdata(client, chip);
|
||||
chip->dev = &client->dev;
|
||||
dev_set_drvdata(chip->dev, chip);
|
||||
|
||||
/*
|
||||
* Both client and companion client shares same platform driver.
|
||||
* Driver distinguishes them by pdata->companion_addr.
|
||||
* pdata->companion_addr is only assigned if companion chip exists.
|
||||
* At the same time, the companion_addr shouldn't equal to client
|
||||
* address.
|
||||
*/
|
||||
if (pdata->companion_addr && (pdata->companion_addr != client->addr)) {
|
||||
chip->companion_addr = pdata->companion_addr;
|
||||
chip->companion = i2c_new_dummy(chip->client->adapter,
|
||||
chip->companion_addr);
|
||||
chip->regmap_companion = regmap_init_i2c(chip->companion,
|
||||
&pm860x_regmap_config);
|
||||
if (IS_ERR(chip->regmap_companion)) {
|
||||
ret = PTR_ERR(chip->regmap_companion);
|
||||
dev_err(&chip->companion->dev,
|
||||
"Failed to allocate register map: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
i2c_set_clientdata(chip->companion, chip);
|
||||
}
|
||||
|
||||
pm860x_device_init(chip, pdata);
|
||||
return 0;
|
||||
err:
|
||||
if (node)
|
||||
devm_kfree(&client->dev, pdata);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit pm860x_remove(struct i2c_client *client)
|
||||
{
|
||||
struct pm860x_chip *chip = i2c_get_clientdata(client);
|
||||
|
||||
pm860x_device_exit(chip);
|
||||
if (chip->companion) {
|
||||
regmap_exit(chip->regmap_companion);
|
||||
i2c_unregister_device(chip->companion);
|
||||
}
|
||||
regmap_exit(chip->regmap);
|
||||
kfree(chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int pm860x_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = container_of(dev, struct i2c_client, dev);
|
||||
struct pm860x_chip *chip = i2c_get_clientdata(client);
|
||||
|
||||
if (device_may_wakeup(dev) && chip->wakeup_flag)
|
||||
enable_irq_wake(chip->core_irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pm860x_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = container_of(dev, struct i2c_client, dev);
|
||||
struct pm860x_chip *chip = i2c_get_clientdata(client);
|
||||
|
||||
if (device_may_wakeup(dev) && chip->wakeup_flag)
|
||||
disable_irq_wake(chip->core_irq);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(pm860x_pm_ops, pm860x_suspend, pm860x_resume);
|
||||
|
||||
static const struct i2c_device_id pm860x_id_table[] = {
|
||||
{ "88PM860x", 0 },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, pm860x_id_table);
|
||||
|
||||
static const struct of_device_id pm860x_dt_ids[] = {
|
||||
{ .compatible = "marvell,88pm860x", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, pm860x_dt_ids);
|
||||
|
||||
static struct i2c_driver pm860x_driver = {
|
||||
.driver = {
|
||||
.name = "88PM860x",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &pm860x_pm_ops,
|
||||
.of_match_table = of_match_ptr(pm860x_dt_ids),
|
||||
},
|
||||
.probe = pm860x_probe,
|
||||
.remove = __devexit_p(pm860x_remove),
|
||||
.id_table = pm860x_id_table,
|
||||
};
|
||||
|
||||
static int __init pm860x_i2c_init(void)
|
||||
{
|
||||
int ret;
|
||||
ret = i2c_add_driver(&pm860x_driver);
|
||||
if (ret != 0)
|
||||
pr_err("Failed to register 88PM860x I2C driver: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
subsys_initcall(pm860x_i2c_init);
|
||||
|
||||
static void __exit pm860x_i2c_exit(void)
|
||||
{
|
||||
i2c_del_driver(&pm860x_driver);
|
||||
}
|
||||
module_exit(pm860x_i2c_exit);
|
||||
|
||||
MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM860x");
|
||||
MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -10,12 +10,9 @@
|
|||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/mfd/88pm860x.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
int pm860x_reg_read(struct i2c_client *i2c, int reg)
|
||||
{
|
||||
|
@ -91,8 +88,18 @@ static int read_device(struct i2c_client *i2c, int reg,
|
|||
unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX + 3];
|
||||
unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX + 2];
|
||||
struct i2c_adapter *adap = i2c->adapter;
|
||||
struct i2c_msg msg[2] = {{i2c->addr, 0, 1, msgbuf0},
|
||||
{i2c->addr, I2C_M_RD, 0, msgbuf1},
|
||||
struct i2c_msg msg[2] = {
|
||||
{
|
||||
.addr = i2c->addr,
|
||||
.flags = 0,
|
||||
.len = 1,
|
||||
.buf = msgbuf0
|
||||
},
|
||||
{ .addr = i2c->addr,
|
||||
.flags = I2C_M_RD,
|
||||
.len = 0,
|
||||
.buf = msgbuf1
|
||||
},
|
||||
};
|
||||
int num = 1, ret = 0;
|
||||
|
||||
|
@ -231,160 +238,3 @@ out:
|
|||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(pm860x_page_set_bits);
|
||||
|
||||
static const struct i2c_device_id pm860x_id_table[] = {
|
||||
{ "88PM860x", 0 },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, pm860x_id_table);
|
||||
|
||||
static int verify_addr(struct i2c_client *i2c)
|
||||
{
|
||||
unsigned short addr_8607[] = {0x30, 0x34};
|
||||
unsigned short addr_8606[] = {0x10, 0x11};
|
||||
int size, i;
|
||||
|
||||
if (i2c == NULL)
|
||||
return 0;
|
||||
size = ARRAY_SIZE(addr_8606);
|
||||
for (i = 0; i < size; i++) {
|
||||
if (i2c->addr == *(addr_8606 + i))
|
||||
return CHIP_PM8606;
|
||||
}
|
||||
size = ARRAY_SIZE(addr_8607);
|
||||
for (i = 0; i < size; i++) {
|
||||
if (i2c->addr == *(addr_8607 + i))
|
||||
return CHIP_PM8607;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct regmap_config pm860x_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
};
|
||||
|
||||
static int __devinit pm860x_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct pm860x_platform_data *pdata = client->dev.platform_data;
|
||||
struct pm860x_chip *chip;
|
||||
int ret;
|
||||
|
||||
if (!pdata) {
|
||||
pr_info("No platform data in %s!\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL);
|
||||
if (chip == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
chip->id = verify_addr(client);
|
||||
chip->regmap = regmap_init_i2c(client, &pm860x_regmap_config);
|
||||
if (IS_ERR(chip->regmap)) {
|
||||
ret = PTR_ERR(chip->regmap);
|
||||
dev_err(&client->dev, "Failed to allocate register map: %d\n",
|
||||
ret);
|
||||
kfree(chip);
|
||||
return ret;
|
||||
}
|
||||
chip->client = client;
|
||||
i2c_set_clientdata(client, chip);
|
||||
chip->dev = &client->dev;
|
||||
dev_set_drvdata(chip->dev, chip);
|
||||
|
||||
/*
|
||||
* Both client and companion client shares same platform driver.
|
||||
* Driver distinguishes them by pdata->companion_addr.
|
||||
* pdata->companion_addr is only assigned if companion chip exists.
|
||||
* At the same time, the companion_addr shouldn't equal to client
|
||||
* address.
|
||||
*/
|
||||
if (pdata->companion_addr && (pdata->companion_addr != client->addr)) {
|
||||
chip->companion_addr = pdata->companion_addr;
|
||||
chip->companion = i2c_new_dummy(chip->client->adapter,
|
||||
chip->companion_addr);
|
||||
chip->regmap_companion = regmap_init_i2c(chip->companion,
|
||||
&pm860x_regmap_config);
|
||||
if (IS_ERR(chip->regmap_companion)) {
|
||||
ret = PTR_ERR(chip->regmap_companion);
|
||||
dev_err(&chip->companion->dev,
|
||||
"Failed to allocate register map: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
i2c_set_clientdata(chip->companion, chip);
|
||||
}
|
||||
|
||||
pm860x_device_init(chip, pdata);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devexit pm860x_remove(struct i2c_client *client)
|
||||
{
|
||||
struct pm860x_chip *chip = i2c_get_clientdata(client);
|
||||
|
||||
pm860x_device_exit(chip);
|
||||
if (chip->companion) {
|
||||
regmap_exit(chip->regmap_companion);
|
||||
i2c_unregister_device(chip->companion);
|
||||
}
|
||||
regmap_exit(chip->regmap);
|
||||
kfree(chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int pm860x_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = container_of(dev, struct i2c_client, dev);
|
||||
struct pm860x_chip *chip = i2c_get_clientdata(client);
|
||||
|
||||
if (device_may_wakeup(dev) && chip->wakeup_flag)
|
||||
enable_irq_wake(chip->core_irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pm860x_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = container_of(dev, struct i2c_client, dev);
|
||||
struct pm860x_chip *chip = i2c_get_clientdata(client);
|
||||
|
||||
if (device_may_wakeup(dev) && chip->wakeup_flag)
|
||||
disable_irq_wake(chip->core_irq);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(pm860x_pm_ops, pm860x_suspend, pm860x_resume);
|
||||
|
||||
static struct i2c_driver pm860x_driver = {
|
||||
.driver = {
|
||||
.name = "88PM860x",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &pm860x_pm_ops,
|
||||
},
|
||||
.probe = pm860x_probe,
|
||||
.remove = __devexit_p(pm860x_remove),
|
||||
.id_table = pm860x_id_table,
|
||||
};
|
||||
|
||||
static int __init pm860x_i2c_init(void)
|
||||
{
|
||||
int ret;
|
||||
ret = i2c_add_driver(&pm860x_driver);
|
||||
if (ret != 0)
|
||||
pr_err("Failed to register 88PM860x I2C driver: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
subsys_initcall(pm860x_i2c_init);
|
||||
|
||||
static void __exit pm860x_i2c_exit(void)
|
||||
{
|
||||
i2c_del_driver(&pm860x_driver);
|
||||
}
|
||||
module_exit(pm860x_i2c_exit);
|
||||
|
||||
MODULE_DESCRIPTION("I2C Driver for Marvell 88PM860x");
|
||||
MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -298,16 +298,6 @@ config MFD_TWL4030_AUDIO
|
|||
select MFD_CORE
|
||||
default n
|
||||
|
||||
config TWL6030_PWM
|
||||
tristate "TWL6030 PWM (Pulse Width Modulator) Support"
|
||||
depends on TWL4030_CORE
|
||||
select HAVE_PWM
|
||||
depends on !PWM
|
||||
default n
|
||||
help
|
||||
Say yes here if you want support for TWL6030 PWM.
|
||||
This is used to control charging LED brightness.
|
||||
|
||||
config TWL6040_CORE
|
||||
bool "Support for TWL6040 audio codec"
|
||||
depends on I2C=y && GENERIC_HARDIRQS
|
||||
|
@ -385,6 +375,18 @@ config MFD_T7L66XB
|
|||
help
|
||||
Support for Toshiba Mobile IO Controller T7L66XB
|
||||
|
||||
config MFD_SMSC
|
||||
bool "Support for the SMSC ECE1099 series chips"
|
||||
depends on I2C=y
|
||||
select MFD_CORE
|
||||
select REGMAP_I2C
|
||||
help
|
||||
If you say yes here you get support for the
|
||||
ece1099 chips from SMSC.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called smsc.
|
||||
|
||||
config MFD_TC6387XB
|
||||
bool "Support Toshiba TC6387XB"
|
||||
depends on ARM && HAVE_CLK
|
||||
|
@ -441,6 +443,23 @@ config MFD_DA9052_I2C
|
|||
for accessing the device, additional drivers must be enabled in
|
||||
order to use the functionality of the device.
|
||||
|
||||
config MFD_DA9055
|
||||
bool "Dialog Semiconductor DA9055 PMIC Support"
|
||||
select REGMAP_I2C
|
||||
select REGMAP_IRQ
|
||||
select PMIC_DA9055
|
||||
select MFD_CORE
|
||||
depends on I2C=y
|
||||
help
|
||||
Say yes here for support of Dialog Semiconductor DA9055. This is
|
||||
a Power Management IC. This driver provides common support for
|
||||
accessing the device as well as the I2C interface to the chip itself.
|
||||
Additional drivers must be enabled in order to use the functionality
|
||||
of the device.
|
||||
|
||||
This driver can be built as a module. If built as a module it will be
|
||||
called "da9055"
|
||||
|
||||
config PMIC_ADP5520
|
||||
bool "Analog Devices ADP5520/01 MFD PMIC Core Support"
|
||||
depends on I2C=y
|
||||
|
@ -451,6 +470,16 @@ config PMIC_ADP5520
|
|||
individual components like LCD backlight, LEDs, GPIOs and Kepad
|
||||
under the corresponding menus.
|
||||
|
||||
config MFD_LP8788
|
||||
bool "Texas Instruments LP8788 Power Management Unit Driver"
|
||||
depends on I2C=y
|
||||
select MFD_CORE
|
||||
select REGMAP_I2C
|
||||
select IRQ_DOMAIN
|
||||
help
|
||||
TI LP8788 PMU supports regulators, battery charger, RTC,
|
||||
ADC, backlight driver and current sinks.
|
||||
|
||||
config MFD_MAX77686
|
||||
bool "Maxim Semiconductor MAX77686 PMIC Support"
|
||||
depends on I2C=y && GENERIC_HARDIRQS
|
||||
|
@ -477,6 +506,18 @@ config MFD_MAX77693
|
|||
additional drivers must be enabled in order to use the functionality
|
||||
of the device.
|
||||
|
||||
config MFD_MAX8907
|
||||
tristate "Maxim Semiconductor MAX8907 PMIC Support"
|
||||
select MFD_CORE
|
||||
depends on I2C=y && GENERIC_HARDIRQS
|
||||
select REGMAP_I2C
|
||||
select REGMAP_IRQ
|
||||
help
|
||||
Say yes here to support for Maxim Semiconductor MAX8907. This is
|
||||
a Power Management IC. This driver provides common support for
|
||||
accessing the device; additional drivers must be enabled in order
|
||||
to use the functionality of the device.
|
||||
|
||||
config MFD_MAX8925
|
||||
bool "Maxim Semiconductor MAX8925 PMIC Support"
|
||||
depends on I2C=y && GENERIC_HARDIRQS
|
||||
|
@ -896,7 +937,7 @@ config MFD_WL1273_CORE
|
|||
audio codec.
|
||||
|
||||
config MFD_OMAP_USB_HOST
|
||||
bool "Support OMAP USBHS core driver"
|
||||
bool "Support OMAP USBHS core and TLL driver"
|
||||
depends on USB_EHCI_HCD_OMAP || USB_OHCI_HCD_OMAP3
|
||||
default y
|
||||
help
|
||||
|
@ -985,13 +1026,13 @@ config MFD_STA2X11
|
|||
depends on STA2X11
|
||||
select MFD_CORE
|
||||
|
||||
config MFD_ANATOP
|
||||
bool "Support for Freescale i.MX on-chip ANATOP controller"
|
||||
depends on SOC_IMX6Q
|
||||
config MFD_SYSCON
|
||||
bool "System Controller Register R/W Based on Regmap"
|
||||
depends on OF
|
||||
select REGMAP_MMIO
|
||||
help
|
||||
Select this option to enable Freescale i.MX on-chip ANATOP
|
||||
MFD controller. This controller embeds regulator and
|
||||
thermal devices for Freescale i.MX platforms.
|
||||
Select this option to enable accessing system control registers
|
||||
via regmap.
|
||||
|
||||
config MFD_PALMAS
|
||||
bool "Support for the TI Palmas series chips"
|
||||
|
|
|
@ -63,7 +63,6 @@ obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o
|
|||
obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
|
||||
obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o
|
||||
obj-$(CONFIG_MFD_TWL4030_AUDIO) += twl4030-audio.o
|
||||
obj-$(CONFIG_TWL6030_PWM) += twl6030-pwm.o
|
||||
obj-$(CONFIG_TWL6040_CORE) += twl6040-core.o twl6040-irq.o
|
||||
|
||||
obj-$(CONFIG_MFD_MC13XXX) += mc13xxx-core.o
|
||||
|
@ -77,6 +76,7 @@ obj-$(CONFIG_EZX_PCAP) += ezx-pcap.o
|
|||
obj-$(CONFIG_MCP) += mcp-core.o
|
||||
obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o
|
||||
obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o
|
||||
obj-$(CONFIG_MFD_SMSC) += smsc-ece1099.o
|
||||
obj-$(CONFIG_MCP_UCB1200_TS) += ucb1x00-ts.o
|
||||
|
||||
ifeq ($(CONFIG_SA1100_ASSABET),y)
|
||||
|
@ -90,8 +90,14 @@ obj-$(CONFIG_PMIC_DA9052) += da9052-core.o
|
|||
obj-$(CONFIG_MFD_DA9052_SPI) += da9052-spi.o
|
||||
obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.o
|
||||
|
||||
obj-$(CONFIG_MFD_LP8788) += lp8788.o lp8788-irq.o
|
||||
|
||||
da9055-objs := da9055-core.o da9055-i2c.o
|
||||
obj-$(CONFIG_MFD_DA9055) += da9055.o
|
||||
|
||||
obj-$(CONFIG_MFD_MAX77686) += max77686.o max77686-irq.o
|
||||
obj-$(CONFIG_MFD_MAX77693) += max77693.o max77693-irq.o
|
||||
obj-$(CONFIG_MFD_MAX8907) += max8907.o
|
||||
max8925-objs := max8925-core.o max8925-i2c.o
|
||||
obj-$(CONFIG_MFD_MAX8925) += max8925.o
|
||||
obj-$(CONFIG_MFD_MAX8997) += max8997.o max8997-irq.o
|
||||
|
@ -120,7 +126,7 @@ obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o
|
|||
obj-$(CONFIG_MFD_VX855) += vx855.o
|
||||
obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o
|
||||
obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o
|
||||
obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o
|
||||
obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o omap-usb-tll.o
|
||||
obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o
|
||||
obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o
|
||||
obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o
|
||||
|
@ -130,5 +136,5 @@ obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o
|
|||
obj-$(CONFIG_MFD_PALMAS) += palmas.o
|
||||
obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o
|
||||
obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o
|
||||
obj-$(CONFIG_MFD_ANATOP) += anatop-mfd.o
|
||||
obj-$(CONFIG_MFD_SYSCON) += syscon.o
|
||||
obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/seq_file.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/ab3100.h>
|
||||
#include <linux/mfd/abx500.h>
|
||||
|
||||
/* These are the only registers inside AB3100 used in this main file */
|
||||
|
|
|
@ -472,6 +472,22 @@ static irqreturn_t ab8500_hierarchical_irq(int irq, void *dev)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* ab8500_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ
|
||||
*
|
||||
* @ab8500: ab8500_irq controller to operate on.
|
||||
* @irq: index of the interrupt requested in the chip IRQs
|
||||
*
|
||||
* Useful for drivers to request their own IRQs.
|
||||
*/
|
||||
static int ab8500_irq_get_virq(struct ab8500 *ab8500, int irq)
|
||||
{
|
||||
if (!ab8500)
|
||||
return -EINVAL;
|
||||
|
||||
return irq_create_mapping(ab8500->domain, irq);
|
||||
}
|
||||
|
||||
static irqreturn_t ab8500_irq(int irq, void *dev)
|
||||
{
|
||||
struct ab8500 *ab8500 = dev;
|
||||
|
@ -501,8 +517,9 @@ static irqreturn_t ab8500_irq(int irq, void *dev)
|
|||
do {
|
||||
int bit = __ffs(value);
|
||||
int line = i * 8 + bit;
|
||||
int virq = ab8500_irq_get_virq(ab8500, line);
|
||||
|
||||
handle_nested_irq(ab8500->irq_base + line);
|
||||
handle_nested_irq(virq);
|
||||
value &= ~(1 << bit);
|
||||
|
||||
} while (value);
|
||||
|
@ -511,23 +528,6 @@ static irqreturn_t ab8500_irq(int irq, void *dev)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* ab8500_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ
|
||||
*
|
||||
* @ab8500: ab8500_irq controller to operate on.
|
||||
* @irq: index of the interrupt requested in the chip IRQs
|
||||
*
|
||||
* Useful for drivers to request their own IRQs.
|
||||
*/
|
||||
int ab8500_irq_get_virq(struct ab8500 *ab8500, int irq)
|
||||
{
|
||||
if (!ab8500)
|
||||
return -EINVAL;
|
||||
|
||||
return irq_create_mapping(ab8500->domain, irq);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ab8500_irq_get_virq);
|
||||
|
||||
static int ab8500_irq_map(struct irq_domain *d, unsigned int virq,
|
||||
irq_hw_number_t hwirq)
|
||||
{
|
||||
|
@ -1076,6 +1076,7 @@ static struct mfd_cell __devinitdata ab8500_devs[] = {
|
|||
},
|
||||
{
|
||||
.name = "ab8500-codec",
|
||||
.of_compatible = "stericsson,ab8500-codec",
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -1,124 +0,0 @@
|
|||
/*
|
||||
* Anatop MFD driver
|
||||
*
|
||||
* Copyright (C) 2012 Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
|
||||
* Copyright (C) 2012 Linaro
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
* 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.
|
||||
*
|
||||
* 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/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/mfd/anatop.h>
|
||||
|
||||
u32 anatop_read_reg(struct anatop *adata, u32 addr)
|
||||
{
|
||||
return readl(adata->ioreg + addr);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(anatop_read_reg);
|
||||
|
||||
void anatop_write_reg(struct anatop *adata, u32 addr, u32 data, u32 mask)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
data &= mask;
|
||||
|
||||
spin_lock(&adata->reglock);
|
||||
val = readl(adata->ioreg + addr);
|
||||
val &= ~mask;
|
||||
val |= data;
|
||||
writel(val, adata->ioreg + addr);
|
||||
spin_unlock(&adata->reglock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(anatop_write_reg);
|
||||
|
||||
static const struct of_device_id of_anatop_match[] = {
|
||||
{ .compatible = "fsl,imx6q-anatop", },
|
||||
{ },
|
||||
};
|
||||
|
||||
static int __devinit of_anatop_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
void *ioreg;
|
||||
struct anatop *drvdata;
|
||||
|
||||
ioreg = of_iomap(np, 0);
|
||||
if (!ioreg)
|
||||
return -EADDRNOTAVAIL;
|
||||
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
|
||||
if (!drvdata)
|
||||
return -ENOMEM;
|
||||
drvdata->ioreg = ioreg;
|
||||
spin_lock_init(&drvdata->reglock);
|
||||
platform_set_drvdata(pdev, drvdata);
|
||||
of_platform_populate(np, NULL, NULL, dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devexit of_anatop_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct anatop *drvdata;
|
||||
drvdata = platform_get_drvdata(pdev);
|
||||
iounmap(drvdata->ioreg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver anatop_of_driver = {
|
||||
.driver = {
|
||||
.name = "anatop-mfd",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_anatop_match,
|
||||
},
|
||||
.probe = of_anatop_probe,
|
||||
.remove = of_anatop_remove,
|
||||
};
|
||||
|
||||
static int __init anatop_init(void)
|
||||
{
|
||||
return platform_driver_register(&anatop_of_driver);
|
||||
}
|
||||
postcore_initcall(anatop_init);
|
||||
|
||||
static void __exit anatop_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&anatop_of_driver);
|
||||
}
|
||||
module_exit(anatop_exit);
|
||||
|
||||
MODULE_AUTHOR("Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>");
|
||||
MODULE_DESCRIPTION("ANATOP MFD driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -94,7 +94,8 @@ static irqreturn_t arizona_ctrlif_err(int irq, void *data)
|
|||
static irqreturn_t arizona_irq_thread(int irq, void *data)
|
||||
{
|
||||
struct arizona *arizona = data;
|
||||
int i, ret;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_get_sync(arizona->dev);
|
||||
if (ret < 0) {
|
||||
|
@ -102,9 +103,20 @@ static irqreturn_t arizona_irq_thread(int irq, void *data)
|
|||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
/* Check both domains */
|
||||
for (i = 0; i < 2; i++)
|
||||
handle_nested_irq(irq_find_mapping(arizona->virq, i));
|
||||
/* Always handle the AoD domain */
|
||||
handle_nested_irq(irq_find_mapping(arizona->virq, 0));
|
||||
|
||||
/*
|
||||
* Check if one of the main interrupts is asserted and only
|
||||
* check that domain if it is.
|
||||
*/
|
||||
ret = regmap_read(arizona->regmap, ARIZONA_IRQ_PIN_STATUS, &val);
|
||||
if (ret == 0 && val & ARIZONA_IRQ1_STS) {
|
||||
handle_nested_irq(irq_find_mapping(arizona->virq, 1));
|
||||
} else if (ret != 0) {
|
||||
dev_err(arizona->dev, "Failed to read main IRQ status: %d\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
pm_runtime_mark_last_busy(arizona->dev);
|
||||
pm_runtime_put_autosuspend(arizona->dev);
|
||||
|
@ -156,18 +168,36 @@ int arizona_irq_init(struct arizona *arizona)
|
|||
int flags = IRQF_ONESHOT;
|
||||
int ret, i;
|
||||
const struct regmap_irq_chip *aod, *irq;
|
||||
bool ctrlif_error = true;
|
||||
|
||||
switch (arizona->type) {
|
||||
#ifdef CONFIG_MFD_WM5102
|
||||
case WM5102:
|
||||
aod = &wm5102_aod;
|
||||
irq = &wm5102_irq;
|
||||
|
||||
switch (arizona->rev) {
|
||||
case 0:
|
||||
ctrlif_error = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_MFD_WM5110
|
||||
case WM5110:
|
||||
aod = &wm5110_aod;
|
||||
irq = &wm5110_irq;
|
||||
|
||||
switch (arizona->rev) {
|
||||
case 0:
|
||||
case 1:
|
||||
ctrlif_error = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
|
@ -226,13 +256,17 @@ int arizona_irq_init(struct arizona *arizona)
|
|||
}
|
||||
|
||||
/* Handle control interface errors in the core */
|
||||
i = arizona_map_irq(arizona, ARIZONA_IRQ_CTRLIF_ERR);
|
||||
ret = request_threaded_irq(i, NULL, arizona_ctrlif_err, IRQF_ONESHOT,
|
||||
"Control interface error", arizona);
|
||||
if (ret != 0) {
|
||||
dev_err(arizona->dev, "Failed to request boot done %d: %d\n",
|
||||
arizona->irq, ret);
|
||||
goto err_ctrlif;
|
||||
if (ctrlif_error) {
|
||||
i = arizona_map_irq(arizona, ARIZONA_IRQ_CTRLIF_ERR);
|
||||
ret = request_threaded_irq(i, NULL, arizona_ctrlif_err,
|
||||
IRQF_ONESHOT,
|
||||
"Control interface error", arizona);
|
||||
if (ret != 0) {
|
||||
dev_err(arizona->dev,
|
||||
"Failed to request CTRLIF_ERR %d: %d\n",
|
||||
arizona->irq, ret);
|
||||
goto err_ctrlif;
|
||||
}
|
||||
}
|
||||
|
||||
ret = request_threaded_irq(arizona->irq, NULL, arizona_irq_thread,
|
||||
|
|
|
@ -0,0 +1,423 @@
|
|||
/*
|
||||
* Device access for Dialog DA9055 PMICs.
|
||||
*
|
||||
* Copyright(c) 2012 Dialog Semiconductor Ltd.
|
||||
*
|
||||
* Author: David Dajun Chen <dchen@diasemi.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.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/da9055/core.h>
|
||||
#include <linux/mfd/da9055/pdata.h>
|
||||
#include <linux/mfd/da9055/reg.h>
|
||||
|
||||
#define DA9055_IRQ_NONKEY_MASK 0x01
|
||||
#define DA9055_IRQ_ALM_MASK 0x02
|
||||
#define DA9055_IRQ_TICK_MASK 0x04
|
||||
#define DA9055_IRQ_ADC_MASK 0x08
|
||||
#define DA9055_IRQ_BUCK_ILIM_MASK 0x08
|
||||
|
||||
static bool da9055_register_readable(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case DA9055_REG_STATUS_A:
|
||||
case DA9055_REG_STATUS_B:
|
||||
case DA9055_REG_EVENT_A:
|
||||
case DA9055_REG_EVENT_B:
|
||||
case DA9055_REG_EVENT_C:
|
||||
case DA9055_REG_IRQ_MASK_A:
|
||||
case DA9055_REG_IRQ_MASK_B:
|
||||
case DA9055_REG_IRQ_MASK_C:
|
||||
|
||||
case DA9055_REG_CONTROL_A:
|
||||
case DA9055_REG_CONTROL_B:
|
||||
case DA9055_REG_CONTROL_C:
|
||||
case DA9055_REG_CONTROL_D:
|
||||
case DA9055_REG_CONTROL_E:
|
||||
|
||||
case DA9055_REG_ADC_MAN:
|
||||
case DA9055_REG_ADC_CONT:
|
||||
case DA9055_REG_VSYS_MON:
|
||||
case DA9055_REG_ADC_RES_L:
|
||||
case DA9055_REG_ADC_RES_H:
|
||||
case DA9055_REG_VSYS_RES:
|
||||
case DA9055_REG_ADCIN1_RES:
|
||||
case DA9055_REG_ADCIN2_RES:
|
||||
case DA9055_REG_ADCIN3_RES:
|
||||
|
||||
case DA9055_REG_COUNT_S:
|
||||
case DA9055_REG_COUNT_MI:
|
||||
case DA9055_REG_COUNT_H:
|
||||
case DA9055_REG_COUNT_D:
|
||||
case DA9055_REG_COUNT_MO:
|
||||
case DA9055_REG_COUNT_Y:
|
||||
case DA9055_REG_ALARM_H:
|
||||
case DA9055_REG_ALARM_D:
|
||||
case DA9055_REG_ALARM_MI:
|
||||
case DA9055_REG_ALARM_MO:
|
||||
case DA9055_REG_ALARM_Y:
|
||||
|
||||
case DA9055_REG_GPIO0_1:
|
||||
case DA9055_REG_GPIO2:
|
||||
case DA9055_REG_GPIO_MODE0_2:
|
||||
|
||||
case DA9055_REG_BCORE_CONT:
|
||||
case DA9055_REG_BMEM_CONT:
|
||||
case DA9055_REG_LDO1_CONT:
|
||||
case DA9055_REG_LDO2_CONT:
|
||||
case DA9055_REG_LDO3_CONT:
|
||||
case DA9055_REG_LDO4_CONT:
|
||||
case DA9055_REG_LDO5_CONT:
|
||||
case DA9055_REG_LDO6_CONT:
|
||||
case DA9055_REG_BUCK_LIM:
|
||||
case DA9055_REG_BCORE_MODE:
|
||||
case DA9055_REG_VBCORE_A:
|
||||
case DA9055_REG_VBMEM_A:
|
||||
case DA9055_REG_VLDO1_A:
|
||||
case DA9055_REG_VLDO2_A:
|
||||
case DA9055_REG_VLDO3_A:
|
||||
case DA9055_REG_VLDO4_A:
|
||||
case DA9055_REG_VLDO5_A:
|
||||
case DA9055_REG_VLDO6_A:
|
||||
case DA9055_REG_VBCORE_B:
|
||||
case DA9055_REG_VBMEM_B:
|
||||
case DA9055_REG_VLDO1_B:
|
||||
case DA9055_REG_VLDO2_B:
|
||||
case DA9055_REG_VLDO3_B:
|
||||
case DA9055_REG_VLDO4_B:
|
||||
case DA9055_REG_VLDO5_B:
|
||||
case DA9055_REG_VLDO6_B:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool da9055_register_writeable(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case DA9055_REG_STATUS_A:
|
||||
case DA9055_REG_STATUS_B:
|
||||
case DA9055_REG_EVENT_A:
|
||||
case DA9055_REG_EVENT_B:
|
||||
case DA9055_REG_EVENT_C:
|
||||
case DA9055_REG_IRQ_MASK_A:
|
||||
case DA9055_REG_IRQ_MASK_B:
|
||||
case DA9055_REG_IRQ_MASK_C:
|
||||
|
||||
case DA9055_REG_CONTROL_A:
|
||||
case DA9055_REG_CONTROL_B:
|
||||
case DA9055_REG_CONTROL_C:
|
||||
case DA9055_REG_CONTROL_D:
|
||||
case DA9055_REG_CONTROL_E:
|
||||
|
||||
case DA9055_REG_ADC_MAN:
|
||||
case DA9055_REG_ADC_CONT:
|
||||
case DA9055_REG_VSYS_MON:
|
||||
case DA9055_REG_ADC_RES_L:
|
||||
case DA9055_REG_ADC_RES_H:
|
||||
case DA9055_REG_VSYS_RES:
|
||||
case DA9055_REG_ADCIN1_RES:
|
||||
case DA9055_REG_ADCIN2_RES:
|
||||
case DA9055_REG_ADCIN3_RES:
|
||||
|
||||
case DA9055_REG_COUNT_S:
|
||||
case DA9055_REG_COUNT_MI:
|
||||
case DA9055_REG_COUNT_H:
|
||||
case DA9055_REG_COUNT_D:
|
||||
case DA9055_REG_COUNT_MO:
|
||||
case DA9055_REG_COUNT_Y:
|
||||
case DA9055_REG_ALARM_H:
|
||||
case DA9055_REG_ALARM_D:
|
||||
case DA9055_REG_ALARM_MI:
|
||||
case DA9055_REG_ALARM_MO:
|
||||
case DA9055_REG_ALARM_Y:
|
||||
|
||||
case DA9055_REG_GPIO0_1:
|
||||
case DA9055_REG_GPIO2:
|
||||
case DA9055_REG_GPIO_MODE0_2:
|
||||
|
||||
case DA9055_REG_BCORE_CONT:
|
||||
case DA9055_REG_BMEM_CONT:
|
||||
case DA9055_REG_LDO1_CONT:
|
||||
case DA9055_REG_LDO2_CONT:
|
||||
case DA9055_REG_LDO3_CONT:
|
||||
case DA9055_REG_LDO4_CONT:
|
||||
case DA9055_REG_LDO5_CONT:
|
||||
case DA9055_REG_LDO6_CONT:
|
||||
case DA9055_REG_BUCK_LIM:
|
||||
case DA9055_REG_BCORE_MODE:
|
||||
case DA9055_REG_VBCORE_A:
|
||||
case DA9055_REG_VBMEM_A:
|
||||
case DA9055_REG_VLDO1_A:
|
||||
case DA9055_REG_VLDO2_A:
|
||||
case DA9055_REG_VLDO3_A:
|
||||
case DA9055_REG_VLDO4_A:
|
||||
case DA9055_REG_VLDO5_A:
|
||||
case DA9055_REG_VLDO6_A:
|
||||
case DA9055_REG_VBCORE_B:
|
||||
case DA9055_REG_VBMEM_B:
|
||||
case DA9055_REG_VLDO1_B:
|
||||
case DA9055_REG_VLDO2_B:
|
||||
case DA9055_REG_VLDO3_B:
|
||||
case DA9055_REG_VLDO4_B:
|
||||
case DA9055_REG_VLDO5_B:
|
||||
case DA9055_REG_VLDO6_B:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool da9055_register_volatile(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case DA9055_REG_STATUS_A:
|
||||
case DA9055_REG_STATUS_B:
|
||||
case DA9055_REG_EVENT_A:
|
||||
case DA9055_REG_EVENT_B:
|
||||
case DA9055_REG_EVENT_C:
|
||||
|
||||
case DA9055_REG_CONTROL_A:
|
||||
case DA9055_REG_CONTROL_E:
|
||||
|
||||
case DA9055_REG_ADC_MAN:
|
||||
case DA9055_REG_ADC_RES_L:
|
||||
case DA9055_REG_ADC_RES_H:
|
||||
case DA9055_REG_VSYS_RES:
|
||||
case DA9055_REG_ADCIN1_RES:
|
||||
case DA9055_REG_ADCIN2_RES:
|
||||
case DA9055_REG_ADCIN3_RES:
|
||||
|
||||
case DA9055_REG_COUNT_S:
|
||||
case DA9055_REG_COUNT_MI:
|
||||
case DA9055_REG_COUNT_H:
|
||||
case DA9055_REG_COUNT_D:
|
||||
case DA9055_REG_COUNT_MO:
|
||||
case DA9055_REG_COUNT_Y:
|
||||
case DA9055_REG_ALARM_MI:
|
||||
|
||||
case DA9055_REG_BCORE_CONT:
|
||||
case DA9055_REG_BMEM_CONT:
|
||||
case DA9055_REG_LDO1_CONT:
|
||||
case DA9055_REG_LDO2_CONT:
|
||||
case DA9055_REG_LDO3_CONT:
|
||||
case DA9055_REG_LDO4_CONT:
|
||||
case DA9055_REG_LDO5_CONT:
|
||||
case DA9055_REG_LDO6_CONT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static struct regmap_irq da9055_irqs[] = {
|
||||
[DA9055_IRQ_NONKEY] = {
|
||||
.reg_offset = 0,
|
||||
.mask = DA9055_IRQ_NONKEY_MASK,
|
||||
},
|
||||
[DA9055_IRQ_ALARM] = {
|
||||
.reg_offset = 0,
|
||||
.mask = DA9055_IRQ_ALM_MASK,
|
||||
},
|
||||
[DA9055_IRQ_TICK] = {
|
||||
.reg_offset = 0,
|
||||
.mask = DA9055_IRQ_TICK_MASK,
|
||||
},
|
||||
[DA9055_IRQ_HWMON] = {
|
||||
.reg_offset = 0,
|
||||
.mask = DA9055_IRQ_ADC_MASK,
|
||||
},
|
||||
[DA9055_IRQ_REGULATOR] = {
|
||||
.reg_offset = 1,
|
||||
.mask = DA9055_IRQ_BUCK_ILIM_MASK,
|
||||
},
|
||||
};
|
||||
|
||||
struct regmap_config da9055_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
|
||||
.max_register = DA9055_MAX_REGISTER_CNT,
|
||||
.readable_reg = da9055_register_readable,
|
||||
.writeable_reg = da9055_register_writeable,
|
||||
.volatile_reg = da9055_register_volatile,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(da9055_regmap_config);
|
||||
|
||||
static struct resource da9055_onkey_resource = {
|
||||
.name = "ONKEY",
|
||||
.start = DA9055_IRQ_NONKEY,
|
||||
.end = DA9055_IRQ_NONKEY,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
};
|
||||
|
||||
static struct resource da9055_rtc_resource[] = {
|
||||
{
|
||||
.name = "ALM",
|
||||
.start = DA9055_IRQ_ALARM,
|
||||
.end = DA9055_IRQ_ALARM,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.name = "TICK",
|
||||
.start = DA9055_IRQ_TICK,
|
||||
.end = DA9055_IRQ_TICK,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource da9055_hwmon_resource = {
|
||||
.name = "HWMON",
|
||||
.start = DA9055_IRQ_HWMON,
|
||||
.end = DA9055_IRQ_HWMON,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
};
|
||||
|
||||
static struct resource da9055_ld05_6_resource = {
|
||||
.name = "REGULATOR",
|
||||
.start = DA9055_IRQ_REGULATOR,
|
||||
.end = DA9055_IRQ_REGULATOR,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
};
|
||||
|
||||
static struct mfd_cell da9055_devs[] = {
|
||||
{
|
||||
.of_compatible = "dialog,da9055-gpio",
|
||||
.name = "da9055-gpio",
|
||||
},
|
||||
{
|
||||
.of_compatible = "dialog,da9055-regulator",
|
||||
.name = "da9055-regulator",
|
||||
.id = 1,
|
||||
},
|
||||
{
|
||||
.of_compatible = "dialog,da9055-regulator",
|
||||
.name = "da9055-regulator",
|
||||
.id = 2,
|
||||
},
|
||||
{
|
||||
.of_compatible = "dialog,da9055-regulator",
|
||||
.name = "da9055-regulator",
|
||||
.id = 3,
|
||||
},
|
||||
{
|
||||
.of_compatible = "dialog,da9055-regulator",
|
||||
.name = "da9055-regulator",
|
||||
.id = 4,
|
||||
},
|
||||
{
|
||||
.of_compatible = "dialog,da9055-regulator",
|
||||
.name = "da9055-regulator",
|
||||
.id = 5,
|
||||
},
|
||||
{
|
||||
.of_compatible = "dialog,da9055-regulator",
|
||||
.name = "da9055-regulator",
|
||||
.id = 6,
|
||||
},
|
||||
{
|
||||
.of_compatible = "dialog,da9055-regulator",
|
||||
.name = "da9055-regulator",
|
||||
.id = 7,
|
||||
.resources = &da9055_ld05_6_resource,
|
||||
.num_resources = 1,
|
||||
},
|
||||
{
|
||||
.of_compatible = "dialog,da9055-regulator",
|
||||
.name = "da9055-regulator",
|
||||
.resources = &da9055_ld05_6_resource,
|
||||
.num_resources = 1,
|
||||
.id = 8,
|
||||
},
|
||||
{
|
||||
.of_compatible = "dialog,da9055-onkey",
|
||||
.name = "da9055-onkey",
|
||||
.resources = &da9055_onkey_resource,
|
||||
.num_resources = 1,
|
||||
},
|
||||
{
|
||||
.of_compatible = "dialog,da9055-rtc",
|
||||
.name = "da9055-rtc",
|
||||
.resources = da9055_rtc_resource,
|
||||
.num_resources = ARRAY_SIZE(da9055_rtc_resource),
|
||||
},
|
||||
{
|
||||
.of_compatible = "dialog,da9055-hwmon",
|
||||
.name = "da9055-hwmon",
|
||||
.resources = &da9055_hwmon_resource,
|
||||
.num_resources = 1,
|
||||
},
|
||||
{
|
||||
.of_compatible = "dialog,da9055-watchdog",
|
||||
.name = "da9055-watchdog",
|
||||
},
|
||||
};
|
||||
|
||||
static struct regmap_irq_chip da9055_regmap_irq_chip = {
|
||||
.name = "da9055_irq",
|
||||
.status_base = DA9055_REG_EVENT_A,
|
||||
.mask_base = DA9055_REG_IRQ_MASK_A,
|
||||
.ack_base = DA9055_REG_EVENT_A,
|
||||
.num_regs = 3,
|
||||
.irqs = da9055_irqs,
|
||||
.num_irqs = ARRAY_SIZE(da9055_irqs),
|
||||
};
|
||||
|
||||
int __devinit da9055_device_init(struct da9055 *da9055)
|
||||
{
|
||||
struct da9055_pdata *pdata = da9055->dev->platform_data;
|
||||
int ret;
|
||||
|
||||
if (pdata && pdata->init != NULL)
|
||||
pdata->init(da9055);
|
||||
|
||||
if (!pdata || !pdata->irq_base)
|
||||
da9055->irq_base = -1;
|
||||
else
|
||||
da9055->irq_base = pdata->irq_base;
|
||||
|
||||
ret = regmap_add_irq_chip(da9055->regmap, da9055->chip_irq,
|
||||
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
|
||||
da9055->irq_base, &da9055_regmap_irq_chip,
|
||||
&da9055->irq_data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
da9055->irq_base = regmap_irq_chip_get_base(da9055->irq_data);
|
||||
|
||||
ret = mfd_add_devices(da9055->dev, -1,
|
||||
da9055_devs, ARRAY_SIZE(da9055_devs),
|
||||
NULL, da9055->irq_base, NULL);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
mfd_remove_devices(da9055->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void __devexit da9055_device_exit(struct da9055 *da9055)
|
||||
{
|
||||
regmap_del_irq_chip(da9055->chip_irq, da9055->irq_data);
|
||||
mfd_remove_devices(da9055->dev);
|
||||
}
|
||||
|
||||
MODULE_DESCRIPTION("Core support for the DA9055 PMIC");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
|
|
@ -0,0 +1,93 @@
|
|||
/* I2C access for DA9055 PMICs.
|
||||
*
|
||||
* Copyright(c) 2012 Dialog Semiconductor Ltd.
|
||||
*
|
||||
* Author: David Dajun Chen <dchen@diasemi.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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include <linux/mfd/da9055/core.h>
|
||||
|
||||
static int __devinit da9055_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct da9055 *da9055;
|
||||
int ret;
|
||||
|
||||
da9055 = devm_kzalloc(&i2c->dev, sizeof(struct da9055), GFP_KERNEL);
|
||||
if (!da9055)
|
||||
return -ENOMEM;
|
||||
|
||||
da9055->regmap = devm_regmap_init_i2c(i2c, &da9055_regmap_config);
|
||||
if (IS_ERR(da9055->regmap)) {
|
||||
ret = PTR_ERR(da9055->regmap);
|
||||
dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
da9055->dev = &i2c->dev;
|
||||
da9055->chip_irq = i2c->irq;
|
||||
|
||||
i2c_set_clientdata(i2c, da9055);
|
||||
|
||||
return da9055_device_init(da9055);
|
||||
}
|
||||
|
||||
static int __devexit da9055_i2c_remove(struct i2c_client *i2c)
|
||||
{
|
||||
struct da9055 *da9055 = i2c_get_clientdata(i2c);
|
||||
|
||||
da9055_device_exit(da9055);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct i2c_device_id da9055_i2c_id[] = {
|
||||
{"da9055-pmic", 0},
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct i2c_driver da9055_i2c_driver = {
|
||||
.probe = da9055_i2c_probe,
|
||||
.remove = __devexit_p(da9055_i2c_remove),
|
||||
.id_table = da9055_i2c_id,
|
||||
.driver = {
|
||||
.name = "da9055",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init da9055_i2c_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = i2c_add_driver(&da9055_i2c_driver);
|
||||
if (ret != 0) {
|
||||
pr_err("DA9055 I2C registration failed %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
subsys_initcall(da9055_i2c_init);
|
||||
|
||||
static void __exit da9055_i2c_exit(void)
|
||||
{
|
||||
i2c_del_driver(&da9055_i2c_driver);
|
||||
}
|
||||
module_exit(da9055_i2c_exit);
|
||||
|
||||
MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
|
||||
MODULE_DESCRIPTION("I2C driver for Dialog DA9055 PMIC");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -270,6 +270,8 @@ static struct {
|
|||
struct prcmu_fw_version version;
|
||||
} fw_info;
|
||||
|
||||
static struct irq_domain *db8500_irq_domain;
|
||||
|
||||
/*
|
||||
* This vector maps irq numbers to the bits in the bit field used in
|
||||
* communication with the PRCMU firmware.
|
||||
|
@ -2624,7 +2626,7 @@ static void prcmu_irq_mask(struct irq_data *d)
|
|||
|
||||
spin_lock_irqsave(&mb0_transfer.dbb_irqs_lock, flags);
|
||||
|
||||
mb0_transfer.req.dbb_irqs &= ~prcmu_irq_bit[d->irq - IRQ_PRCMU_BASE];
|
||||
mb0_transfer.req.dbb_irqs &= ~prcmu_irq_bit[d->hwirq];
|
||||
|
||||
spin_unlock_irqrestore(&mb0_transfer.dbb_irqs_lock, flags);
|
||||
|
||||
|
@ -2638,7 +2640,7 @@ static void prcmu_irq_unmask(struct irq_data *d)
|
|||
|
||||
spin_lock_irqsave(&mb0_transfer.dbb_irqs_lock, flags);
|
||||
|
||||
mb0_transfer.req.dbb_irqs |= prcmu_irq_bit[d->irq - IRQ_PRCMU_BASE];
|
||||
mb0_transfer.req.dbb_irqs |= prcmu_irq_bit[d->hwirq];
|
||||
|
||||
spin_unlock_irqrestore(&mb0_transfer.dbb_irqs_lock, flags);
|
||||
|
||||
|
@ -2678,9 +2680,37 @@ static char *fw_project_name(u8 project)
|
|||
}
|
||||
}
|
||||
|
||||
static int db8500_irq_map(struct irq_domain *d, unsigned int virq,
|
||||
irq_hw_number_t hwirq)
|
||||
{
|
||||
irq_set_chip_and_handler(virq, &prcmu_irq_chip,
|
||||
handle_simple_irq);
|
||||
set_irq_flags(virq, IRQF_VALID);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct irq_domain_ops db8500_irq_ops = {
|
||||
.map = db8500_irq_map,
|
||||
.xlate = irq_domain_xlate_twocell,
|
||||
};
|
||||
|
||||
static int db8500_irq_init(struct device_node *np)
|
||||
{
|
||||
db8500_irq_domain = irq_domain_add_legacy(
|
||||
np, NUM_PRCMU_WAKEUPS, IRQ_PRCMU_BASE,
|
||||
0, &db8500_irq_ops, NULL);
|
||||
|
||||
if (!db8500_irq_domain) {
|
||||
pr_err("Failed to create irqdomain\n");
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __init db8500_prcmu_early_init(void)
|
||||
{
|
||||
unsigned int i;
|
||||
if (cpu_is_u8500v2()) {
|
||||
void *tcpm_base = ioremap_nocache(U8500_PRCMU_TCPM_BASE, SZ_4K);
|
||||
|
||||
|
@ -2725,15 +2755,6 @@ void __init db8500_prcmu_early_init(void)
|
|||
|
||||
INIT_WORK(&mb0_transfer.mask_work, prcmu_mask_work);
|
||||
|
||||
/* Initalize irqs. */
|
||||
for (i = 0; i < NUM_PRCMU_WAKEUPS; i++) {
|
||||
unsigned int irq;
|
||||
|
||||
irq = IRQ_PRCMU_BASE + i;
|
||||
irq_set_chip_and_handler(irq, &prcmu_irq_chip,
|
||||
handle_simple_irq);
|
||||
set_irq_flags(irq, IRQF_VALID);
|
||||
}
|
||||
compute_armss_rate();
|
||||
}
|
||||
|
||||
|
@ -3041,6 +3062,8 @@ static int __devinit db8500_prcmu_probe(struct platform_device *pdev)
|
|||
goto no_irq_return;
|
||||
}
|
||||
|
||||
db8500_irq_init(np);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(db8500_prcmu_devs); i++) {
|
||||
if (!strcmp(db8500_prcmu_devs[i].name, "ab8500-core")) {
|
||||
db8500_prcmu_devs[i].platform_data = ab8500_platdata;
|
||||
|
|
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* TI LP8788 MFD - interrupt handler
|
||||
*
|
||||
* Copyright 2012 Texas Instruments
|
||||
*
|
||||
* Author: Milo(Woogyom) Kim <milo.kim@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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/mfd/lp8788.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/* register address */
|
||||
#define LP8788_INT_1 0x00
|
||||
#define LP8788_INTEN_1 0x03
|
||||
|
||||
#define BASE_INTEN_ADDR LP8788_INTEN_1
|
||||
#define SIZE_REG 8
|
||||
#define NUM_REGS 3
|
||||
|
||||
/*
|
||||
* struct lp8788_irq_data
|
||||
* @lp : used for accessing to lp8788 registers
|
||||
* @irq_lock : mutex for enabling/disabling the interrupt
|
||||
* @domain : IRQ domain for handling nested interrupt
|
||||
* @enabled : status of enabled interrupt
|
||||
*/
|
||||
struct lp8788_irq_data {
|
||||
struct lp8788 *lp;
|
||||
struct mutex irq_lock;
|
||||
struct irq_domain *domain;
|
||||
int enabled[LP8788_INT_MAX];
|
||||
};
|
||||
|
||||
static inline u8 _irq_to_addr(enum lp8788_int_id id)
|
||||
{
|
||||
return id / SIZE_REG;
|
||||
}
|
||||
|
||||
static inline u8 _irq_to_enable_addr(enum lp8788_int_id id)
|
||||
{
|
||||
return _irq_to_addr(id) + BASE_INTEN_ADDR;
|
||||
}
|
||||
|
||||
static inline u8 _irq_to_mask(enum lp8788_int_id id)
|
||||
{
|
||||
return 1 << (id % SIZE_REG);
|
||||
}
|
||||
|
||||
static inline u8 _irq_to_val(enum lp8788_int_id id, int enable)
|
||||
{
|
||||
return enable << (id % SIZE_REG);
|
||||
}
|
||||
|
||||
static void lp8788_irq_enable(struct irq_data *data)
|
||||
{
|
||||
struct lp8788_irq_data *irqd = irq_data_get_irq_chip_data(data);
|
||||
irqd->enabled[data->hwirq] = 1;
|
||||
}
|
||||
|
||||
static void lp8788_irq_disable(struct irq_data *data)
|
||||
{
|
||||
struct lp8788_irq_data *irqd = irq_data_get_irq_chip_data(data);
|
||||
irqd->enabled[data->hwirq] = 0;
|
||||
}
|
||||
|
||||
static void lp8788_irq_bus_lock(struct irq_data *data)
|
||||
{
|
||||
struct lp8788_irq_data *irqd = irq_data_get_irq_chip_data(data);
|
||||
|
||||
mutex_lock(&irqd->irq_lock);
|
||||
}
|
||||
|
||||
static void lp8788_irq_bus_sync_unlock(struct irq_data *data)
|
||||
{
|
||||
struct lp8788_irq_data *irqd = irq_data_get_irq_chip_data(data);
|
||||
enum lp8788_int_id irq = data->hwirq;
|
||||
u8 addr, mask, val;
|
||||
|
||||
addr = _irq_to_enable_addr(irq);
|
||||
mask = _irq_to_mask(irq);
|
||||
val = _irq_to_val(irq, irqd->enabled[irq]);
|
||||
|
||||
lp8788_update_bits(irqd->lp, addr, mask, val);
|
||||
|
||||
mutex_unlock(&irqd->irq_lock);
|
||||
}
|
||||
|
||||
static struct irq_chip lp8788_irq_chip = {
|
||||
.name = "lp8788",
|
||||
.irq_enable = lp8788_irq_enable,
|
||||
.irq_disable = lp8788_irq_disable,
|
||||
.irq_bus_lock = lp8788_irq_bus_lock,
|
||||
.irq_bus_sync_unlock = lp8788_irq_bus_sync_unlock,
|
||||
};
|
||||
|
||||
static irqreturn_t lp8788_irq_handler(int irq, void *ptr)
|
||||
{
|
||||
struct lp8788_irq_data *irqd = ptr;
|
||||
struct lp8788 *lp = irqd->lp;
|
||||
u8 status[NUM_REGS], addr, mask;
|
||||
bool handled;
|
||||
int i;
|
||||
|
||||
if (lp8788_read_multi_bytes(lp, LP8788_INT_1, status, NUM_REGS))
|
||||
return IRQ_NONE;
|
||||
|
||||
for (i = 0 ; i < LP8788_INT_MAX ; i++) {
|
||||
addr = _irq_to_addr(i);
|
||||
mask = _irq_to_mask(i);
|
||||
|
||||
/* reporting only if the irq is enabled */
|
||||
if (status[addr] & mask) {
|
||||
handle_nested_irq(irq_find_mapping(irqd->domain, i));
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
return handled ? IRQ_HANDLED : IRQ_NONE;
|
||||
}
|
||||
|
||||
static int lp8788_irq_map(struct irq_domain *d, unsigned int virq,
|
||||
irq_hw_number_t hwirq)
|
||||
{
|
||||
struct lp8788_irq_data *irqd = d->host_data;
|
||||
struct irq_chip *chip = &lp8788_irq_chip;
|
||||
|
||||
irq_set_chip_data(virq, irqd);
|
||||
irq_set_chip_and_handler(virq, chip, handle_edge_irq);
|
||||
irq_set_nested_thread(virq, 1);
|
||||
|
||||
#ifdef CONFIG_ARM
|
||||
set_irq_flags(virq, IRQF_VALID);
|
||||
#else
|
||||
irq_set_noprobe(virq);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct irq_domain_ops lp8788_domain_ops = {
|
||||
.map = lp8788_irq_map,
|
||||
};
|
||||
|
||||
int lp8788_irq_init(struct lp8788 *lp, int irq)
|
||||
{
|
||||
struct lp8788_irq_data *irqd;
|
||||
int ret;
|
||||
|
||||
if (irq <= 0) {
|
||||
dev_warn(lp->dev, "invalid irq number: %d\n", irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
irqd = devm_kzalloc(lp->dev, sizeof(*irqd), GFP_KERNEL);
|
||||
if (!irqd)
|
||||
return -ENOMEM;
|
||||
|
||||
irqd->lp = lp;
|
||||
irqd->domain = irq_domain_add_linear(lp->dev->of_node, LP8788_INT_MAX,
|
||||
&lp8788_domain_ops, irqd);
|
||||
if (!irqd->domain) {
|
||||
dev_err(lp->dev, "failed to add irq domain err\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
lp->irqdm = irqd->domain;
|
||||
mutex_init(&irqd->irq_lock);
|
||||
|
||||
ret = request_threaded_irq(irq, NULL, lp8788_irq_handler,
|
||||
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
|
||||
"lp8788-irq", irqd);
|
||||
if (ret) {
|
||||
dev_err(lp->dev, "failed to create a thread for IRQ_N\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
lp->irq = irq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void lp8788_irq_exit(struct lp8788 *lp)
|
||||
{
|
||||
if (lp->irq)
|
||||
free_irq(lp->irq, lp->irqdm);
|
||||
}
|
|
@ -0,0 +1,245 @@
|
|||
/*
|
||||
* TI LP8788 MFD - core interface
|
||||
*
|
||||
* Copyright 2012 Texas Instruments
|
||||
*
|
||||
* Author: Milo(Woogyom) Kim <milo.kim@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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/lp8788.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define MAX_LP8788_REGISTERS 0xA2
|
||||
|
||||
#define MFD_DEV_SIMPLE(_name) \
|
||||
{ \
|
||||
.name = LP8788_DEV_##_name, \
|
||||
}
|
||||
|
||||
#define MFD_DEV_WITH_ID(_name, _id) \
|
||||
{ \
|
||||
.name = LP8788_DEV_##_name, \
|
||||
.id = _id, \
|
||||
}
|
||||
|
||||
#define MFD_DEV_WITH_RESOURCE(_name, _resource, num_resource) \
|
||||
{ \
|
||||
.name = LP8788_DEV_##_name, \
|
||||
.resources = _resource, \
|
||||
.num_resources = num_resource, \
|
||||
}
|
||||
|
||||
static struct resource chg_irqs[] = {
|
||||
/* Charger Interrupts */
|
||||
{
|
||||
.start = LP8788_INT_CHG_INPUT_STATE,
|
||||
.end = LP8788_INT_PRECHG_TIMEOUT,
|
||||
.name = LP8788_CHG_IRQ,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
/* Power Routing Switch Interrupts */
|
||||
{
|
||||
.start = LP8788_INT_ENTER_SYS_SUPPORT,
|
||||
.end = LP8788_INT_EXIT_SYS_SUPPORT,
|
||||
.name = LP8788_PRSW_IRQ,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
/* Battery Interrupts */
|
||||
{
|
||||
.start = LP8788_INT_BATT_LOW,
|
||||
.end = LP8788_INT_NO_BATT,
|
||||
.name = LP8788_BATT_IRQ,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource rtc_irqs[] = {
|
||||
{
|
||||
.start = LP8788_INT_RTC_ALARM1,
|
||||
.end = LP8788_INT_RTC_ALARM2,
|
||||
.name = LP8788_ALM_IRQ,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct mfd_cell lp8788_devs[] = {
|
||||
/* 4 bucks */
|
||||
MFD_DEV_WITH_ID(BUCK, 1),
|
||||
MFD_DEV_WITH_ID(BUCK, 2),
|
||||
MFD_DEV_WITH_ID(BUCK, 3),
|
||||
MFD_DEV_WITH_ID(BUCK, 4),
|
||||
|
||||
/* 12 digital ldos */
|
||||
MFD_DEV_WITH_ID(DLDO, 1),
|
||||
MFD_DEV_WITH_ID(DLDO, 2),
|
||||
MFD_DEV_WITH_ID(DLDO, 3),
|
||||
MFD_DEV_WITH_ID(DLDO, 4),
|
||||
MFD_DEV_WITH_ID(DLDO, 5),
|
||||
MFD_DEV_WITH_ID(DLDO, 6),
|
||||
MFD_DEV_WITH_ID(DLDO, 7),
|
||||
MFD_DEV_WITH_ID(DLDO, 8),
|
||||
MFD_DEV_WITH_ID(DLDO, 9),
|
||||
MFD_DEV_WITH_ID(DLDO, 10),
|
||||
MFD_DEV_WITH_ID(DLDO, 11),
|
||||
MFD_DEV_WITH_ID(DLDO, 12),
|
||||
|
||||
/* 10 analog ldos */
|
||||
MFD_DEV_WITH_ID(ALDO, 1),
|
||||
MFD_DEV_WITH_ID(ALDO, 2),
|
||||
MFD_DEV_WITH_ID(ALDO, 3),
|
||||
MFD_DEV_WITH_ID(ALDO, 4),
|
||||
MFD_DEV_WITH_ID(ALDO, 5),
|
||||
MFD_DEV_WITH_ID(ALDO, 6),
|
||||
MFD_DEV_WITH_ID(ALDO, 7),
|
||||
MFD_DEV_WITH_ID(ALDO, 8),
|
||||
MFD_DEV_WITH_ID(ALDO, 9),
|
||||
MFD_DEV_WITH_ID(ALDO, 10),
|
||||
|
||||
/* ADC */
|
||||
MFD_DEV_SIMPLE(ADC),
|
||||
|
||||
/* battery charger */
|
||||
MFD_DEV_WITH_RESOURCE(CHARGER, chg_irqs, ARRAY_SIZE(chg_irqs)),
|
||||
|
||||
/* rtc */
|
||||
MFD_DEV_WITH_RESOURCE(RTC, rtc_irqs, ARRAY_SIZE(rtc_irqs)),
|
||||
|
||||
/* backlight */
|
||||
MFD_DEV_SIMPLE(BACKLIGHT),
|
||||
|
||||
/* current sink for vibrator */
|
||||
MFD_DEV_SIMPLE(VIBRATOR),
|
||||
|
||||
/* current sink for keypad LED */
|
||||
MFD_DEV_SIMPLE(KEYLED),
|
||||
};
|
||||
|
||||
int lp8788_read_byte(struct lp8788 *lp, u8 reg, u8 *data)
|
||||
{
|
||||
int ret;
|
||||
unsigned int val;
|
||||
|
||||
ret = regmap_read(lp->regmap, reg, &val);
|
||||
if (ret < 0) {
|
||||
dev_err(lp->dev, "failed to read 0x%.2x\n", reg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
*data = (u8)val;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lp8788_read_byte);
|
||||
|
||||
int lp8788_read_multi_bytes(struct lp8788 *lp, u8 reg, u8 *data, size_t count)
|
||||
{
|
||||
return regmap_bulk_read(lp->regmap, reg, data, count);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lp8788_read_multi_bytes);
|
||||
|
||||
int lp8788_write_byte(struct lp8788 *lp, u8 reg, u8 data)
|
||||
{
|
||||
return regmap_write(lp->regmap, reg, data);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lp8788_write_byte);
|
||||
|
||||
int lp8788_update_bits(struct lp8788 *lp, u8 reg, u8 mask, u8 data)
|
||||
{
|
||||
return regmap_update_bits(lp->regmap, reg, mask, data);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lp8788_update_bits);
|
||||
|
||||
static int lp8788_platform_init(struct lp8788 *lp)
|
||||
{
|
||||
struct lp8788_platform_data *pdata = lp->pdata;
|
||||
|
||||
return (pdata && pdata->init_func) ? pdata->init_func(lp) : 0;
|
||||
}
|
||||
|
||||
static const struct regmap_config lp8788_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = MAX_LP8788_REGISTERS,
|
||||
};
|
||||
|
||||
static int lp8788_probe(struct i2c_client *cl, const struct i2c_device_id *id)
|
||||
{
|
||||
struct lp8788 *lp;
|
||||
struct lp8788_platform_data *pdata = cl->dev.platform_data;
|
||||
int ret;
|
||||
|
||||
lp = devm_kzalloc(&cl->dev, sizeof(struct lp8788), GFP_KERNEL);
|
||||
if (!lp)
|
||||
return -ENOMEM;
|
||||
|
||||
lp->regmap = devm_regmap_init_i2c(cl, &lp8788_regmap_config);
|
||||
if (IS_ERR(lp->regmap)) {
|
||||
ret = PTR_ERR(lp->regmap);
|
||||
dev_err(&cl->dev, "regmap init i2c err: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
lp->pdata = pdata;
|
||||
lp->dev = &cl->dev;
|
||||
i2c_set_clientdata(cl, lp);
|
||||
|
||||
ret = lp8788_platform_init(lp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = lp8788_irq_init(lp, cl->irq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return mfd_add_devices(lp->dev, -1, lp8788_devs,
|
||||
ARRAY_SIZE(lp8788_devs), NULL, 0, NULL);
|
||||
}
|
||||
|
||||
static int __devexit lp8788_remove(struct i2c_client *cl)
|
||||
{
|
||||
struct lp8788 *lp = i2c_get_clientdata(cl);
|
||||
|
||||
mfd_remove_devices(lp->dev);
|
||||
lp8788_irq_exit(lp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id lp8788_ids[] = {
|
||||
{"lp8788", 0},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, lp8788_ids);
|
||||
|
||||
static struct i2c_driver lp8788_driver = {
|
||||
.driver = {
|
||||
.name = "lp8788",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = lp8788_probe,
|
||||
.remove = __devexit_p(lp8788_remove),
|
||||
.id_table = lp8788_ids,
|
||||
};
|
||||
|
||||
static int __init lp8788_init(void)
|
||||
{
|
||||
return i2c_add_driver(&lp8788_driver);
|
||||
}
|
||||
subsys_initcall(lp8788_init);
|
||||
|
||||
static void __exit lp8788_exit(void)
|
||||
{
|
||||
i2c_del_driver(&lp8788_driver);
|
||||
}
|
||||
module_exit(lp8788_exit);
|
||||
|
||||
MODULE_DESCRIPTION("TI LP8788 MFD Driver");
|
||||
MODULE_AUTHOR("Milo Kim");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -49,6 +49,7 @@
|
|||
* document number TBD : DH89xxCC
|
||||
* document number TBD : Panther Point
|
||||
* document number TBD : Lynx Point
|
||||
* document number TBD : Lynx Point-LP
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
@ -192,6 +193,7 @@ enum lpc_chipsets {
|
|||
LPC_DH89XXCC, /* DH89xxCC */
|
||||
LPC_PPT, /* Panther Point */
|
||||
LPC_LPT, /* Lynx Point */
|
||||
LPC_LPT_LP, /* Lynx Point-LP */
|
||||
};
|
||||
|
||||
struct lpc_ich_info lpc_chipset_info[] __devinitdata = {
|
||||
|
@ -468,6 +470,10 @@ struct lpc_ich_info lpc_chipset_info[] __devinitdata = {
|
|||
.name = "Lynx Point",
|
||||
.iTCO_version = 2,
|
||||
},
|
||||
[LPC_LPT_LP] = {
|
||||
.name = "Lynx Point_LP",
|
||||
.iTCO_version = 2,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -641,6 +647,14 @@ static DEFINE_PCI_DEVICE_TABLE(lpc_ich_ids) = {
|
|||
{ PCI_VDEVICE(INTEL, 0x8c5d), LPC_LPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x8c5e), LPC_LPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x8c5f), LPC_LPT},
|
||||
{ PCI_VDEVICE(INTEL, 0x9c40), LPC_LPT_LP},
|
||||
{ PCI_VDEVICE(INTEL, 0x9c41), LPC_LPT_LP},
|
||||
{ PCI_VDEVICE(INTEL, 0x9c42), LPC_LPT_LP},
|
||||
{ PCI_VDEVICE(INTEL, 0x9c43), LPC_LPT_LP},
|
||||
{ PCI_VDEVICE(INTEL, 0x9c44), LPC_LPT_LP},
|
||||
{ PCI_VDEVICE(INTEL, 0x9c45), LPC_LPT_LP},
|
||||
{ PCI_VDEVICE(INTEL, 0x9c46), LPC_LPT_LP},
|
||||
{ PCI_VDEVICE(INTEL, 0x9c47), LPC_LPT_LP},
|
||||
{ 0, }, /* End of list */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, lpc_ich_ids);
|
||||
|
@ -683,6 +697,30 @@ static void __devinit lpc_ich_finalize_cell(struct mfd_cell *cell,
|
|||
cell->pdata_size = sizeof(struct lpc_ich_info);
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't check for resource conflict globally. There are 2 or 3 independent
|
||||
* GPIO groups and it's enough to have access to one of these to instantiate
|
||||
* the device.
|
||||
*/
|
||||
static int __devinit lpc_ich_check_conflict_gpio(struct resource *res)
|
||||
{
|
||||
int ret;
|
||||
u8 use_gpio = 0;
|
||||
|
||||
if (resource_size(res) >= 0x50 &&
|
||||
!acpi_check_region(res->start + 0x40, 0x10, "LPC ICH GPIO3"))
|
||||
use_gpio |= 1 << 2;
|
||||
|
||||
if (!acpi_check_region(res->start + 0x30, 0x10, "LPC ICH GPIO2"))
|
||||
use_gpio |= 1 << 1;
|
||||
|
||||
ret = acpi_check_region(res->start + 0x00, 0x30, "LPC ICH GPIO1");
|
||||
if (!ret)
|
||||
use_gpio |= 1 << 0;
|
||||
|
||||
return use_gpio ? use_gpio : ret;
|
||||
}
|
||||
|
||||
static int __devinit lpc_ich_init_gpio(struct pci_dev *dev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
|
@ -740,12 +778,13 @@ gpe0_done:
|
|||
break;
|
||||
}
|
||||
|
||||
ret = acpi_check_resource_conflict(res);
|
||||
if (ret) {
|
||||
ret = lpc_ich_check_conflict_gpio(res);
|
||||
if (ret < 0) {
|
||||
/* this isn't necessarily fatal for the GPIO */
|
||||
acpi_conflict = true;
|
||||
goto gpio_done;
|
||||
}
|
||||
lpc_chipset_info[id->driver_data].use_gpio = ret;
|
||||
lpc_ich_enable_gpio_space(dev);
|
||||
|
||||
lpc_ich_finalize_cell(&lpc_ich_cells[LPC_GPIO], id);
|
||||
|
|
|
@ -0,0 +1,351 @@
|
|||
/*
|
||||
* max8907.c - mfd driver for MAX8907
|
||||
*
|
||||
* Copyright (C) 2010 Gyungoh Yoo <jack.yoo@maxim-ic.com>
|
||||
* Copyright (C) 2010-2012, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* 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/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/max8907.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
static struct mfd_cell max8907_cells[] = {
|
||||
{ .name = "max8907-regulator", },
|
||||
{ .name = "max8907-rtc", },
|
||||
};
|
||||
|
||||
static bool max8907_gen_is_volatile_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case MAX8907_REG_ON_OFF_IRQ1:
|
||||
case MAX8907_REG_ON_OFF_STAT:
|
||||
case MAX8907_REG_ON_OFF_IRQ2:
|
||||
case MAX8907_REG_CHG_IRQ1:
|
||||
case MAX8907_REG_CHG_IRQ2:
|
||||
case MAX8907_REG_CHG_STAT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool max8907_gen_is_precious_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case MAX8907_REG_ON_OFF_IRQ1:
|
||||
case MAX8907_REG_ON_OFF_IRQ2:
|
||||
case MAX8907_REG_CHG_IRQ1:
|
||||
case MAX8907_REG_CHG_IRQ2:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool max8907_gen_is_writeable_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
return !max8907_gen_is_volatile_reg(dev, reg);
|
||||
}
|
||||
|
||||
static const struct regmap_config max8907_regmap_gen_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.volatile_reg = max8907_gen_is_volatile_reg,
|
||||
.precious_reg = max8907_gen_is_precious_reg,
|
||||
.writeable_reg = max8907_gen_is_writeable_reg,
|
||||
.max_register = MAX8907_REG_LDO20VOUT,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
static bool max8907_rtc_is_volatile_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
if (reg <= MAX8907_REG_RTC_YEAR2)
|
||||
return true;
|
||||
|
||||
switch (reg) {
|
||||
case MAX8907_REG_RTC_STATUS:
|
||||
case MAX8907_REG_RTC_IRQ:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool max8907_rtc_is_precious_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case MAX8907_REG_RTC_IRQ:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool max8907_rtc_is_writeable_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case MAX8907_REG_RTC_STATUS:
|
||||
case MAX8907_REG_RTC_IRQ:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct regmap_config max8907_regmap_rtc_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.volatile_reg = max8907_rtc_is_volatile_reg,
|
||||
.precious_reg = max8907_rtc_is_precious_reg,
|
||||
.writeable_reg = max8907_rtc_is_writeable_reg,
|
||||
.max_register = MAX8907_REG_MPL_CNTL,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
static const struct regmap_irq max8907_chg_irqs[] = {
|
||||
{ .reg_offset = 0, .mask = 1 << 0, },
|
||||
{ .reg_offset = 0, .mask = 1 << 1, },
|
||||
{ .reg_offset = 0, .mask = 1 << 2, },
|
||||
{ .reg_offset = 1, .mask = 1 << 0, },
|
||||
{ .reg_offset = 1, .mask = 1 << 1, },
|
||||
{ .reg_offset = 1, .mask = 1 << 2, },
|
||||
{ .reg_offset = 1, .mask = 1 << 3, },
|
||||
{ .reg_offset = 1, .mask = 1 << 4, },
|
||||
{ .reg_offset = 1, .mask = 1 << 5, },
|
||||
{ .reg_offset = 1, .mask = 1 << 6, },
|
||||
{ .reg_offset = 1, .mask = 1 << 7, },
|
||||
};
|
||||
|
||||
static const struct regmap_irq_chip max8907_chg_irq_chip = {
|
||||
.name = "max8907 chg",
|
||||
.status_base = MAX8907_REG_CHG_IRQ1,
|
||||
.mask_base = MAX8907_REG_CHG_IRQ1_MASK,
|
||||
.wake_base = MAX8907_REG_CHG_IRQ1_MASK,
|
||||
.irq_reg_stride = MAX8907_REG_CHG_IRQ2 - MAX8907_REG_CHG_IRQ1,
|
||||
.num_regs = 2,
|
||||
.irqs = max8907_chg_irqs,
|
||||
.num_irqs = ARRAY_SIZE(max8907_chg_irqs),
|
||||
};
|
||||
|
||||
static const struct regmap_irq max8907_on_off_irqs[] = {
|
||||
{ .reg_offset = 0, .mask = 1 << 0, },
|
||||
{ .reg_offset = 0, .mask = 1 << 1, },
|
||||
{ .reg_offset = 0, .mask = 1 << 2, },
|
||||
{ .reg_offset = 0, .mask = 1 << 3, },
|
||||
{ .reg_offset = 0, .mask = 1 << 4, },
|
||||
{ .reg_offset = 0, .mask = 1 << 5, },
|
||||
{ .reg_offset = 0, .mask = 1 << 6, },
|
||||
{ .reg_offset = 0, .mask = 1 << 7, },
|
||||
{ .reg_offset = 1, .mask = 1 << 0, },
|
||||
{ .reg_offset = 1, .mask = 1 << 1, },
|
||||
};
|
||||
|
||||
static const struct regmap_irq_chip max8907_on_off_irq_chip = {
|
||||
.name = "max8907 on_off",
|
||||
.status_base = MAX8907_REG_ON_OFF_IRQ1,
|
||||
.mask_base = MAX8907_REG_ON_OFF_IRQ1_MASK,
|
||||
.irq_reg_stride = MAX8907_REG_ON_OFF_IRQ2 - MAX8907_REG_ON_OFF_IRQ1,
|
||||
.num_regs = 2,
|
||||
.irqs = max8907_on_off_irqs,
|
||||
.num_irqs = ARRAY_SIZE(max8907_on_off_irqs),
|
||||
};
|
||||
|
||||
static const struct regmap_irq max8907_rtc_irqs[] = {
|
||||
{ .reg_offset = 0, .mask = 1 << 2, },
|
||||
{ .reg_offset = 0, .mask = 1 << 3, },
|
||||
};
|
||||
|
||||
static const struct regmap_irq_chip max8907_rtc_irq_chip = {
|
||||
.name = "max8907 rtc",
|
||||
.status_base = MAX8907_REG_RTC_IRQ,
|
||||
.mask_base = MAX8907_REG_RTC_IRQ_MASK,
|
||||
.num_regs = 1,
|
||||
.irqs = max8907_rtc_irqs,
|
||||
.num_irqs = ARRAY_SIZE(max8907_rtc_irqs),
|
||||
};
|
||||
|
||||
static struct max8907 *max8907_pm_off;
|
||||
static void max8907_power_off(void)
|
||||
{
|
||||
regmap_update_bits(max8907_pm_off->regmap_gen, MAX8907_REG_RESET_CNFG,
|
||||
MAX8907_MASK_POWER_OFF, MAX8907_MASK_POWER_OFF);
|
||||
}
|
||||
|
||||
static __devinit int max8907_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct max8907 *max8907;
|
||||
int ret;
|
||||
struct max8907_platform_data *pdata = dev_get_platdata(&i2c->dev);
|
||||
bool pm_off = false;
|
||||
|
||||
if (pdata)
|
||||
pm_off = pdata->pm_off;
|
||||
else if (i2c->dev.of_node)
|
||||
pm_off = of_property_read_bool(i2c->dev.of_node,
|
||||
"maxim,system-power-controller");
|
||||
|
||||
max8907 = devm_kzalloc(&i2c->dev, sizeof(struct max8907), GFP_KERNEL);
|
||||
if (!max8907) {
|
||||
ret = -ENOMEM;
|
||||
goto err_alloc_drvdata;
|
||||
}
|
||||
|
||||
max8907->dev = &i2c->dev;
|
||||
dev_set_drvdata(max8907->dev, max8907);
|
||||
|
||||
max8907->i2c_gen = i2c;
|
||||
i2c_set_clientdata(i2c, max8907);
|
||||
max8907->regmap_gen = devm_regmap_init_i2c(i2c,
|
||||
&max8907_regmap_gen_config);
|
||||
if (IS_ERR(max8907->regmap_gen)) {
|
||||
ret = PTR_ERR(max8907->regmap_gen);
|
||||
dev_err(&i2c->dev, "gen regmap init failed: %d\n", ret);
|
||||
goto err_regmap_gen;
|
||||
}
|
||||
|
||||
max8907->i2c_rtc = i2c_new_dummy(i2c->adapter, MAX8907_RTC_I2C_ADDR);
|
||||
if (!max8907->i2c_rtc) {
|
||||
ret = -ENOMEM;
|
||||
goto err_dummy_rtc;
|
||||
}
|
||||
i2c_set_clientdata(max8907->i2c_rtc, max8907);
|
||||
max8907->regmap_rtc = devm_regmap_init_i2c(max8907->i2c_rtc,
|
||||
&max8907_regmap_rtc_config);
|
||||
if (IS_ERR(max8907->regmap_rtc)) {
|
||||
ret = PTR_ERR(max8907->regmap_rtc);
|
||||
dev_err(&i2c->dev, "rtc regmap init failed: %d\n", ret);
|
||||
goto err_regmap_rtc;
|
||||
}
|
||||
|
||||
irq_set_status_flags(max8907->i2c_gen->irq, IRQ_NOAUTOEN);
|
||||
|
||||
ret = regmap_add_irq_chip(max8907->regmap_gen, max8907->i2c_gen->irq,
|
||||
IRQF_ONESHOT | IRQF_SHARED, -1,
|
||||
&max8907_chg_irq_chip,
|
||||
&max8907->irqc_chg);
|
||||
if (ret != 0) {
|
||||
dev_err(&i2c->dev, "failed to add chg irq chip: %d\n", ret);
|
||||
goto err_irqc_chg;
|
||||
}
|
||||
ret = regmap_add_irq_chip(max8907->regmap_gen, max8907->i2c_gen->irq,
|
||||
IRQF_ONESHOT | IRQF_SHARED, -1,
|
||||
&max8907_on_off_irq_chip,
|
||||
&max8907->irqc_on_off);
|
||||
if (ret != 0) {
|
||||
dev_err(&i2c->dev, "failed to add on off irq chip: %d\n", ret);
|
||||
goto err_irqc_on_off;
|
||||
}
|
||||
ret = regmap_add_irq_chip(max8907->regmap_rtc, max8907->i2c_gen->irq,
|
||||
IRQF_ONESHOT | IRQF_SHARED, -1,
|
||||
&max8907_rtc_irq_chip,
|
||||
&max8907->irqc_rtc);
|
||||
if (ret != 0) {
|
||||
dev_err(&i2c->dev, "failed to add rtc irq chip: %d\n", ret);
|
||||
goto err_irqc_rtc;
|
||||
}
|
||||
|
||||
enable_irq(max8907->i2c_gen->irq);
|
||||
|
||||
ret = mfd_add_devices(max8907->dev, -1, max8907_cells,
|
||||
ARRAY_SIZE(max8907_cells), NULL, 0, NULL);
|
||||
if (ret != 0) {
|
||||
dev_err(&i2c->dev, "failed to add MFD devices %d\n", ret);
|
||||
goto err_add_devices;
|
||||
}
|
||||
|
||||
if (pm_off && !pm_power_off) {
|
||||
max8907_pm_off = max8907;
|
||||
pm_power_off = max8907_power_off;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_add_devices:
|
||||
regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_rtc);
|
||||
err_irqc_rtc:
|
||||
regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_on_off);
|
||||
err_irqc_on_off:
|
||||
regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_chg);
|
||||
err_irqc_chg:
|
||||
err_regmap_rtc:
|
||||
i2c_unregister_device(max8907->i2c_rtc);
|
||||
err_dummy_rtc:
|
||||
err_regmap_gen:
|
||||
err_alloc_drvdata:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __devexit int max8907_i2c_remove(struct i2c_client *i2c)
|
||||
{
|
||||
struct max8907 *max8907 = i2c_get_clientdata(i2c);
|
||||
|
||||
mfd_remove_devices(max8907->dev);
|
||||
|
||||
regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_rtc);
|
||||
regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_on_off);
|
||||
regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_chg);
|
||||
|
||||
i2c_unregister_device(max8907->i2c_rtc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct of_device_id max8907_of_match[] = {
|
||||
{ .compatible = "maxim,max8907" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, max8907_of_match);
|
||||
#endif
|
||||
|
||||
static const struct i2c_device_id max8907_i2c_id[] = {
|
||||
{"max8907", 0},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, max8907_i2c_id);
|
||||
|
||||
static struct i2c_driver max8907_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "max8907",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(max8907_of_match),
|
||||
},
|
||||
.probe = max8907_i2c_probe,
|
||||
.remove = max8907_i2c_remove,
|
||||
.id_table = max8907_i2c_id,
|
||||
};
|
||||
|
||||
static int __init max8907_i2c_init(void)
|
||||
{
|
||||
int ret = -ENODEV;
|
||||
|
||||
ret = i2c_add_driver(&max8907_i2c_driver);
|
||||
if (ret != 0)
|
||||
pr_err("Failed to register I2C driver: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
subsys_initcall(max8907_i2c_init);
|
||||
|
||||
static void __exit max8907_i2c_exit(void)
|
||||
{
|
||||
i2c_del_driver(&max8907_i2c_driver);
|
||||
}
|
||||
module_exit(max8907_i2c_exit);
|
||||
|
||||
MODULE_DESCRIPTION("MAX8907 multi-function core driver");
|
||||
MODULE_AUTHOR("Gyungoh Yoo <jack.yoo@maxim-ic.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -15,23 +15,20 @@
|
|||
#include <linux/irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/max8925.h>
|
||||
|
||||
static struct resource backlight_resources[] = {
|
||||
{
|
||||
.name = "max8925-backlight",
|
||||
.start = MAX8925_WLED_MODE_CNTL,
|
||||
.end = MAX8925_WLED_CNTL,
|
||||
.flags = IORESOURCE_IO,
|
||||
},
|
||||
static struct resource bk_resources[] __devinitdata = {
|
||||
{ 0x84, 0x84, "mode control", IORESOURCE_REG, },
|
||||
{ 0x85, 0x85, "control", IORESOURCE_REG, },
|
||||
};
|
||||
|
||||
static struct mfd_cell backlight_devs[] = {
|
||||
static struct mfd_cell bk_devs[] __devinitdata = {
|
||||
{
|
||||
.name = "max8925-backlight",
|
||||
.num_resources = 1,
|
||||
.resources = &backlight_resources[0],
|
||||
.num_resources = ARRAY_SIZE(bk_resources),
|
||||
.resources = &bk_resources[0],
|
||||
.id = -1,
|
||||
},
|
||||
};
|
||||
|
@ -41,7 +38,7 @@ static struct resource touch_resources[] = {
|
|||
.name = "max8925-tsc",
|
||||
.start = MAX8925_TSC_IRQ,
|
||||
.end = MAX8925_ADC_RES_END,
|
||||
.flags = IORESOURCE_IO,
|
||||
.flags = IORESOURCE_REG,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -59,7 +56,7 @@ static struct resource power_supply_resources[] = {
|
|||
.name = "max8925-power",
|
||||
.start = MAX8925_CHG_IRQ1,
|
||||
.end = MAX8925_CHG_IRQ1_MASK,
|
||||
.flags = IORESOURCE_IO,
|
||||
.flags = IORESOURCE_REG,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -113,71 +110,215 @@ static struct mfd_cell onkey_devs[] = {
|
|||
},
|
||||
};
|
||||
|
||||
#define MAX8925_REG_RESOURCE(_start, _end) \
|
||||
{ \
|
||||
.start = MAX8925_##_start, \
|
||||
.end = MAX8925_##_end, \
|
||||
.flags = IORESOURCE_IO, \
|
||||
}
|
||||
|
||||
static struct resource regulator_resources[] = {
|
||||
MAX8925_REG_RESOURCE(SDCTL1, SDCTL1),
|
||||
MAX8925_REG_RESOURCE(SDCTL2, SDCTL2),
|
||||
MAX8925_REG_RESOURCE(SDCTL3, SDCTL3),
|
||||
MAX8925_REG_RESOURCE(LDOCTL1, LDOCTL1),
|
||||
MAX8925_REG_RESOURCE(LDOCTL2, LDOCTL2),
|
||||
MAX8925_REG_RESOURCE(LDOCTL3, LDOCTL3),
|
||||
MAX8925_REG_RESOURCE(LDOCTL4, LDOCTL4),
|
||||
MAX8925_REG_RESOURCE(LDOCTL5, LDOCTL5),
|
||||
MAX8925_REG_RESOURCE(LDOCTL6, LDOCTL6),
|
||||
MAX8925_REG_RESOURCE(LDOCTL7, LDOCTL7),
|
||||
MAX8925_REG_RESOURCE(LDOCTL8, LDOCTL8),
|
||||
MAX8925_REG_RESOURCE(LDOCTL9, LDOCTL9),
|
||||
MAX8925_REG_RESOURCE(LDOCTL10, LDOCTL10),
|
||||
MAX8925_REG_RESOURCE(LDOCTL11, LDOCTL11),
|
||||
MAX8925_REG_RESOURCE(LDOCTL12, LDOCTL12),
|
||||
MAX8925_REG_RESOURCE(LDOCTL13, LDOCTL13),
|
||||
MAX8925_REG_RESOURCE(LDOCTL14, LDOCTL14),
|
||||
MAX8925_REG_RESOURCE(LDOCTL15, LDOCTL15),
|
||||
MAX8925_REG_RESOURCE(LDOCTL16, LDOCTL16),
|
||||
MAX8925_REG_RESOURCE(LDOCTL17, LDOCTL17),
|
||||
MAX8925_REG_RESOURCE(LDOCTL18, LDOCTL18),
|
||||
MAX8925_REG_RESOURCE(LDOCTL19, LDOCTL19),
|
||||
MAX8925_REG_RESOURCE(LDOCTL20, LDOCTL20),
|
||||
static struct resource sd1_resources[] __devinitdata = {
|
||||
{0x06, 0x06, "sdv", IORESOURCE_REG, },
|
||||
};
|
||||
|
||||
#define MAX8925_REG_DEVS(_id) \
|
||||
{ \
|
||||
.name = "max8925-regulator", \
|
||||
.num_resources = 1, \
|
||||
.resources = ®ulator_resources[MAX8925_ID_##_id], \
|
||||
.id = MAX8925_ID_##_id, \
|
||||
}
|
||||
static struct resource sd2_resources[] __devinitdata = {
|
||||
{0x09, 0x09, "sdv", IORESOURCE_REG, },
|
||||
};
|
||||
|
||||
static struct mfd_cell regulator_devs[] = {
|
||||
MAX8925_REG_DEVS(SD1),
|
||||
MAX8925_REG_DEVS(SD2),
|
||||
MAX8925_REG_DEVS(SD3),
|
||||
MAX8925_REG_DEVS(LDO1),
|
||||
MAX8925_REG_DEVS(LDO2),
|
||||
MAX8925_REG_DEVS(LDO3),
|
||||
MAX8925_REG_DEVS(LDO4),
|
||||
MAX8925_REG_DEVS(LDO5),
|
||||
MAX8925_REG_DEVS(LDO6),
|
||||
MAX8925_REG_DEVS(LDO7),
|
||||
MAX8925_REG_DEVS(LDO8),
|
||||
MAX8925_REG_DEVS(LDO9),
|
||||
MAX8925_REG_DEVS(LDO10),
|
||||
MAX8925_REG_DEVS(LDO11),
|
||||
MAX8925_REG_DEVS(LDO12),
|
||||
MAX8925_REG_DEVS(LDO13),
|
||||
MAX8925_REG_DEVS(LDO14),
|
||||
MAX8925_REG_DEVS(LDO15),
|
||||
MAX8925_REG_DEVS(LDO16),
|
||||
MAX8925_REG_DEVS(LDO17),
|
||||
MAX8925_REG_DEVS(LDO18),
|
||||
MAX8925_REG_DEVS(LDO19),
|
||||
MAX8925_REG_DEVS(LDO20),
|
||||
static struct resource sd3_resources[] __devinitdata = {
|
||||
{0x0c, 0x0c, "sdv", IORESOURCE_REG, },
|
||||
};
|
||||
|
||||
static struct resource ldo1_resources[] __devinitdata = {
|
||||
{0x1a, 0x1a, "ldov", IORESOURCE_REG, },
|
||||
};
|
||||
|
||||
static struct resource ldo2_resources[] __devinitdata = {
|
||||
{0x1e, 0x1e, "ldov", IORESOURCE_REG, },
|
||||
};
|
||||
|
||||
static struct resource ldo3_resources[] __devinitdata = {
|
||||
{0x22, 0x22, "ldov", IORESOURCE_REG, },
|
||||
};
|
||||
|
||||
static struct resource ldo4_resources[] __devinitdata = {
|
||||
{0x26, 0x26, "ldov", IORESOURCE_REG, },
|
||||
};
|
||||
|
||||
static struct resource ldo5_resources[] __devinitdata = {
|
||||
{0x2a, 0x2a, "ldov", IORESOURCE_REG, },
|
||||
};
|
||||
|
||||
static struct resource ldo6_resources[] __devinitdata = {
|
||||
{0x2e, 0x2e, "ldov", IORESOURCE_REG, },
|
||||
};
|
||||
|
||||
static struct resource ldo7_resources[] __devinitdata = {
|
||||
{0x32, 0x32, "ldov", IORESOURCE_REG, },
|
||||
};
|
||||
|
||||
static struct resource ldo8_resources[] __devinitdata = {
|
||||
{0x36, 0x36, "ldov", IORESOURCE_REG, },
|
||||
};
|
||||
|
||||
static struct resource ldo9_resources[] __devinitdata = {
|
||||
{0x3a, 0x3a, "ldov", IORESOURCE_REG, },
|
||||
};
|
||||
|
||||
static struct resource ldo10_resources[] __devinitdata = {
|
||||
{0x3e, 0x3e, "ldov", IORESOURCE_REG, },
|
||||
};
|
||||
|
||||
static struct resource ldo11_resources[] __devinitdata = {
|
||||
{0x42, 0x42, "ldov", IORESOURCE_REG, },
|
||||
};
|
||||
|
||||
static struct resource ldo12_resources[] __devinitdata = {
|
||||
{0x46, 0x46, "ldov", IORESOURCE_REG, },
|
||||
};
|
||||
|
||||
static struct resource ldo13_resources[] __devinitdata = {
|
||||
{0x4a, 0x4a, "ldov", IORESOURCE_REG, },
|
||||
};
|
||||
|
||||
static struct resource ldo14_resources[] __devinitdata = {
|
||||
{0x4e, 0x4e, "ldov", IORESOURCE_REG, },
|
||||
};
|
||||
|
||||
static struct resource ldo15_resources[] __devinitdata = {
|
||||
{0x52, 0x52, "ldov", IORESOURCE_REG, },
|
||||
};
|
||||
|
||||
static struct resource ldo16_resources[] __devinitdata = {
|
||||
{0x12, 0x12, "ldov", IORESOURCE_REG, },
|
||||
};
|
||||
|
||||
static struct resource ldo17_resources[] __devinitdata = {
|
||||
{0x16, 0x16, "ldov", IORESOURCE_REG, },
|
||||
};
|
||||
|
||||
static struct resource ldo18_resources[] __devinitdata = {
|
||||
{0x74, 0x74, "ldov", IORESOURCE_REG, },
|
||||
};
|
||||
|
||||
static struct resource ldo19_resources[] __devinitdata = {
|
||||
{0x5e, 0x5e, "ldov", IORESOURCE_REG, },
|
||||
};
|
||||
|
||||
static struct resource ldo20_resources[] __devinitdata = {
|
||||
{0x9e, 0x9e, "ldov", IORESOURCE_REG, },
|
||||
};
|
||||
|
||||
static struct mfd_cell reg_devs[] __devinitdata = {
|
||||
{
|
||||
.name = "max8925-regulator",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(sd1_resources),
|
||||
.resources = sd1_resources,
|
||||
}, {
|
||||
.name = "max8925-regulator",
|
||||
.id = 1,
|
||||
.num_resources = ARRAY_SIZE(sd2_resources),
|
||||
.resources = sd2_resources,
|
||||
}, {
|
||||
.name = "max8925-regulator",
|
||||
.id = 2,
|
||||
.num_resources = ARRAY_SIZE(sd3_resources),
|
||||
.resources = sd3_resources,
|
||||
}, {
|
||||
.name = "max8925-regulator",
|
||||
.id = 3,
|
||||
.num_resources = ARRAY_SIZE(ldo1_resources),
|
||||
.resources = ldo1_resources,
|
||||
}, {
|
||||
.name = "max8925-regulator",
|
||||
.id = 4,
|
||||
.num_resources = ARRAY_SIZE(ldo2_resources),
|
||||
.resources = ldo2_resources,
|
||||
}, {
|
||||
.name = "max8925-regulator",
|
||||
.id = 5,
|
||||
.num_resources = ARRAY_SIZE(ldo3_resources),
|
||||
.resources = ldo3_resources,
|
||||
}, {
|
||||
.name = "max8925-regulator",
|
||||
.id = 6,
|
||||
.num_resources = ARRAY_SIZE(ldo4_resources),
|
||||
.resources = ldo4_resources,
|
||||
}, {
|
||||
.name = "max8925-regulator",
|
||||
.id = 7,
|
||||
.num_resources = ARRAY_SIZE(ldo5_resources),
|
||||
.resources = ldo5_resources,
|
||||
}, {
|
||||
.name = "max8925-regulator",
|
||||
.id = 8,
|
||||
.num_resources = ARRAY_SIZE(ldo6_resources),
|
||||
.resources = ldo6_resources,
|
||||
}, {
|
||||
.name = "max8925-regulator",
|
||||
.id = 9,
|
||||
.num_resources = ARRAY_SIZE(ldo7_resources),
|
||||
.resources = ldo7_resources,
|
||||
}, {
|
||||
.name = "max8925-regulator",
|
||||
.id = 10,
|
||||
.num_resources = ARRAY_SIZE(ldo8_resources),
|
||||
.resources = ldo8_resources,
|
||||
}, {
|
||||
.name = "max8925-regulator",
|
||||
.id = 11,
|
||||
.num_resources = ARRAY_SIZE(ldo9_resources),
|
||||
.resources = ldo9_resources,
|
||||
}, {
|
||||
.name = "max8925-regulator",
|
||||
.id = 12,
|
||||
.num_resources = ARRAY_SIZE(ldo10_resources),
|
||||
.resources = ldo10_resources,
|
||||
}, {
|
||||
.name = "max8925-regulator",
|
||||
.id = 13,
|
||||
.num_resources = ARRAY_SIZE(ldo11_resources),
|
||||
.resources = ldo11_resources,
|
||||
}, {
|
||||
.name = "max8925-regulator",
|
||||
.id = 14,
|
||||
.num_resources = ARRAY_SIZE(ldo12_resources),
|
||||
.resources = ldo12_resources,
|
||||
}, {
|
||||
.name = "max8925-regulator",
|
||||
.id = 15,
|
||||
.num_resources = ARRAY_SIZE(ldo13_resources),
|
||||
.resources = ldo13_resources,
|
||||
}, {
|
||||
.name = "max8925-regulator",
|
||||
.id = 16,
|
||||
.num_resources = ARRAY_SIZE(ldo14_resources),
|
||||
.resources = ldo14_resources,
|
||||
}, {
|
||||
.name = "max8925-regulator",
|
||||
.id = 17,
|
||||
.num_resources = ARRAY_SIZE(ldo15_resources),
|
||||
.resources = ldo15_resources,
|
||||
}, {
|
||||
.name = "max8925-regulator",
|
||||
.id = 18,
|
||||
.num_resources = ARRAY_SIZE(ldo16_resources),
|
||||
.resources = ldo16_resources,
|
||||
}, {
|
||||
.name = "max8925-regulator",
|
||||
.id = 19,
|
||||
.num_resources = ARRAY_SIZE(ldo17_resources),
|
||||
.resources = ldo17_resources,
|
||||
}, {
|
||||
.name = "max8925-regulator",
|
||||
.id = 20,
|
||||
.num_resources = ARRAY_SIZE(ldo18_resources),
|
||||
.resources = ldo18_resources,
|
||||
}, {
|
||||
.name = "max8925-regulator",
|
||||
.id = 21,
|
||||
.num_resources = ARRAY_SIZE(ldo19_resources),
|
||||
.resources = ldo19_resources,
|
||||
}, {
|
||||
.name = "max8925-regulator",
|
||||
.id = 22,
|
||||
.num_resources = ARRAY_SIZE(ldo20_resources),
|
||||
.resources = ldo20_resources,
|
||||
},
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -547,7 +688,7 @@ static int max8925_irq_init(struct max8925_chip *chip, int irq,
|
|||
goto tsc_irq;
|
||||
}
|
||||
|
||||
ret = request_threaded_irq(irq, NULL, max8925_irq, flags,
|
||||
ret = request_threaded_irq(irq, NULL, max8925_irq, flags | IRQF_ONESHOT,
|
||||
"max8925", chip);
|
||||
if (ret) {
|
||||
dev_err(chip->dev, "Failed to request core IRQ: %d\n", ret);
|
||||
|
@ -565,7 +706,7 @@ tsc_irq:
|
|||
chip->tsc_irq = pdata->tsc_irq;
|
||||
|
||||
ret = request_threaded_irq(chip->tsc_irq, NULL, max8925_tsc_irq,
|
||||
flags, "max8925-tsc", chip);
|
||||
flags | IRQF_ONESHOT, "max8925-tsc", chip);
|
||||
if (ret) {
|
||||
dev_err(chip->dev, "Failed to request TSC IRQ: %d\n", ret);
|
||||
chip->tsc_irq = 0;
|
||||
|
@ -573,6 +714,113 @@ tsc_irq:
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void __devinit init_regulator(struct max8925_chip *chip,
|
||||
struct max8925_platform_data *pdata)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!pdata)
|
||||
return;
|
||||
if (pdata->sd1) {
|
||||
reg_devs[0].platform_data = pdata->sd1;
|
||||
reg_devs[0].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->sd2) {
|
||||
reg_devs[1].platform_data = pdata->sd2;
|
||||
reg_devs[1].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->sd3) {
|
||||
reg_devs[2].platform_data = pdata->sd3;
|
||||
reg_devs[2].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->ldo1) {
|
||||
reg_devs[3].platform_data = pdata->ldo1;
|
||||
reg_devs[3].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->ldo2) {
|
||||
reg_devs[4].platform_data = pdata->ldo2;
|
||||
reg_devs[4].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->ldo3) {
|
||||
reg_devs[5].platform_data = pdata->ldo3;
|
||||
reg_devs[5].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->ldo4) {
|
||||
reg_devs[6].platform_data = pdata->ldo4;
|
||||
reg_devs[6].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->ldo5) {
|
||||
reg_devs[7].platform_data = pdata->ldo5;
|
||||
reg_devs[7].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->ldo6) {
|
||||
reg_devs[8].platform_data = pdata->ldo6;
|
||||
reg_devs[8].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->ldo7) {
|
||||
reg_devs[9].platform_data = pdata->ldo7;
|
||||
reg_devs[9].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->ldo8) {
|
||||
reg_devs[10].platform_data = pdata->ldo8;
|
||||
reg_devs[10].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->ldo9) {
|
||||
reg_devs[11].platform_data = pdata->ldo9;
|
||||
reg_devs[11].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->ldo10) {
|
||||
reg_devs[12].platform_data = pdata->ldo10;
|
||||
reg_devs[12].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->ldo11) {
|
||||
reg_devs[13].platform_data = pdata->ldo11;
|
||||
reg_devs[13].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->ldo12) {
|
||||
reg_devs[14].platform_data = pdata->ldo12;
|
||||
reg_devs[14].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->ldo13) {
|
||||
reg_devs[15].platform_data = pdata->ldo13;
|
||||
reg_devs[15].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->ldo14) {
|
||||
reg_devs[16].platform_data = pdata->ldo14;
|
||||
reg_devs[16].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->ldo15) {
|
||||
reg_devs[17].platform_data = pdata->ldo15;
|
||||
reg_devs[17].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->ldo16) {
|
||||
reg_devs[18].platform_data = pdata->ldo16;
|
||||
reg_devs[18].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->ldo17) {
|
||||
reg_devs[19].platform_data = pdata->ldo17;
|
||||
reg_devs[19].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->ldo18) {
|
||||
reg_devs[20].platform_data = pdata->ldo18;
|
||||
reg_devs[20].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->ldo19) {
|
||||
reg_devs[21].platform_data = pdata->ldo19;
|
||||
reg_devs[21].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
if (pdata->ldo20) {
|
||||
reg_devs[22].platform_data = pdata->ldo20;
|
||||
reg_devs[22].pdata_size = sizeof(struct regulator_init_data);
|
||||
}
|
||||
ret = mfd_add_devices(chip->dev, 0, reg_devs, ARRAY_SIZE(reg_devs),
|
||||
NULL, 0, NULL);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "Failed to add regulator subdev\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int __devinit max8925_device_init(struct max8925_chip *chip,
|
||||
struct max8925_platform_data *pdata)
|
||||
{
|
||||
|
@ -612,24 +860,17 @@ int __devinit max8925_device_init(struct max8925_chip *chip,
|
|||
goto out_dev;
|
||||
}
|
||||
|
||||
if (pdata) {
|
||||
ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[0],
|
||||
ARRAY_SIZE(regulator_devs),
|
||||
®ulator_resources[0], 0, NULL);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "Failed to add regulator subdev\n");
|
||||
goto out_dev;
|
||||
}
|
||||
}
|
||||
init_regulator(chip, pdata);
|
||||
|
||||
if (pdata && pdata->backlight) {
|
||||
ret = mfd_add_devices(chip->dev, 0, &backlight_devs[0],
|
||||
ARRAY_SIZE(backlight_devs),
|
||||
&backlight_resources[0], 0, NULL);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "Failed to add backlight subdev\n");
|
||||
goto out_dev;
|
||||
}
|
||||
bk_devs[0].platform_data = &pdata->backlight;
|
||||
bk_devs[0].pdata_size = sizeof(struct max8925_backlight_pdata);
|
||||
}
|
||||
ret = mfd_add_devices(chip->dev, 0, bk_devs, ARRAY_SIZE(bk_devs),
|
||||
NULL, 0, NULL);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "Failed to add backlight subdev\n");
|
||||
goto out_dev;
|
||||
}
|
||||
|
||||
if (pdata && pdata->power) {
|
||||
|
|
|
@ -676,7 +676,6 @@ int mc13xxx_common_init(struct mc13xxx *mc13xxx,
|
|||
err_mask:
|
||||
err_revision:
|
||||
mc13xxx_unlock(mc13xxx);
|
||||
kfree(mc13xxx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
@ -36,63 +35,6 @@
|
|||
|
||||
/* OMAP USBHOST Register addresses */
|
||||
|
||||
/* TLL Register Set */
|
||||
#define OMAP_USBTLL_REVISION (0x00)
|
||||
#define OMAP_USBTLL_SYSCONFIG (0x10)
|
||||
#define OMAP_USBTLL_SYSCONFIG_CACTIVITY (1 << 8)
|
||||
#define OMAP_USBTLL_SYSCONFIG_SIDLEMODE (1 << 3)
|
||||
#define OMAP_USBTLL_SYSCONFIG_ENAWAKEUP (1 << 2)
|
||||
#define OMAP_USBTLL_SYSCONFIG_SOFTRESET (1 << 1)
|
||||
#define OMAP_USBTLL_SYSCONFIG_AUTOIDLE (1 << 0)
|
||||
|
||||
#define OMAP_USBTLL_SYSSTATUS (0x14)
|
||||
#define OMAP_USBTLL_SYSSTATUS_RESETDONE (1 << 0)
|
||||
|
||||
#define OMAP_USBTLL_IRQSTATUS (0x18)
|
||||
#define OMAP_USBTLL_IRQENABLE (0x1C)
|
||||
|
||||
#define OMAP_TLL_SHARED_CONF (0x30)
|
||||
#define OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN (1 << 6)
|
||||
#define OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN (1 << 5)
|
||||
#define OMAP_TLL_SHARED_CONF_USB_DIVRATION (1 << 2)
|
||||
#define OMAP_TLL_SHARED_CONF_FCLK_REQ (1 << 1)
|
||||
#define OMAP_TLL_SHARED_CONF_FCLK_IS_ON (1 << 0)
|
||||
|
||||
#define OMAP_TLL_CHANNEL_CONF(num) (0x040 + 0x004 * num)
|
||||
#define OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT 24
|
||||
#define OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF (1 << 11)
|
||||
#define OMAP_TLL_CHANNEL_CONF_ULPI_ULPIAUTOIDLE (1 << 10)
|
||||
#define OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE (1 << 9)
|
||||
#define OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE (1 << 8)
|
||||
#define OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS (1 << 1)
|
||||
#define OMAP_TLL_CHANNEL_CONF_CHANEN (1 << 0)
|
||||
|
||||
#define OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0 0x0
|
||||
#define OMAP_TLL_FSLSMODE_6PIN_PHY_DP_DM 0x1
|
||||
#define OMAP_TLL_FSLSMODE_3PIN_PHY 0x2
|
||||
#define OMAP_TLL_FSLSMODE_4PIN_PHY 0x3
|
||||
#define OMAP_TLL_FSLSMODE_6PIN_TLL_DAT_SE0 0x4
|
||||
#define OMAP_TLL_FSLSMODE_6PIN_TLL_DP_DM 0x5
|
||||
#define OMAP_TLL_FSLSMODE_3PIN_TLL 0x6
|
||||
#define OMAP_TLL_FSLSMODE_4PIN_TLL 0x7
|
||||
#define OMAP_TLL_FSLSMODE_2PIN_TLL_DAT_SE0 0xA
|
||||
#define OMAP_TLL_FSLSMODE_2PIN_DAT_DP_DM 0xB
|
||||
|
||||
#define OMAP_TLL_ULPI_FUNCTION_CTRL(num) (0x804 + 0x100 * num)
|
||||
#define OMAP_TLL_ULPI_INTERFACE_CTRL(num) (0x807 + 0x100 * num)
|
||||
#define OMAP_TLL_ULPI_OTG_CTRL(num) (0x80A + 0x100 * num)
|
||||
#define OMAP_TLL_ULPI_INT_EN_RISE(num) (0x80D + 0x100 * num)
|
||||
#define OMAP_TLL_ULPI_INT_EN_FALL(num) (0x810 + 0x100 * num)
|
||||
#define OMAP_TLL_ULPI_INT_STATUS(num) (0x813 + 0x100 * num)
|
||||
#define OMAP_TLL_ULPI_INT_LATCH(num) (0x814 + 0x100 * num)
|
||||
#define OMAP_TLL_ULPI_DEBUG(num) (0x815 + 0x100 * num)
|
||||
#define OMAP_TLL_ULPI_SCRATCH_REGISTER(num) (0x816 + 0x100 * num)
|
||||
|
||||
#define OMAP_TLL_CHANNEL_COUNT 3
|
||||
#define OMAP_TLL_CHANNEL_1_EN_MASK (1 << 0)
|
||||
#define OMAP_TLL_CHANNEL_2_EN_MASK (1 << 1)
|
||||
#define OMAP_TLL_CHANNEL_3_EN_MASK (1 << 2)
|
||||
|
||||
/* UHH Register Set */
|
||||
#define OMAP_UHH_REVISION (0x00)
|
||||
#define OMAP_UHH_SYSCONFIG (0x10)
|
||||
|
@ -132,8 +74,6 @@
|
|||
#define OMAP4_P2_MODE_TLL (1 << 18)
|
||||
#define OMAP4_P2_MODE_HSIC (3 << 18)
|
||||
|
||||
#define OMAP_REV2_TLL_CHANNEL_COUNT 2
|
||||
|
||||
#define OMAP_UHH_DEBUG_CSR (0x44)
|
||||
|
||||
/* Values of UHH_REVISION - Note: these are not given in the TRM */
|
||||
|
@ -153,15 +93,12 @@ struct usbhs_hcd_omap {
|
|||
struct clk *xclk60mhsp2_ck;
|
||||
struct clk *utmi_p1_fck;
|
||||
struct clk *usbhost_p1_fck;
|
||||
struct clk *usbtll_p1_fck;
|
||||
struct clk *utmi_p2_fck;
|
||||
struct clk *usbhost_p2_fck;
|
||||
struct clk *usbtll_p2_fck;
|
||||
struct clk *init_60m_fclk;
|
||||
struct clk *ehci_logic_fck;
|
||||
|
||||
void __iomem *uhh_base;
|
||||
void __iomem *tll_base;
|
||||
|
||||
struct usbhs_omap_platform_data platdata;
|
||||
|
||||
|
@ -336,93 +273,6 @@ static bool is_ohci_port(enum usbhs_omap_port_mode pmode)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* convert the port-mode enum to a value we can use in the FSLSMODE
|
||||
* field of USBTLL_CHANNEL_CONF
|
||||
*/
|
||||
static unsigned ohci_omap3_fslsmode(enum usbhs_omap_port_mode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case OMAP_USBHS_PORT_MODE_UNUSED:
|
||||
case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0:
|
||||
return OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0;
|
||||
|
||||
case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM:
|
||||
return OMAP_TLL_FSLSMODE_6PIN_PHY_DP_DM;
|
||||
|
||||
case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0:
|
||||
return OMAP_TLL_FSLSMODE_3PIN_PHY;
|
||||
|
||||
case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM:
|
||||
return OMAP_TLL_FSLSMODE_4PIN_PHY;
|
||||
|
||||
case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0:
|
||||
return OMAP_TLL_FSLSMODE_6PIN_TLL_DAT_SE0;
|
||||
|
||||
case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM:
|
||||
return OMAP_TLL_FSLSMODE_6PIN_TLL_DP_DM;
|
||||
|
||||
case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0:
|
||||
return OMAP_TLL_FSLSMODE_3PIN_TLL;
|
||||
|
||||
case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM:
|
||||
return OMAP_TLL_FSLSMODE_4PIN_TLL;
|
||||
|
||||
case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0:
|
||||
return OMAP_TLL_FSLSMODE_2PIN_TLL_DAT_SE0;
|
||||
|
||||
case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM:
|
||||
return OMAP_TLL_FSLSMODE_2PIN_DAT_DP_DM;
|
||||
default:
|
||||
pr_warning("Invalid port mode, using default\n");
|
||||
return OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0;
|
||||
}
|
||||
}
|
||||
|
||||
static void usbhs_omap_tll_init(struct device *dev, u8 tll_channel_count)
|
||||
{
|
||||
struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
|
||||
struct usbhs_omap_platform_data *pdata = dev->platform_data;
|
||||
unsigned reg;
|
||||
int i;
|
||||
|
||||
/* Program Common TLL register */
|
||||
reg = usbhs_read(omap->tll_base, OMAP_TLL_SHARED_CONF);
|
||||
reg |= (OMAP_TLL_SHARED_CONF_FCLK_IS_ON
|
||||
| OMAP_TLL_SHARED_CONF_USB_DIVRATION);
|
||||
reg &= ~OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN;
|
||||
reg &= ~OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN;
|
||||
|
||||
usbhs_write(omap->tll_base, OMAP_TLL_SHARED_CONF, reg);
|
||||
|
||||
/* Enable channels now */
|
||||
for (i = 0; i < tll_channel_count; i++) {
|
||||
reg = usbhs_read(omap->tll_base,
|
||||
OMAP_TLL_CHANNEL_CONF(i));
|
||||
|
||||
if (is_ohci_port(pdata->port_mode[i])) {
|
||||
reg |= ohci_omap3_fslsmode(pdata->port_mode[i])
|
||||
<< OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT;
|
||||
reg |= OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS;
|
||||
} else if (pdata->port_mode[i] == OMAP_EHCI_PORT_MODE_TLL) {
|
||||
|
||||
/* Disable AutoIdle, BitStuffing and use SDR Mode */
|
||||
reg &= ~(OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE
|
||||
| OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF
|
||||
| OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE);
|
||||
|
||||
} else
|
||||
continue;
|
||||
|
||||
reg |= OMAP_TLL_CHANNEL_CONF_CHANEN;
|
||||
usbhs_write(omap->tll_base,
|
||||
OMAP_TLL_CHANNEL_CONF(i), reg);
|
||||
|
||||
usbhs_writeb(omap->tll_base,
|
||||
OMAP_TLL_ULPI_SCRATCH_REGISTER(i), 0xbe);
|
||||
}
|
||||
}
|
||||
|
||||
static int usbhs_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
|
||||
|
@ -436,19 +286,17 @@ static int usbhs_runtime_resume(struct device *dev)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
omap_tll_enable();
|
||||
spin_lock_irqsave(&omap->lock, flags);
|
||||
|
||||
if (omap->ehci_logic_fck && !IS_ERR(omap->ehci_logic_fck))
|
||||
clk_enable(omap->ehci_logic_fck);
|
||||
|
||||
if (is_ehci_tll_mode(pdata->port_mode[0])) {
|
||||
if (is_ehci_tll_mode(pdata->port_mode[0]))
|
||||
clk_enable(omap->usbhost_p1_fck);
|
||||
clk_enable(omap->usbtll_p1_fck);
|
||||
}
|
||||
if (is_ehci_tll_mode(pdata->port_mode[1])) {
|
||||
if (is_ehci_tll_mode(pdata->port_mode[1]))
|
||||
clk_enable(omap->usbhost_p2_fck);
|
||||
clk_enable(omap->usbtll_p2_fck);
|
||||
}
|
||||
|
||||
clk_enable(omap->utmi_p1_fck);
|
||||
clk_enable(omap->utmi_p2_fck);
|
||||
|
||||
|
@ -472,14 +320,11 @@ static int usbhs_runtime_suspend(struct device *dev)
|
|||
|
||||
spin_lock_irqsave(&omap->lock, flags);
|
||||
|
||||
if (is_ehci_tll_mode(pdata->port_mode[0])) {
|
||||
if (is_ehci_tll_mode(pdata->port_mode[0]))
|
||||
clk_disable(omap->usbhost_p1_fck);
|
||||
clk_disable(omap->usbtll_p1_fck);
|
||||
}
|
||||
if (is_ehci_tll_mode(pdata->port_mode[1])) {
|
||||
if (is_ehci_tll_mode(pdata->port_mode[1]))
|
||||
clk_disable(omap->usbhost_p2_fck);
|
||||
clk_disable(omap->usbtll_p2_fck);
|
||||
}
|
||||
|
||||
clk_disable(omap->utmi_p2_fck);
|
||||
clk_disable(omap->utmi_p1_fck);
|
||||
|
||||
|
@ -487,6 +332,7 @@ static int usbhs_runtime_suspend(struct device *dev)
|
|||
clk_disable(omap->ehci_logic_fck);
|
||||
|
||||
spin_unlock_irqrestore(&omap->lock, flags);
|
||||
omap_tll_disable();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -500,8 +346,6 @@ static void omap_usbhs_init(struct device *dev)
|
|||
|
||||
dev_dbg(dev, "starting TI HSUSB Controller\n");
|
||||
|
||||
pm_runtime_get_sync(dev);
|
||||
|
||||
if (pdata->ehci_data->phy_reset) {
|
||||
if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
|
||||
gpio_request_one(pdata->ehci_data->reset_gpio_port[0],
|
||||
|
@ -515,6 +359,7 @@ static void omap_usbhs_init(struct device *dev)
|
|||
udelay(10);
|
||||
}
|
||||
|
||||
pm_runtime_get_sync(dev);
|
||||
spin_lock_irqsave(&omap->lock, flags);
|
||||
omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION);
|
||||
dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev);
|
||||
|
@ -580,22 +425,9 @@ static void omap_usbhs_init(struct device *dev)
|
|||
usbhs_write(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg);
|
||||
dev_dbg(dev, "UHH setup done, uhh_hostconfig=%x\n", reg);
|
||||
|
||||
if (is_ehci_tll_mode(pdata->port_mode[0]) ||
|
||||
is_ehci_tll_mode(pdata->port_mode[1]) ||
|
||||
is_ehci_tll_mode(pdata->port_mode[2]) ||
|
||||
(is_ohci_port(pdata->port_mode[0])) ||
|
||||
(is_ohci_port(pdata->port_mode[1])) ||
|
||||
(is_ohci_port(pdata->port_mode[2]))) {
|
||||
|
||||
/* Enable UTMI mode for required TLL channels */
|
||||
if (is_omap_usbhs_rev2(omap))
|
||||
usbhs_omap_tll_init(dev, OMAP_REV2_TLL_CHANNEL_COUNT);
|
||||
else
|
||||
usbhs_omap_tll_init(dev, OMAP_TLL_CHANNEL_COUNT);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&omap->lock, flags);
|
||||
|
||||
pm_runtime_put_sync(dev);
|
||||
if (pdata->ehci_data->phy_reset) {
|
||||
/* Hold the PHY in RESET for enough time till
|
||||
* PHY is settled and ready
|
||||
|
@ -610,8 +442,6 @@ static void omap_usbhs_init(struct device *dev)
|
|||
gpio_set_value_cansleep
|
||||
(pdata->ehci_data->reset_gpio_port[1], 1);
|
||||
}
|
||||
|
||||
pm_runtime_put_sync(dev);
|
||||
}
|
||||
|
||||
static void omap_usbhs_deinit(struct device *dev)
|
||||
|
@ -714,32 +544,18 @@ static int __devinit usbhs_omap_probe(struct platform_device *pdev)
|
|||
goto err_xclk60mhsp2_ck;
|
||||
}
|
||||
|
||||
omap->usbtll_p1_fck = clk_get(dev, "usb_tll_hs_usb_ch0_clk");
|
||||
if (IS_ERR(omap->usbtll_p1_fck)) {
|
||||
ret = PTR_ERR(omap->usbtll_p1_fck);
|
||||
dev_err(dev, "usbtll_p1_fck failed error:%d\n", ret);
|
||||
goto err_usbhost_p1_fck;
|
||||
}
|
||||
|
||||
omap->usbhost_p2_fck = clk_get(dev, "usb_host_hs_utmi_p2_clk");
|
||||
if (IS_ERR(omap->usbhost_p2_fck)) {
|
||||
ret = PTR_ERR(omap->usbhost_p2_fck);
|
||||
dev_err(dev, "usbhost_p2_fck failed error:%d\n", ret);
|
||||
goto err_usbtll_p1_fck;
|
||||
}
|
||||
|
||||
omap->usbtll_p2_fck = clk_get(dev, "usb_tll_hs_usb_ch1_clk");
|
||||
if (IS_ERR(omap->usbtll_p2_fck)) {
|
||||
ret = PTR_ERR(omap->usbtll_p2_fck);
|
||||
dev_err(dev, "usbtll_p2_fck failed error:%d\n", ret);
|
||||
goto err_usbhost_p2_fck;
|
||||
goto err_usbhost_p1_fck;
|
||||
}
|
||||
|
||||
omap->init_60m_fclk = clk_get(dev, "init_60m_fclk");
|
||||
if (IS_ERR(omap->init_60m_fclk)) {
|
||||
ret = PTR_ERR(omap->init_60m_fclk);
|
||||
dev_err(dev, "init_60m_fclk failed error:%d\n", ret);
|
||||
goto err_usbtll_p2_fck;
|
||||
goto err_usbhost_p2_fck;
|
||||
}
|
||||
|
||||
if (is_ehci_phy_mode(pdata->port_mode[0])) {
|
||||
|
@ -785,20 +601,6 @@ static int __devinit usbhs_omap_probe(struct platform_device *pdev)
|
|||
goto err_init_60m_fclk;
|
||||
}
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tll");
|
||||
if (!res) {
|
||||
dev_err(dev, "UHH EHCI get resource failed\n");
|
||||
ret = -ENODEV;
|
||||
goto err_tll;
|
||||
}
|
||||
|
||||
omap->tll_base = ioremap(res->start, resource_size(res));
|
||||
if (!omap->tll_base) {
|
||||
dev_err(dev, "TLL ioremap failed\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_tll;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, omap);
|
||||
|
||||
omap_usbhs_init(dev);
|
||||
|
@ -812,23 +614,14 @@ static int __devinit usbhs_omap_probe(struct platform_device *pdev)
|
|||
|
||||
err_alloc:
|
||||
omap_usbhs_deinit(&pdev->dev);
|
||||
iounmap(omap->tll_base);
|
||||
|
||||
err_tll:
|
||||
iounmap(omap->uhh_base);
|
||||
|
||||
err_init_60m_fclk:
|
||||
clk_put(omap->init_60m_fclk);
|
||||
|
||||
err_usbtll_p2_fck:
|
||||
clk_put(omap->usbtll_p2_fck);
|
||||
|
||||
err_usbhost_p2_fck:
|
||||
clk_put(omap->usbhost_p2_fck);
|
||||
|
||||
err_usbtll_p1_fck:
|
||||
clk_put(omap->usbtll_p1_fck);
|
||||
|
||||
err_usbhost_p1_fck:
|
||||
clk_put(omap->usbhost_p1_fck);
|
||||
|
||||
|
@ -864,12 +657,9 @@ static int __devexit usbhs_omap_remove(struct platform_device *pdev)
|
|||
struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev);
|
||||
|
||||
omap_usbhs_deinit(&pdev->dev);
|
||||
iounmap(omap->tll_base);
|
||||
iounmap(omap->uhh_base);
|
||||
clk_put(omap->init_60m_fclk);
|
||||
clk_put(omap->usbtll_p2_fck);
|
||||
clk_put(omap->usbhost_p2_fck);
|
||||
clk_put(omap->usbtll_p1_fck);
|
||||
clk_put(omap->usbhost_p1_fck);
|
||||
clk_put(omap->xclk60mhsp2_ck);
|
||||
clk_put(omap->utmi_p2_fck);
|
||||
|
@ -910,8 +700,10 @@ static int __init omap_usbhs_drvinit(void)
|
|||
* init before ehci and ohci drivers;
|
||||
* The usbhs core driver should be initialized much before
|
||||
* the omap ehci and ohci probe functions are called.
|
||||
* This usbhs core driver should be initialized after
|
||||
* usb tll driver
|
||||
*/
|
||||
fs_initcall(omap_usbhs_drvinit);
|
||||
fs_initcall_sync(omap_usbhs_drvinit);
|
||||
|
||||
static void __exit omap_usbhs_drvexit(void)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,471 @@
|
|||
/**
|
||||
* omap-usb-tll.c - The USB TLL driver for OMAP EHCI & OHCI
|
||||
*
|
||||
* Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com
|
||||
* Author: Keshava Munegowda <keshava_mgowda@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 of
|
||||
* the 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/>.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/err.h>
|
||||
#include <plat/usb.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#define USBTLL_DRIVER_NAME "usbhs_tll"
|
||||
|
||||
/* TLL Register Set */
|
||||
#define OMAP_USBTLL_REVISION (0x00)
|
||||
#define OMAP_USBTLL_SYSCONFIG (0x10)
|
||||
#define OMAP_USBTLL_SYSCONFIG_CACTIVITY (1 << 8)
|
||||
#define OMAP_USBTLL_SYSCONFIG_SIDLEMODE (1 << 3)
|
||||
#define OMAP_USBTLL_SYSCONFIG_ENAWAKEUP (1 << 2)
|
||||
#define OMAP_USBTLL_SYSCONFIG_SOFTRESET (1 << 1)
|
||||
#define OMAP_USBTLL_SYSCONFIG_AUTOIDLE (1 << 0)
|
||||
|
||||
#define OMAP_USBTLL_SYSSTATUS (0x14)
|
||||
#define OMAP_USBTLL_SYSSTATUS_RESETDONE (1 << 0)
|
||||
|
||||
#define OMAP_USBTLL_IRQSTATUS (0x18)
|
||||
#define OMAP_USBTLL_IRQENABLE (0x1C)
|
||||
|
||||
#define OMAP_TLL_SHARED_CONF (0x30)
|
||||
#define OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN (1 << 6)
|
||||
#define OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN (1 << 5)
|
||||
#define OMAP_TLL_SHARED_CONF_USB_DIVRATION (1 << 2)
|
||||
#define OMAP_TLL_SHARED_CONF_FCLK_REQ (1 << 1)
|
||||
#define OMAP_TLL_SHARED_CONF_FCLK_IS_ON (1 << 0)
|
||||
|
||||
#define OMAP_TLL_CHANNEL_CONF(num) (0x040 + 0x004 * num)
|
||||
#define OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT 24
|
||||
#define OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF (1 << 11)
|
||||
#define OMAP_TLL_CHANNEL_CONF_ULPI_ULPIAUTOIDLE (1 << 10)
|
||||
#define OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE (1 << 9)
|
||||
#define OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE (1 << 8)
|
||||
#define OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS (1 << 1)
|
||||
#define OMAP_TLL_CHANNEL_CONF_CHANEN (1 << 0)
|
||||
|
||||
#define OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0 0x0
|
||||
#define OMAP_TLL_FSLSMODE_6PIN_PHY_DP_DM 0x1
|
||||
#define OMAP_TLL_FSLSMODE_3PIN_PHY 0x2
|
||||
#define OMAP_TLL_FSLSMODE_4PIN_PHY 0x3
|
||||
#define OMAP_TLL_FSLSMODE_6PIN_TLL_DAT_SE0 0x4
|
||||
#define OMAP_TLL_FSLSMODE_6PIN_TLL_DP_DM 0x5
|
||||
#define OMAP_TLL_FSLSMODE_3PIN_TLL 0x6
|
||||
#define OMAP_TLL_FSLSMODE_4PIN_TLL 0x7
|
||||
#define OMAP_TLL_FSLSMODE_2PIN_TLL_DAT_SE0 0xA
|
||||
#define OMAP_TLL_FSLSMODE_2PIN_DAT_DP_DM 0xB
|
||||
|
||||
#define OMAP_TLL_ULPI_FUNCTION_CTRL(num) (0x804 + 0x100 * num)
|
||||
#define OMAP_TLL_ULPI_INTERFACE_CTRL(num) (0x807 + 0x100 * num)
|
||||
#define OMAP_TLL_ULPI_OTG_CTRL(num) (0x80A + 0x100 * num)
|
||||
#define OMAP_TLL_ULPI_INT_EN_RISE(num) (0x80D + 0x100 * num)
|
||||
#define OMAP_TLL_ULPI_INT_EN_FALL(num) (0x810 + 0x100 * num)
|
||||
#define OMAP_TLL_ULPI_INT_STATUS(num) (0x813 + 0x100 * num)
|
||||
#define OMAP_TLL_ULPI_INT_LATCH(num) (0x814 + 0x100 * num)
|
||||
#define OMAP_TLL_ULPI_DEBUG(num) (0x815 + 0x100 * num)
|
||||
#define OMAP_TLL_ULPI_SCRATCH_REGISTER(num) (0x816 + 0x100 * num)
|
||||
|
||||
#define OMAP_REV2_TLL_CHANNEL_COUNT 2
|
||||
#define OMAP_TLL_CHANNEL_COUNT 3
|
||||
#define OMAP_TLL_CHANNEL_1_EN_MASK (1 << 0)
|
||||
#define OMAP_TLL_CHANNEL_2_EN_MASK (1 << 1)
|
||||
#define OMAP_TLL_CHANNEL_3_EN_MASK (1 << 2)
|
||||
|
||||
/* Values of USBTLL_REVISION - Note: these are not given in the TRM */
|
||||
#define OMAP_USBTLL_REV1 0x00000015 /* OMAP3 */
|
||||
#define OMAP_USBTLL_REV2 0x00000018 /* OMAP 3630 */
|
||||
#define OMAP_USBTLL_REV3 0x00000004 /* OMAP4 */
|
||||
|
||||
#define is_ehci_tll_mode(x) (x == OMAP_EHCI_PORT_MODE_TLL)
|
||||
|
||||
struct usbtll_omap {
|
||||
struct clk *usbtll_p1_fck;
|
||||
struct clk *usbtll_p2_fck;
|
||||
struct usbtll_omap_platform_data platdata;
|
||||
/* secure the register updates */
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
const char usbtll_driver_name[] = USBTLL_DRIVER_NAME;
|
||||
struct platform_device *tll_pdev;
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static inline void usbtll_write(void __iomem *base, u32 reg, u32 val)
|
||||
{
|
||||
__raw_writel(val, base + reg);
|
||||
}
|
||||
|
||||
static inline u32 usbtll_read(void __iomem *base, u32 reg)
|
||||
{
|
||||
return __raw_readl(base + reg);
|
||||
}
|
||||
|
||||
static inline void usbtll_writeb(void __iomem *base, u8 reg, u8 val)
|
||||
{
|
||||
__raw_writeb(val, base + reg);
|
||||
}
|
||||
|
||||
static inline u8 usbtll_readb(void __iomem *base, u8 reg)
|
||||
{
|
||||
return __raw_readb(base + reg);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static bool is_ohci_port(enum usbhs_omap_port_mode pmode)
|
||||
{
|
||||
switch (pmode) {
|
||||
case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0:
|
||||
case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM:
|
||||
case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0:
|
||||
case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM:
|
||||
case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0:
|
||||
case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM:
|
||||
case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0:
|
||||
case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM:
|
||||
case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0:
|
||||
case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* convert the port-mode enum to a value we can use in the FSLSMODE
|
||||
* field of USBTLL_CHANNEL_CONF
|
||||
*/
|
||||
static unsigned ohci_omap3_fslsmode(enum usbhs_omap_port_mode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case OMAP_USBHS_PORT_MODE_UNUSED:
|
||||
case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0:
|
||||
return OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0;
|
||||
|
||||
case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM:
|
||||
return OMAP_TLL_FSLSMODE_6PIN_PHY_DP_DM;
|
||||
|
||||
case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0:
|
||||
return OMAP_TLL_FSLSMODE_3PIN_PHY;
|
||||
|
||||
case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM:
|
||||
return OMAP_TLL_FSLSMODE_4PIN_PHY;
|
||||
|
||||
case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0:
|
||||
return OMAP_TLL_FSLSMODE_6PIN_TLL_DAT_SE0;
|
||||
|
||||
case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM:
|
||||
return OMAP_TLL_FSLSMODE_6PIN_TLL_DP_DM;
|
||||
|
||||
case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0:
|
||||
return OMAP_TLL_FSLSMODE_3PIN_TLL;
|
||||
|
||||
case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM:
|
||||
return OMAP_TLL_FSLSMODE_4PIN_TLL;
|
||||
|
||||
case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0:
|
||||
return OMAP_TLL_FSLSMODE_2PIN_TLL_DAT_SE0;
|
||||
|
||||
case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM:
|
||||
return OMAP_TLL_FSLSMODE_2PIN_DAT_DP_DM;
|
||||
default:
|
||||
pr_warn("Invalid port mode, using default\n");
|
||||
return OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* usbtll_omap_probe - initialize TI-based HCDs
|
||||
*
|
||||
* Allocates basic resources for this USB host controller.
|
||||
*/
|
||||
static int __devinit usbtll_omap_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct usbtll_omap_platform_data *pdata = dev->platform_data;
|
||||
void __iomem *base;
|
||||
struct resource *res;
|
||||
struct usbtll_omap *tll;
|
||||
unsigned reg;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
int i, ver, count;
|
||||
|
||||
dev_dbg(dev, "starting TI HSUSB TLL Controller\n");
|
||||
|
||||
tll = kzalloc(sizeof(struct usbtll_omap), GFP_KERNEL);
|
||||
if (!tll) {
|
||||
dev_err(dev, "Memory allocation failed\n");
|
||||
ret = -ENOMEM;
|
||||
goto end;
|
||||
}
|
||||
|
||||
spin_lock_init(&tll->lock);
|
||||
|
||||
for (i = 0; i < OMAP3_HS_USB_PORTS; i++)
|
||||
tll->platdata.port_mode[i] = pdata->port_mode[i];
|
||||
|
||||
tll->usbtll_p1_fck = clk_get(dev, "usb_tll_hs_usb_ch0_clk");
|
||||
if (IS_ERR(tll->usbtll_p1_fck)) {
|
||||
ret = PTR_ERR(tll->usbtll_p1_fck);
|
||||
dev_err(dev, "usbtll_p1_fck failed error:%d\n", ret);
|
||||
goto err_tll;
|
||||
}
|
||||
|
||||
tll->usbtll_p2_fck = clk_get(dev, "usb_tll_hs_usb_ch1_clk");
|
||||
if (IS_ERR(tll->usbtll_p2_fck)) {
|
||||
ret = PTR_ERR(tll->usbtll_p2_fck);
|
||||
dev_err(dev, "usbtll_p2_fck failed error:%d\n", ret);
|
||||
goto err_usbtll_p1_fck;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(dev, "usb tll get resource failed\n");
|
||||
ret = -ENODEV;
|
||||
goto err_usbtll_p2_fck;
|
||||
}
|
||||
|
||||
base = ioremap(res->start, resource_size(res));
|
||||
if (!base) {
|
||||
dev_err(dev, "TLL ioremap failed\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_usbtll_p2_fck;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, tll);
|
||||
pm_runtime_enable(dev);
|
||||
pm_runtime_get_sync(dev);
|
||||
|
||||
spin_lock_irqsave(&tll->lock, flags);
|
||||
|
||||
ver = usbtll_read(base, OMAP_USBTLL_REVISION);
|
||||
switch (ver) {
|
||||
case OMAP_USBTLL_REV1:
|
||||
case OMAP_USBTLL_REV2:
|
||||
count = OMAP_TLL_CHANNEL_COUNT;
|
||||
break;
|
||||
case OMAP_USBTLL_REV3:
|
||||
count = OMAP_REV2_TLL_CHANNEL_COUNT;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "TLL version failed\n");
|
||||
ret = -ENODEV;
|
||||
goto err_ioremap;
|
||||
}
|
||||
|
||||
if (is_ehci_tll_mode(pdata->port_mode[0]) ||
|
||||
is_ehci_tll_mode(pdata->port_mode[1]) ||
|
||||
is_ehci_tll_mode(pdata->port_mode[2]) ||
|
||||
is_ohci_port(pdata->port_mode[0]) ||
|
||||
is_ohci_port(pdata->port_mode[1]) ||
|
||||
is_ohci_port(pdata->port_mode[2])) {
|
||||
|
||||
/* Program Common TLL register */
|
||||
reg = usbtll_read(base, OMAP_TLL_SHARED_CONF);
|
||||
reg |= (OMAP_TLL_SHARED_CONF_FCLK_IS_ON
|
||||
| OMAP_TLL_SHARED_CONF_USB_DIVRATION);
|
||||
reg &= ~OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN;
|
||||
reg &= ~OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN;
|
||||
|
||||
usbtll_write(base, OMAP_TLL_SHARED_CONF, reg);
|
||||
|
||||
/* Enable channels now */
|
||||
for (i = 0; i < count; i++) {
|
||||
reg = usbtll_read(base, OMAP_TLL_CHANNEL_CONF(i));
|
||||
|
||||
if (is_ohci_port(pdata->port_mode[i])) {
|
||||
reg |= ohci_omap3_fslsmode(pdata->port_mode[i])
|
||||
<< OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT;
|
||||
reg |= OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS;
|
||||
} else if (pdata->port_mode[i] ==
|
||||
OMAP_EHCI_PORT_MODE_TLL) {
|
||||
/*
|
||||
* Disable AutoIdle, BitStuffing
|
||||
* and use SDR Mode
|
||||
*/
|
||||
reg &= ~(OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE
|
||||
| OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF
|
||||
| OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
reg |= OMAP_TLL_CHANNEL_CONF_CHANEN;
|
||||
usbtll_write(base, OMAP_TLL_CHANNEL_CONF(i), reg);
|
||||
|
||||
usbtll_writeb(base,
|
||||
OMAP_TLL_ULPI_SCRATCH_REGISTER(i),
|
||||
0xbe);
|
||||
}
|
||||
}
|
||||
|
||||
err_ioremap:
|
||||
spin_unlock_irqrestore(&tll->lock, flags);
|
||||
iounmap(base);
|
||||
pm_runtime_put_sync(dev);
|
||||
tll_pdev = pdev;
|
||||
if (!ret)
|
||||
goto end;
|
||||
pm_runtime_disable(dev);
|
||||
|
||||
err_usbtll_p2_fck:
|
||||
clk_put(tll->usbtll_p2_fck);
|
||||
|
||||
err_usbtll_p1_fck:
|
||||
clk_put(tll->usbtll_p1_fck);
|
||||
|
||||
err_tll:
|
||||
kfree(tll);
|
||||
|
||||
end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* usbtll_omap_remove - shutdown processing for UHH & TLL HCDs
|
||||
* @pdev: USB Host Controller being removed
|
||||
*
|
||||
* Reverses the effect of usbtll_omap_probe().
|
||||
*/
|
||||
static int __devexit usbtll_omap_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct usbtll_omap *tll = platform_get_drvdata(pdev);
|
||||
|
||||
clk_put(tll->usbtll_p2_fck);
|
||||
clk_put(tll->usbtll_p1_fck);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
kfree(tll);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usbtll_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct usbtll_omap *tll = dev_get_drvdata(dev);
|
||||
struct usbtll_omap_platform_data *pdata = &tll->platdata;
|
||||
unsigned long flags;
|
||||
|
||||
dev_dbg(dev, "usbtll_runtime_resume\n");
|
||||
|
||||
if (!pdata) {
|
||||
dev_dbg(dev, "missing platform_data\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&tll->lock, flags);
|
||||
|
||||
if (is_ehci_tll_mode(pdata->port_mode[0]))
|
||||
clk_enable(tll->usbtll_p1_fck);
|
||||
|
||||
if (is_ehci_tll_mode(pdata->port_mode[1]))
|
||||
clk_enable(tll->usbtll_p2_fck);
|
||||
|
||||
spin_unlock_irqrestore(&tll->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usbtll_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct usbtll_omap *tll = dev_get_drvdata(dev);
|
||||
struct usbtll_omap_platform_data *pdata = &tll->platdata;
|
||||
unsigned long flags;
|
||||
|
||||
dev_dbg(dev, "usbtll_runtime_suspend\n");
|
||||
|
||||
if (!pdata) {
|
||||
dev_dbg(dev, "missing platform_data\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&tll->lock, flags);
|
||||
|
||||
if (is_ehci_tll_mode(pdata->port_mode[0]))
|
||||
clk_disable(tll->usbtll_p1_fck);
|
||||
|
||||
if (is_ehci_tll_mode(pdata->port_mode[1]))
|
||||
clk_disable(tll->usbtll_p2_fck);
|
||||
|
||||
spin_unlock_irqrestore(&tll->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops usbtllomap_dev_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(usbtll_runtime_suspend,
|
||||
usbtll_runtime_resume,
|
||||
NULL)
|
||||
};
|
||||
|
||||
static struct platform_driver usbtll_omap_driver = {
|
||||
.driver = {
|
||||
.name = (char *)usbtll_driver_name,
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &usbtllomap_dev_pm_ops,
|
||||
},
|
||||
.probe = usbtll_omap_probe,
|
||||
.remove = __devexit_p(usbtll_omap_remove),
|
||||
};
|
||||
|
||||
int omap_tll_enable(void)
|
||||
{
|
||||
if (!tll_pdev) {
|
||||
pr_err("missing omap usbhs tll platform_data\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
return pm_runtime_get_sync(&tll_pdev->dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_tll_enable);
|
||||
|
||||
int omap_tll_disable(void)
|
||||
{
|
||||
if (!tll_pdev) {
|
||||
pr_err("missing omap usbhs tll platform_data\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
return pm_runtime_put_sync(&tll_pdev->dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_tll_disable);
|
||||
|
||||
MODULE_AUTHOR("Keshava Munegowda <keshava_mgowda@ti.com>");
|
||||
MODULE_ALIAS("platform:" USBHS_DRIVER_NAME);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("usb tll driver for TI OMAP EHCI and OHCI controllers");
|
||||
|
||||
static int __init omap_usbtll_drvinit(void)
|
||||
{
|
||||
return platform_driver_register(&usbtll_omap_driver);
|
||||
}
|
||||
|
||||
/*
|
||||
* init before usbhs core driver;
|
||||
* The usbtll driver should be initialized before
|
||||
* the usbhs core driver probe function is called.
|
||||
*/
|
||||
fs_initcall(omap_usbtll_drvinit);
|
||||
|
||||
static void __exit omap_usbtll_drvexit(void)
|
||||
{
|
||||
platform_driver_unregister(&usbtll_omap_driver);
|
||||
}
|
||||
module_exit(omap_usbtll_drvexit);
|
|
@ -23,60 +23,7 @@
|
|||
#include <linux/err.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/palmas.h>
|
||||
|
||||
static const struct resource gpadc_resource[] = {
|
||||
{
|
||||
.name = "EOC_SW",
|
||||
.start = PALMAS_GPADC_EOC_SW_IRQ,
|
||||
.end = PALMAS_GPADC_EOC_SW_IRQ,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct resource usb_resource[] = {
|
||||
{
|
||||
.name = "ID",
|
||||
.start = PALMAS_ID_OTG_IRQ,
|
||||
.end = PALMAS_ID_OTG_IRQ,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.name = "ID_WAKEUP",
|
||||
.start = PALMAS_ID_IRQ,
|
||||
.end = PALMAS_ID_IRQ,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.name = "VBUS",
|
||||
.start = PALMAS_VBUS_OTG_IRQ,
|
||||
.end = PALMAS_VBUS_OTG_IRQ,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.name = "VBUS_WAKEUP",
|
||||
.start = PALMAS_VBUS_IRQ,
|
||||
.end = PALMAS_VBUS_IRQ,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct resource rtc_resource[] = {
|
||||
{
|
||||
.name = "RTC_ALARM",
|
||||
.start = PALMAS_RTC_ALARM_IRQ,
|
||||
.end = PALMAS_RTC_ALARM_IRQ,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct resource pwron_resource[] = {
|
||||
{
|
||||
.name = "PWRON_BUTTON",
|
||||
.start = PALMAS_PWRON_IRQ,
|
||||
.end = PALMAS_PWRON_IRQ,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
enum palmas_ids {
|
||||
PALMAS_PMIC_ID,
|
||||
|
@ -111,20 +58,14 @@ static const struct mfd_cell palmas_children[] = {
|
|||
},
|
||||
{
|
||||
.name = "palmas-rtc",
|
||||
.num_resources = ARRAY_SIZE(rtc_resource),
|
||||
.resources = rtc_resource,
|
||||
.id = PALMAS_RTC_ID,
|
||||
},
|
||||
{
|
||||
.name = "palmas-pwrbutton",
|
||||
.num_resources = ARRAY_SIZE(pwron_resource),
|
||||
.resources = pwron_resource,
|
||||
.id = PALMAS_PWRBUTTON_ID,
|
||||
},
|
||||
{
|
||||
.name = "palmas-gpadc",
|
||||
.num_resources = ARRAY_SIZE(gpadc_resource),
|
||||
.resources = gpadc_resource,
|
||||
.id = PALMAS_GPADC_ID,
|
||||
},
|
||||
{
|
||||
|
@ -141,8 +82,6 @@ static const struct mfd_cell palmas_children[] = {
|
|||
},
|
||||
{
|
||||
.name = "palmas-usb",
|
||||
.num_resources = ARRAY_SIZE(usb_resource),
|
||||
.resources = usb_resource,
|
||||
.id = PALMAS_USB_ID,
|
||||
}
|
||||
};
|
||||
|
@ -308,17 +247,56 @@ static struct regmap_irq_chip palmas_irq_chip = {
|
|||
PALMAS_INT1_MASK),
|
||||
};
|
||||
|
||||
static void __devinit palmas_dt_to_pdata(struct device_node *node,
|
||||
struct palmas_platform_data *pdata)
|
||||
{
|
||||
int ret;
|
||||
u32 prop;
|
||||
|
||||
ret = of_property_read_u32(node, "ti,mux_pad1", &prop);
|
||||
if (!ret) {
|
||||
pdata->mux_from_pdata = 1;
|
||||
pdata->pad1 = prop;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(node, "ti,mux_pad2", &prop);
|
||||
if (!ret) {
|
||||
pdata->mux_from_pdata = 1;
|
||||
pdata->pad2 = prop;
|
||||
}
|
||||
|
||||
/* The default for this register is all masked */
|
||||
ret = of_property_read_u32(node, "ti,power_ctrl", &prop);
|
||||
if (!ret)
|
||||
pdata->power_ctrl = prop;
|
||||
else
|
||||
pdata->power_ctrl = PALMAS_POWER_CTRL_NSLEEP_MASK |
|
||||
PALMAS_POWER_CTRL_ENABLE1_MASK |
|
||||
PALMAS_POWER_CTRL_ENABLE2_MASK;
|
||||
}
|
||||
|
||||
static int __devinit palmas_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct palmas *palmas;
|
||||
struct palmas_platform_data *pdata;
|
||||
struct device_node *node = i2c->dev.of_node;
|
||||
int ret = 0, i;
|
||||
unsigned int reg, addr;
|
||||
int slave;
|
||||
struct mfd_cell *children;
|
||||
|
||||
pdata = dev_get_platdata(&i2c->dev);
|
||||
|
||||
if (node && !pdata) {
|
||||
pdata = devm_kzalloc(&i2c->dev, sizeof(*pdata), GFP_KERNEL);
|
||||
|
||||
if (!pdata)
|
||||
return -ENOMEM;
|
||||
|
||||
palmas_dt_to_pdata(node, pdata);
|
||||
}
|
||||
|
||||
if (!pdata)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -364,7 +342,7 @@ static int __devinit palmas_i2c_probe(struct i2c_client *i2c,
|
|||
regmap_write(palmas->regmap[slave], addr, reg);
|
||||
|
||||
ret = regmap_add_irq_chip(palmas->regmap[slave], palmas->irq,
|
||||
IRQF_ONESHOT | IRQF_TRIGGER_LOW, -1, &palmas_irq_chip,
|
||||
IRQF_ONESHOT | IRQF_TRIGGER_LOW, 0, &palmas_irq_chip,
|
||||
&palmas->irq_data);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
@ -377,11 +355,11 @@ static int __devinit palmas_i2c_probe(struct i2c_client *i2c,
|
|||
reg = pdata->pad1;
|
||||
ret = regmap_write(palmas->regmap[slave], addr, reg);
|
||||
if (ret)
|
||||
goto err;
|
||||
goto err_irq;
|
||||
} else {
|
||||
ret = regmap_read(palmas->regmap[slave], addr, ®);
|
||||
if (ret)
|
||||
goto err;
|
||||
goto err_irq;
|
||||
}
|
||||
|
||||
if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_0))
|
||||
|
@ -412,11 +390,11 @@ static int __devinit palmas_i2c_probe(struct i2c_client *i2c,
|
|||
reg = pdata->pad2;
|
||||
ret = regmap_write(palmas->regmap[slave], addr, reg);
|
||||
if (ret)
|
||||
goto err;
|
||||
goto err_irq;
|
||||
} else {
|
||||
ret = regmap_read(palmas->regmap[slave], addr, ®);
|
||||
if (ret)
|
||||
goto err;
|
||||
goto err_irq;
|
||||
}
|
||||
|
||||
if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_4))
|
||||
|
@ -439,18 +417,43 @@ static int __devinit palmas_i2c_probe(struct i2c_client *i2c,
|
|||
|
||||
ret = regmap_write(palmas->regmap[slave], addr, reg);
|
||||
if (ret)
|
||||
goto err;
|
||||
goto err_irq;
|
||||
|
||||
/*
|
||||
* If we are probing with DT do this the DT way and return here
|
||||
* otherwise continue and add devices using mfd helpers.
|
||||
*/
|
||||
if (node) {
|
||||
ret = of_platform_populate(node, NULL, NULL, &i2c->dev);
|
||||
if (ret < 0)
|
||||
goto err_irq;
|
||||
else
|
||||
return ret;
|
||||
}
|
||||
|
||||
children = kmemdup(palmas_children, sizeof(palmas_children),
|
||||
GFP_KERNEL);
|
||||
if (!children) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
goto err_irq;
|
||||
}
|
||||
|
||||
children[PALMAS_PMIC_ID].platform_data = pdata->pmic_pdata;
|
||||
children[PALMAS_PMIC_ID].pdata_size = sizeof(*pdata->pmic_pdata);
|
||||
|
||||
children[PALMAS_GPADC_ID].platform_data = pdata->gpadc_pdata;
|
||||
children[PALMAS_GPADC_ID].pdata_size = sizeof(*pdata->gpadc_pdata);
|
||||
|
||||
children[PALMAS_RESOURCE_ID].platform_data = pdata->resource_pdata;
|
||||
children[PALMAS_RESOURCE_ID].pdata_size =
|
||||
sizeof(*pdata->resource_pdata);
|
||||
|
||||
children[PALMAS_USB_ID].platform_data = pdata->usb_pdata;
|
||||
children[PALMAS_USB_ID].pdata_size = sizeof(*pdata->usb_pdata);
|
||||
|
||||
children[PALMAS_CLK_ID].platform_data = pdata->clk_pdata;
|
||||
children[PALMAS_CLK_ID].pdata_size = sizeof(*pdata->clk_pdata);
|
||||
|
||||
ret = mfd_add_devices(palmas->dev, -1,
|
||||
children, ARRAY_SIZE(palmas_children),
|
||||
NULL, regmap_irq_chip_get_base(palmas->irq_data),
|
||||
|
@ -458,13 +461,15 @@ static int __devinit palmas_i2c_probe(struct i2c_client *i2c,
|
|||
kfree(children);
|
||||
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
goto err_devices;
|
||||
|
||||
return ret;
|
||||
|
||||
err:
|
||||
err_devices:
|
||||
mfd_remove_devices(palmas->dev);
|
||||
kfree(palmas);
|
||||
err_irq:
|
||||
regmap_del_irq_chip(palmas->irq, palmas->irq_data);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -255,7 +255,7 @@ static irqreturn_t rc5t583_irq(int irq, void *data)
|
|||
{
|
||||
struct rc5t583 *rc5t583 = data;
|
||||
uint8_t int_sts[RC5T583_MAX_INTERRUPT_MASK_REGS];
|
||||
uint8_t master_int;
|
||||
uint8_t master_int = 0;
|
||||
int i;
|
||||
int ret;
|
||||
unsigned int rtc_int_sts = 0;
|
||||
|
|
|
@ -85,7 +85,7 @@ static int __rc5t583_set_ext_pwrreq1_control(struct device *dev,
|
|||
int id, int ext_pwr, int slots)
|
||||
{
|
||||
int ret;
|
||||
uint8_t sleepseq_val;
|
||||
uint8_t sleepseq_val = 0;
|
||||
unsigned int en_bit;
|
||||
unsigned int slot_bit;
|
||||
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* TI SMSC MFD Driver
|
||||
*
|
||||
* Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com
|
||||
*
|
||||
* Author: Sourav Poddar <sourav.poddar@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; GPL v2.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/smsc.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
static struct regmap_config smsc_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = SMSC_VEN_ID_H,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
static int smsc_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct smsc *smsc;
|
||||
int devid, rev, venid_l, venid_h;
|
||||
int ret = 0;
|
||||
|
||||
smsc = devm_kzalloc(&i2c->dev, sizeof(struct smsc),
|
||||
GFP_KERNEL);
|
||||
if (!smsc) {
|
||||
dev_err(&i2c->dev, "smsc mfd driver memory allocation failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
smsc->regmap = devm_regmap_init_i2c(i2c, &smsc_regmap_config);
|
||||
if (IS_ERR(smsc->regmap)) {
|
||||
ret = PTR_ERR(smsc->regmap);
|
||||
goto err;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(i2c, smsc);
|
||||
smsc->dev = &i2c->dev;
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
of_property_read_u32(i2c->dev.of_node, "clock", &smsc->clk);
|
||||
#endif
|
||||
|
||||
regmap_read(smsc->regmap, SMSC_DEV_ID, &devid);
|
||||
regmap_read(smsc->regmap, SMSC_DEV_REV, &rev);
|
||||
regmap_read(smsc->regmap, SMSC_VEN_ID_L, &venid_l);
|
||||
regmap_read(smsc->regmap, SMSC_VEN_ID_H, &venid_h);
|
||||
|
||||
dev_info(&i2c->dev, "SMSCxxx devid: %02x rev: %02x venid: %02x\n",
|
||||
devid, rev, (venid_h << 8) | venid_l);
|
||||
|
||||
ret = regmap_write(smsc->regmap, SMSC_CLK_CTRL, smsc->clk);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
if (i2c->dev.of_node)
|
||||
ret = of_platform_populate(i2c->dev.of_node,
|
||||
NULL, NULL, &i2c->dev);
|
||||
#endif
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int smsc_i2c_remove(struct i2c_client *i2c)
|
||||
{
|
||||
struct smsc *smsc = i2c_get_clientdata(i2c);
|
||||
|
||||
mfd_remove_devices(smsc->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id smsc_i2c_id[] = {
|
||||
{ "smscece1099", 0},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, smsc_i2c_id);
|
||||
|
||||
static struct i2c_driver smsc_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "smsc",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = smsc_i2c_probe,
|
||||
.remove = smsc_i2c_remove,
|
||||
.id_table = smsc_i2c_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(smsc_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Sourav Poddar <sourav.poddar@ti.com>");
|
||||
MODULE_DESCRIPTION("SMSC chip multi-function driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
* System Control Driver
|
||||
*
|
||||
* Copyright (C) 2012 Freescale Semiconductor, Inc.
|
||||
* Copyright (C) 2012 Linaro Ltd.
|
||||
*
|
||||
* Author: Dong Aisheng <dong.aisheng@linaro.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
static struct platform_driver syscon_driver;
|
||||
|
||||
struct syscon {
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
static int syscon_match(struct device *dev, void *data)
|
||||
{
|
||||
struct syscon *syscon = dev_get_drvdata(dev);
|
||||
struct device_node *dn = data;
|
||||
|
||||
return (syscon->dev->of_node == dn) ? 1 : 0;
|
||||
}
|
||||
|
||||
struct regmap *syscon_node_to_regmap(struct device_node *np)
|
||||
{
|
||||
struct syscon *syscon;
|
||||
struct device *dev;
|
||||
|
||||
dev = driver_find_device(&syscon_driver.driver, NULL, np,
|
||||
syscon_match);
|
||||
if (!dev)
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
|
||||
syscon = dev_get_drvdata(dev);
|
||||
|
||||
return syscon->regmap;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(syscon_node_to_regmap);
|
||||
|
||||
struct regmap *syscon_regmap_lookup_by_compatible(const char *s)
|
||||
{
|
||||
struct device_node *syscon_np;
|
||||
struct regmap *regmap;
|
||||
|
||||
syscon_np = of_find_compatible_node(NULL, NULL, s);
|
||||
if (!syscon_np)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
regmap = syscon_node_to_regmap(syscon_np);
|
||||
of_node_put(syscon_np);
|
||||
|
||||
return regmap;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_compatible);
|
||||
|
||||
struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np,
|
||||
const char *property)
|
||||
{
|
||||
struct device_node *syscon_np;
|
||||
struct regmap *regmap;
|
||||
|
||||
syscon_np = of_parse_phandle(np, property, 0);
|
||||
if (!syscon_np)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
regmap = syscon_node_to_regmap(syscon_np);
|
||||
of_node_put(syscon_np);
|
||||
|
||||
return regmap;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_phandle);
|
||||
|
||||
static const struct of_device_id of_syscon_match[] = {
|
||||
{ .compatible = "syscon", },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct regmap_config syscon_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
};
|
||||
|
||||
static int __devinit syscon_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct syscon *syscon;
|
||||
struct resource res;
|
||||
int ret;
|
||||
|
||||
if (!np)
|
||||
return -ENOENT;
|
||||
|
||||
syscon = devm_kzalloc(dev, sizeof(struct syscon),
|
||||
GFP_KERNEL);
|
||||
if (!syscon)
|
||||
return -ENOMEM;
|
||||
|
||||
syscon->base = of_iomap(np, 0);
|
||||
if (!syscon->base)
|
||||
return -EADDRNOTAVAIL;
|
||||
|
||||
ret = of_address_to_resource(np, 0, &res);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
syscon_regmap_config.max_register = res.end - res.start - 3;
|
||||
syscon->regmap = devm_regmap_init_mmio(dev, syscon->base,
|
||||
&syscon_regmap_config);
|
||||
if (IS_ERR(syscon->regmap)) {
|
||||
dev_err(dev, "regmap init failed\n");
|
||||
return PTR_ERR(syscon->regmap);
|
||||
}
|
||||
|
||||
syscon->dev = dev;
|
||||
platform_set_drvdata(pdev, syscon);
|
||||
|
||||
dev_info(dev, "syscon regmap start 0x%x end 0x%x registered\n",
|
||||
res.start, res.end);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devexit syscon_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct syscon *syscon;
|
||||
|
||||
syscon = platform_get_drvdata(pdev);
|
||||
iounmap(syscon->base);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver syscon_driver = {
|
||||
.driver = {
|
||||
.name = "syscon",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_syscon_match,
|
||||
},
|
||||
.probe = syscon_probe,
|
||||
.remove = __devexit_p(syscon_remove),
|
||||
};
|
||||
|
||||
static int __init syscon_init(void)
|
||||
{
|
||||
return platform_driver_register(&syscon_driver);
|
||||
}
|
||||
postcore_initcall(syscon_init);
|
||||
|
||||
static void __exit syscon_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&syscon_driver);
|
||||
}
|
||||
module_exit(syscon_exit);
|
||||
|
||||
MODULE_AUTHOR("Dong Aisheng <dong.aisheng@linaro.org>");
|
||||
MODULE_DESCRIPTION("System Control driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -9,8 +9,10 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/tc3589x.h>
|
||||
|
||||
|
@ -145,6 +147,7 @@ static struct mfd_cell tc3589x_dev_gpio[] = {
|
|||
.name = "tc3589x-gpio",
|
||||
.num_resources = ARRAY_SIZE(gpio_resources),
|
||||
.resources = &gpio_resources[0],
|
||||
.of_compatible = "tc3589x-gpio",
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -153,6 +156,7 @@ static struct mfd_cell tc3589x_dev_keypad[] = {
|
|||
.name = "tc3589x-keypad",
|
||||
.num_resources = ARRAY_SIZE(keypad_resources),
|
||||
.resources = &keypad_resources[0],
|
||||
.of_compatible = "tc3589x-keypad",
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -168,8 +172,9 @@ again:
|
|||
|
||||
while (status) {
|
||||
int bit = __ffs(status);
|
||||
int virq = irq_create_mapping(tc3589x->domain, bit);
|
||||
|
||||
handle_nested_irq(tc3589x->irq_base + bit);
|
||||
handle_nested_irq(virq);
|
||||
status &= ~(1 << bit);
|
||||
}
|
||||
|
||||
|
@ -186,38 +191,60 @@ again:
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int tc3589x_irq_init(struct tc3589x *tc3589x)
|
||||
static int tc3589x_irq_map(struct irq_domain *d, unsigned int virq,
|
||||
irq_hw_number_t hwirq)
|
||||
{
|
||||
int base = tc3589x->irq_base;
|
||||
int irq;
|
||||
struct tc3589x *tc3589x = d->host_data;
|
||||
|
||||
for (irq = base; irq < base + TC3589x_NR_INTERNAL_IRQS; irq++) {
|
||||
irq_set_chip_data(irq, tc3589x);
|
||||
irq_set_chip_and_handler(irq, &dummy_irq_chip,
|
||||
handle_edge_irq);
|
||||
irq_set_nested_thread(irq, 1);
|
||||
irq_set_chip_data(virq, tc3589x);
|
||||
irq_set_chip_and_handler(virq, &dummy_irq_chip,
|
||||
handle_edge_irq);
|
||||
irq_set_nested_thread(virq, 1);
|
||||
#ifdef CONFIG_ARM
|
||||
set_irq_flags(irq, IRQF_VALID);
|
||||
set_irq_flags(virq, IRQF_VALID);
|
||||
#else
|
||||
irq_set_noprobe(irq);
|
||||
irq_set_noprobe(virq);
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tc3589x_irq_remove(struct tc3589x *tc3589x)
|
||||
static void tc3589x_irq_unmap(struct irq_domain *d, unsigned int virq)
|
||||
{
|
||||
#ifdef CONFIG_ARM
|
||||
set_irq_flags(virq, 0);
|
||||
#endif
|
||||
irq_set_chip_and_handler(virq, NULL, NULL);
|
||||
irq_set_chip_data(virq, NULL);
|
||||
}
|
||||
|
||||
static struct irq_domain_ops tc3589x_irq_ops = {
|
||||
.map = tc3589x_irq_map,
|
||||
.unmap = tc3589x_irq_unmap,
|
||||
.xlate = irq_domain_xlate_twocell,
|
||||
};
|
||||
|
||||
static int tc3589x_irq_init(struct tc3589x *tc3589x, struct device_node *np)
|
||||
{
|
||||
int base = tc3589x->irq_base;
|
||||
int irq;
|
||||
|
||||
for (irq = base; irq < base + TC3589x_NR_INTERNAL_IRQS; irq++) {
|
||||
#ifdef CONFIG_ARM
|
||||
set_irq_flags(irq, 0);
|
||||
#endif
|
||||
irq_set_chip_and_handler(irq, NULL, NULL);
|
||||
irq_set_chip_data(irq, NULL);
|
||||
if (base) {
|
||||
tc3589x->domain = irq_domain_add_legacy(
|
||||
NULL, TC3589x_NR_INTERNAL_IRQS, base,
|
||||
0, &tc3589x_irq_ops, tc3589x);
|
||||
}
|
||||
else {
|
||||
tc3589x->domain = irq_domain_add_linear(
|
||||
np, TC3589x_NR_INTERNAL_IRQS,
|
||||
&tc3589x_irq_ops, tc3589x);
|
||||
}
|
||||
|
||||
if (!tc3589x->domain) {
|
||||
dev_err(tc3589x->dev, "Failed to create irqdomain\n");
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tc3589x_chip_init(struct tc3589x *tc3589x)
|
||||
|
@ -263,7 +290,7 @@ static int __devinit tc3589x_device_init(struct tc3589x *tc3589x)
|
|||
if (blocks & TC3589x_BLOCK_GPIO) {
|
||||
ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_gpio,
|
||||
ARRAY_SIZE(tc3589x_dev_gpio), NULL,
|
||||
tc3589x->irq_base, NULL);
|
||||
tc3589x->irq_base, tc3589x->domain);
|
||||
if (ret) {
|
||||
dev_err(tc3589x->dev, "failed to add gpio child\n");
|
||||
return ret;
|
||||
|
@ -274,7 +301,7 @@ static int __devinit tc3589x_device_init(struct tc3589x *tc3589x)
|
|||
if (blocks & TC3589x_BLOCK_KEYPAD) {
|
||||
ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_keypad,
|
||||
ARRAY_SIZE(tc3589x_dev_keypad), NULL,
|
||||
tc3589x->irq_base, NULL);
|
||||
tc3589x->irq_base, tc3589x->domain);
|
||||
if (ret) {
|
||||
dev_err(tc3589x->dev, "failed to keypad child\n");
|
||||
return ret;
|
||||
|
@ -285,13 +312,47 @@ static int __devinit tc3589x_device_init(struct tc3589x *tc3589x)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int tc3589x_of_probe(struct device_node *np,
|
||||
struct tc3589x_platform_data *pdata)
|
||||
{
|
||||
struct device_node *child;
|
||||
|
||||
for_each_child_of_node(np, child) {
|
||||
if (!strcmp(child->name, "tc3589x_gpio")) {
|
||||
pdata->block |= TC3589x_BLOCK_GPIO;
|
||||
}
|
||||
if (!strcmp(child->name, "tc3589x_keypad")) {
|
||||
pdata->block |= TC3589x_BLOCK_KEYPAD;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit tc3589x_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct tc3589x_platform_data *pdata = i2c->dev.platform_data;
|
||||
struct device_node *np = i2c->dev.of_node;
|
||||
struct tc3589x *tc3589x;
|
||||
int ret;
|
||||
|
||||
if (!pdata) {
|
||||
if (np) {
|
||||
pdata = devm_kzalloc(&i2c->dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = tc3589x_of_probe(np, pdata);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
else {
|
||||
dev_err(&i2c->dev, "No platform data or DT found\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA
|
||||
| I2C_FUNC_SMBUS_I2C_BLOCK))
|
||||
return -EIO;
|
||||
|
@ -314,7 +375,7 @@ static int __devinit tc3589x_probe(struct i2c_client *i2c,
|
|||
if (ret)
|
||||
goto out_free;
|
||||
|
||||
ret = tc3589x_irq_init(tc3589x);
|
||||
ret = tc3589x_irq_init(tc3589x, np);
|
||||
if (ret)
|
||||
goto out_free;
|
||||
|
||||
|
@ -323,7 +384,7 @@ static int __devinit tc3589x_probe(struct i2c_client *i2c,
|
|||
"tc3589x", tc3589x);
|
||||
if (ret) {
|
||||
dev_err(tc3589x->dev, "failed to request IRQ: %d\n", ret);
|
||||
goto out_removeirq;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
ret = tc3589x_device_init(tc3589x);
|
||||
|
@ -336,8 +397,6 @@ static int __devinit tc3589x_probe(struct i2c_client *i2c,
|
|||
|
||||
out_freeirq:
|
||||
free_irq(tc3589x->i2c->irq, tc3589x);
|
||||
out_removeirq:
|
||||
tc3589x_irq_remove(tc3589x);
|
||||
out_free:
|
||||
kfree(tc3589x);
|
||||
return ret;
|
||||
|
@ -350,7 +409,6 @@ static int __devexit tc3589x_remove(struct i2c_client *client)
|
|||
mfd_remove_devices(tc3589x->dev);
|
||||
|
||||
free_irq(tc3589x->i2c->irq, tc3589x);
|
||||
tc3589x_irq_remove(tc3589x);
|
||||
|
||||
kfree(tc3589x);
|
||||
|
||||
|
|
|
@ -236,7 +236,7 @@ static int __devinit tps65090_irq_init(struct tps65090 *tps65090, int irq,
|
|||
|
||||
static bool is_volatile_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
if ((reg == TPS65090_INT_STS) || (reg == TPS65090_INT_STS))
|
||||
if (reg == TPS65090_INT_STS)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
|
|
|
@ -34,6 +34,9 @@ static struct mfd_cell tps65217s[] = {
|
|||
{
|
||||
.name = "tps65217-pmic",
|
||||
},
|
||||
{
|
||||
.name = "tps65217-bl",
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -30,6 +30,10 @@
|
|||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/tps6586x.h>
|
||||
|
||||
#define TPS6586X_SUPPLYENE 0x14
|
||||
#define EXITSLREQ_BIT BIT(1)
|
||||
#define SLEEP_MODE_BIT BIT(3)
|
||||
|
||||
/* interrupt control registers */
|
||||
#define TPS6586X_INT_ACK1 0xb5
|
||||
#define TPS6586X_INT_ACK2 0xb6
|
||||
|
@ -422,6 +426,7 @@ static struct tps6586x_platform_data *tps6586x_parse_dt(struct i2c_client *clien
|
|||
pdata->subdevs = devs;
|
||||
pdata->gpio_base = -1;
|
||||
pdata->irq_base = -1;
|
||||
pdata->pm_off = of_property_read_bool(np, "ti,system-power-controller");
|
||||
|
||||
return pdata;
|
||||
}
|
||||
|
@ -454,6 +459,15 @@ static const struct regmap_config tps6586x_regmap_config = {
|
|||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
static struct device *tps6586x_dev;
|
||||
static void tps6586x_power_off(void)
|
||||
{
|
||||
if (tps6586x_clr_bits(tps6586x_dev, TPS6586X_SUPPLYENE, EXITSLREQ_BIT))
|
||||
return;
|
||||
|
||||
tps6586x_set_bits(tps6586x_dev, TPS6586X_SUPPLYENE, SLEEP_MODE_BIT);
|
||||
}
|
||||
|
||||
static int __devinit tps6586x_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
|
@ -519,6 +533,11 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client,
|
|||
goto err_add_devs;
|
||||
}
|
||||
|
||||
if (pdata->pm_off && !pm_power_off) {
|
||||
tps6586x_dev = &client->dev;
|
||||
pm_power_off = tps6586x_power_off;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_add_devs:
|
||||
|
|
|
@ -24,6 +24,14 @@
|
|||
#include <linux/mfd/tps65910.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
static struct resource rtc_resources[] = {
|
||||
{
|
||||
.start = TPS65910_IRQ_RTC_ALARM,
|
||||
.end = TPS65910_IRQ_RTC_ALARM,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
}
|
||||
};
|
||||
|
||||
static struct mfd_cell tps65910s[] = {
|
||||
{
|
||||
.name = "tps65910-gpio",
|
||||
|
@ -33,6 +41,8 @@ static struct mfd_cell tps65910s[] = {
|
|||
},
|
||||
{
|
||||
.name = "tps65910-rtc",
|
||||
.num_resources = ARRAY_SIZE(rtc_resources),
|
||||
.resources = &rtc_resources[0],
|
||||
},
|
||||
{
|
||||
.name = "tps65910-power",
|
||||
|
@ -198,6 +208,8 @@ static struct tps65910_board *tps65910_parse_dt(struct i2c_client *client,
|
|||
|
||||
board_info->irq = client->irq;
|
||||
board_info->irq_base = -1;
|
||||
board_info->pm_off = of_property_read_bool(np,
|
||||
"ti,system-power-controller");
|
||||
|
||||
return board_info;
|
||||
}
|
||||
|
@ -210,6 +222,21 @@ struct tps65910_board *tps65910_parse_dt(struct i2c_client *client,
|
|||
}
|
||||
#endif
|
||||
|
||||
static struct i2c_client *tps65910_i2c_client;
|
||||
static void tps65910_power_off(void)
|
||||
{
|
||||
struct tps65910 *tps65910;
|
||||
|
||||
tps65910 = dev_get_drvdata(&tps65910_i2c_client->dev);
|
||||
|
||||
if (tps65910_reg_set_bits(tps65910, TPS65910_DEVCTRL,
|
||||
DEVCTRL_PWR_OFF_MASK) < 0)
|
||||
return;
|
||||
|
||||
tps65910_reg_clear_bits(tps65910, TPS65910_DEVCTRL,
|
||||
DEVCTRL_DEV_ON_MASK);
|
||||
}
|
||||
|
||||
static __devinit int tps65910_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
|
@ -267,6 +294,11 @@ static __devinit int tps65910_i2c_probe(struct i2c_client *i2c,
|
|||
tps65910_ck32k_init(tps65910, pmic_plat_data);
|
||||
tps65910_sleepinit(tps65910, pmic_plat_data);
|
||||
|
||||
if (pmic_plat_data->pm_off && !pm_power_off) {
|
||||
tps65910_i2c_client = i2c;
|
||||
pm_power_off = tps65910_power_off;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -63,70 +63,6 @@
|
|||
|
||||
#define DRIVER_NAME "twl"
|
||||
|
||||
#if defined(CONFIG_KEYBOARD_TWL4030) || defined(CONFIG_KEYBOARD_TWL4030_MODULE)
|
||||
#define twl_has_keypad() true
|
||||
#else
|
||||
#define twl_has_keypad() false
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_GPIO_TWL4030) || defined(CONFIG_GPIO_TWL4030_MODULE)
|
||||
#define twl_has_gpio() true
|
||||
#else
|
||||
#define twl_has_gpio() false
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_REGULATOR_TWL4030) \
|
||||
|| defined(CONFIG_REGULATOR_TWL4030_MODULE)
|
||||
#define twl_has_regulator() true
|
||||
#else
|
||||
#define twl_has_regulator() false
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_TWL4030_MADC) || defined(CONFIG_TWL4030_MADC_MODULE)
|
||||
#define twl_has_madc() true
|
||||
#else
|
||||
#define twl_has_madc() false
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TWL4030_POWER
|
||||
#define twl_has_power() true
|
||||
#else
|
||||
#define twl_has_power() false
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_RTC_DRV_TWL4030) || defined(CONFIG_RTC_DRV_TWL4030_MODULE)
|
||||
#define twl_has_rtc() true
|
||||
#else
|
||||
#define twl_has_rtc() false
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_TWL4030_USB) || defined(CONFIG_TWL4030_USB_MODULE) ||\
|
||||
defined(CONFIG_TWL6030_USB) || defined(CONFIG_TWL6030_USB_MODULE)
|
||||
#define twl_has_usb() true
|
||||
#else
|
||||
#define twl_has_usb() false
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_TWL4030_WATCHDOG) || \
|
||||
defined(CONFIG_TWL4030_WATCHDOG_MODULE)
|
||||
#define twl_has_watchdog() true
|
||||
#else
|
||||
#define twl_has_watchdog() false
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_MFD_TWL4030_AUDIO) || \
|
||||
defined(CONFIG_MFD_TWL4030_AUDIO_MODULE)
|
||||
#define twl_has_codec() true
|
||||
#else
|
||||
#define twl_has_codec() false
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_CHARGER_TWL4030) || defined(CONFIG_CHARGER_TWL4030_MODULE)
|
||||
#define twl_has_bci() true
|
||||
#else
|
||||
#define twl_has_bci() false
|
||||
#endif
|
||||
|
||||
/* Triton Core internal information (BEGIN) */
|
||||
|
||||
/* Last - for index max*/
|
||||
|
@ -134,13 +70,6 @@
|
|||
|
||||
#define TWL_NUM_SLAVES 4
|
||||
|
||||
#if defined(CONFIG_INPUT_TWL4030_PWRBUTTON) \
|
||||
|| defined(CONFIG_INPUT_TWL4030_PWRBUTTON_MODULE)
|
||||
#define twl_has_pwrbutton() true
|
||||
#else
|
||||
#define twl_has_pwrbutton() false
|
||||
#endif
|
||||
|
||||
#define SUB_CHIP_ID0 0
|
||||
#define SUB_CHIP_ID1 1
|
||||
#define SUB_CHIP_ID2 2
|
||||
|
@ -552,6 +481,38 @@ int twl_get_version(void)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(twl_get_version);
|
||||
|
||||
/**
|
||||
* twl_get_hfclk_rate - API to get TWL external HFCLK clock rate.
|
||||
*
|
||||
* Api to get the TWL HFCLK rate based on BOOT_CFG register.
|
||||
*/
|
||||
int twl_get_hfclk_rate(void)
|
||||
{
|
||||
u8 ctrl;
|
||||
int rate;
|
||||
|
||||
twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &ctrl, R_CFG_BOOT);
|
||||
|
||||
switch (ctrl & 0x3) {
|
||||
case HFCLK_FREQ_19p2_MHZ:
|
||||
rate = 19200000;
|
||||
break;
|
||||
case HFCLK_FREQ_26_MHZ:
|
||||
rate = 26000000;
|
||||
break;
|
||||
case HFCLK_FREQ_38p4_MHZ:
|
||||
rate = 38400000;
|
||||
break;
|
||||
default:
|
||||
pr_err("TWL4030: HFCLK is not configured\n");
|
||||
rate = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return rate;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(twl_get_hfclk_rate);
|
||||
|
||||
static struct device *
|
||||
add_numbered_child(unsigned chip, const char *name, int num,
|
||||
void *pdata, unsigned pdata_len,
|
||||
|
@ -669,7 +630,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
|
|||
struct device *child;
|
||||
unsigned sub_chip_id;
|
||||
|
||||
if (twl_has_gpio() && pdata->gpio) {
|
||||
if (IS_ENABLED(CONFIG_GPIO_TWL4030) && pdata->gpio) {
|
||||
child = add_child(SUB_CHIP_ID1, "twl4030_gpio",
|
||||
pdata->gpio, sizeof(*pdata->gpio),
|
||||
false, irq_base + GPIO_INTR_OFFSET, 0);
|
||||
|
@ -677,7 +638,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
|
|||
return PTR_ERR(child);
|
||||
}
|
||||
|
||||
if (twl_has_keypad() && pdata->keypad) {
|
||||
if (IS_ENABLED(CONFIG_KEYBOARD_TWL4030) && pdata->keypad) {
|
||||
child = add_child(SUB_CHIP_ID2, "twl4030_keypad",
|
||||
pdata->keypad, sizeof(*pdata->keypad),
|
||||
true, irq_base + KEYPAD_INTR_OFFSET, 0);
|
||||
|
@ -685,7 +646,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
|
|||
return PTR_ERR(child);
|
||||
}
|
||||
|
||||
if (twl_has_madc() && pdata->madc) {
|
||||
if (IS_ENABLED(CONFIG_TWL4030_MADC) && pdata->madc) {
|
||||
child = add_child(2, "twl4030_madc",
|
||||
pdata->madc, sizeof(*pdata->madc),
|
||||
true, irq_base + MADC_INTR_OFFSET, 0);
|
||||
|
@ -693,7 +654,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
|
|||
return PTR_ERR(child);
|
||||
}
|
||||
|
||||
if (twl_has_rtc()) {
|
||||
if (IS_ENABLED(CONFIG_RTC_DRV_TWL4030)) {
|
||||
/*
|
||||
* REVISIT platform_data here currently might expose the
|
||||
* "msecure" line ... but for now we just expect board
|
||||
|
@ -709,7 +670,15 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
|
|||
return PTR_ERR(child);
|
||||
}
|
||||
|
||||
if (twl_has_usb() && pdata->usb && twl_class_is_4030()) {
|
||||
if (IS_ENABLED(CONFIG_PWM_TWL6030) && twl_class_is_6030()) {
|
||||
child = add_child(TWL6030_MODULE_ID1, "twl6030-pwm", NULL, 0,
|
||||
false, 0, 0);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_TWL4030_USB) && pdata->usb &&
|
||||
twl_class_is_4030()) {
|
||||
|
||||
static struct regulator_consumer_supply usb1v5 = {
|
||||
.supply = "usb1v5",
|
||||
|
@ -723,7 +692,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
|
|||
};
|
||||
|
||||
/* First add the regulators so that they can be used by transceiver */
|
||||
if (twl_has_regulator()) {
|
||||
if (IS_ENABLED(CONFIG_REGULATOR_TWL4030)) {
|
||||
/* this is a template that gets copied */
|
||||
struct regulator_init_data usb_fixed = {
|
||||
.constraints.valid_modes_mask =
|
||||
|
@ -765,18 +734,19 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
|
|||
return PTR_ERR(child);
|
||||
|
||||
/* we need to connect regulators to this transceiver */
|
||||
if (twl_has_regulator() && child) {
|
||||
if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && child) {
|
||||
usb1v5.dev_name = dev_name(child);
|
||||
usb1v8.dev_name = dev_name(child);
|
||||
usb3v1[0].dev_name = dev_name(child);
|
||||
}
|
||||
}
|
||||
if (twl_has_usb() && pdata->usb && twl_class_is_6030()) {
|
||||
if (IS_ENABLED(CONFIG_TWL6030_USB) && pdata->usb &&
|
||||
twl_class_is_6030()) {
|
||||
|
||||
static struct regulator_consumer_supply usb3v3;
|
||||
int regulator;
|
||||
|
||||
if (twl_has_regulator()) {
|
||||
if (IS_ENABLED(CONFIG_REGULATOR_TWL4030)) {
|
||||
/* this is a template that gets copied */
|
||||
struct regulator_init_data usb_fixed = {
|
||||
.constraints.valid_modes_mask =
|
||||
|
@ -813,9 +783,10 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
|
|||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
/* we need to connect regulators to this transceiver */
|
||||
if (twl_has_regulator() && child)
|
||||
if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && child)
|
||||
usb3v3.dev_name = dev_name(child);
|
||||
} else if (twl_has_regulator() && twl_class_is_6030()) {
|
||||
} else if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) &&
|
||||
twl_class_is_6030()) {
|
||||
if (features & TWL6025_SUBCLASS)
|
||||
child = add_regulator(TWL6025_REG_LDOUSB,
|
||||
pdata->ldousb, features);
|
||||
|
@ -827,20 +798,21 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
|
|||
return PTR_ERR(child);
|
||||
}
|
||||
|
||||
if (twl_has_watchdog() && twl_class_is_4030()) {
|
||||
if (IS_ENABLED(CONFIG_TWL4030_WATCHDOG) && twl_class_is_4030()) {
|
||||
child = add_child(0, "twl4030_wdt", NULL, 0, false, 0, 0);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
}
|
||||
|
||||
if (twl_has_pwrbutton() && twl_class_is_4030()) {
|
||||
if (IS_ENABLED(CONFIG_INPUT_TWL4030_PWRBUTTON) && twl_class_is_4030()) {
|
||||
child = add_child(1, "twl4030_pwrbutton",
|
||||
NULL, 0, true, irq_base + 8 + 0, 0);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
}
|
||||
|
||||
if (twl_has_codec() && pdata->audio && twl_class_is_4030()) {
|
||||
if (IS_ENABLED(CONFIG_MFD_TWL4030_AUDIO) && pdata->audio &&
|
||||
twl_class_is_4030()) {
|
||||
sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
|
||||
child = add_child(sub_chip_id, "twl4030-audio",
|
||||
pdata->audio, sizeof(*pdata->audio),
|
||||
|
@ -850,7 +822,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
|
|||
}
|
||||
|
||||
/* twl4030 regulators */
|
||||
if (twl_has_regulator() && twl_class_is_4030()) {
|
||||
if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && twl_class_is_4030()) {
|
||||
child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
|
@ -905,7 +877,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
|
|||
}
|
||||
|
||||
/* maybe add LDOs that are omitted on cost-reduced parts */
|
||||
if (twl_has_regulator() && !(features & TPS_SUBSET)
|
||||
if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && !(features & TPS_SUBSET)
|
||||
&& twl_class_is_4030()) {
|
||||
child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2,
|
||||
features);
|
||||
|
@ -939,7 +911,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
|
|||
}
|
||||
|
||||
/* twl6030 regulators */
|
||||
if (twl_has_regulator() && twl_class_is_6030() &&
|
||||
if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && twl_class_is_6030() &&
|
||||
!(features & TWL6025_SUBCLASS)) {
|
||||
child = add_regulator(TWL6030_REG_VDD1, pdata->vdd1,
|
||||
features);
|
||||
|
@ -1013,7 +985,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
|
|||
}
|
||||
|
||||
/* 6030 and 6025 share this regulator */
|
||||
if (twl_has_regulator() && twl_class_is_6030()) {
|
||||
if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && twl_class_is_6030()) {
|
||||
child = add_regulator(TWL6030_REG_VANA, pdata->vana,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
|
@ -1021,7 +993,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
|
|||
}
|
||||
|
||||
/* twl6025 regulators */
|
||||
if (twl_has_regulator() && twl_class_is_6030() &&
|
||||
if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && twl_class_is_6030() &&
|
||||
(features & TWL6025_SUBCLASS)) {
|
||||
child = add_regulator(TWL6025_REG_LDO5, pdata->ldo5,
|
||||
features);
|
||||
|
@ -1080,7 +1052,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
|
|||
|
||||
}
|
||||
|
||||
if (twl_has_bci() && pdata->bci &&
|
||||
if (IS_ENABLED(CONFIG_CHARGER_TWL4030) && pdata->bci &&
|
||||
!(features & (TPS_SUBSET | TWL5031))) {
|
||||
child = add_child(3, "twl4030_bci",
|
||||
pdata->bci, sizeof(*pdata->bci), false,
|
||||
|
@ -1295,7 +1267,7 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||
}
|
||||
|
||||
/* load power event scripts */
|
||||
if (twl_has_power() && pdata->power)
|
||||
if (IS_ENABLED(CONFIG_TWL4030_POWER) && pdata->power)
|
||||
twl4030_power_init(pdata->power);
|
||||
|
||||
/* Maybe init the T2 Interrupt subsystem */
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/i2c/twl.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/twl4030-audio.h>
|
||||
|
@ -156,47 +158,70 @@ unsigned int twl4030_audio_get_mclk(void)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(twl4030_audio_get_mclk);
|
||||
|
||||
static bool twl4030_audio_has_codec(struct twl4030_audio_data *pdata,
|
||||
struct device_node *node)
|
||||
{
|
||||
if (pdata && pdata->codec)
|
||||
return true;
|
||||
|
||||
if (of_find_node_by_name(node, "codec"))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool twl4030_audio_has_vibra(struct twl4030_audio_data *pdata,
|
||||
struct device_node *node)
|
||||
{
|
||||
int vibra;
|
||||
|
||||
if (pdata && pdata->vibra)
|
||||
return true;
|
||||
|
||||
if (!of_property_read_u32(node, "ti,enable-vibra", &vibra) && vibra)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int __devinit twl4030_audio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct twl4030_audio *audio;
|
||||
struct twl4030_audio_data *pdata = pdev->dev.platform_data;
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
struct mfd_cell *cell = NULL;
|
||||
int ret, childs = 0;
|
||||
u8 val;
|
||||
|
||||
if (!pdata) {
|
||||
if (!pdata && !node) {
|
||||
dev_err(&pdev->dev, "Platform data is missing\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
audio = devm_kzalloc(&pdev->dev, sizeof(struct twl4030_audio),
|
||||
GFP_KERNEL);
|
||||
if (!audio)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&audio->mutex);
|
||||
audio->audio_mclk = twl_get_hfclk_rate();
|
||||
|
||||
/* Configure APLL_INFREQ and disable APLL if enabled */
|
||||
val = 0;
|
||||
switch (pdata->audio_mclk) {
|
||||
switch (audio->audio_mclk) {
|
||||
case 19200000:
|
||||
val |= TWL4030_APLL_INFREQ_19200KHZ;
|
||||
val = TWL4030_APLL_INFREQ_19200KHZ;
|
||||
break;
|
||||
case 26000000:
|
||||
val |= TWL4030_APLL_INFREQ_26000KHZ;
|
||||
val = TWL4030_APLL_INFREQ_26000KHZ;
|
||||
break;
|
||||
case 38400000:
|
||||
val |= TWL4030_APLL_INFREQ_38400KHZ;
|
||||
val = TWL4030_APLL_INFREQ_38400KHZ;
|
||||
break;
|
||||
default:
|
||||
dev_err(&pdev->dev, "Invalid audio_mclk\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
|
||||
val, TWL4030_REG_APLL_CTL);
|
||||
|
||||
audio = kzalloc(sizeof(struct twl4030_audio), GFP_KERNEL);
|
||||
if (!audio)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, audio);
|
||||
|
||||
twl4030_audio_dev = pdev;
|
||||
mutex_init(&audio->mutex);
|
||||
audio->audio_mclk = pdata->audio_mclk;
|
||||
twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, val, TWL4030_REG_APLL_CTL);
|
||||
|
||||
/* Codec power */
|
||||
audio->resource[TWL4030_AUDIO_RES_POWER].reg = TWL4030_REG_CODEC_MODE;
|
||||
|
@ -206,21 +231,28 @@ static int __devinit twl4030_audio_probe(struct platform_device *pdev)
|
|||
audio->resource[TWL4030_AUDIO_RES_APLL].reg = TWL4030_REG_APLL_CTL;
|
||||
audio->resource[TWL4030_AUDIO_RES_APLL].mask = TWL4030_APLL_EN;
|
||||
|
||||
if (pdata->codec) {
|
||||
if (twl4030_audio_has_codec(pdata, node)) {
|
||||
cell = &audio->cells[childs];
|
||||
cell->name = "twl4030-codec";
|
||||
cell->platform_data = pdata->codec;
|
||||
cell->pdata_size = sizeof(*pdata->codec);
|
||||
if (pdata) {
|
||||
cell->platform_data = pdata->codec;
|
||||
cell->pdata_size = sizeof(*pdata->codec);
|
||||
}
|
||||
childs++;
|
||||
}
|
||||
if (pdata->vibra) {
|
||||
if (twl4030_audio_has_vibra(pdata, node)) {
|
||||
cell = &audio->cells[childs];
|
||||
cell->name = "twl4030-vibra";
|
||||
cell->platform_data = pdata->vibra;
|
||||
cell->pdata_size = sizeof(*pdata->vibra);
|
||||
if (pdata) {
|
||||
cell->platform_data = pdata->vibra;
|
||||
cell->pdata_size = sizeof(*pdata->vibra);
|
||||
}
|
||||
childs++;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, audio);
|
||||
twl4030_audio_dev = pdev;
|
||||
|
||||
if (childs)
|
||||
ret = mfd_add_devices(&pdev->dev, pdev->id, audio->cells,
|
||||
childs, NULL, 0, NULL);
|
||||
|
@ -229,39 +261,42 @@ static int __devinit twl4030_audio_probe(struct platform_device *pdev)
|
|||
ret = -ENODEV;
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
return 0;
|
||||
if (ret) {
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
twl4030_audio_dev = NULL;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(audio);
|
||||
twl4030_audio_dev = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit twl4030_audio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct twl4030_audio *audio = platform_get_drvdata(pdev);
|
||||
|
||||
mfd_remove_devices(&pdev->dev);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(audio);
|
||||
twl4030_audio_dev = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_ALIAS("platform:twl4030-audio");
|
||||
static const struct of_device_id twl4030_audio_of_match[] = {
|
||||
{.compatible = "ti,twl4030-audio", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, twl4030_audio_of_match);
|
||||
|
||||
static struct platform_driver twl4030_audio_driver = {
|
||||
.probe = twl4030_audio_probe,
|
||||
.remove = __devexit_p(twl4030_audio_remove),
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "twl4030-audio",
|
||||
.of_match_table = twl4030_audio_of_match,
|
||||
},
|
||||
.probe = twl4030_audio_probe,
|
||||
.remove = __devexit_p(twl4030_audio_remove),
|
||||
};
|
||||
|
||||
module_platform_driver(twl4030_audio_driver);
|
||||
|
||||
MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
|
||||
MODULE_DESCRIPTION("TWL4030 audio block MFD driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:twl4030-audio");
|
||||
|
|
|
@ -584,7 +584,7 @@ static int __devinit twl6040_probe(struct i2c_client *client,
|
|||
goto irq_init_err;
|
||||
|
||||
ret = request_threaded_irq(twl6040->irq_base + TWL6040_IRQ_READY,
|
||||
NULL, twl6040_naudint_handler, 0,
|
||||
NULL, twl6040_naudint_handler, IRQF_ONESHOT,
|
||||
"twl6040_irq_ready", twl6040);
|
||||
if (ret) {
|
||||
dev_err(twl6040->dev, "READY IRQ request failed: %d\n",
|
||||
|
@ -631,6 +631,21 @@ static int __devinit twl6040_probe(struct i2c_client *client,
|
|||
children++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable the GPO driver in the following cases:
|
||||
* DT booted kernel or legacy boot with valid gpo platform_data
|
||||
*/
|
||||
if (!pdata || (pdata && pdata->gpo)) {
|
||||
cell = &twl6040->cells[children];
|
||||
cell->name = "twl6040-gpo";
|
||||
|
||||
if (pdata) {
|
||||
cell->platform_data = pdata->gpo;
|
||||
cell->pdata_size = sizeof(*pdata->gpo);
|
||||
}
|
||||
children++;
|
||||
}
|
||||
|
||||
ret = mfd_add_devices(&client->dev, -1, twl6040->cells, children,
|
||||
NULL, 0, NULL);
|
||||
if (ret)
|
||||
|
|
|
@ -133,15 +133,109 @@ static const struct reg_default wm5110_reva_patch[] = {
|
|||
{ 0x209, 0x002A },
|
||||
};
|
||||
|
||||
static const struct reg_default wm5110_revb_patch[] = {
|
||||
{ 0x80, 0x3 },
|
||||
{ 0x36e, 0x0210 },
|
||||
{ 0x370, 0x0210 },
|
||||
{ 0x372, 0x0210 },
|
||||
{ 0x374, 0x0210 },
|
||||
{ 0x376, 0x0210 },
|
||||
{ 0x378, 0x0210 },
|
||||
{ 0x36d, 0x0028 },
|
||||
{ 0x36f, 0x0028 },
|
||||
{ 0x371, 0x0028 },
|
||||
{ 0x373, 0x0028 },
|
||||
{ 0x375, 0x0028 },
|
||||
{ 0x377, 0x0028 },
|
||||
{ 0x280, 0x2002 },
|
||||
{ 0x44, 0x20 },
|
||||
{ 0x45, 0x40 },
|
||||
{ 0x46, 0x60 },
|
||||
{ 0x47, 0x80 },
|
||||
{ 0x48, 0xa0 },
|
||||
{ 0x51, 0x13 },
|
||||
{ 0x52, 0x33 },
|
||||
{ 0x53, 0x53 },
|
||||
{ 0x54, 0x73 },
|
||||
{ 0x55, 0x93 },
|
||||
{ 0x56, 0xb3 },
|
||||
{ 0xc30, 0x3e3e },
|
||||
{ 0xc31, 0x3e },
|
||||
{ 0xc32, 0x3e3e },
|
||||
{ 0xc33, 0x3e3e },
|
||||
{ 0xc34, 0x3e3e },
|
||||
{ 0xc35, 0x3e3e },
|
||||
{ 0xc36, 0x3e3e },
|
||||
{ 0xc37, 0x3e3e },
|
||||
{ 0xc38, 0x3e3e },
|
||||
{ 0xc39, 0x3e3e },
|
||||
{ 0xc3a, 0x3e3e },
|
||||
{ 0xc3b, 0x3e3e },
|
||||
{ 0xc3c, 0x3e },
|
||||
{ 0x201, 0x18a5 },
|
||||
{ 0x202, 0x4100 },
|
||||
{ 0x460, 0x0c40 },
|
||||
{ 0x461, 0x8000 },
|
||||
{ 0x462, 0x0c41 },
|
||||
{ 0x463, 0x4820 },
|
||||
{ 0x464, 0x0c41 },
|
||||
{ 0x465, 0x4040 },
|
||||
{ 0x466, 0x0841 },
|
||||
{ 0x467, 0x3940 },
|
||||
{ 0x468, 0x0841 },
|
||||
{ 0x469, 0x2030 },
|
||||
{ 0x46a, 0x0842 },
|
||||
{ 0x46b, 0x1990 },
|
||||
{ 0x46c, 0x08c2 },
|
||||
{ 0x46d, 0x1450 },
|
||||
{ 0x46e, 0x08c6 },
|
||||
{ 0x46f, 0x1020 },
|
||||
{ 0x470, 0x08c6 },
|
||||
{ 0x471, 0x0cd0 },
|
||||
{ 0x472, 0x08c6 },
|
||||
{ 0x473, 0x0a30 },
|
||||
{ 0x474, 0x0442 },
|
||||
{ 0x475, 0x0660 },
|
||||
{ 0x476, 0x0446 },
|
||||
{ 0x477, 0x0510 },
|
||||
{ 0x478, 0x04c6 },
|
||||
{ 0x479, 0x0400 },
|
||||
{ 0x47a, 0x04ce },
|
||||
{ 0x47b, 0x0330 },
|
||||
{ 0x47c, 0x05df },
|
||||
{ 0x47d, 0x0001 },
|
||||
{ 0x47e, 0x07ff },
|
||||
{ 0x2db, 0x0a00 },
|
||||
{ 0x2dd, 0x0023 },
|
||||
{ 0x2df, 0x0102 },
|
||||
{ 0x2ef, 0x924 },
|
||||
{ 0x2f0, 0x924 },
|
||||
{ 0x2f1, 0x924 },
|
||||
{ 0x2f2, 0x924 },
|
||||
{ 0x2f3, 0x924 },
|
||||
{ 0x2f4, 0x924 },
|
||||
{ 0x2eb, 0x60 },
|
||||
{ 0x2ec, 0x60 },
|
||||
{ 0x2ed, 0x60 },
|
||||
{ 0x4f2, 0x33e },
|
||||
{ 0x458, 0x0000 },
|
||||
{ 0x15a, 0x0003 },
|
||||
{ 0x80, 0x0 },
|
||||
};
|
||||
|
||||
/* We use a function so we can use ARRAY_SIZE() */
|
||||
int wm5110_patch(struct arizona *arizona)
|
||||
{
|
||||
switch (arizona->rev) {
|
||||
case 0:
|
||||
case 1:
|
||||
return regmap_register_patch(arizona->regmap,
|
||||
wm5110_reva_patch,
|
||||
ARRAY_SIZE(wm5110_reva_patch));
|
||||
case 1:
|
||||
return regmap_register_patch(arizona->regmap,
|
||||
wm5110_revb_patch,
|
||||
ARRAY_SIZE(wm5110_revb_patch));
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -614,18 +614,11 @@ int wm831x_set_bits(struct wm831x *wm831x, unsigned short reg,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(wm831x_set_bits);
|
||||
|
||||
static struct resource wm831x_io_parent = {
|
||||
.start = 0,
|
||||
.end = 0xffffffff,
|
||||
.flags = IORESOURCE_IO,
|
||||
};
|
||||
|
||||
static struct resource wm831x_dcdc1_resources[] = {
|
||||
{
|
||||
.parent = &wm831x_io_parent,
|
||||
.start = WM831X_DC1_CONTROL_1,
|
||||
.end = WM831X_DC1_DVS_CONTROL,
|
||||
.flags = IORESOURCE_IO,
|
||||
.flags = IORESOURCE_REG,
|
||||
},
|
||||
{
|
||||
.name = "UV",
|
||||
|
@ -644,10 +637,9 @@ static struct resource wm831x_dcdc1_resources[] = {
|
|||
|
||||
static struct resource wm831x_dcdc2_resources[] = {
|
||||
{
|
||||
.parent = &wm831x_io_parent,
|
||||
.start = WM831X_DC2_CONTROL_1,
|
||||
.end = WM831X_DC2_DVS_CONTROL,
|
||||
.flags = IORESOURCE_IO,
|
||||
.flags = IORESOURCE_REG,
|
||||
},
|
||||
{
|
||||
.name = "UV",
|
||||
|
@ -665,10 +657,9 @@ static struct resource wm831x_dcdc2_resources[] = {
|
|||
|
||||
static struct resource wm831x_dcdc3_resources[] = {
|
||||
{
|
||||
.parent = &wm831x_io_parent,
|
||||
.start = WM831X_DC3_CONTROL_1,
|
||||
.end = WM831X_DC3_SLEEP_CONTROL,
|
||||
.flags = IORESOURCE_IO,
|
||||
.flags = IORESOURCE_REG,
|
||||
},
|
||||
{
|
||||
.name = "UV",
|
||||
|
@ -680,10 +671,9 @@ static struct resource wm831x_dcdc3_resources[] = {
|
|||
|
||||
static struct resource wm831x_dcdc4_resources[] = {
|
||||
{
|
||||
.parent = &wm831x_io_parent,
|
||||
.start = WM831X_DC4_CONTROL,
|
||||
.end = WM831X_DC4_SLEEP_CONTROL,
|
||||
.flags = IORESOURCE_IO,
|
||||
.flags = IORESOURCE_REG,
|
||||
},
|
||||
{
|
||||
.name = "UV",
|
||||
|
@ -695,10 +685,9 @@ static struct resource wm831x_dcdc4_resources[] = {
|
|||
|
||||
static struct resource wm8320_dcdc4_buck_resources[] = {
|
||||
{
|
||||
.parent = &wm831x_io_parent,
|
||||
.start = WM831X_DC4_CONTROL,
|
||||
.end = WM832X_DC4_SLEEP_CONTROL,
|
||||
.flags = IORESOURCE_IO,
|
||||
.flags = IORESOURCE_REG,
|
||||
},
|
||||
{
|
||||
.name = "UV",
|
||||
|
@ -718,10 +707,9 @@ static struct resource wm831x_gpio_resources[] = {
|
|||
|
||||
static struct resource wm831x_isink1_resources[] = {
|
||||
{
|
||||
.parent = &wm831x_io_parent,
|
||||
.start = WM831X_CURRENT_SINK_1,
|
||||
.end = WM831X_CURRENT_SINK_1,
|
||||
.flags = IORESOURCE_IO,
|
||||
.flags = IORESOURCE_REG,
|
||||
},
|
||||
{
|
||||
.start = WM831X_IRQ_CS1,
|
||||
|
@ -732,10 +720,9 @@ static struct resource wm831x_isink1_resources[] = {
|
|||
|
||||
static struct resource wm831x_isink2_resources[] = {
|
||||
{
|
||||
.parent = &wm831x_io_parent,
|
||||
.start = WM831X_CURRENT_SINK_2,
|
||||
.end = WM831X_CURRENT_SINK_2,
|
||||
.flags = IORESOURCE_IO,
|
||||
.flags = IORESOURCE_REG,
|
||||
},
|
||||
{
|
||||
.start = WM831X_IRQ_CS2,
|
||||
|
@ -746,10 +733,9 @@ static struct resource wm831x_isink2_resources[] = {
|
|||
|
||||
static struct resource wm831x_ldo1_resources[] = {
|
||||
{
|
||||
.parent = &wm831x_io_parent,
|
||||
.start = WM831X_LDO1_CONTROL,
|
||||
.end = WM831X_LDO1_SLEEP_CONTROL,
|
||||
.flags = IORESOURCE_IO,
|
||||
.flags = IORESOURCE_REG,
|
||||
},
|
||||
{
|
||||
.name = "UV",
|
||||
|
@ -761,10 +747,9 @@ static struct resource wm831x_ldo1_resources[] = {
|
|||
|
||||
static struct resource wm831x_ldo2_resources[] = {
|
||||
{
|
||||
.parent = &wm831x_io_parent,
|
||||
.start = WM831X_LDO2_CONTROL,
|
||||
.end = WM831X_LDO2_SLEEP_CONTROL,
|
||||
.flags = IORESOURCE_IO,
|
||||
.flags = IORESOURCE_REG,
|
||||
},
|
||||
{
|
||||
.name = "UV",
|
||||
|
@ -776,10 +761,9 @@ static struct resource wm831x_ldo2_resources[] = {
|
|||
|
||||
static struct resource wm831x_ldo3_resources[] = {
|
||||
{
|
||||
.parent = &wm831x_io_parent,
|
||||
.start = WM831X_LDO3_CONTROL,
|
||||
.end = WM831X_LDO3_SLEEP_CONTROL,
|
||||
.flags = IORESOURCE_IO,
|
||||
.flags = IORESOURCE_REG,
|
||||
},
|
||||
{
|
||||
.name = "UV",
|
||||
|
@ -791,10 +775,9 @@ static struct resource wm831x_ldo3_resources[] = {
|
|||
|
||||
static struct resource wm831x_ldo4_resources[] = {
|
||||
{
|
||||
.parent = &wm831x_io_parent,
|
||||
.start = WM831X_LDO4_CONTROL,
|
||||
.end = WM831X_LDO4_SLEEP_CONTROL,
|
||||
.flags = IORESOURCE_IO,
|
||||
.flags = IORESOURCE_REG,
|
||||
},
|
||||
{
|
||||
.name = "UV",
|
||||
|
@ -806,10 +789,9 @@ static struct resource wm831x_ldo4_resources[] = {
|
|||
|
||||
static struct resource wm831x_ldo5_resources[] = {
|
||||
{
|
||||
.parent = &wm831x_io_parent,
|
||||
.start = WM831X_LDO5_CONTROL,
|
||||
.end = WM831X_LDO5_SLEEP_CONTROL,
|
||||
.flags = IORESOURCE_IO,
|
||||
.flags = IORESOURCE_REG,
|
||||
},
|
||||
{
|
||||
.name = "UV",
|
||||
|
@ -821,10 +803,9 @@ static struct resource wm831x_ldo5_resources[] = {
|
|||
|
||||
static struct resource wm831x_ldo6_resources[] = {
|
||||
{
|
||||
.parent = &wm831x_io_parent,
|
||||
.start = WM831X_LDO6_CONTROL,
|
||||
.end = WM831X_LDO6_SLEEP_CONTROL,
|
||||
.flags = IORESOURCE_IO,
|
||||
.flags = IORESOURCE_REG,
|
||||
},
|
||||
{
|
||||
.name = "UV",
|
||||
|
@ -836,10 +817,9 @@ static struct resource wm831x_ldo6_resources[] = {
|
|||
|
||||
static struct resource wm831x_ldo7_resources[] = {
|
||||
{
|
||||
.parent = &wm831x_io_parent,
|
||||
.start = WM831X_LDO7_CONTROL,
|
||||
.end = WM831X_LDO7_SLEEP_CONTROL,
|
||||
.flags = IORESOURCE_IO,
|
||||
.flags = IORESOURCE_REG,
|
||||
},
|
||||
{
|
||||
.name = "UV",
|
||||
|
@ -851,10 +831,9 @@ static struct resource wm831x_ldo7_resources[] = {
|
|||
|
||||
static struct resource wm831x_ldo8_resources[] = {
|
||||
{
|
||||
.parent = &wm831x_io_parent,
|
||||
.start = WM831X_LDO8_CONTROL,
|
||||
.end = WM831X_LDO8_SLEEP_CONTROL,
|
||||
.flags = IORESOURCE_IO,
|
||||
.flags = IORESOURCE_REG,
|
||||
},
|
||||
{
|
||||
.name = "UV",
|
||||
|
@ -866,10 +845,9 @@ static struct resource wm831x_ldo8_resources[] = {
|
|||
|
||||
static struct resource wm831x_ldo9_resources[] = {
|
||||
{
|
||||
.parent = &wm831x_io_parent,
|
||||
.start = WM831X_LDO9_CONTROL,
|
||||
.end = WM831X_LDO9_SLEEP_CONTROL,
|
||||
.flags = IORESOURCE_IO,
|
||||
.flags = IORESOURCE_REG,
|
||||
},
|
||||
{
|
||||
.name = "UV",
|
||||
|
@ -881,10 +859,9 @@ static struct resource wm831x_ldo9_resources[] = {
|
|||
|
||||
static struct resource wm831x_ldo10_resources[] = {
|
||||
{
|
||||
.parent = &wm831x_io_parent,
|
||||
.start = WM831X_LDO10_CONTROL,
|
||||
.end = WM831X_LDO10_SLEEP_CONTROL,
|
||||
.flags = IORESOURCE_IO,
|
||||
.flags = IORESOURCE_REG,
|
||||
},
|
||||
{
|
||||
.name = "UV",
|
||||
|
@ -896,10 +873,9 @@ static struct resource wm831x_ldo10_resources[] = {
|
|||
|
||||
static struct resource wm831x_ldo11_resources[] = {
|
||||
{
|
||||
.parent = &wm831x_io_parent,
|
||||
.start = WM831X_LDO11_ON_CONTROL,
|
||||
.end = WM831X_LDO11_SLEEP_CONTROL,
|
||||
.flags = IORESOURCE_IO,
|
||||
.flags = IORESOURCE_REG,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -998,19 +974,17 @@ static struct resource wm831x_rtc_resources[] = {
|
|||
|
||||
static struct resource wm831x_status1_resources[] = {
|
||||
{
|
||||
.parent = &wm831x_io_parent,
|
||||
.start = WM831X_STATUS_LED_1,
|
||||
.end = WM831X_STATUS_LED_1,
|
||||
.flags = IORESOURCE_IO,
|
||||
.flags = IORESOURCE_REG,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource wm831x_status2_resources[] = {
|
||||
{
|
||||
.parent = &wm831x_io_parent,
|
||||
.start = WM831X_STATUS_LED_2,
|
||||
.end = WM831X_STATUS_LED_2,
|
||||
.flags = IORESOURCE_IO,
|
||||
.flags = IORESOURCE_REG,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -390,7 +390,7 @@ static const __devinitdata struct reg_default wm8958_reva_patch[] = {
|
|||
|
||||
static const __devinitdata struct reg_default wm1811_reva_patch[] = {
|
||||
{ 0x102, 0x3 },
|
||||
{ 0x56, 0x7 },
|
||||
{ 0x56, 0xc07 },
|
||||
{ 0x5d, 0x7e },
|
||||
{ 0x5e, 0x0 },
|
||||
{ 0x102, 0x0 },
|
||||
|
|
|
@ -1136,7 +1136,7 @@ static bool wm1811_volatile_register(struct device *dev, unsigned int reg)
|
|||
|
||||
switch (reg) {
|
||||
case WM8994_GPIO_6:
|
||||
if (wm8994->revision > 1)
|
||||
if (wm8994->cust_id > 1 || wm8994->revision > 1)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
|
|
|
@ -115,6 +115,15 @@ config PWM_TIEHRPWM
|
|||
To compile this driver as a module, choose M here: the module
|
||||
will be called pwm-tiehrpwm.
|
||||
|
||||
config PWM_TWL6030
|
||||
tristate "TWL6030 PWM support"
|
||||
depends on TWL4030_CORE
|
||||
help
|
||||
Generic PWM framework driver for TWL6030.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called pwm-twl6030.
|
||||
|
||||
config PWM_VT8500
|
||||
tristate "vt8500 pwm support"
|
||||
depends on ARCH_VT8500
|
||||
|
|
|
@ -8,4 +8,5 @@ obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
|
|||
obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o
|
||||
obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o
|
||||
obj-$(CONFIG_PWM_TIEHRPWM) += pwm-tiehrpwm.o
|
||||
obj-$(CONFIG_PWM_TWL6030) += pwm-twl6030.o
|
||||
obj-$(CONFIG_PWM_VT8500) += pwm-vt8500.o
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pwm.h>
|
||||
#include <linux/i2c/twl.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
|
@ -45,40 +46,54 @@
|
|||
|
||||
#define PWM_CTRL2_MODE_MASK 0x3
|
||||
|
||||
struct pwm_device {
|
||||
const char *label;
|
||||
unsigned int pwm_id;
|
||||
struct twl6030_pwm_chip {
|
||||
struct pwm_chip chip;
|
||||
};
|
||||
|
||||
int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
|
||||
static int twl6030_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
u8 duty_cycle;
|
||||
int ret;
|
||||
u8 val;
|
||||
|
||||
/* Configure PWM */
|
||||
val = PWM_CTRL2_DIS_PD | PWM_CTRL2_CURR_02 | PWM_CTRL2_SRC_VAC |
|
||||
PWM_CTRL2_MODE_HW;
|
||||
|
||||
ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "%s: Failed to configure PWM, Error %d\n",
|
||||
pwm->label, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int twl6030_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
int duty_ns, int period_ns)
|
||||
{
|
||||
u8 duty_cycle = (duty_ns * PWM_CTRL1_MAX) / period_ns;
|
||||
int ret;
|
||||
|
||||
if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
|
||||
return -EINVAL;
|
||||
|
||||
duty_cycle = (duty_ns * PWM_CTRL1_MAX) / period_ns;
|
||||
|
||||
ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, duty_cycle, LED_PWM_CTRL1);
|
||||
|
||||
if (ret < 0) {
|
||||
pr_err("%s: Failed to configure PWM, Error %d\n",
|
||||
pwm->label, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(pwm_config);
|
||||
|
||||
int pwm_enable(struct pwm_device *pwm)
|
||||
static int twl6030_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
u8 val;
|
||||
int ret;
|
||||
u8 val;
|
||||
|
||||
ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2);
|
||||
if (ret < 0) {
|
||||
pr_err("%s: Failed to enable PWM, Error %d\n", pwm->label, ret);
|
||||
dev_err(chip->dev, "%s: Failed to enable PWM, Error %d\n",
|
||||
pwm->label, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -88,23 +103,23 @@ int pwm_enable(struct pwm_device *pwm)
|
|||
|
||||
ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2);
|
||||
if (ret < 0) {
|
||||
pr_err("%s: Failed to enable PWM, Error %d\n", pwm->label, ret);
|
||||
dev_err(chip->dev, "%s: Failed to enable PWM, Error %d\n",
|
||||
pwm->label, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(pwm_enable);
|
||||
|
||||
void pwm_disable(struct pwm_device *pwm)
|
||||
static void twl6030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
u8 val;
|
||||
int ret;
|
||||
u8 val;
|
||||
|
||||
ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2);
|
||||
if (ret < 0) {
|
||||
pr_err("%s: Failed to disable PWM, Error %d\n",
|
||||
dev_err(chip->dev, "%s: Failed to disable PWM, Error %d\n",
|
||||
pwm->label, ret);
|
||||
return;
|
||||
}
|
||||
|
@ -114,52 +129,56 @@ void pwm_disable(struct pwm_device *pwm)
|
|||
|
||||
ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2);
|
||||
if (ret < 0) {
|
||||
pr_err("%s: Failed to disable PWM, Error %d\n",
|
||||
dev_err(chip->dev, "%s: Failed to disable PWM, Error %d\n",
|
||||
pwm->label, ret);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL(pwm_disable);
|
||||
|
||||
struct pwm_device *pwm_request(int pwm_id, const char *label)
|
||||
static const struct pwm_ops twl6030_pwm_ops = {
|
||||
.request = twl6030_pwm_request,
|
||||
.config = twl6030_pwm_config,
|
||||
.enable = twl6030_pwm_enable,
|
||||
.disable = twl6030_pwm_disable,
|
||||
};
|
||||
|
||||
static int twl6030_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
u8 val;
|
||||
struct twl6030_pwm_chip *twl6030;
|
||||
int ret;
|
||||
struct pwm_device *pwm;
|
||||
|
||||
pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
|
||||
if (pwm == NULL) {
|
||||
pr_err("%s: failed to allocate memory\n", label);
|
||||
return NULL;
|
||||
}
|
||||
twl6030 = devm_kzalloc(&pdev->dev, sizeof(*twl6030), GFP_KERNEL);
|
||||
if (!twl6030)
|
||||
return -ENOMEM;
|
||||
|
||||
pwm->label = label;
|
||||
pwm->pwm_id = pwm_id;
|
||||
twl6030->chip.dev = &pdev->dev;
|
||||
twl6030->chip.ops = &twl6030_pwm_ops;
|
||||
twl6030->chip.base = -1;
|
||||
twl6030->chip.npwm = 1;
|
||||
|
||||
/* Configure PWM */
|
||||
val = PWM_CTRL2_DIS_PD | PWM_CTRL2_CURR_02 | PWM_CTRL2_SRC_VAC |
|
||||
PWM_CTRL2_MODE_HW;
|
||||
ret = pwmchip_add(&twl6030->chip);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2);
|
||||
platform_set_drvdata(pdev, twl6030);
|
||||
|
||||
if (ret < 0) {
|
||||
pr_err("%s: Failed to configure PWM, Error %d\n",
|
||||
pwm->label, ret);
|
||||
|
||||
kfree(pwm);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pwm;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(pwm_request);
|
||||
|
||||
void pwm_free(struct pwm_device *pwm)
|
||||
static int twl6030_pwm_remove(struct platform_device *pdev)
|
||||
{
|
||||
pwm_disable(pwm);
|
||||
kfree(pwm);
|
||||
}
|
||||
EXPORT_SYMBOL(pwm_free);
|
||||
struct twl6030_pwm_chip *twl6030 = platform_get_drvdata(pdev);
|
||||
|
||||
return pwmchip_remove(&twl6030->chip);
|
||||
}
|
||||
|
||||
static struct platform_driver twl6030_pwm_driver = {
|
||||
.driver = {
|
||||
.name = "twl6030-pwm",
|
||||
},
|
||||
.probe = twl6030_pwm_probe,
|
||||
.remove = __devexit_p(twl6030_pwm_remove),
|
||||
};
|
||||
module_platform_driver(twl6030_pwm_driver);
|
||||
|
||||
MODULE_ALIAS("platform:twl6030-pwm");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -12,6 +12,8 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regulator/of_regulator.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
|
@ -23,6 +25,7 @@ struct pm8607_regulator_info {
|
|||
struct pm860x_chip *chip;
|
||||
struct regulator_dev *regulator;
|
||||
struct i2c_client *i2c;
|
||||
struct i2c_client *i2c_8606;
|
||||
|
||||
unsigned int *vol_table;
|
||||
unsigned int *vol_suspend;
|
||||
|
@ -242,6 +245,35 @@ static int pm8607_set_voltage_sel(struct regulator_dev *rdev, unsigned selector)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int pm8606_preg_enable(struct regulator_dev *rdev)
|
||||
{
|
||||
struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
|
||||
|
||||
return pm860x_set_bits(info->i2c, rdev->desc->enable_reg,
|
||||
1 << rdev->desc->enable_mask, 0);
|
||||
}
|
||||
|
||||
static int pm8606_preg_disable(struct regulator_dev *rdev)
|
||||
{
|
||||
struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
|
||||
|
||||
return pm860x_set_bits(info->i2c, rdev->desc->enable_reg,
|
||||
1 << rdev->desc->enable_mask,
|
||||
1 << rdev->desc->enable_mask);
|
||||
}
|
||||
|
||||
static int pm8606_preg_is_enabled(struct regulator_dev *rdev)
|
||||
{
|
||||
struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
|
||||
int ret;
|
||||
|
||||
ret = pm860x_reg_read(info->i2c, rdev->desc->enable_reg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return !((unsigned char)ret & (1 << rdev->desc->enable_mask));
|
||||
}
|
||||
|
||||
static struct regulator_ops pm8607_regulator_ops = {
|
||||
.list_voltage = pm8607_list_voltage,
|
||||
.set_voltage_sel = pm8607_set_voltage_sel,
|
||||
|
@ -251,6 +283,25 @@ static struct regulator_ops pm8607_regulator_ops = {
|
|||
.is_enabled = regulator_is_enabled_regmap,
|
||||
};
|
||||
|
||||
static struct regulator_ops pm8606_preg_ops = {
|
||||
.enable = pm8606_preg_enable,
|
||||
.disable = pm8606_preg_disable,
|
||||
.is_enabled = pm8606_preg_is_enabled,
|
||||
};
|
||||
|
||||
#define PM8606_PREG(ereg, ebit) \
|
||||
{ \
|
||||
.desc = { \
|
||||
.name = "PREG", \
|
||||
.ops = &pm8606_preg_ops, \
|
||||
.type = REGULATOR_CURRENT, \
|
||||
.id = PM8606_ID_PREG, \
|
||||
.owner = THIS_MODULE, \
|
||||
.enable_reg = PM8606_##ereg, \
|
||||
.enable_mask = (ebit), \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define PM8607_DVC(vreg, ureg, ubit, ereg, ebit) \
|
||||
{ \
|
||||
.desc = { \
|
||||
|
@ -311,6 +362,38 @@ static struct pm8607_regulator_info pm8607_regulator_info[] = {
|
|||
PM8607_LDO(14, LDO14, 0, SUPPLIES_EN12, 6),
|
||||
};
|
||||
|
||||
static struct pm8607_regulator_info pm8606_regulator_info[] = {
|
||||
PM8606_PREG(PREREGULATORB, 5),
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int pm8607_regulator_dt_init(struct platform_device *pdev,
|
||||
struct pm8607_regulator_info *info,
|
||||
struct regulator_config *config)
|
||||
{
|
||||
struct device_node *nproot, *np;
|
||||
nproot = pdev->dev.parent->of_node;
|
||||
if (!nproot)
|
||||
return -ENODEV;
|
||||
nproot = of_find_node_by_name(nproot, "regulators");
|
||||
if (!nproot) {
|
||||
dev_err(&pdev->dev, "failed to find regulators node\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
for_each_child_of_node(nproot, np) {
|
||||
if (!of_node_cmp(np->name, info->desc.name)) {
|
||||
config->init_data =
|
||||
of_get_regulator_init_data(&pdev->dev, np);
|
||||
config->of_node = np;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define pm8607_regulator_dt_init(x, y, z) (-1)
|
||||
#endif
|
||||
|
||||
static int __devinit pm8607_regulator_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
|
||||
|
@ -320,22 +403,28 @@ static int __devinit pm8607_regulator_probe(struct platform_device *pdev)
|
|||
struct resource *res;
|
||||
int i;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
if (res == NULL) {
|
||||
dev_err(&pdev->dev, "No I/O resource!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) {
|
||||
info = &pm8607_regulator_info[i];
|
||||
if (info->desc.id == res->start)
|
||||
break;
|
||||
}
|
||||
if (i == ARRAY_SIZE(pm8607_regulator_info)) {
|
||||
dev_err(&pdev->dev, "Failed to find regulator %llu\n",
|
||||
(unsigned long long)res->start);
|
||||
return -EINVAL;
|
||||
res = platform_get_resource(pdev, IORESOURCE_REG, 0);
|
||||
if (res) {
|
||||
/* There're resources in 88PM8607 regulator driver */
|
||||
for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) {
|
||||
info = &pm8607_regulator_info[i];
|
||||
if (info->desc.vsel_reg == res->start)
|
||||
break;
|
||||
}
|
||||
if (i == ARRAY_SIZE(pm8607_regulator_info)) {
|
||||
dev_err(&pdev->dev, "Failed to find regulator %llu\n",
|
||||
(unsigned long long)res->start);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
/* There's no resource in 88PM8606 PREG regulator driver */
|
||||
info = &pm8606_regulator_info[0];
|
||||
/* i is used to check regulator ID */
|
||||
i = -1;
|
||||
}
|
||||
info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
|
||||
info->i2c_8606 = (chip->id == CHIP_PM8607) ? chip->companion :
|
||||
chip->client;
|
||||
info->chip = chip;
|
||||
|
||||
/* check DVC ramp slope double */
|
||||
|
@ -343,15 +432,17 @@ static int __devinit pm8607_regulator_probe(struct platform_device *pdev)
|
|||
info->slope_double = 1;
|
||||
|
||||
config.dev = &pdev->dev;
|
||||
config.init_data = pdata;
|
||||
config.driver_data = info;
|
||||
|
||||
if (pm8607_regulator_dt_init(pdev, info, &config))
|
||||
if (pdata)
|
||||
config.init_data = pdata;
|
||||
|
||||
if (chip->id == CHIP_PM8607)
|
||||
config.regmap = chip->regmap;
|
||||
else
|
||||
config.regmap = chip->regmap_companion;
|
||||
|
||||
/* replace driver_data with info */
|
||||
info->regulator = regulator_register(&info->desc, &config);
|
||||
if (IS_ERR(info->regulator)) {
|
||||
dev_err(&pdev->dev, "failed to register regulator %s\n",
|
||||
|
@ -372,6 +463,18 @@ static int __devexit pm8607_regulator_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_device_id pm8607_regulator_driver_ids[] = {
|
||||
{
|
||||
.name = "88pm860x-regulator",
|
||||
.driver_data = 0,
|
||||
}, {
|
||||
.name = "88pm860x-preg",
|
||||
.driver_data = 0,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, pm8607_regulator_driver_ids);
|
||||
|
||||
static struct platform_driver pm8607_regulator_driver = {
|
||||
.driver = {
|
||||
.name = "88pm860x-regulator",
|
||||
|
@ -379,6 +482,7 @@ static struct platform_driver pm8607_regulator_driver = {
|
|||
},
|
||||
.probe = pm8607_regulator_probe,
|
||||
.remove = __devexit_p(pm8607_regulator_remove),
|
||||
.id_table = pm8607_regulator_driver_ids,
|
||||
};
|
||||
|
||||
static int __init pm8607_regulator_init(void)
|
||||
|
|
|
@ -122,7 +122,7 @@ config REGULATOR_FAN53555
|
|||
|
||||
config REGULATOR_ANATOP
|
||||
tristate "Freescale i.MX on-chip ANATOP LDO regulators"
|
||||
depends on MFD_ANATOP
|
||||
depends on MFD_SYSCON
|
||||
help
|
||||
Say y here to support Freescale i.MX on-chip ANATOP LDOs
|
||||
regulators. It is recommended that this option be
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <linux/err.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/mfd/ab3100.h>
|
||||
#include <linux/mfd/abx500.h>
|
||||
|
||||
/* LDO registers and some handy masking definitions for AB3100 */
|
||||
|
|
|
@ -21,19 +21,20 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/mfd/anatop.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/regulator/of_regulator.h>
|
||||
|
||||
struct anatop_regulator {
|
||||
const char *name;
|
||||
u32 control_reg;
|
||||
struct anatop *mfd;
|
||||
struct regmap *anatop;
|
||||
int vol_bit_shift;
|
||||
int vol_bit_width;
|
||||
int min_bit_val;
|
||||
|
@ -43,7 +44,8 @@ struct anatop_regulator {
|
|||
struct regulator_init_data *initdata;
|
||||
};
|
||||
|
||||
static int anatop_set_voltage_sel(struct regulator_dev *reg, unsigned selector)
|
||||
static int anatop_regmap_set_voltage_sel(struct regulator_dev *reg,
|
||||
unsigned selector)
|
||||
{
|
||||
struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
|
||||
u32 val, mask;
|
||||
|
@ -56,12 +58,13 @@ static int anatop_set_voltage_sel(struct regulator_dev *reg, unsigned selector)
|
|||
mask = ((1 << anatop_reg->vol_bit_width) - 1) <<
|
||||
anatop_reg->vol_bit_shift;
|
||||
val <<= anatop_reg->vol_bit_shift;
|
||||
anatop_write_reg(anatop_reg->mfd, anatop_reg->control_reg, val, mask);
|
||||
regmap_update_bits(anatop_reg->anatop, anatop_reg->control_reg,
|
||||
mask, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int anatop_get_voltage_sel(struct regulator_dev *reg)
|
||||
static int anatop_regmap_get_voltage_sel(struct regulator_dev *reg)
|
||||
{
|
||||
struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
|
||||
u32 val, mask;
|
||||
|
@ -69,7 +72,7 @@ static int anatop_get_voltage_sel(struct regulator_dev *reg)
|
|||
if (!anatop_reg->control_reg)
|
||||
return -ENOTSUPP;
|
||||
|
||||
val = anatop_read_reg(anatop_reg->mfd, anatop_reg->control_reg);
|
||||
regmap_read(anatop_reg->anatop, anatop_reg->control_reg, &val);
|
||||
mask = ((1 << anatop_reg->vol_bit_width) - 1) <<
|
||||
anatop_reg->vol_bit_shift;
|
||||
val = (val & mask) >> anatop_reg->vol_bit_shift;
|
||||
|
@ -78,8 +81,8 @@ static int anatop_get_voltage_sel(struct regulator_dev *reg)
|
|||
}
|
||||
|
||||
static struct regulator_ops anatop_rops = {
|
||||
.set_voltage_sel = anatop_set_voltage_sel,
|
||||
.get_voltage_sel = anatop_get_voltage_sel,
|
||||
.set_voltage_sel = anatop_regmap_set_voltage_sel,
|
||||
.get_voltage_sel = anatop_regmap_get_voltage_sel,
|
||||
.list_voltage = regulator_list_voltage_linear,
|
||||
.map_voltage = regulator_map_voltage_linear,
|
||||
};
|
||||
|
@ -88,11 +91,11 @@ static int __devinit anatop_regulator_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct device_node *anatop_np;
|
||||
struct regulator_desc *rdesc;
|
||||
struct regulator_dev *rdev;
|
||||
struct anatop_regulator *sreg;
|
||||
struct regulator_init_data *initdata;
|
||||
struct anatop *anatopmfd = dev_get_drvdata(pdev->dev.parent);
|
||||
struct regulator_config config = { };
|
||||
int ret = 0;
|
||||
|
||||
|
@ -109,7 +112,15 @@ static int __devinit anatop_regulator_probe(struct platform_device *pdev)
|
|||
rdesc->ops = &anatop_rops;
|
||||
rdesc->type = REGULATOR_VOLTAGE;
|
||||
rdesc->owner = THIS_MODULE;
|
||||
sreg->mfd = anatopmfd;
|
||||
|
||||
anatop_np = of_get_parent(np);
|
||||
if (!anatop_np)
|
||||
return -ENODEV;
|
||||
sreg->anatop = syscon_node_to_regmap(anatop_np);
|
||||
of_node_put(anatop_np);
|
||||
if (IS_ERR(sreg->anatop))
|
||||
return PTR_ERR(sreg->anatop);
|
||||
|
||||
ret = of_property_read_u32(np, "anatop-reg-offset",
|
||||
&sreg->control_reg);
|
||||
if (ret) {
|
||||
|
|
|
@ -214,37 +214,36 @@ static struct max8925_regulator_info max8925_regulator_info[] = {
|
|||
MAX8925_LDO(20, 750, 3900, 50),
|
||||
};
|
||||
|
||||
static struct max8925_regulator_info * __devinit find_regulator_info(int id)
|
||||
{
|
||||
struct max8925_regulator_info *ri;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(max8925_regulator_info); i++) {
|
||||
ri = &max8925_regulator_info[i];
|
||||
if (ri->desc.id == id)
|
||||
return ri;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int __devinit max8925_regulator_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
|
||||
struct max8925_platform_data *pdata = chip->dev->platform_data;
|
||||
struct regulator_init_data *pdata = pdev->dev.platform_data;
|
||||
struct regulator_config config = { };
|
||||
struct max8925_regulator_info *ri;
|
||||
struct resource *res;
|
||||
struct regulator_dev *rdev;
|
||||
int i;
|
||||
|
||||
ri = find_regulator_info(pdev->id);
|
||||
if (ri == NULL) {
|
||||
dev_err(&pdev->dev, "invalid regulator ID specified\n");
|
||||
res = platform_get_resource(pdev, IORESOURCE_REG, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "No REG resource!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(max8925_regulator_info); i++) {
|
||||
ri = &max8925_regulator_info[i];
|
||||
if (ri->vol_reg == res->start)
|
||||
break;
|
||||
}
|
||||
if (i == ARRAY_SIZE(max8925_regulator_info)) {
|
||||
dev_err(&pdev->dev, "Failed to find regulator %llu\n",
|
||||
(unsigned long long)res->start);
|
||||
return -EINVAL;
|
||||
}
|
||||
ri->i2c = chip->i2c;
|
||||
ri->chip = chip;
|
||||
|
||||
config.dev = &pdev->dev;
|
||||
config.init_data = pdata->regulator[pdev->id];
|
||||
config.init_data = pdata;
|
||||
config.driver_data = ri;
|
||||
|
||||
rdev = regulator_register(&ri->desc, &config);
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/mfd/palmas.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/regulator/of_regulator.h>
|
||||
|
||||
struct regs_info {
|
||||
char *name;
|
||||
|
@ -568,10 +571,103 @@ static int palmas_ldo_init(struct palmas *palmas, int id,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct of_regulator_match palmas_matches[] = {
|
||||
{ .name = "smps12", },
|
||||
{ .name = "smps123", },
|
||||
{ .name = "smps3", },
|
||||
{ .name = "smps45", },
|
||||
{ .name = "smps457", },
|
||||
{ .name = "smps6", },
|
||||
{ .name = "smps7", },
|
||||
{ .name = "smps8", },
|
||||
{ .name = "smps9", },
|
||||
{ .name = "smps10", },
|
||||
{ .name = "ldo1", },
|
||||
{ .name = "ldo2", },
|
||||
{ .name = "ldo3", },
|
||||
{ .name = "ldo4", },
|
||||
{ .name = "ldo5", },
|
||||
{ .name = "ldo6", },
|
||||
{ .name = "ldo7", },
|
||||
{ .name = "ldo8", },
|
||||
{ .name = "ldo9", },
|
||||
{ .name = "ldoln", },
|
||||
{ .name = "ldousb", },
|
||||
};
|
||||
|
||||
static void __devinit palmas_dt_to_pdata(struct device *dev,
|
||||
struct device_node *node,
|
||||
struct palmas_pmic_platform_data *pdata)
|
||||
{
|
||||
struct device_node *regulators;
|
||||
u32 prop;
|
||||
int idx, ret;
|
||||
|
||||
regulators = of_find_node_by_name(node, "regulators");
|
||||
if (!regulators) {
|
||||
dev_info(dev, "regulator node not found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = of_regulator_match(dev, regulators, palmas_matches,
|
||||
PALMAS_NUM_REGS);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Error parsing regulator init data: %d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
for (idx = 0; idx < PALMAS_NUM_REGS; idx++) {
|
||||
if (!palmas_matches[idx].init_data ||
|
||||
!palmas_matches[idx].of_node)
|
||||
continue;
|
||||
|
||||
pdata->reg_data[idx] = palmas_matches[idx].init_data;
|
||||
|
||||
pdata->reg_init[idx] = devm_kzalloc(dev,
|
||||
sizeof(struct palmas_reg_init), GFP_KERNEL);
|
||||
|
||||
ret = of_property_read_u32(palmas_matches[idx].of_node,
|
||||
"ti,warm_reset", &prop);
|
||||
if (!ret)
|
||||
pdata->reg_init[idx]->warm_reset = prop;
|
||||
|
||||
ret = of_property_read_u32(palmas_matches[idx].of_node,
|
||||
"ti,roof_floor", &prop);
|
||||
if (!ret)
|
||||
pdata->reg_init[idx]->roof_floor = prop;
|
||||
|
||||
ret = of_property_read_u32(palmas_matches[idx].of_node,
|
||||
"ti,mode_sleep", &prop);
|
||||
if (!ret)
|
||||
pdata->reg_init[idx]->mode_sleep = prop;
|
||||
|
||||
ret = of_property_read_u32(palmas_matches[idx].of_node,
|
||||
"ti,warm_reset", &prop);
|
||||
if (!ret)
|
||||
pdata->reg_init[idx]->warm_reset = prop;
|
||||
|
||||
ret = of_property_read_u32(palmas_matches[idx].of_node,
|
||||
"ti,tstep", &prop);
|
||||
if (!ret)
|
||||
pdata->reg_init[idx]->tstep = prop;
|
||||
|
||||
ret = of_property_read_u32(palmas_matches[idx].of_node,
|
||||
"ti,vsel", &prop);
|
||||
if (!ret)
|
||||
pdata->reg_init[idx]->vsel = prop;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(node, "ti,ldo6_vibrator", &prop);
|
||||
if (!ret)
|
||||
pdata->ldo6_vibrator = prop;
|
||||
}
|
||||
|
||||
|
||||
static __devinit int palmas_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);
|
||||
struct palmas_pmic_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
struct regulator_dev *rdev;
|
||||
struct regulator_config config = { };
|
||||
struct palmas_pmic *pmic;
|
||||
|
@ -579,10 +675,14 @@ static __devinit int palmas_probe(struct platform_device *pdev)
|
|||
int id = 0, ret;
|
||||
unsigned int addr, reg;
|
||||
|
||||
if (!pdata)
|
||||
return -EINVAL;
|
||||
if (!pdata->reg_data)
|
||||
return -EINVAL;
|
||||
if (node && !pdata) {
|
||||
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
|
||||
|
||||
if (!pdata)
|
||||
return -ENOMEM;
|
||||
|
||||
palmas_dt_to_pdata(&pdev->dev, node, pdata);
|
||||
}
|
||||
|
||||
pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
|
||||
if (!pmic)
|
||||
|
@ -661,7 +761,7 @@ static __devinit int palmas_probe(struct platform_device *pdev)
|
|||
pmic->desc[id].owner = THIS_MODULE;
|
||||
|
||||
/* Initialise sleep/init values from platform data */
|
||||
if (pdata && pdata->reg_init) {
|
||||
if (pdata) {
|
||||
reg_init = pdata->reg_init[id];
|
||||
if (reg_init) {
|
||||
ret = palmas_smps_init(palmas, id, reg_init);
|
||||
|
@ -685,11 +785,13 @@ static __devinit int palmas_probe(struct platform_device *pdev)
|
|||
pmic->range[id] = 1;
|
||||
}
|
||||
|
||||
if (pdata && pdata->reg_data)
|
||||
if (pdata)
|
||||
config.init_data = pdata->reg_data[id];
|
||||
else
|
||||
config.init_data = NULL;
|
||||
|
||||
config.of_node = palmas_matches[id].of_node;
|
||||
|
||||
rdev = regulator_register(&pmic->desc[id], &config);
|
||||
if (IS_ERR(rdev)) {
|
||||
dev_err(&pdev->dev,
|
||||
|
@ -726,11 +828,13 @@ static __devinit int palmas_probe(struct platform_device *pdev)
|
|||
palmas_regs_info[id].ctrl_addr);
|
||||
pmic->desc[id].enable_mask = PALMAS_LDO1_CTRL_MODE_ACTIVE;
|
||||
|
||||
if (pdata && pdata->reg_data)
|
||||
if (pdata)
|
||||
config.init_data = pdata->reg_data[id];
|
||||
else
|
||||
config.init_data = NULL;
|
||||
|
||||
config.of_node = palmas_matches[id].of_node;
|
||||
|
||||
rdev = regulator_register(&pmic->desc[id], &config);
|
||||
if (IS_ERR(rdev)) {
|
||||
dev_err(&pdev->dev,
|
||||
|
@ -744,7 +848,7 @@ static __devinit int palmas_probe(struct platform_device *pdev)
|
|||
pmic->rdev[id] = rdev;
|
||||
|
||||
/* Initialise sleep/init values from platform data */
|
||||
if (pdata->reg_init) {
|
||||
if (pdata) {
|
||||
reg_init = pdata->reg_init[id];
|
||||
if (reg_init) {
|
||||
ret = palmas_ldo_init(palmas, id, reg_init);
|
||||
|
@ -774,9 +878,15 @@ static int __devexit palmas_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id __devinitdata of_palmas_match_tbl[] = {
|
||||
{ .compatible = "ti,palmas-pmic", },
|
||||
{ /* end */ }
|
||||
};
|
||||
|
||||
static struct platform_driver palmas_driver = {
|
||||
.driver = {
|
||||
.name = "palmas-pmic",
|
||||
.of_match_table = of_palmas_match_tbl,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = palmas_probe,
|
||||
|
@ -799,3 +909,4 @@ MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>");
|
|||
MODULE_DESCRIPTION("Palmas voltage regulator driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:palmas-pmic");
|
||||
MODULE_DEVICE_TABLE(of, of_palmas_match_tbl);
|
||||
|
|
|
@ -475,9 +475,9 @@ static __devinit int wm831x_buckv_probe(struct platform_device *pdev)
|
|||
|
||||
dcdc->wm831x = wm831x;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
res = platform_get_resource(pdev, IORESOURCE_REG, 0);
|
||||
if (res == NULL) {
|
||||
dev_err(&pdev->dev, "No I/O resource\n");
|
||||
dev_err(&pdev->dev, "No REG resource\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
@ -650,9 +650,9 @@ static __devinit int wm831x_buckp_probe(struct platform_device *pdev)
|
|||
|
||||
dcdc->wm831x = wm831x;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
res = platform_get_resource(pdev, IORESOURCE_REG, 0);
|
||||
if (res == NULL) {
|
||||
dev_err(&pdev->dev, "No I/O resource\n");
|
||||
dev_err(&pdev->dev, "No REG resource\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
@ -794,9 +794,9 @@ static __devinit int wm831x_boostp_probe(struct platform_device *pdev)
|
|||
|
||||
dcdc->wm831x = wm831x;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
res = platform_get_resource(pdev, IORESOURCE_REG, 0);
|
||||
if (res == NULL) {
|
||||
dev_err(&pdev->dev, "No I/O resource\n");
|
||||
dev_err(&pdev->dev, "No REG resource\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
|
|
@ -172,9 +172,9 @@ static __devinit int wm831x_isink_probe(struct platform_device *pdev)
|
|||
|
||||
isink->wm831x = wm831x;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
res = platform_get_resource(pdev, IORESOURCE_REG, 0);
|
||||
if (res == NULL) {
|
||||
dev_err(&pdev->dev, "No I/O resource\n");
|
||||
dev_err(&pdev->dev, "No REG resource\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
|
|
@ -273,9 +273,9 @@ static __devinit int wm831x_gp_ldo_probe(struct platform_device *pdev)
|
|||
|
||||
ldo->wm831x = wm831x;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
res = platform_get_resource(pdev, IORESOURCE_REG, 0);
|
||||
if (res == NULL) {
|
||||
dev_err(&pdev->dev, "No I/O resource\n");
|
||||
dev_err(&pdev->dev, "No REG resource\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
@ -530,9 +530,9 @@ static __devinit int wm831x_aldo_probe(struct platform_device *pdev)
|
|||
|
||||
ldo->wm831x = wm831x;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
res = platform_get_resource(pdev, IORESOURCE_REG, 0);
|
||||
if (res == NULL) {
|
||||
dev_err(&pdev->dev, "No I/O resource\n");
|
||||
dev_err(&pdev->dev, "No REG resource\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
@ -687,9 +687,9 @@ static __devinit int wm831x_alive_ldo_probe(struct platform_device *pdev)
|
|||
|
||||
ldo->wm831x = wm831x;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
res = platform_get_resource(pdev, IORESOURCE_REG, 0);
|
||||
if (res == NULL) {
|
||||
dev_err(&pdev->dev, "No I/O resource\n");
|
||||
dev_err(&pdev->dev, "No REG resource\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mutex.h>
|
||||
|
@ -284,6 +285,28 @@ out:
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int __devinit pm860x_rtc_dt_init(struct platform_device *pdev,
|
||||
struct pm860x_rtc_info *info)
|
||||
{
|
||||
struct device_node *np = pdev->dev.parent->of_node;
|
||||
int ret;
|
||||
if (!np)
|
||||
return -ENODEV;
|
||||
np = of_find_node_by_name(np, "rtc");
|
||||
if (!np) {
|
||||
dev_err(&pdev->dev, "failed to find rtc node\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
ret = of_property_read_u32(np, "marvell,88pm860x-vrtc", &info->vrtc);
|
||||
if (ret)
|
||||
info->vrtc = 0;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define pm860x_rtc_dt_init(x, y) (-1)
|
||||
#endif
|
||||
|
||||
static int __devinit pm860x_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
|
||||
|
@ -294,8 +317,6 @@ static int __devinit pm860x_rtc_probe(struct platform_device *pdev)
|
|||
int ret;
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
if (pdata == NULL)
|
||||
dev_warn(&pdev->dev, "No platform data!\n");
|
||||
|
||||
info = kzalloc(sizeof(struct pm860x_rtc_info), GFP_KERNEL);
|
||||
if (!info)
|
||||
|
@ -345,9 +366,11 @@ static int __devinit pm860x_rtc_probe(struct platform_device *pdev)
|
|||
}
|
||||
}
|
||||
rtc_tm_to_time(&tm, &ticks);
|
||||
if (pdata && pdata->sync) {
|
||||
pdata->sync(ticks);
|
||||
info->sync = pdata->sync;
|
||||
if (pm860x_rtc_dt_init(pdev, info)) {
|
||||
if (pdata && pdata->sync) {
|
||||
pdata->sync(ticks);
|
||||
info->sync = pdata->sync;
|
||||
}
|
||||
}
|
||||
|
||||
info->rtc_dev = rtc_device_register("88pm860x-rtc", &pdev->dev,
|
||||
|
@ -366,10 +389,12 @@ static int __devinit pm860x_rtc_probe(struct platform_device *pdev)
|
|||
|
||||
#ifdef VRTC_CALIBRATION
|
||||
/* <00> -- 2.7V, <01> -- 2.9V, <10> -- 3.1V, <11> -- 3.3V */
|
||||
if (pdata && pdata->vrtc)
|
||||
info->vrtc = pdata->vrtc & 0x3;
|
||||
else
|
||||
info->vrtc = 1;
|
||||
if (pm860x_rtc_dt_init(pdev, info)) {
|
||||
if (pdata && pdata->vrtc)
|
||||
info->vrtc = pdata->vrtc & 0x3;
|
||||
else
|
||||
info->vrtc = 1;
|
||||
}
|
||||
pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, MEAS2_VRTC);
|
||||
|
||||
/* calibrate VRTC */
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/fb.h>
|
||||
|
@ -31,57 +32,26 @@ struct pm860x_backlight_data {
|
|||
int port;
|
||||
int pwm;
|
||||
int iset;
|
||||
int reg_duty_cycle;
|
||||
int reg_always_on;
|
||||
int reg_current;
|
||||
};
|
||||
|
||||
static inline int wled_a(int port)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ((port - PM8606_BACKLIGHT1) << 1) + 2;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int wled_b(int port)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ((port - PM8606_BACKLIGHT1) << 1) + 3;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* WLED2 & WLED3 share the same IDC */
|
||||
static inline int wled_idc(int port)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (port) {
|
||||
case PM8606_BACKLIGHT1:
|
||||
case PM8606_BACKLIGHT2:
|
||||
ret = ((port - PM8606_BACKLIGHT1) << 1) + 3;
|
||||
break;
|
||||
case PM8606_BACKLIGHT3:
|
||||
default:
|
||||
ret = ((port - PM8606_BACKLIGHT2) << 1) + 3;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int backlight_power_set(struct pm860x_chip *chip, int port,
|
||||
int on)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
|
||||
switch (port) {
|
||||
case PM8606_BACKLIGHT1:
|
||||
case 0:
|
||||
ret = on ? pm8606_osc_enable(chip, WLED1_DUTY) :
|
||||
pm8606_osc_disable(chip, WLED1_DUTY);
|
||||
break;
|
||||
case PM8606_BACKLIGHT2:
|
||||
case 1:
|
||||
ret = on ? pm8606_osc_enable(chip, WLED2_DUTY) :
|
||||
pm8606_osc_disable(chip, WLED2_DUTY);
|
||||
break;
|
||||
case PM8606_BACKLIGHT3:
|
||||
case 2:
|
||||
ret = on ? pm8606_osc_enable(chip, WLED3_DUTY) :
|
||||
pm8606_osc_disable(chip, WLED3_DUTY);
|
||||
break;
|
||||
|
@ -104,13 +74,13 @@ static int pm860x_backlight_set(struct backlight_device *bl, int brightness)
|
|||
if (brightness)
|
||||
backlight_power_set(chip, data->port, 1);
|
||||
|
||||
ret = pm860x_reg_write(data->i2c, wled_a(data->port), value);
|
||||
ret = pm860x_reg_write(data->i2c, data->reg_duty_cycle, value);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if ((data->current_brightness == 0) && brightness) {
|
||||
if (data->iset) {
|
||||
ret = pm860x_set_bits(data->i2c, wled_idc(data->port),
|
||||
ret = pm860x_set_bits(data->i2c, data->reg_current,
|
||||
CURRENT_BITMASK, data->iset);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
@ -123,17 +93,17 @@ static int pm860x_backlight_set(struct backlight_device *bl, int brightness)
|
|||
}
|
||||
if (brightness == MAX_BRIGHTNESS) {
|
||||
/* set WLED_ON bit as 100% */
|
||||
ret = pm860x_set_bits(data->i2c, wled_b(data->port),
|
||||
ret = pm860x_set_bits(data->i2c, data->reg_always_on,
|
||||
PM8606_WLED_ON, PM8606_WLED_ON);
|
||||
}
|
||||
} else {
|
||||
if (brightness == MAX_BRIGHTNESS) {
|
||||
/* set WLED_ON bit as 100% */
|
||||
ret = pm860x_set_bits(data->i2c, wled_b(data->port),
|
||||
ret = pm860x_set_bits(data->i2c, data->reg_always_on,
|
||||
PM8606_WLED_ON, PM8606_WLED_ON);
|
||||
} else {
|
||||
/* clear WLED_ON bit since it's not 100% */
|
||||
ret = pm860x_set_bits(data->i2c, wled_b(data->port),
|
||||
ret = pm860x_set_bits(data->i2c, data->reg_always_on,
|
||||
PM8606_WLED_ON, 0);
|
||||
}
|
||||
}
|
||||
|
@ -174,7 +144,7 @@ static int pm860x_backlight_get_brightness(struct backlight_device *bl)
|
|||
struct pm860x_chip *chip = data->chip;
|
||||
int ret;
|
||||
|
||||
ret = pm860x_reg_read(data->i2c, wled_a(data->port));
|
||||
ret = pm860x_reg_read(data->i2c, data->reg_duty_cycle);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
data->current_brightness = ret;
|
||||
|
@ -190,45 +160,85 @@ static const struct backlight_ops pm860x_backlight_ops = {
|
|||
.get_brightness = pm860x_backlight_get_brightness,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int pm860x_backlight_dt_init(struct platform_device *pdev,
|
||||
struct pm860x_backlight_data *data,
|
||||
char *name)
|
||||
{
|
||||
struct device_node *nproot = pdev->dev.parent->of_node, *np;
|
||||
int iset = 0;
|
||||
if (!nproot)
|
||||
return -ENODEV;
|
||||
nproot = of_find_node_by_name(nproot, "backlights");
|
||||
if (!nproot) {
|
||||
dev_err(&pdev->dev, "failed to find backlights node\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
for_each_child_of_node(nproot, np) {
|
||||
if (!of_node_cmp(np->name, name)) {
|
||||
of_property_read_u32(np, "marvell,88pm860x-iset",
|
||||
&iset);
|
||||
data->iset = PM8606_WLED_CURRENT(iset);
|
||||
of_property_read_u32(np, "marvell,88pm860x-pwm",
|
||||
&data->pwm);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define pm860x_backlight_dt_init(x, y, z) (-1)
|
||||
#endif
|
||||
|
||||
static int pm860x_backlight_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
|
||||
struct pm860x_backlight_pdata *pdata = NULL;
|
||||
struct pm860x_backlight_pdata *pdata = pdev->dev.platform_data;
|
||||
struct pm860x_backlight_data *data;
|
||||
struct backlight_device *bl;
|
||||
struct resource *res;
|
||||
struct backlight_properties props;
|
||||
char name[MFD_NAME_SIZE];
|
||||
int ret;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
if (res == NULL) {
|
||||
dev_err(&pdev->dev, "No I/O resource!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
if (pdata == NULL) {
|
||||
dev_err(&pdev->dev, "platform data isn't assigned to "
|
||||
"backlight\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
int ret = 0;
|
||||
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(struct pm860x_backlight_data),
|
||||
GFP_KERNEL);
|
||||
if (data == NULL)
|
||||
return -ENOMEM;
|
||||
strncpy(name, res->name, MFD_NAME_SIZE);
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_REG, "duty cycle");
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "No REG resource for duty cycle\n");
|
||||
ret = -ENXIO;
|
||||
goto out;
|
||||
}
|
||||
data->reg_duty_cycle = res->start;
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_REG, "always on");
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "No REG resorce for always on\n");
|
||||
ret = -ENXIO;
|
||||
goto out;
|
||||
}
|
||||
data->reg_always_on = res->start;
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_REG, "current");
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "No REG resource for current\n");
|
||||
ret = -ENXIO;
|
||||
goto out;
|
||||
}
|
||||
data->reg_current = res->start;
|
||||
|
||||
memset(name, 0, MFD_NAME_SIZE);
|
||||
sprintf(name, "backlight-%d", pdev->id);
|
||||
data->port = pdev->id;
|
||||
data->chip = chip;
|
||||
data->i2c = (chip->id == CHIP_PM8606) ? chip->client \
|
||||
: chip->companion;
|
||||
data->current_brightness = MAX_BRIGHTNESS;
|
||||
data->pwm = pdata->pwm;
|
||||
data->iset = pdata->iset;
|
||||
data->port = pdata->flags;
|
||||
if (data->port < 0) {
|
||||
dev_err(&pdev->dev, "wrong platform data is assigned");
|
||||
return -EINVAL;
|
||||
if (pm860x_backlight_dt_init(pdev, data, name)) {
|
||||
if (pdata) {
|
||||
data->pwm = pdata->pwm;
|
||||
data->iset = pdata->iset;
|
||||
}
|
||||
}
|
||||
|
||||
memset(&props, 0, sizeof(struct backlight_properties));
|
||||
|
@ -247,12 +257,14 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
|
|||
/* read current backlight */
|
||||
ret = pm860x_backlight_get_brightness(bl);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
goto out_brt;
|
||||
|
||||
backlight_update_status(bl);
|
||||
return 0;
|
||||
out:
|
||||
out_brt:
|
||||
backlight_device_unregister(bl);
|
||||
out:
|
||||
devm_kfree(&pdev->dev, data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -373,6 +373,13 @@ config BACKLIGHT_PANDORA
|
|||
If you have a Pandora console, say Y to enable the
|
||||
backlight driver.
|
||||
|
||||
config BACKLIGHT_TPS65217
|
||||
tristate "TPS65217 Backlight"
|
||||
depends on BACKLIGHT_CLASS_DEVICE && MFD_TPS65217
|
||||
help
|
||||
If you have a Texas Instruments TPS65217 say Y to enable the
|
||||
backlight driver.
|
||||
|
||||
endif # BACKLIGHT_CLASS_DEVICE
|
||||
|
||||
endif # BACKLIGHT_LCD_SUPPORT
|
||||
|
|
|
@ -43,3 +43,4 @@ obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o
|
|||
obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o
|
||||
obj-$(CONFIG_BACKLIGHT_AAT2870) += aat2870_bl.o
|
||||
obj-$(CONFIG_BACKLIGHT_OT200) += ot200_bl.o
|
||||
obj-$(CONFIG_BACKLIGHT_TPS65217) += tps65217_bl.o
|
||||
|
|
|
@ -27,7 +27,9 @@
|
|||
struct max8925_backlight_data {
|
||||
struct max8925_chip *chip;
|
||||
|
||||
int current_brightness;
|
||||
int current_brightness;
|
||||
int reg_mode_cntl;
|
||||
int reg_cntl;
|
||||
};
|
||||
|
||||
static int max8925_backlight_set(struct backlight_device *bl, int brightness)
|
||||
|
@ -42,16 +44,16 @@ static int max8925_backlight_set(struct backlight_device *bl, int brightness)
|
|||
else
|
||||
value = brightness;
|
||||
|
||||
ret = max8925_reg_write(chip->i2c, MAX8925_WLED_CNTL, value);
|
||||
ret = max8925_reg_write(chip->i2c, data->reg_cntl, value);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if (!data->current_brightness && brightness)
|
||||
/* enable WLED output */
|
||||
ret = max8925_set_bits(chip->i2c, MAX8925_WLED_MODE_CNTL, 1, 1);
|
||||
ret = max8925_set_bits(chip->i2c, data->reg_mode_cntl, 1, 1);
|
||||
else if (!brightness)
|
||||
/* disable WLED output */
|
||||
ret = max8925_set_bits(chip->i2c, MAX8925_WLED_MODE_CNTL, 1, 0);
|
||||
ret = max8925_set_bits(chip->i2c, data->reg_mode_cntl, 1, 0);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
dev_dbg(chip->dev, "set brightness %d\n", value);
|
||||
|
@ -85,7 +87,7 @@ static int max8925_backlight_get_brightness(struct backlight_device *bl)
|
|||
struct max8925_chip *chip = data->chip;
|
||||
int ret;
|
||||
|
||||
ret = max8925_reg_read(chip->i2c, MAX8925_WLED_CNTL);
|
||||
ret = max8925_reg_read(chip->i2c, data->reg_cntl);
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
data->current_brightness = ret;
|
||||
|
@ -102,69 +104,70 @@ static const struct backlight_ops max8925_backlight_ops = {
|
|||
static int __devinit max8925_backlight_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
|
||||
struct max8925_platform_data *max8925_pdata;
|
||||
struct max8925_backlight_pdata *pdata = NULL;
|
||||
struct max8925_backlight_pdata *pdata = pdev->dev.platform_data;
|
||||
struct max8925_backlight_data *data;
|
||||
struct backlight_device *bl;
|
||||
struct backlight_properties props;
|
||||
struct resource *res;
|
||||
char name[MAX8925_NAME_SIZE];
|
||||
unsigned char value;
|
||||
int ret;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
if (res == NULL) {
|
||||
dev_err(&pdev->dev, "No I/O resource!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (pdev->dev.parent->platform_data) {
|
||||
max8925_pdata = pdev->dev.parent->platform_data;
|
||||
pdata = max8925_pdata->backlight;
|
||||
}
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "platform data isn't assigned to "
|
||||
"backlight\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
int ret = 0;
|
||||
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(struct max8925_backlight_data),
|
||||
GFP_KERNEL);
|
||||
if (data == NULL)
|
||||
return -ENOMEM;
|
||||
strncpy(name, res->name, MAX8925_NAME_SIZE);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_REG, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "No REG resource for mode control!\n");
|
||||
ret = -ENXIO;
|
||||
goto out;
|
||||
}
|
||||
data->reg_mode_cntl = res->start;
|
||||
res = platform_get_resource(pdev, IORESOURCE_REG, 1);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "No REG resource for control!\n");
|
||||
ret = -ENXIO;
|
||||
goto out;
|
||||
}
|
||||
data->reg_cntl = res->start;
|
||||
|
||||
data->chip = chip;
|
||||
data->current_brightness = 0;
|
||||
|
||||
memset(&props, 0, sizeof(struct backlight_properties));
|
||||
props.type = BACKLIGHT_RAW;
|
||||
props.max_brightness = MAX_BRIGHTNESS;
|
||||
bl = backlight_device_register(name, &pdev->dev, data,
|
||||
bl = backlight_device_register("max8925-backlight", &pdev->dev, data,
|
||||
&max8925_backlight_ops, &props);
|
||||
if (IS_ERR(bl)) {
|
||||
dev_err(&pdev->dev, "failed to register backlight\n");
|
||||
return PTR_ERR(bl);
|
||||
ret = PTR_ERR(bl);
|
||||
goto out;
|
||||
}
|
||||
bl->props.brightness = MAX_BRIGHTNESS;
|
||||
|
||||
platform_set_drvdata(pdev, bl);
|
||||
|
||||
value = 0;
|
||||
if (pdata->lxw_scl)
|
||||
value |= (1 << 7);
|
||||
if (pdata->lxw_freq)
|
||||
value |= (LWX_FREQ(pdata->lxw_freq) << 4);
|
||||
if (pdata->dual_string)
|
||||
value |= (1 << 1);
|
||||
ret = max8925_set_bits(chip->i2c, MAX8925_WLED_MODE_CNTL, 0xfe, value);
|
||||
if (pdata) {
|
||||
if (pdata->lxw_scl)
|
||||
value |= (1 << 7);
|
||||
if (pdata->lxw_freq)
|
||||
value |= (LWX_FREQ(pdata->lxw_freq) << 4);
|
||||
if (pdata->dual_string)
|
||||
value |= (1 << 1);
|
||||
}
|
||||
ret = max8925_set_bits(chip->i2c, data->reg_mode_cntl, 0xfe, value);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
goto out_brt;
|
||||
|
||||
backlight_update_status(bl);
|
||||
return 0;
|
||||
out:
|
||||
out_brt:
|
||||
backlight_device_unregister(bl);
|
||||
out:
|
||||
devm_kfree(&pdev->dev, data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,342 @@
|
|||
/*
|
||||
* tps65217_bl.c
|
||||
*
|
||||
* TPS65217 backlight driver
|
||||
*
|
||||
* Copyright (C) 2012 Matthias Kaehlcke
|
||||
* Author: Matthias Kaehlcke <matthias@kaehlcke.net>
|
||||
*
|
||||
* 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/kernel.h>
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/mfd/tps65217.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
struct tps65217_bl {
|
||||
struct tps65217 *tps;
|
||||
struct device *dev;
|
||||
struct backlight_device *bl;
|
||||
bool is_enabled;
|
||||
};
|
||||
|
||||
static int tps65217_bl_enable(struct tps65217_bl *tps65217_bl)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = tps65217_set_bits(tps65217_bl->tps, TPS65217_REG_WLEDCTRL1,
|
||||
TPS65217_WLEDCTRL1_ISINK_ENABLE,
|
||||
TPS65217_WLEDCTRL1_ISINK_ENABLE, TPS65217_PROTECT_NONE);
|
||||
if (rc) {
|
||||
dev_err(tps65217_bl->dev,
|
||||
"failed to enable backlight: %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
tps65217_bl->is_enabled = true;
|
||||
|
||||
dev_dbg(tps65217_bl->dev, "backlight enabled\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tps65217_bl_disable(struct tps65217_bl *tps65217_bl)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = tps65217_clear_bits(tps65217_bl->tps,
|
||||
TPS65217_REG_WLEDCTRL1,
|
||||
TPS65217_WLEDCTRL1_ISINK_ENABLE,
|
||||
TPS65217_PROTECT_NONE);
|
||||
if (rc) {
|
||||
dev_err(tps65217_bl->dev,
|
||||
"failed to disable backlight: %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
tps65217_bl->is_enabled = false;
|
||||
|
||||
dev_dbg(tps65217_bl->dev, "backlight disabled\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tps65217_bl_update_status(struct backlight_device *bl)
|
||||
{
|
||||
struct tps65217_bl *tps65217_bl = bl_get_data(bl);
|
||||
int rc;
|
||||
int brightness = bl->props.brightness;
|
||||
|
||||
if (bl->props.state & BL_CORE_SUSPENDED)
|
||||
brightness = 0;
|
||||
|
||||
if ((bl->props.power != FB_BLANK_UNBLANK) ||
|
||||
(bl->props.fb_blank != FB_BLANK_UNBLANK))
|
||||
/* framebuffer in low power mode or blanking active */
|
||||
brightness = 0;
|
||||
|
||||
if (brightness > 0) {
|
||||
rc = tps65217_reg_write(tps65217_bl->tps,
|
||||
TPS65217_REG_WLEDCTRL2,
|
||||
brightness - 1,
|
||||
TPS65217_PROTECT_NONE);
|
||||
if (rc) {
|
||||
dev_err(tps65217_bl->dev,
|
||||
"failed to set brightness level: %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
dev_dbg(tps65217_bl->dev, "brightness set to %d\n", brightness);
|
||||
|
||||
if (!tps65217_bl->is_enabled)
|
||||
rc = tps65217_bl_enable(tps65217_bl);
|
||||
} else {
|
||||
rc = tps65217_bl_disable(tps65217_bl);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int tps65217_bl_get_brightness(struct backlight_device *bl)
|
||||
{
|
||||
return bl->props.brightness;
|
||||
}
|
||||
|
||||
static const struct backlight_ops tps65217_bl_ops = {
|
||||
.options = BL_CORE_SUSPENDRESUME,
|
||||
.update_status = tps65217_bl_update_status,
|
||||
.get_brightness = tps65217_bl_get_brightness
|
||||
};
|
||||
|
||||
static int tps65217_bl_hw_init(struct tps65217_bl *tps65217_bl,
|
||||
struct tps65217_bl_pdata *pdata)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = tps65217_bl_disable(tps65217_bl);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
switch (pdata->isel) {
|
||||
case TPS65217_BL_ISET1:
|
||||
/* select ISET_1 current level */
|
||||
rc = tps65217_clear_bits(tps65217_bl->tps,
|
||||
TPS65217_REG_WLEDCTRL1,
|
||||
TPS65217_WLEDCTRL1_ISEL,
|
||||
TPS65217_PROTECT_NONE);
|
||||
if (rc) {
|
||||
dev_err(tps65217_bl->dev,
|
||||
"failed to select ISET1 current level: %d)\n",
|
||||
rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
dev_dbg(tps65217_bl->dev, "selected ISET1 current level\n");
|
||||
|
||||
break;
|
||||
|
||||
case TPS65217_BL_ISET2:
|
||||
/* select ISET2 current level */
|
||||
rc = tps65217_set_bits(tps65217_bl->tps, TPS65217_REG_WLEDCTRL1,
|
||||
TPS65217_WLEDCTRL1_ISEL,
|
||||
TPS65217_WLEDCTRL1_ISEL, TPS65217_PROTECT_NONE);
|
||||
if (rc) {
|
||||
dev_err(tps65217_bl->dev,
|
||||
"failed to select ISET2 current level: %d\n",
|
||||
rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
dev_dbg(tps65217_bl->dev, "selected ISET2 current level\n");
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(tps65217_bl->dev,
|
||||
"invalid value for current level: %d\n", pdata->isel);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* set PWM frequency */
|
||||
rc = tps65217_set_bits(tps65217_bl->tps,
|
||||
TPS65217_REG_WLEDCTRL1,
|
||||
TPS65217_WLEDCTRL1_FDIM_MASK,
|
||||
pdata->fdim,
|
||||
TPS65217_PROTECT_NONE);
|
||||
if (rc) {
|
||||
dev_err(tps65217_bl->dev,
|
||||
"failed to select PWM dimming frequency: %d\n",
|
||||
rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct tps65217_bl_pdata *
|
||||
tps65217_bl_parse_dt(struct platform_device *pdev)
|
||||
{
|
||||
struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent);
|
||||
struct device_node *node = of_node_get(tps->dev->of_node);
|
||||
struct tps65217_bl_pdata *pdata, *err;
|
||||
u32 val;
|
||||
|
||||
node = of_find_node_by_name(node, "backlight");
|
||||
if (!node)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "failed to allocate platform data\n");
|
||||
err = ERR_PTR(-ENOMEM);
|
||||
goto err;
|
||||
}
|
||||
|
||||
pdata->isel = TPS65217_BL_ISET1;
|
||||
if (!of_property_read_u32(node, "isel", &val)) {
|
||||
if (val < TPS65217_BL_ISET1 ||
|
||||
val > TPS65217_BL_ISET2) {
|
||||
dev_err(&pdev->dev,
|
||||
"invalid 'isel' value in the device tree\n");
|
||||
err = ERR_PTR(-EINVAL);
|
||||
goto err;
|
||||
}
|
||||
|
||||
pdata->isel = val;
|
||||
}
|
||||
|
||||
pdata->fdim = TPS65217_BL_FDIM_200HZ;
|
||||
if (!of_property_read_u32(node, "fdim", &val)) {
|
||||
switch (val) {
|
||||
case 100:
|
||||
pdata->fdim = TPS65217_BL_FDIM_100HZ;
|
||||
break;
|
||||
|
||||
case 200:
|
||||
pdata->fdim = TPS65217_BL_FDIM_200HZ;
|
||||
break;
|
||||
|
||||
case 500:
|
||||
pdata->fdim = TPS65217_BL_FDIM_500HZ;
|
||||
break;
|
||||
|
||||
case 1000:
|
||||
pdata->fdim = TPS65217_BL_FDIM_1000HZ;
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(&pdev->dev,
|
||||
"invalid 'fdim' value in the device tree\n");
|
||||
err = ERR_PTR(-EINVAL);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
of_node_put(node);
|
||||
|
||||
return pdata;
|
||||
|
||||
err:
|
||||
of_node_put(node);
|
||||
|
||||
return err;
|
||||
}
|
||||
#else
|
||||
static struct tps65217_bl_pdata *
|
||||
tps65217_bl_parse_dt(struct platform_device *pdev)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int tps65217_bl_probe(struct platform_device *pdev)
|
||||
{
|
||||
int rc;
|
||||
struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent);
|
||||
struct tps65217_bl *tps65217_bl;
|
||||
struct tps65217_bl_pdata *pdata;
|
||||
struct backlight_properties bl_props;
|
||||
|
||||
if (tps->dev->of_node) {
|
||||
pdata = tps65217_bl_parse_dt(pdev);
|
||||
if (IS_ERR(pdata))
|
||||
return PTR_ERR(pdata);
|
||||
} else {
|
||||
if (!pdev->dev.platform_data) {
|
||||
dev_err(&pdev->dev, "no platform data provided\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
}
|
||||
|
||||
tps65217_bl = devm_kzalloc(&pdev->dev, sizeof(*tps65217_bl),
|
||||
GFP_KERNEL);
|
||||
if (tps65217_bl == NULL) {
|
||||
dev_err(&pdev->dev, "allocation of struct tps65217_bl failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
tps65217_bl->tps = tps;
|
||||
tps65217_bl->dev = &pdev->dev;
|
||||
tps65217_bl->is_enabled = false;
|
||||
|
||||
rc = tps65217_bl_hw_init(tps65217_bl, pdata);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
memset(&bl_props, 0, sizeof(struct backlight_properties));
|
||||
bl_props.type = BACKLIGHT_RAW;
|
||||
bl_props.max_brightness = 100;
|
||||
|
||||
tps65217_bl->bl = backlight_device_register(pdev->name,
|
||||
tps65217_bl->dev, tps65217_bl,
|
||||
&tps65217_bl_ops, &bl_props);
|
||||
if (IS_ERR(tps65217_bl->bl)) {
|
||||
dev_err(tps65217_bl->dev,
|
||||
"registration of backlight device failed: %d\n", rc);
|
||||
return PTR_ERR(tps65217_bl->bl);
|
||||
}
|
||||
|
||||
tps65217_bl->bl->props.brightness = 0;
|
||||
platform_set_drvdata(pdev, tps65217_bl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tps65217_bl_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct tps65217_bl *tps65217_bl = platform_get_drvdata(pdev);
|
||||
|
||||
backlight_device_unregister(tps65217_bl->bl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver tps65217_bl_driver = {
|
||||
.probe = tps65217_bl_probe,
|
||||
.remove = tps65217_bl_remove,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "tps65217-bl",
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(tps65217_bl_driver);
|
||||
|
||||
MODULE_DESCRIPTION("TPS65217 Backlight driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Matthias Kaehlcke <matthias@kaehlcke.net>");
|
|
@ -37,6 +37,7 @@
|
|||
* document number TBD : DH89xxCC
|
||||
* document number TBD : Panther Point
|
||||
* document number TBD : Lynx Point
|
||||
* document number TBD : Lynx Point-LP
|
||||
*/
|
||||
|
||||
/*
|
||||
|
|
|
@ -188,6 +188,7 @@ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes);
|
|||
|
||||
int twl_get_type(void);
|
||||
int twl_get_version(void);
|
||||
int twl_get_hfclk_rate(void);
|
||||
|
||||
int twl6030_interrupt_unmask(u8 bit_mask, u8 offset);
|
||||
int twl6030_interrupt_mask(u8 bit_mask, u8 offset);
|
||||
|
|
|
@ -29,8 +29,9 @@ struct resource {
|
|||
#define IORESOURCE_BITS 0x000000ff /* Bus-specific bits */
|
||||
|
||||
#define IORESOURCE_TYPE_BITS 0x00001f00 /* Resource type */
|
||||
#define IORESOURCE_IO 0x00000100
|
||||
#define IORESOURCE_IO 0x00000100 /* PCI/ISA I/O ports */
|
||||
#define IORESOURCE_MEM 0x00000200
|
||||
#define IORESOURCE_REG 0x00000300 /* Register offsets */
|
||||
#define IORESOURCE_IRQ 0x00000400
|
||||
#define IORESOURCE_DMA 0x00000800
|
||||
#define IORESOURCE_BUS 0x00001000
|
||||
|
|
|
@ -34,22 +34,6 @@ enum {
|
|||
PM8606_ID_MAX,
|
||||
};
|
||||
|
||||
enum {
|
||||
PM8606_BACKLIGHT1 = 0,
|
||||
PM8606_BACKLIGHT2,
|
||||
PM8606_BACKLIGHT3,
|
||||
};
|
||||
|
||||
enum {
|
||||
PM8606_LED1_RED = 0,
|
||||
PM8606_LED1_GREEN,
|
||||
PM8606_LED1_BLUE,
|
||||
PM8606_LED2_RED,
|
||||
PM8606_LED2_GREEN,
|
||||
PM8606_LED2_BLUE,
|
||||
PM8607_LED_VIBRATOR,
|
||||
};
|
||||
|
||||
|
||||
/* 8606 Registers */
|
||||
#define PM8606_DCM_BOOST (0x00)
|
||||
|
@ -322,7 +306,7 @@ struct pm860x_chip {
|
|||
struct regmap *regmap_companion;
|
||||
|
||||
int buck3_double; /* DVC ramp slope double */
|
||||
unsigned short companion_addr;
|
||||
int companion_addr;
|
||||
unsigned short osc_vote;
|
||||
int id;
|
||||
int irq_mode;
|
||||
|
@ -340,16 +324,12 @@ enum {
|
|||
};
|
||||
|
||||
struct pm860x_backlight_pdata {
|
||||
int id;
|
||||
int pwm;
|
||||
int iset;
|
||||
unsigned long flags;
|
||||
};
|
||||
|
||||
struct pm860x_led_pdata {
|
||||
int id;
|
||||
int iset;
|
||||
unsigned long flags;
|
||||
};
|
||||
|
||||
struct pm860x_rtc_pdata {
|
||||
|
@ -379,15 +359,29 @@ struct pm860x_platform_data {
|
|||
struct pm860x_rtc_pdata *rtc;
|
||||
struct pm860x_touch_pdata *touch;
|
||||
struct pm860x_power_pdata *power;
|
||||
struct regulator_init_data *regulator;
|
||||
struct regulator_init_data *buck1;
|
||||
struct regulator_init_data *buck2;
|
||||
struct regulator_init_data *buck3;
|
||||
struct regulator_init_data *ldo1;
|
||||
struct regulator_init_data *ldo2;
|
||||
struct regulator_init_data *ldo3;
|
||||
struct regulator_init_data *ldo4;
|
||||
struct regulator_init_data *ldo5;
|
||||
struct regulator_init_data *ldo6;
|
||||
struct regulator_init_data *ldo7;
|
||||
struct regulator_init_data *ldo8;
|
||||
struct regulator_init_data *ldo9;
|
||||
struct regulator_init_data *ldo10;
|
||||
struct regulator_init_data *ldo12;
|
||||
struct regulator_init_data *ldo_vibrator;
|
||||
struct regulator_init_data *ldo14;
|
||||
|
||||
unsigned short companion_addr; /* I2C address of companion chip */
|
||||
int companion_addr; /* I2C address of companion chip */
|
||||
int i2c_port; /* Controlled by GI2C or PI2C */
|
||||
int irq_mode; /* Clear interrupt by read/write(0/1) */
|
||||
int irq_base; /* IRQ base number of 88pm860x */
|
||||
int num_leds;
|
||||
int num_backlights;
|
||||
int num_regulators;
|
||||
};
|
||||
|
||||
extern int pm8606_osc_enable(struct pm860x_chip *, unsigned short);
|
||||
|
@ -408,8 +402,4 @@ extern int pm860x_page_bulk_write(struct i2c_client *, int, int,
|
|||
extern int pm860x_page_set_bits(struct i2c_client *, int, unsigned char,
|
||||
unsigned char);
|
||||
|
||||
extern int pm860x_device_init(struct pm860x_chip *chip,
|
||||
struct pm860x_platform_data *pdata) __devinit ;
|
||||
extern void pm860x_device_exit(struct pm860x_chip *chip) __devexit ;
|
||||
|
||||
#endif /* __LINUX_MFD_88PM860X_H */
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* Copyright (C) 2007-2009 ST-Ericsson AB
|
||||
* License terms: GNU General Public License (GPL) version 2
|
||||
* AB3100 core access functions
|
||||
* Author: Linus Walleij <linus.walleij@stericsson.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/regulator/machine.h>
|
||||
|
||||
struct device;
|
||||
|
||||
#ifndef MFD_AB3100_H
|
||||
#define MFD_AB3100_H
|
||||
|
||||
|
||||
#define AB3100_P1A 0xc0
|
||||
#define AB3100_P1B 0xc1
|
||||
#define AB3100_P1C 0xc2
|
||||
#define AB3100_P1D 0xc3
|
||||
#define AB3100_P1E 0xc4
|
||||
#define AB3100_P1F 0xc5
|
||||
#define AB3100_P1G 0xc6
|
||||
#define AB3100_R2A 0xc7
|
||||
#define AB3100_R2B 0xc8
|
||||
|
||||
/*
|
||||
* AB3100, EVENTA1, A2 and A3 event register flags
|
||||
* these are catenated into a single 32-bit flag in the code
|
||||
* for event notification broadcasts.
|
||||
*/
|
||||
#define AB3100_EVENTA1_ONSWA (0x01<<16)
|
||||
#define AB3100_EVENTA1_ONSWB (0x02<<16)
|
||||
#define AB3100_EVENTA1_ONSWC (0x04<<16)
|
||||
#define AB3100_EVENTA1_DCIO (0x08<<16)
|
||||
#define AB3100_EVENTA1_OVER_TEMP (0x10<<16)
|
||||
#define AB3100_EVENTA1_SIM_OFF (0x20<<16)
|
||||
#define AB3100_EVENTA1_VBUS (0x40<<16)
|
||||
#define AB3100_EVENTA1_VSET_USB (0x80<<16)
|
||||
|
||||
#define AB3100_EVENTA2_READY_TX (0x01<<8)
|
||||
#define AB3100_EVENTA2_READY_RX (0x02<<8)
|
||||
#define AB3100_EVENTA2_OVERRUN_ERROR (0x04<<8)
|
||||
#define AB3100_EVENTA2_FRAMING_ERROR (0x08<<8)
|
||||
#define AB3100_EVENTA2_CHARG_OVERCURRENT (0x10<<8)
|
||||
#define AB3100_EVENTA2_MIDR (0x20<<8)
|
||||
#define AB3100_EVENTA2_BATTERY_REM (0x40<<8)
|
||||
#define AB3100_EVENTA2_ALARM (0x80<<8)
|
||||
|
||||
#define AB3100_EVENTA3_ADC_TRIG5 (0x01)
|
||||
#define AB3100_EVENTA3_ADC_TRIG4 (0x02)
|
||||
#define AB3100_EVENTA3_ADC_TRIG3 (0x04)
|
||||
#define AB3100_EVENTA3_ADC_TRIG2 (0x08)
|
||||
#define AB3100_EVENTA3_ADC_TRIGVBAT (0x10)
|
||||
#define AB3100_EVENTA3_ADC_TRIGVTX (0x20)
|
||||
#define AB3100_EVENTA3_ADC_TRIG1 (0x40)
|
||||
#define AB3100_EVENTA3_ADC_TRIG0 (0x80)
|
||||
|
||||
/* AB3100, STR register flags */
|
||||
#define AB3100_STR_ONSWA (0x01)
|
||||
#define AB3100_STR_ONSWB (0x02)
|
||||
#define AB3100_STR_ONSWC (0x04)
|
||||
#define AB3100_STR_DCIO (0x08)
|
||||
#define AB3100_STR_BOOT_MODE (0x10)
|
||||
#define AB3100_STR_SIM_OFF (0x20)
|
||||
#define AB3100_STR_BATT_REMOVAL (0x40)
|
||||
#define AB3100_STR_VBUS (0x80)
|
||||
|
||||
/*
|
||||
* AB3100 contains 8 regulators, one external regulator controller
|
||||
* and a buck converter, further the LDO E and buck converter can
|
||||
* have separate settings if they are in sleep mode, this is
|
||||
* modeled as a separate regulator.
|
||||
*/
|
||||
#define AB3100_NUM_REGULATORS 10
|
||||
|
||||
/**
|
||||
* struct ab3100
|
||||
* @access_mutex: lock out concurrent accesses to the AB3100 registers
|
||||
* @dev: pointer to the containing device
|
||||
* @i2c_client: I2C client for this chip
|
||||
* @testreg_client: secondary client for test registers
|
||||
* @chip_name: name of this chip variant
|
||||
* @chip_id: 8 bit chip ID for this chip variant
|
||||
* @event_subscribers: event subscribers are listed here
|
||||
* @startup_events: a copy of the first reading of the event registers
|
||||
* @startup_events_read: whether the first events have been read
|
||||
*
|
||||
* This struct is PRIVATE and devices using it should NOT
|
||||
* access ANY fields. It is used as a token for calling the
|
||||
* AB3100 functions.
|
||||
*/
|
||||
struct ab3100 {
|
||||
struct mutex access_mutex;
|
||||
struct device *dev;
|
||||
struct i2c_client *i2c_client;
|
||||
struct i2c_client *testreg_client;
|
||||
char chip_name[32];
|
||||
u8 chip_id;
|
||||
struct blocking_notifier_head event_subscribers;
|
||||
u8 startup_events[3];
|
||||
bool startup_events_read;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ab3100_platform_data
|
||||
* Data supplied to initialize board connections to the AB3100
|
||||
* @reg_constraints: regulator constraints for target board
|
||||
* the order of these constraints are: LDO A, C, D, E,
|
||||
* F, G, H, K, EXT and BUCK.
|
||||
* @reg_initvals: initial values for the regulator registers
|
||||
* plus two sleep settings for LDO E and the BUCK converter.
|
||||
* exactly AB3100_NUM_REGULATORS+2 values must be sent in.
|
||||
* Order: LDO A, C, E, E sleep, F, G, H, K, EXT, BUCK,
|
||||
* BUCK sleep, LDO D. (LDO D need to be initialized last.)
|
||||
* @external_voltage: voltage level of the external regulator.
|
||||
*/
|
||||
struct ab3100_platform_data {
|
||||
struct regulator_init_data reg_constraints[AB3100_NUM_REGULATORS];
|
||||
u8 reg_initvals[AB3100_NUM_REGULATORS+2];
|
||||
int external_voltage;
|
||||
};
|
||||
|
||||
int ab3100_event_register(struct ab3100 *ab3100,
|
||||
struct notifier_block *nb);
|
||||
int ab3100_event_unregister(struct ab3100 *ab3100,
|
||||
struct notifier_block *nb);
|
||||
|
||||
#endif /* MFD_AB3100_H */
|
|
@ -1,12 +1,9 @@
|
|||
/*
|
||||
* Copyright (C) 2007-2009 ST-Ericsson AB
|
||||
* License terms: GNU General Public License (GPL) version 2
|
||||
* AB3100 core access functions
|
||||
* Author: Linus Walleij <linus.walleij@stericsson.com>
|
||||
*
|
||||
* ABX500 core access functions.
|
||||
* The abx500 interface is used for the Analog Baseband chip
|
||||
* ab3100 and ab8500.
|
||||
* The abx500 interface is used for the Analog Baseband chips.
|
||||
*
|
||||
* Author: Mattias Wallin <mattias.wallin@stericsson.com>
|
||||
* Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
|
||||
|
@ -21,118 +18,6 @@ struct device;
|
|||
#ifndef MFD_ABX500_H
|
||||
#define MFD_ABX500_H
|
||||
|
||||
#define AB3100_P1A 0xc0
|
||||
#define AB3100_P1B 0xc1
|
||||
#define AB3100_P1C 0xc2
|
||||
#define AB3100_P1D 0xc3
|
||||
#define AB3100_P1E 0xc4
|
||||
#define AB3100_P1F 0xc5
|
||||
#define AB3100_P1G 0xc6
|
||||
#define AB3100_R2A 0xc7
|
||||
#define AB3100_R2B 0xc8
|
||||
|
||||
/*
|
||||
* AB3100, EVENTA1, A2 and A3 event register flags
|
||||
* these are catenated into a single 32-bit flag in the code
|
||||
* for event notification broadcasts.
|
||||
*/
|
||||
#define AB3100_EVENTA1_ONSWA (0x01<<16)
|
||||
#define AB3100_EVENTA1_ONSWB (0x02<<16)
|
||||
#define AB3100_EVENTA1_ONSWC (0x04<<16)
|
||||
#define AB3100_EVENTA1_DCIO (0x08<<16)
|
||||
#define AB3100_EVENTA1_OVER_TEMP (0x10<<16)
|
||||
#define AB3100_EVENTA1_SIM_OFF (0x20<<16)
|
||||
#define AB3100_EVENTA1_VBUS (0x40<<16)
|
||||
#define AB3100_EVENTA1_VSET_USB (0x80<<16)
|
||||
|
||||
#define AB3100_EVENTA2_READY_TX (0x01<<8)
|
||||
#define AB3100_EVENTA2_READY_RX (0x02<<8)
|
||||
#define AB3100_EVENTA2_OVERRUN_ERROR (0x04<<8)
|
||||
#define AB3100_EVENTA2_FRAMING_ERROR (0x08<<8)
|
||||
#define AB3100_EVENTA2_CHARG_OVERCURRENT (0x10<<8)
|
||||
#define AB3100_EVENTA2_MIDR (0x20<<8)
|
||||
#define AB3100_EVENTA2_BATTERY_REM (0x40<<8)
|
||||
#define AB3100_EVENTA2_ALARM (0x80<<8)
|
||||
|
||||
#define AB3100_EVENTA3_ADC_TRIG5 (0x01)
|
||||
#define AB3100_EVENTA3_ADC_TRIG4 (0x02)
|
||||
#define AB3100_EVENTA3_ADC_TRIG3 (0x04)
|
||||
#define AB3100_EVENTA3_ADC_TRIG2 (0x08)
|
||||
#define AB3100_EVENTA3_ADC_TRIGVBAT (0x10)
|
||||
#define AB3100_EVENTA3_ADC_TRIGVTX (0x20)
|
||||
#define AB3100_EVENTA3_ADC_TRIG1 (0x40)
|
||||
#define AB3100_EVENTA3_ADC_TRIG0 (0x80)
|
||||
|
||||
/* AB3100, STR register flags */
|
||||
#define AB3100_STR_ONSWA (0x01)
|
||||
#define AB3100_STR_ONSWB (0x02)
|
||||
#define AB3100_STR_ONSWC (0x04)
|
||||
#define AB3100_STR_DCIO (0x08)
|
||||
#define AB3100_STR_BOOT_MODE (0x10)
|
||||
#define AB3100_STR_SIM_OFF (0x20)
|
||||
#define AB3100_STR_BATT_REMOVAL (0x40)
|
||||
#define AB3100_STR_VBUS (0x80)
|
||||
|
||||
/*
|
||||
* AB3100 contains 8 regulators, one external regulator controller
|
||||
* and a buck converter, further the LDO E and buck converter can
|
||||
* have separate settings if they are in sleep mode, this is
|
||||
* modeled as a separate regulator.
|
||||
*/
|
||||
#define AB3100_NUM_REGULATORS 10
|
||||
|
||||
/**
|
||||
* struct ab3100
|
||||
* @access_mutex: lock out concurrent accesses to the AB3100 registers
|
||||
* @dev: pointer to the containing device
|
||||
* @i2c_client: I2C client for this chip
|
||||
* @testreg_client: secondary client for test registers
|
||||
* @chip_name: name of this chip variant
|
||||
* @chip_id: 8 bit chip ID for this chip variant
|
||||
* @event_subscribers: event subscribers are listed here
|
||||
* @startup_events: a copy of the first reading of the event registers
|
||||
* @startup_events_read: whether the first events have been read
|
||||
*
|
||||
* This struct is PRIVATE and devices using it should NOT
|
||||
* access ANY fields. It is used as a token for calling the
|
||||
* AB3100 functions.
|
||||
*/
|
||||
struct ab3100 {
|
||||
struct mutex access_mutex;
|
||||
struct device *dev;
|
||||
struct i2c_client *i2c_client;
|
||||
struct i2c_client *testreg_client;
|
||||
char chip_name[32];
|
||||
u8 chip_id;
|
||||
struct blocking_notifier_head event_subscribers;
|
||||
u8 startup_events[3];
|
||||
bool startup_events_read;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ab3100_platform_data
|
||||
* Data supplied to initialize board connections to the AB3100
|
||||
* @reg_constraints: regulator constraints for target board
|
||||
* the order of these constraints are: LDO A, C, D, E,
|
||||
* F, G, H, K, EXT and BUCK.
|
||||
* @reg_initvals: initial values for the regulator registers
|
||||
* plus two sleep settings for LDO E and the BUCK converter.
|
||||
* exactly AB3100_NUM_REGULATORS+2 values must be sent in.
|
||||
* Order: LDO A, C, E, E sleep, F, G, H, K, EXT, BUCK,
|
||||
* BUCK sleep, LDO D. (LDO D need to be initialized last.)
|
||||
* @external_voltage: voltage level of the external regulator.
|
||||
*/
|
||||
struct ab3100_platform_data {
|
||||
struct regulator_init_data reg_constraints[AB3100_NUM_REGULATORS];
|
||||
u8 reg_initvals[AB3100_NUM_REGULATORS+2];
|
||||
int external_voltage;
|
||||
};
|
||||
|
||||
int ab3100_event_register(struct ab3100 *ab3100,
|
||||
struct notifier_block *nb);
|
||||
int ab3100_event_unregister(struct ab3100 *ab3100,
|
||||
struct notifier_block *nb);
|
||||
|
||||
/**
|
||||
* struct abx500_init_setting
|
||||
* Initial value of the registers for driver to use during setup.
|
||||
|
|
|
@ -341,6 +341,4 @@ static inline int is_ab8500_2p0(struct ab8500 *ab)
|
|||
return (is_ab8500(ab) && (ab->chip_id == AB8500_CUT2P0));
|
||||
}
|
||||
|
||||
int ab8500_irq_get_virq(struct ab8500 *ab8500, int irq);
|
||||
|
||||
#endif /* MFD_AB8500_H */
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
* anatop.h - Anatop MFD driver
|
||||
*
|
||||
* Copyright (C) 2012 Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
|
||||
* Copyright (C) 2012 Linaro
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_MFD_ANATOP_H
|
||||
#define __LINUX_MFD_ANATOP_H
|
||||
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
/**
|
||||
* anatop - MFD data
|
||||
* @ioreg: ioremap register
|
||||
* @reglock: spinlock for register read/write
|
||||
*/
|
||||
struct anatop {
|
||||
void *ioreg;
|
||||
spinlock_t reglock;
|
||||
};
|
||||
|
||||
extern u32 anatop_read_reg(struct anatop *, u32);
|
||||
extern void anatop_write_reg(struct anatop *, u32, u32, u32);
|
||||
|
||||
#endif /* __LINUX_MFD_ANATOP_H */
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* da9055 declarations for DA9055 PMICs.
|
||||
*
|
||||
* Copyright(c) 2012 Dialog Semiconductor Ltd.
|
||||
*
|
||||
* Author: David Dajun Chen <dchen@diasemi.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.
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __DA9055_CORE_H
|
||||
#define __DA9055_CORE_H
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
/*
|
||||
* PMIC IRQ
|
||||
*/
|
||||
#define DA9055_IRQ_ALARM 0x01
|
||||
#define DA9055_IRQ_TICK 0x02
|
||||
#define DA9055_IRQ_NONKEY 0x00
|
||||
#define DA9055_IRQ_REGULATOR 0x0B
|
||||
#define DA9055_IRQ_HWMON 0x03
|
||||
|
||||
struct da9055_pdata;
|
||||
|
||||
struct da9055 {
|
||||
struct regmap *regmap;
|
||||
struct regmap_irq_chip_data *irq_data;
|
||||
struct device *dev;
|
||||
struct i2c_client *i2c_client;
|
||||
|
||||
int irq_base;
|
||||
int chip_irq;
|
||||
};
|
||||
|
||||
/* Device I/O */
|
||||
static inline int da9055_reg_read(struct da9055 *da9055, unsigned char reg)
|
||||
{
|
||||
int val, ret;
|
||||
|
||||
ret = regmap_read(da9055->regmap, reg, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline int da9055_reg_write(struct da9055 *da9055, unsigned char reg,
|
||||
unsigned char val)
|
||||
{
|
||||
return regmap_write(da9055->regmap, reg, val);
|
||||
}
|
||||
|
||||
static inline int da9055_group_read(struct da9055 *da9055, unsigned char reg,
|
||||
unsigned reg_cnt, unsigned char *val)
|
||||
{
|
||||
return regmap_bulk_read(da9055->regmap, reg, val, reg_cnt);
|
||||
}
|
||||
|
||||
static inline int da9055_group_write(struct da9055 *da9055, unsigned char reg,
|
||||
unsigned reg_cnt, unsigned char *val)
|
||||
{
|
||||
return regmap_raw_write(da9055->regmap, reg, val, reg_cnt);
|
||||
}
|
||||
|
||||
static inline int da9055_reg_update(struct da9055 *da9055, unsigned char reg,
|
||||
unsigned char bit_mask,
|
||||
unsigned char reg_val)
|
||||
{
|
||||
return regmap_update_bits(da9055->regmap, reg, bit_mask, reg_val);
|
||||
}
|
||||
|
||||
/* Generic Device API */
|
||||
int da9055_device_init(struct da9055 *da9055);
|
||||
void da9055_device_exit(struct da9055 *da9055);
|
||||
|
||||
extern struct regmap_config da9055_regmap_config;
|
||||
|
||||
#endif /* __DA9055_CORE_H */
|
|
@ -0,0 +1,32 @@
|
|||
/* Copyright (C) 2012 Dialog Semiconductor 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 __DA9055_PDATA_H
|
||||
#define __DA9055_PDATA_H
|
||||
|
||||
#define DA9055_MAX_REGULATORS 8
|
||||
|
||||
struct da9055;
|
||||
|
||||
enum gpio_select {
|
||||
NO_GPIO = 0,
|
||||
GPIO_1,
|
||||
GPIO_2
|
||||
};
|
||||
|
||||
struct da9055_pdata {
|
||||
int (*init) (struct da9055 *da9055);
|
||||
int irq_base;
|
||||
int gpio_base;
|
||||
|
||||
struct regulator_init_data *regulators[DA9055_MAX_REGULATORS];
|
||||
bool reset_enable; /* Enable RTC in RESET Mode */
|
||||
enum gpio_select *gpio_rsel; /* Select regulator set thru GPIO 1/2 */
|
||||
enum gpio_select *gpio_ren; /* Enable regulator thru GPIO 1/2 */
|
||||
};
|
||||
#endif /* __DA9055_PDATA_H */
|
|
@ -0,0 +1,699 @@
|
|||
/*
|
||||
* DA9055 declarations for DA9055 PMICs.
|
||||
*
|
||||
* Copyright(c) 2012 Dialog Semiconductor Ltd.
|
||||
*
|
||||
* Author: David Dajun Chen <dchen@diasemi.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.
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __DA9055_REG_H
|
||||
#define __DA9055_REG_H
|
||||
|
||||
/*
|
||||
* PMIC registers
|
||||
*/
|
||||
/* PAGE0 */
|
||||
#define DA9055_REG_PAGE_CON 0x00
|
||||
|
||||
/* System Control and Event Registers */
|
||||
#define DA9055_REG_STATUS_A 0x01
|
||||
#define DA9055_REG_STATUS_B 0x02
|
||||
#define DA9055_REG_FAULT_LOG 0x03
|
||||
#define DA9055_REG_EVENT_A 0x04
|
||||
#define DA9055_REG_EVENT_B 0x05
|
||||
#define DA9055_REG_EVENT_C 0x06
|
||||
#define DA9055_REG_IRQ_MASK_A 0x07
|
||||
#define DA9055_REG_IRQ_MASK_B 0x08
|
||||
#define DA9055_REG_IRQ_MASK_C 0x09
|
||||
#define DA9055_REG_CONTROL_A 0x0A
|
||||
#define DA9055_REG_CONTROL_B 0x0B
|
||||
#define DA9055_REG_CONTROL_C 0x0C
|
||||
#define DA9055_REG_CONTROL_D 0x0D
|
||||
#define DA9055_REG_CONTROL_E 0x0E
|
||||
#define DA9055_REG_PD_DIS 0x0F
|
||||
|
||||
/* GPIO Control Registers */
|
||||
#define DA9055_REG_GPIO0_1 0x10
|
||||
#define DA9055_REG_GPIO2 0x11
|
||||
#define DA9055_REG_GPIO_MODE0_2 0x12
|
||||
|
||||
/* Regulator Control Registers */
|
||||
#define DA9055_REG_BCORE_CONT 0x13
|
||||
#define DA9055_REG_BMEM_CONT 0x14
|
||||
#define DA9055_REG_LDO1_CONT 0x15
|
||||
#define DA9055_REG_LDO2_CONT 0x16
|
||||
#define DA9055_REG_LDO3_CONT 0x17
|
||||
#define DA9055_REG_LDO4_CONT 0x18
|
||||
#define DA9055_REG_LDO5_CONT 0x19
|
||||
#define DA9055_REG_LDO6_CONT 0x1A
|
||||
|
||||
/* GP-ADC Control Registers */
|
||||
#define DA9055_REG_ADC_MAN 0x1B
|
||||
#define DA9055_REG_ADC_CONT 0x1C
|
||||
#define DA9055_REG_VSYS_MON 0x1D
|
||||
#define DA9055_REG_ADC_RES_L 0x1E
|
||||
#define DA9055_REG_ADC_RES_H 0x1F
|
||||
#define DA9055_REG_VSYS_RES 0x20
|
||||
#define DA9055_REG_ADCIN1_RES 0x21
|
||||
#define DA9055_REG_ADCIN2_RES 0x22
|
||||
#define DA9055_REG_ADCIN3_RES 0x23
|
||||
|
||||
/* Sequencer Control Registers */
|
||||
#define DA9055_REG_EN_32K 0x35
|
||||
|
||||
/* Regulator Setting Registers */
|
||||
#define DA9055_REG_BUCK_LIM 0x37
|
||||
#define DA9055_REG_BCORE_MODE 0x38
|
||||
#define DA9055_REG_VBCORE_A 0x39
|
||||
#define DA9055_REG_VBMEM_A 0x3A
|
||||
#define DA9055_REG_VLDO1_A 0x3B
|
||||
#define DA9055_REG_VLDO2_A 0x3C
|
||||
#define DA9055_REG_VLDO3_A 0x3D
|
||||
#define DA9055_REG_VLDO4_A 0x3E
|
||||
#define DA9055_REG_VLDO5_A 0x3F
|
||||
#define DA9055_REG_VLDO6_A 0x40
|
||||
#define DA9055_REG_VBCORE_B 0x41
|
||||
#define DA9055_REG_VBMEM_B 0x42
|
||||
#define DA9055_REG_VLDO1_B 0x43
|
||||
#define DA9055_REG_VLDO2_B 0x44
|
||||
#define DA9055_REG_VLDO3_B 0x45
|
||||
#define DA9055_REG_VLDO4_B 0x46
|
||||
#define DA9055_REG_VLDO5_B 0x47
|
||||
#define DA9055_REG_VLDO6_B 0x48
|
||||
|
||||
/* GP-ADC Threshold Registers */
|
||||
#define DA9055_REG_AUTO1_HIGH 0x49
|
||||
#define DA9055_REG_AUTO1_LOW 0x4A
|
||||
#define DA9055_REG_AUTO2_HIGH 0x4B
|
||||
#define DA9055_REG_AUTO2_LOW 0x4C
|
||||
#define DA9055_REG_AUTO3_HIGH 0x4D
|
||||
#define DA9055_REG_AUTO3_LOW 0x4E
|
||||
|
||||
/* OTP */
|
||||
#define DA9055_REG_OPT_COUNT 0x50
|
||||
#define DA9055_REG_OPT_ADDR 0x51
|
||||
#define DA9055_REG_OPT_DATA 0x52
|
||||
|
||||
/* RTC Calendar and Alarm Registers */
|
||||
#define DA9055_REG_COUNT_S 0x53
|
||||
#define DA9055_REG_COUNT_MI 0x54
|
||||
#define DA9055_REG_COUNT_H 0x55
|
||||
#define DA9055_REG_COUNT_D 0x56
|
||||
#define DA9055_REG_COUNT_MO 0x57
|
||||
#define DA9055_REG_COUNT_Y 0x58
|
||||
#define DA9055_REG_ALARM_MI 0x59
|
||||
#define DA9055_REG_ALARM_H 0x5A
|
||||
#define DA9055_REG_ALARM_D 0x5B
|
||||
#define DA9055_REG_ALARM_MO 0x5C
|
||||
#define DA9055_REG_ALARM_Y 0x5D
|
||||
#define DA9055_REG_SECOND_A 0x5E
|
||||
#define DA9055_REG_SECOND_B 0x5F
|
||||
#define DA9055_REG_SECOND_C 0x60
|
||||
#define DA9055_REG_SECOND_D 0x61
|
||||
|
||||
/* Customer Trim and Configuration */
|
||||
#define DA9055_REG_T_OFFSET 0x63
|
||||
#define DA9055_REG_INTERFACE 0x64
|
||||
#define DA9055_REG_CONFIG_A 0x65
|
||||
#define DA9055_REG_CONFIG_B 0x66
|
||||
#define DA9055_REG_CONFIG_C 0x67
|
||||
#define DA9055_REG_CONFIG_D 0x68
|
||||
#define DA9055_REG_CONFIG_E 0x69
|
||||
#define DA9055_REG_TRIM_CLDR 0x6F
|
||||
|
||||
/* General Purpose Registers */
|
||||
#define DA9055_REG_GP_ID_0 0x70
|
||||
#define DA9055_REG_GP_ID_1 0x71
|
||||
#define DA9055_REG_GP_ID_2 0x72
|
||||
#define DA9055_REG_GP_ID_3 0x73
|
||||
#define DA9055_REG_GP_ID_4 0x74
|
||||
#define DA9055_REG_GP_ID_5 0x75
|
||||
#define DA9055_REG_GP_ID_6 0x76
|
||||
#define DA9055_REG_GP_ID_7 0x77
|
||||
#define DA9055_REG_GP_ID_8 0x78
|
||||
#define DA9055_REG_GP_ID_9 0x79
|
||||
#define DA9055_REG_GP_ID_10 0x7A
|
||||
#define DA9055_REG_GP_ID_11 0x7B
|
||||
#define DA9055_REG_GP_ID_12 0x7C
|
||||
#define DA9055_REG_GP_ID_13 0x7D
|
||||
#define DA9055_REG_GP_ID_14 0x7E
|
||||
#define DA9055_REG_GP_ID_15 0x7F
|
||||
#define DA9055_REG_GP_ID_16 0x80
|
||||
#define DA9055_REG_GP_ID_17 0x81
|
||||
#define DA9055_REG_GP_ID_18 0x82
|
||||
#define DA9055_REG_GP_ID_19 0x83
|
||||
|
||||
#define DA9055_MAX_REGISTER_CNT DA9055_REG_GP_ID_19
|
||||
|
||||
/*
|
||||
* PMIC registers bits
|
||||
*/
|
||||
|
||||
/* DA9055_REG_PAGE_CON (addr=0x00) */
|
||||
#define DA9055_PAGE_WRITE_MODE (0<<6)
|
||||
#define DA9055_REPEAT_WRITE_MODE (1<<6)
|
||||
|
||||
/* DA9055_REG_STATUS_A (addr=0x01) */
|
||||
#define DA9055_NOKEY_STS 0x01
|
||||
#define DA9055_WAKE_STS 0x02
|
||||
#define DA9055_DVC_BUSY_STS 0x04
|
||||
#define DA9055_COMP1V2_STS 0x08
|
||||
#define DA9055_NJIG_STS 0x10
|
||||
#define DA9055_LDO5_LIM_STS 0x20
|
||||
#define DA9055_LDO6_LIM_STS 0x40
|
||||
|
||||
/* DA9055_REG_STATUS_B (addr=0x02) */
|
||||
#define DA9055_GPI0_STS 0x01
|
||||
#define DA9055_GPI1_STS 0x02
|
||||
#define DA9055_GPI2_STS 0x04
|
||||
|
||||
/* DA9055_REG_FAULT_LOG (addr=0x03) */
|
||||
#define DA9055_TWD_ERROR_FLG 0x01
|
||||
#define DA9055_POR_FLG 0x02
|
||||
#define DA9055_VDD_FAULT_FLG 0x04
|
||||
#define DA9055_VDD_START_FLG 0x08
|
||||
#define DA9055_TEMP_CRIT_FLG 0x10
|
||||
#define DA9055_KEY_RESET_FLG 0x20
|
||||
#define DA9055_WAIT_SHUT_FLG 0x80
|
||||
|
||||
/* DA9055_REG_EVENT_A (addr=0x04) */
|
||||
#define DA9055_NOKEY_EINT 0x01
|
||||
#define DA9055_ALARM_EINT 0x02
|
||||
#define DA9055_TICK_EINT 0x04
|
||||
#define DA9055_ADC_RDY_EINT 0x08
|
||||
#define DA9055_SEQ_RDY_EINT 0x10
|
||||
#define DA9055_EVENTS_B_EINT 0x20
|
||||
#define DA9055_EVENTS_C_EINT 0x40
|
||||
|
||||
/* DA9055_REG_EVENT_B (addr=0x05) */
|
||||
#define DA9055_E_WAKE_EINT 0x01
|
||||
#define DA9055_E_TEMP_EINT 0x02
|
||||
#define DA9055_E_COMP1V2_EINT 0x04
|
||||
#define DA9055_E_LDO_LIM_EINT 0x08
|
||||
#define DA9055_E_NJIG_EINT 0x20
|
||||
#define DA9055_E_VDD_MON_EINT 0x40
|
||||
#define DA9055_E_VDD_WARN_EINT 0x80
|
||||
|
||||
/* DA9055_REG_EVENT_C (addr=0x06) */
|
||||
#define DA9055_E_GPI0_EINT 0x01
|
||||
#define DA9055_E_GPI1_EINT 0x02
|
||||
#define DA9055_E_GPI2_EINT 0x04
|
||||
|
||||
/* DA9055_REG_IRQ_MASK_A (addr=0x07) */
|
||||
#define DA9055_M_NONKEY_EINT 0x01
|
||||
#define DA9055_M_ALARM_EINT 0x02
|
||||
#define DA9055_M_TICK_EINT 0x04
|
||||
#define DA9055_M_ADC_RDY_EINT 0x08
|
||||
#define DA9055_M_SEQ_RDY_EINT 0x10
|
||||
|
||||
/* DA9055_REG_IRQ_MASK_B (addr=0x08) */
|
||||
#define DA9055_M_WAKE_EINT 0x01
|
||||
#define DA9055_M_TEMP_EINT 0x02
|
||||
#define DA9055_M_COMP_1V2_EINT 0x04
|
||||
#define DA9055_M_LDO_LIM_EINT 0x08
|
||||
#define DA9055_M_NJIG_EINT 0x20
|
||||
#define DA9055_M_VDD_MON_EINT 0x40
|
||||
#define DA9055_M_VDD_WARN_EINT 0x80
|
||||
|
||||
/* DA9055_REG_IRQ_MASK_C (addr=0x09) */
|
||||
#define DA9055_M_GPI0_EINT 0x01
|
||||
#define DA9055_M_GPI1_EINT 0x02
|
||||
#define DA9055_M_GPI2_EINT 0x04
|
||||
|
||||
/* DA9055_REG_CONTROL_A (addr=0xA) */
|
||||
#define DA9055_DEBOUNCING_SHIFT 0x00
|
||||
#define DA9055_DEBOUNCING_MASK 0x07
|
||||
#define DA9055_NRES_MODE_SHIFT 0x03
|
||||
#define DA9055_NRES_MODE_MASK 0x08
|
||||
#define DA9055_SLEW_RATE_SHIFT 0x04
|
||||
#define DA9055_SLEW_RATE_MASK 0x30
|
||||
#define DA9055_NOKEY_LOCK_SHIFT 0x06
|
||||
#define DA9055_NOKEY_LOCK_MASK 0x40
|
||||
|
||||
/* DA9055_REG_CONTROL_B (addr=0xB) */
|
||||
#define DA9055_RTC_MODE_PD 0x01
|
||||
#define DA9055_RTC_MODE_SD_SHIFT 0x01
|
||||
#define DA9055_RTC_MODE_SD 0x02
|
||||
#define DA9055_RTC_EN 0x04
|
||||
#define DA9055_ECO_MODE_SHIFT 0x03
|
||||
#define DA9055_ECO_MODE_MASK 0x08
|
||||
#define DA9055_TWDSCALE_SHIFT 4
|
||||
#define DA9055_TWDSCALE_MASK 0x70
|
||||
#define DA9055_V_LOCK_SHIFT 0x07
|
||||
#define DA9055_V_LOCK_MASK 0x80
|
||||
|
||||
/* DA9055_REG_CONTROL_C (addr=0xC) */
|
||||
#define DA9055_SYSTEM_EN_SHIFT 0x00
|
||||
#define DA9055_SYSTEM_EN_MASK 0x01
|
||||
#define DA9055_POWERN_EN_SHIFT 0x01
|
||||
#define DA9055_POWERN_EN_MASK 0x02
|
||||
#define DA9055_POWER1_EN_SHIFT 0x02
|
||||
#define DA9055_POWER1_EN_MASK 0x04
|
||||
|
||||
/* DA9055_REG_CONTROL_D (addr=0xD) */
|
||||
#define DA9055_STANDBY_SHIFT 0x02
|
||||
#define DA9055_STANDBY_MASK 0x08
|
||||
#define DA9055_AUTO_BOOT_SHIFT 0x03
|
||||
#define DA9055_AUTO_BOOT_MASK 0x04
|
||||
|
||||
/* DA9055_REG_CONTROL_E (addr=0xE) */
|
||||
#define DA9055_WATCHDOG_SHIFT 0x00
|
||||
#define DA9055_WATCHDOG_MASK 0x01
|
||||
#define DA9055_SHUTDOWN_SHIFT 0x01
|
||||
#define DA9055_SHUTDOWN_MASK 0x02
|
||||
#define DA9055_WAKE_UP_SHIFT 0x02
|
||||
#define DA9055_WAKE_UP_MASK 0x04
|
||||
|
||||
/* DA9055_REG_GPIO (addr=0x10/0x11) */
|
||||
#define DA9055_GPIO0_PIN_SHIFT 0x00
|
||||
#define DA9055_GPIO0_PIN_MASK 0x03
|
||||
#define DA9055_GPIO0_TYPE_SHIFT 0x02
|
||||
#define DA9055_GPIO0_TYPE_MASK 0x04
|
||||
#define DA9055_GPIO0_WEN_SHIFT 0x03
|
||||
#define DA9055_GPIO0_WEN_MASK 0x08
|
||||
#define DA9055_GPIO1_PIN_SHIFT 0x04
|
||||
#define DA9055_GPIO1_PIN_MASK 0x30
|
||||
#define DA9055_GPIO1_TYPE_SHIFT 0x06
|
||||
#define DA9055_GPIO1_TYPE_MASK 0x40
|
||||
#define DA9055_GPIO1_WEN_SHIFT 0x07
|
||||
#define DA9055_GPIO1_WEN_MASK 0x80
|
||||
#define DA9055_GPIO2_PIN_SHIFT 0x00
|
||||
#define DA9055_GPIO2_PIN_MASK 0x30
|
||||
#define DA9055_GPIO2_TYPE_SHIFT 0x02
|
||||
#define DA9055_GPIO2_TYPE_MASK 0x04
|
||||
#define DA9055_GPIO2_WEN_SHIFT 0x03
|
||||
#define DA9055_GPIO2_WEN_MASK 0x08
|
||||
|
||||
/* DA9055_REG_GPIO_MODE (addr=0x12) */
|
||||
#define DA9055_GPIO0_MODE_SHIFT 0x00
|
||||
#define DA9055_GPIO0_MODE_MASK 0x01
|
||||
#define DA9055_GPIO1_MODE_SHIFT 0x01
|
||||
#define DA9055_GPIO1_MODE_MASK 0x02
|
||||
#define DA9055_GPIO2_MODE_SHIFT 0x02
|
||||
#define DA9055_GPIO2_MODE_MASK 0x04
|
||||
|
||||
/* DA9055_REG_BCORE_CONT (addr=0x13) */
|
||||
#define DA9055_BCORE_EN_SHIFT 0x00
|
||||
#define DA9055_BCORE_EN_MASK 0x01
|
||||
#define DA9055_BCORE_GPI_SHIFT 0x01
|
||||
#define DA9055_BCORE_GPI_MASK 0x02
|
||||
#define DA9055_BCORE_PD_DIS_SHIFT 0x03
|
||||
#define DA9055_BCORE_PD_DIS_MASK 0x04
|
||||
#define DA9055_VBCORE_SEL_SHIFT 0x04
|
||||
#define DA9055_SEL_REG_A 0x0
|
||||
#define DA9055_SEL_REG_B 0x10
|
||||
#define DA9055_VBCORE_SEL_MASK 0x10
|
||||
#define DA9055_V_GPI_MASK 0x60
|
||||
#define DA9055_V_GPI_SHIFT 0x05
|
||||
#define DA9055_E_GPI_MASK 0x06
|
||||
#define DA9055_E_GPI_SHIFT 0x01
|
||||
#define DA9055_VBCORE_GPI_SHIFT 0x05
|
||||
#define DA9055_VBCORE_GPI_MASK 0x60
|
||||
#define DA9055_BCORE_CONF_SHIFT 0x07
|
||||
#define DA9055_BCORE_CONF_MASK 0x80
|
||||
|
||||
/* DA9055_REG_BMEM_CONT (addr=0x14) */
|
||||
#define DA9055_BMEM_EN_SHIFT 0x00
|
||||
#define DA9055_BMEM_EN_MASK 0x01
|
||||
#define DA9055_BMEM_GPI_SHIFT 0x01
|
||||
#define DA9055_BMEM_GPI_MASK 0x06
|
||||
#define DA9055_BMEM_PD_DIS_SHIFT 0x03
|
||||
#define DA9055_BMEM_PD_DIS_MASK 0x08
|
||||
#define DA9055_VBMEM_SEL_SHIT 0x04
|
||||
#define DA9055_VBMEM_SEL_VBMEM_A (0<<4)
|
||||
#define DA9055_VBMEM_SEL_VBMEM_B (1<<4)
|
||||
#define DA9055_VBMEM_SEL_MASK 0x10
|
||||
#define DA9055_VBMEM_GPI_SHIFT 0x05
|
||||
#define DA9055_VBMEM_GPI_MASK 0x60
|
||||
#define DA9055_BMEM_CONF_SHIFT 0x07
|
||||
#define DA9055_BMEM_CONF_MASK 0x80
|
||||
|
||||
/* DA9055_REG_LDO_CONT (addr=0x15-0x1A) */
|
||||
#define DA9055_LDO_EN_SHIFT 0x00
|
||||
#define DA9055_LDO_EN_MASK 0x01
|
||||
#define DA9055_LDO_GPI_SHIFT 0x01
|
||||
#define DA9055_LDO_GPI_MASK 0x06
|
||||
#define DA9055_LDO_PD_DIS_SHIFT 0x03
|
||||
#define DA9055_LDO_PD_DIS_MASK 0x08
|
||||
#define DA9055_VLDO_SEL_SHIFT 0x04
|
||||
#define DA9055_VLDO_SEL_MASK 0x10
|
||||
#define DA9055_VLDO_SEL_VLDO_A 0x00
|
||||
#define DA9055_VLDO_SEL_VLDO_B 0x01
|
||||
#define DA9055_VLDO_GPI_SHIFT 0x05
|
||||
#define DA9055_VLDO_GPI_MASK 0x60
|
||||
#define DA9055_LDO_CONF_SHIFT 0x07
|
||||
#define DA9055_LDO_CONF_MASK 0x80
|
||||
#define DA9055_REGUALTOR_SET_A 0x00
|
||||
#define DA9055_REGUALTOR_SET_B 0x10
|
||||
|
||||
/* DA9055_REG_ADC_MAN (addr=0x1B) */
|
||||
#define DA9055_ADC_MUX_SHIFT 0
|
||||
#define DA9055_ADC_MUX_MASK 0xF
|
||||
#define DA9055_ADC_MUX_VSYS 0x0
|
||||
#define DA9055_ADC_MUX_ADCIN1 0x01
|
||||
#define DA9055_ADC_MUX_ADCIN2 0x02
|
||||
#define DA9055_ADC_MUX_ADCIN3 0x03
|
||||
#define DA9055_ADC_MUX_T_SENSE 0x04
|
||||
#define DA9055_ADC_MAN_SHIFT 0x04
|
||||
#define DA9055_ADC_MAN_CONV 0x10
|
||||
#define DA9055_ADC_LSB_MASK 0X03
|
||||
#define DA9055_ADC_MODE_MASK 0x20
|
||||
#define DA9055_ADC_MODE_SHIFT 5
|
||||
#define DA9055_ADC_MODE_1MS (1<<5)
|
||||
#define DA9055_COMP1V2_EN_SHIFT 7
|
||||
|
||||
/* DA9055_REG_ADC_CONT (addr=0x1C) */
|
||||
#define DA9055_ADC_AUTO_VSYS_EN_SHIFT 0
|
||||
#define DA9055_ADC_AUTO_AD1_EN_SHIFT 1
|
||||
#define DA9055_ADC_AUTO_AD2_EN_SHIFT 2
|
||||
#define DA9055_ADC_AUTO_AD3_EN_SHIFT 3
|
||||
#define DA9055_ADC_ISRC_EN_SHIFT 4
|
||||
#define DA9055_ADC_ADCIN1_DEB_SHIFT 5
|
||||
#define DA9055_ADC_ADCIN2_DEB_SHIFT 6
|
||||
#define DA9055_ADC_ADCIN3_DEB_SHIFT 7
|
||||
#define DA9055_AD1_ISRC_MASK 0x10
|
||||
#define DA9055_AD1_ISRC_SHIFT 4
|
||||
|
||||
/* DA9055_REG_VSYS_MON (addr=0x1D) */
|
||||
#define DA9055_VSYS_VAL_SHIFT 0
|
||||
#define DA9055_VSYS_VAL_MASK 0xFF
|
||||
#define DA9055_VSYS_VAL_BASE 0x00
|
||||
#define DA9055_VSYS_VAL_MAX DA9055_VSYS_VAL_MASK
|
||||
#define DA9055_VSYS_VOLT_BASE 2500
|
||||
#define DA9055_VSYS_VOLT_INC 10
|
||||
#define DA9055_VSYS_STEPS 255
|
||||
#define DA9055_VSYS_VOLT_MIN 2500
|
||||
|
||||
/* DA9044_REG_XXX_RES (addr=0x20-0x23) */
|
||||
#define DA9055_ADC_VAL_SHIFT 0
|
||||
#define DA9055_ADC_VAL_MASK 0xFF
|
||||
#define DA9055_ADC_VAL_BASE 0x00
|
||||
#define DA9055_ADC_VAL_MAX DA9055_ADC_VAL_MASK
|
||||
#define DA9055_ADC_VOLT_BASE 0
|
||||
#define DA9055_ADC_VSYS_VOLT_BASE 2500
|
||||
#define DA9055_ADC_VOLT_INC 10
|
||||
#define DA9055_ADC_VSYS_VOLT_INC 12
|
||||
#define DA9055_ADC_STEPS 255
|
||||
|
||||
/* DA9055_REG_EN_32K (addr=0x35)*/
|
||||
#define DA9055_STARTUP_TIME_MASK 0x07
|
||||
#define DA9055_STARTUP_TIME_0S 0x0
|
||||
#define DA9055_STARTUP_TIME_0_52S 0x1
|
||||
#define DA9055_STARTUP_TIME_1S 0x2
|
||||
#define DA9055_CRYSTAL_EN 0x08
|
||||
#define DA9055_DELAY_MODE_EN 0x10
|
||||
#define DA9055_OUT_CLCK_GATED 0x20
|
||||
#define DA9055_RTC_CLOCK_GATED 0x40
|
||||
#define DA9055_EN_32KOUT_BUF 0x80
|
||||
|
||||
/* DA9055_REG_RESET (addr=0x36) */
|
||||
/* Timer up to 31.744 ms */
|
||||
#define DA9055_RESET_TIMER_VAL_SHIFT 0
|
||||
#define DA9055_RESET_LOW_VAL_MASK 0x3F
|
||||
#define DA9055_RESET_LOW_VAL_BASE 0
|
||||
#define DA9055_RESET_LOW_VAL_MAX DA9055_RESET_LOW_VAL_MASK
|
||||
#define DA9055_RESET_US_LOW_BASE 1024 /* min val in units of us */
|
||||
#define DA9055_RESET_US_LOW_INC 1024 /* inc val in units of us */
|
||||
#define DA9055_RESET_US_LOW_STEP 30
|
||||
|
||||
/* Timer up to 1048.576ms */
|
||||
#define DA9055_RESET_HIGH_VAL_MASK 0x3F
|
||||
#define DA9055_RESET_HIGH_VAL_BASE 0
|
||||
#define DA9055_RESET_HIGH_VAL_MAX DA9055_RESET_HIGH_VAL_MASK
|
||||
#define DA9055_RESET_US_HIGH_BASE 32768 /* min val in units of us */
|
||||
#define DA9055_RESET_US_HIGH_INC 32768 /* inv val in units of us */
|
||||
#define DA9055_RESET_US_HIGH_STEP 31
|
||||
|
||||
/* DA9055_REG_BUCK_ILIM (addr=0x37)*/
|
||||
#define DA9055_BMEM_ILIM_SHIFT 0
|
||||
#define DA9055_ILIM_MASK 0x3
|
||||
#define DA9055_ILIM_500MA 0x0
|
||||
#define DA9055_ILIM_600MA 0x1
|
||||
#define DA9055_ILIM_700MA 0x2
|
||||
#define DA9055_ILIM_800MA 0x3
|
||||
#define DA9055_BCORE_ILIM_SHIFT 2
|
||||
|
||||
/* DA9055_REG_BCORE_MODE (addr=0x38) */
|
||||
#define DA9055_BMEM_MODE_SHIFT 0
|
||||
#define DA9055_MODE_MASK 0x3
|
||||
#define DA9055_MODE_AB 0x0
|
||||
#define DA9055_MODE_SLEEP 0x1
|
||||
#define DA9055_MODE_SYNCHRO 0x2
|
||||
#define DA9055_MODE_AUTO 0x3
|
||||
#define DA9055_BCORE_MODE_SHIFT 2
|
||||
|
||||
/* DA9055_REG_VBCORE_A/B (addr=0x39/0x41)*/
|
||||
#define DA9055_VBCORE_VAL_SHIFT 0
|
||||
#define DA9055_VBCORE_VAL_MASK 0x3F
|
||||
#define DA9055_VBCORE_VAL_BASE 0x09
|
||||
#define DA9055_VBCORE_VAL_MAX DA9055_VBCORE_VAL_MASK
|
||||
#define DA9055_VBCORE_VOLT_BASE 750
|
||||
#define DA9055_VBCORE_VOLT_INC 25
|
||||
#define DA9055_VBCORE_STEPS 53
|
||||
#define DA9055_VBCORE_VOLT_MIN DA9055_VBCORE_VOLT_BASE
|
||||
#define DA9055_BCORE_SL_SYNCHRO (0<<7)
|
||||
#define DA9055_BCORE_SL_SLEEP (1<<7)
|
||||
|
||||
/* DA9055_REG_VBMEM_A/B (addr=0x3A/0x42)*/
|
||||
#define DA9055_VBMEM_VAL_SHIFT 0
|
||||
#define DA9055_VBMEM_VAL_MASK 0x3F
|
||||
#define DA9055_VBMEM_VAL_BASE 0x00
|
||||
#define DA9055_VBMEM_VAL_MAX DA9055_VBMEM_VAL_MASK
|
||||
#define DA9055_VBMEM_VOLT_BASE 925
|
||||
#define DA9055_VBMEM_VOLT_INC 25
|
||||
#define DA9055_VBMEM_STEPS 63
|
||||
#define DA9055_VBMEM_VOLT_MIN DA9055_VBMEM_VOLT_BASE
|
||||
#define DA9055_BCMEM_SL_SYNCHRO (0<<7)
|
||||
#define DA9055_BCMEM_SL_SLEEP (1<<7)
|
||||
|
||||
|
||||
/* DA9055_REG_VLDO (addr=0x3B-0x40/0x43-0x48)*/
|
||||
#define DA9055_VLDO_VAL_SHIFT 0
|
||||
#define DA9055_VLDO_VAL_MASK 0x3F
|
||||
#define DA9055_VLDO6_VAL_MASK 0x7F
|
||||
#define DA9055_VLDO_VAL_BASE 0x02
|
||||
#define DA9055_VLDO2_VAL_BASE 0x03
|
||||
#define DA9055_VLDO6_VAL_BASE 0x00
|
||||
#define DA9055_VLDO_VAL_MAX DA9055_VLDO_VAL_MASK
|
||||
#define DA9055_VLDO6_VAL_MAX DA9055_VLDO6_VAL_MASK
|
||||
#define DA9055_VLDO_VOLT_BASE 900
|
||||
#define DA9055_VLDO_VOLT_INC 50
|
||||
#define DA9055_VLDO6_VOLT_INC 20
|
||||
#define DA9055_VLDO_STEPS 48
|
||||
#define DA9055_VLDO5_STEPS 37
|
||||
#define DA9055_VLDO6_STEPS 120
|
||||
#define DA9055_VLDO_VOLT_MIN DA9055_VLDO_VOLT_BASE
|
||||
#define DA9055_LDO_MODE_SHIFT 7
|
||||
#define DA9055_LDO_SL_NORMAL 0
|
||||
#define DA9055_LDO_SL_SLEEP 1
|
||||
|
||||
/* DA9055_REG_OTP_CONT (addr=0x50) */
|
||||
#define DA9055_OTP_TIM_NORMAL (0<<0)
|
||||
#define DA9055_OTP_TIM_MARGINAL (1<<0)
|
||||
#define DA9055_OTP_GP_RD_SHIFT 1
|
||||
#define DA9055_OTP_APPS_RD_SHIFT 2
|
||||
#define DA9055_PC_DONE_SHIFT 3
|
||||
#define DA9055_OTP_GP_LOCK_SHIFT 4
|
||||
#define DA9055_OTP_APPS_LOCK_SHIFT 5
|
||||
#define DA9055_OTP_CONF_LOCK_SHIFT 6
|
||||
#define DA9055_OTP_WRITE_DIS_SHIFT 7
|
||||
|
||||
/* DA9055_REG_COUNT_S (addr=0x53) */
|
||||
#define DA9055_RTC_SEC 0x3F
|
||||
#define DA9055_RTC_MONITOR_EN 0x40
|
||||
#define DA9055_RTC_READ 0x80
|
||||
|
||||
/* DA9055_REG_COUNT_MI (addr=0x54) */
|
||||
#define DA9055_RTC_MIN 0x3F
|
||||
|
||||
/* DA9055_REG_COUNT_H (addr=0x55) */
|
||||
#define DA9055_RTC_HOUR 0x1F
|
||||
|
||||
/* DA9055_REG_COUNT_D (addr=0x56) */
|
||||
#define DA9055_RTC_DAY 0x1F
|
||||
|
||||
/* DA9055_REG_COUNT_MO (addr=0x57) */
|
||||
#define DA9055_RTC_MONTH 0x0F
|
||||
|
||||
/* DA9055_REG_COUNT_Y (addr=0x58) */
|
||||
#define DA9055_RTC_YEAR 0x3F
|
||||
#define DA9055_RTC_YEAR_BASE 2000
|
||||
|
||||
/* DA9055_REG_ALARM_MI (addr=0x59) */
|
||||
#define DA9055_RTC_ALM_MIN 0x3F
|
||||
#define DA9055_ALARM_STATUS_SHIFT 6
|
||||
#define DA9055_ALARM_STATUS_MASK 0x3
|
||||
#define DA9055_ALARM_STATUS_NO_ALARM 0x0
|
||||
#define DA9055_ALARM_STATUS_TICK 0x1
|
||||
#define DA9055_ALARM_STATUS_TIMER_ALARM 0x2
|
||||
#define DA9055_ALARM_STATUS_BOTH 0x3
|
||||
|
||||
/* DA9055_REG_ALARM_H (addr=0x5A) */
|
||||
#define DA9055_RTC_ALM_HOUR 0x1F
|
||||
|
||||
/* DA9055_REG_ALARM_D (addr=0x5B) */
|
||||
#define DA9055_RTC_ALM_DAY 0x1F
|
||||
|
||||
/* DA9055_REG_ALARM_MO (addr=0x5C) */
|
||||
#define DA9055_RTC_ALM_MONTH 0x0F
|
||||
#define DA9055_RTC_TICK_WAKE_MASK 0x20
|
||||
#define DA9055_RTC_TICK_WAKE_SHIFT 5
|
||||
#define DA9055_RTC_TICK_TYPE 0x10
|
||||
#define DA9055_RTC_TICK_TYPE_SHIFT 0x4
|
||||
#define DA9055_RTC_TICK_SEC 0x0
|
||||
#define DA9055_RTC_TICK_MIN 0x1
|
||||
#define DA9055_ALARAM_TICK_WAKE 0x20
|
||||
|
||||
/* DA9055_REG_ALARM_Y (addr=0x5D) */
|
||||
#define DA9055_RTC_TICK_EN 0x80
|
||||
#define DA9055_RTC_ALM_EN 0x40
|
||||
#define DA9055_RTC_TICK_ALM_MASK 0xC0
|
||||
#define DA9055_RTC_ALM_YEAR 0x3F
|
||||
|
||||
/* DA9055_REG_TRIM_CLDR (addr=0x62) */
|
||||
#define DA9055_TRIM_32K_SHIFT 0
|
||||
#define DA9055_TRIM_32K_MASK 0x7F
|
||||
#define DA9055_TRIM_DECREMENT (1<<7)
|
||||
#define DA9055_TRIM_INCREMENT (0<<7)
|
||||
#define DA9055_TRIM_VAL_BASE 0x0
|
||||
#define DA9055_TRIM_PPM_BASE 0x0 /* min val in units of 0.1PPM */
|
||||
#define DA9055_TRIM_PPM_INC 19 /* min inc in units of 0.1PPM */
|
||||
#define DA9055_TRIM_STEPS 127
|
||||
|
||||
/* DA9055_REG_CONFIG_A (addr=0x65) */
|
||||
#define DA9055_PM_I_V_VDDCORE (0<<0)
|
||||
#define DA9055_PM_I_V_VDD_IO (1<<0)
|
||||
#define DA9055_VDD_FAULT_TYPE_ACT_LOW (0<<1)
|
||||
#define DA9055_VDD_FAULT_TYPE_ACT_HIGH (1<<1)
|
||||
#define DA9055_PM_O_TYPE_PUSH_PULL (0<<2)
|
||||
#define DA9055_PM_O_TYPE_OPEN_DRAIN (1<<2)
|
||||
#define DA9055_IRQ_TYPE_ACT_LOW (0<<3)
|
||||
#define DA9055_IRQ_TYPE_ACT_HIGH (1<<3)
|
||||
#define DA9055_NIRQ_MODE_IMM (0<<4)
|
||||
#define DA9055_NIRQ_MODE_ACTIVE (1<<4)
|
||||
#define DA9055_GPI_V_VDDCORE (0<<5)
|
||||
#define DA9055_GPI_V_VDD_IO (1<<5)
|
||||
#define DA9055_PM_IF_V_VDDCORE (0<<6)
|
||||
#define DA9055_PM_IF_V_VDD_IO (1<<6)
|
||||
|
||||
/* DA9055_REG_CONFIG_B (addr=0x66) */
|
||||
#define DA9055_VDD_FAULT_VAL_SHIFT 0
|
||||
#define DA9055_VDD_FAULT_VAL_MASK 0xF
|
||||
#define DA9055_VDD_FAULT_VAL_BASE 0x0
|
||||
#define DA9055_VDD_FAULT_VAL_MAX DA9055_VDD_FAULT_VAL_MASK
|
||||
#define DA9055_VDD_FAULT_VOLT_BASE 2500
|
||||
#define DA9055_VDD_FAULT_VOLT_INC 50
|
||||
#define DA9055_VDD_FAULT_STEPS 15
|
||||
|
||||
#define DA9055_VDD_HYST_VAL_SHIFT 4
|
||||
#define DA9055_VDD_HYST_VAL_MASK 0x7
|
||||
#define DA9055_VDD_HYST_VAL_BASE 0x0
|
||||
#define DA9055_VDD_HYST_VAL_MAX DA9055_VDD_HYST_VAL_MASK
|
||||
#define DA9055_VDD_HYST_VOLT_BASE 100
|
||||
#define DA9055_VDD_HYST_VOLT_INC 50
|
||||
#define DA9055_VDD_HYST_STEPS 7
|
||||
#define DA9055_VDD_HYST_VOLT_MIN DA9055_VDD_HYST_VOLT_BASE
|
||||
|
||||
#define DA9055_VDD_FAULT_EN_SHIFT 7
|
||||
|
||||
/* DA9055_REG_CONFIG_C (addr=0x67) */
|
||||
#define DA9055_BCORE_CLK_INV_SHIFT 0
|
||||
#define DA9055_BMEM_CLK_INV_SHIFT 1
|
||||
#define DA9055_NFAULT_CONF_SHIFT 2
|
||||
#define DA9055_LDO_SD_SHIFT 4
|
||||
#define DA9055_LDO5_BYP_SHIFT 6
|
||||
#define DA9055_LDO6_BYP_SHIFT 7
|
||||
|
||||
/* DA9055_REG_CONFIG_D (addr=0x68) */
|
||||
#define DA9055_NONKEY_PIN_SHIFT 0
|
||||
#define DA9055_NONKEY_PIN_MASK 0x3
|
||||
#define DA9055_NONKEY_PIN_PORT_MODE 0x0
|
||||
#define DA9055_NONKEY_PIN_KEY_MODE 0x1
|
||||
#define DA9055_NONKEY_PIN_MULTI_FUNC 0x2
|
||||
#define DA9055_NONKEY_PIN_DEDICT 0x3
|
||||
#define DA9055_NONKEY_SD_SHIFT 2
|
||||
#define DA9055_KEY_DELAY_SHIFT 3
|
||||
#define DA9055_KEY_DELAY_MASK 0x3
|
||||
#define DA9055_KEY_DELAY_4S 0x0
|
||||
#define DA9055_KEY_DELAY_6S 0x1
|
||||
#define DA9055_KEY_DELAY_8S 0x2
|
||||
#define DA9055_KEY_DELAY_10S 0x3
|
||||
|
||||
/* DA9055_REG_CONFIG_E (addr=0x69) */
|
||||
#define DA9055_GPIO_PUPD_PULL_UP 0x0
|
||||
#define DA9055_GPIO_PUPD_OPEN_DRAIN 0x1
|
||||
#define DA9055_GPIO0_PUPD_SHIFT 0
|
||||
#define DA9055_GPIO1_PUPD_SHIFT 1
|
||||
#define DA9055_GPIO2_PUPD_SHIFT 2
|
||||
#define DA9055_UVOV_DELAY_SHIFT 4
|
||||
#define DA9055_UVOV_DELAY_MASK 0x3
|
||||
#define DA9055_RESET_DURATION_SHIFT 6
|
||||
#define DA9055_RESET_DURATION_MASK 0x3
|
||||
#define DA9055_RESET_DURATION_0MS 0x0
|
||||
#define DA9055_RESET_DURATION_100MS 0x1
|
||||
#define DA9055_RESET_DURATION_500MS 0x2
|
||||
#define DA9055_RESET_DURATION_1000MS 0x3
|
||||
|
||||
/* DA9055_REG_MON_REG_1 (addr=0x6A) */
|
||||
#define DA9055_MON_THRES_SHIFT 0
|
||||
#define DA9055_MON_THRES_MASK 0x3
|
||||
#define DA9055_MON_RES_SHIFT 2
|
||||
#define DA9055_MON_DEB_SHIFT 3
|
||||
#define DA9055_MON_MODE_SHIFT 4
|
||||
#define DA9055_MON_MODE_MASK 0x3
|
||||
#define DA9055_START_MAX_SHIFT 6
|
||||
#define DA9055_START_MAX_MASK 0x3
|
||||
|
||||
/* DA9055_REG_MON_REG_2 (addr=0x6B) */
|
||||
#define DA9055_LDO1_MON_EN_SHIFT 0
|
||||
#define DA9055_LDO2_MON_EN_SHIFT 1
|
||||
#define DA9055_LDO3_MON_EN_SHIFT 2
|
||||
#define DA9055_LDO4_MON_EN_SHIFT 3
|
||||
#define DA9055_LDO5_MON_EN_SHIFT 4
|
||||
#define DA9055_LDO6_MON_EN_SHIFT 5
|
||||
#define DA9055_BCORE_MON_EN_SHIFT 6
|
||||
#define DA9055_BMEM_MON_EN_SHIFT 7
|
||||
|
||||
/* DA9055_REG_CONFIG_F (addr=0x6C) */
|
||||
#define DA9055_LDO1_DEF_SHIFT 0
|
||||
#define DA9055_LDO2_DEF_SHIFT 1
|
||||
#define DA9055_LDO3_DEF_SHIFT 2
|
||||
#define DA9055_LDO4_DEF_SHIFT 3
|
||||
#define DA9055_LDO5_DEF_SHIFT 4
|
||||
#define DA9055_LDO6_DEF_SHIFT 5
|
||||
#define DA9055_BCORE_DEF_SHIFT 6
|
||||
#define DA9055_BMEM_DEF_SHIFT 7
|
||||
|
||||
/* DA9055_REG_MON_REG_4 (addr=0x6D) */
|
||||
#define DA9055_MON_A8_IDX_SHIFT 0
|
||||
#define DA9055_MON_A89_IDX_MASK 0x3
|
||||
#define DA9055_MON_A89_IDX_NONE 0x0
|
||||
#define DA9055_MON_A89_IDX_BUCKCORE 0x1
|
||||
#define DA9055_MON_A89_IDX_LDO3 0x2
|
||||
#define DA9055_MON_A9_IDX_SHIFT 5
|
||||
|
||||
/* DA9055_REG_MON_REG_5 (addr=0x6E) */
|
||||
#define DA9055_MON_A10_IDX_SHIFT 0
|
||||
#define DA9055_MON_A10_IDX_MASK 0x3
|
||||
#define DA9055_MON_A10_IDX_NONE 0x0
|
||||
#define DA9055_MON_A10_IDX_LDO1 0x1
|
||||
#define DA9055_MON_A10_IDX_LDO2 0x2
|
||||
#define DA9055_MON_A10_IDX_LDO5 0x3
|
||||
#define DA9055_MON_A10_IDX_LDO6 0x4
|
||||
|
||||
#endif /* __DA9055_REG_H */
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* TI LP8788 MFD - common definitions for current sinks
|
||||
*
|
||||
* Copyright 2012 Texas Instruments
|
||||
*
|
||||
* Author: Milo(Woogyom) Kim <milo.kim@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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __ISINK_LP8788_H__
|
||||
#define __ISINK_LP8788_H__
|
||||
|
||||
/* register address */
|
||||
#define LP8788_ISINK_CTRL 0x99
|
||||
#define LP8788_ISINK12_IOUT 0x9A
|
||||
#define LP8788_ISINK3_IOUT 0x9B
|
||||
#define LP8788_ISINK1_PWM 0x9C
|
||||
#define LP8788_ISINK2_PWM 0x9D
|
||||
#define LP8788_ISINK3_PWM 0x9E
|
||||
|
||||
/* mask bits */
|
||||
#define LP8788_ISINK1_IOUT_M 0x0F /* Addr 9Ah */
|
||||
#define LP8788_ISINK2_IOUT_M 0xF0
|
||||
#define LP8788_ISINK3_IOUT_M 0x0F /* Addr 9Bh */
|
||||
|
||||
/* 6 bits used for PWM code : Addr 9C ~ 9Eh */
|
||||
#define LP8788_ISINK_MAX_PWM 63
|
||||
#define LP8788_ISINK_SCALE_OFFSET 3
|
||||
|
||||
static const u8 lp8788_iout_addr[] = {
|
||||
LP8788_ISINK12_IOUT,
|
||||
LP8788_ISINK12_IOUT,
|
||||
LP8788_ISINK3_IOUT,
|
||||
};
|
||||
|
||||
static const u8 lp8788_iout_mask[] = {
|
||||
LP8788_ISINK1_IOUT_M,
|
||||
LP8788_ISINK2_IOUT_M,
|
||||
LP8788_ISINK3_IOUT_M,
|
||||
};
|
||||
|
||||
static const u8 lp8788_pwm_addr[] = {
|
||||
LP8788_ISINK1_PWM,
|
||||
LP8788_ISINK2_PWM,
|
||||
LP8788_ISINK3_PWM,
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,364 @@
|
|||
/*
|
||||
* TI LP8788 MFD Device
|
||||
*
|
||||
* Copyright 2012 Texas Instruments
|
||||
*
|
||||
* Author: Milo(Woogyom) Kim <milo.kim@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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __MFD_LP8788_H__
|
||||
#define __MFD_LP8788_H__
|
||||
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define LP8788_DEV_BUCK "lp8788-buck"
|
||||
#define LP8788_DEV_DLDO "lp8788-dldo"
|
||||
#define LP8788_DEV_ALDO "lp8788-aldo"
|
||||
#define LP8788_DEV_CHARGER "lp8788-charger"
|
||||
#define LP8788_DEV_RTC "lp8788-rtc"
|
||||
#define LP8788_DEV_BACKLIGHT "lp8788-backlight"
|
||||
#define LP8788_DEV_VIBRATOR "lp8788-vibrator"
|
||||
#define LP8788_DEV_KEYLED "lp8788-keyled"
|
||||
#define LP8788_DEV_ADC "lp8788-adc"
|
||||
|
||||
#define LP8788_NUM_BUCKS 4
|
||||
#define LP8788_NUM_DLDOS 12
|
||||
#define LP8788_NUM_ALDOS 10
|
||||
#define LP8788_NUM_BUCK2_DVS 2
|
||||
|
||||
#define LP8788_CHG_IRQ "CHG_IRQ"
|
||||
#define LP8788_PRSW_IRQ "PRSW_IRQ"
|
||||
#define LP8788_BATT_IRQ "BATT_IRQ"
|
||||
#define LP8788_ALM_IRQ "ALARM_IRQ"
|
||||
|
||||
enum lp8788_int_id {
|
||||
/* interrup register 1 : Addr 00h */
|
||||
LP8788_INT_TSDL,
|
||||
LP8788_INT_TSDH,
|
||||
LP8788_INT_UVLO,
|
||||
LP8788_INT_FLAGMON,
|
||||
LP8788_INT_PWRON_TIME,
|
||||
LP8788_INT_PWRON,
|
||||
LP8788_INT_COMP1,
|
||||
LP8788_INT_COMP2,
|
||||
|
||||
/* interrupt register 2 : Addr 01h */
|
||||
LP8788_INT_CHG_INPUT_STATE,
|
||||
LP8788_INT_CHG_STATE,
|
||||
LP8788_INT_EOC,
|
||||
LP8788_INT_CHG_RESTART,
|
||||
LP8788_INT_RESTART_TIMEOUT,
|
||||
LP8788_INT_FULLCHG_TIMEOUT,
|
||||
LP8788_INT_PRECHG_TIMEOUT,
|
||||
|
||||
/* interrupt register 3 : Addr 02h */
|
||||
LP8788_INT_RTC_ALARM1 = 17,
|
||||
LP8788_INT_RTC_ALARM2,
|
||||
LP8788_INT_ENTER_SYS_SUPPORT,
|
||||
LP8788_INT_EXIT_SYS_SUPPORT,
|
||||
LP8788_INT_BATT_LOW,
|
||||
LP8788_INT_NO_BATT,
|
||||
|
||||
LP8788_INT_MAX = 24,
|
||||
};
|
||||
|
||||
enum lp8788_dvs_sel {
|
||||
DVS_SEL_V0,
|
||||
DVS_SEL_V1,
|
||||
DVS_SEL_V2,
|
||||
DVS_SEL_V3,
|
||||
};
|
||||
|
||||
enum lp8788_ext_ldo_en_id {
|
||||
EN_ALDO1,
|
||||
EN_ALDO234,
|
||||
EN_ALDO5,
|
||||
EN_ALDO7,
|
||||
EN_DLDO7,
|
||||
EN_DLDO911,
|
||||
EN_LDOS_MAX,
|
||||
};
|
||||
|
||||
enum lp8788_charger_event {
|
||||
NO_CHARGER,
|
||||
CHARGER_DETECTED,
|
||||
};
|
||||
|
||||
enum lp8788_bl_ctrl_mode {
|
||||
LP8788_BL_REGISTER_ONLY,
|
||||
LP8788_BL_COMB_PWM_BASED, /* PWM + I2C, changed by PWM input */
|
||||
LP8788_BL_COMB_REGISTER_BASED, /* PWM + I2C, changed by I2C */
|
||||
};
|
||||
|
||||
enum lp8788_bl_dim_mode {
|
||||
LP8788_DIM_EXPONENTIAL,
|
||||
LP8788_DIM_LINEAR,
|
||||
};
|
||||
|
||||
enum lp8788_bl_full_scale_current {
|
||||
LP8788_FULLSCALE_5000uA,
|
||||
LP8788_FULLSCALE_8500uA,
|
||||
LP8788_FULLSCALE_1200uA,
|
||||
LP8788_FULLSCALE_1550uA,
|
||||
LP8788_FULLSCALE_1900uA,
|
||||
LP8788_FULLSCALE_2250uA,
|
||||
LP8788_FULLSCALE_2600uA,
|
||||
LP8788_FULLSCALE_2950uA,
|
||||
};
|
||||
|
||||
enum lp8788_bl_ramp_step {
|
||||
LP8788_RAMP_8us,
|
||||
LP8788_RAMP_1024us,
|
||||
LP8788_RAMP_2048us,
|
||||
LP8788_RAMP_4096us,
|
||||
LP8788_RAMP_8192us,
|
||||
LP8788_RAMP_16384us,
|
||||
LP8788_RAMP_32768us,
|
||||
LP8788_RAMP_65538us,
|
||||
};
|
||||
|
||||
enum lp8788_bl_pwm_polarity {
|
||||
LP8788_PWM_ACTIVE_HIGH,
|
||||
LP8788_PWM_ACTIVE_LOW,
|
||||
};
|
||||
|
||||
enum lp8788_isink_scale {
|
||||
LP8788_ISINK_SCALE_100mA,
|
||||
LP8788_ISINK_SCALE_120mA,
|
||||
};
|
||||
|
||||
enum lp8788_isink_number {
|
||||
LP8788_ISINK_1,
|
||||
LP8788_ISINK_2,
|
||||
LP8788_ISINK_3,
|
||||
};
|
||||
|
||||
enum lp8788_alarm_sel {
|
||||
LP8788_ALARM_1,
|
||||
LP8788_ALARM_2,
|
||||
LP8788_ALARM_MAX,
|
||||
};
|
||||
|
||||
enum lp8788_adc_id {
|
||||
LPADC_VBATT_5P5,
|
||||
LPADC_VIN_CHG,
|
||||
LPADC_IBATT,
|
||||
LPADC_IC_TEMP,
|
||||
LPADC_VBATT_6P0,
|
||||
LPADC_VBATT_5P0,
|
||||
LPADC_ADC1,
|
||||
LPADC_ADC2,
|
||||
LPADC_VDD,
|
||||
LPADC_VCOIN,
|
||||
LPADC_VDD_LDO,
|
||||
LPADC_ADC3,
|
||||
LPADC_ADC4,
|
||||
LPADC_MAX,
|
||||
};
|
||||
|
||||
struct lp8788;
|
||||
|
||||
/*
|
||||
* lp8788_buck1_dvs
|
||||
* @gpio : gpio pin number for dvs control
|
||||
* @vsel : dvs selector for buck v1 register
|
||||
*/
|
||||
struct lp8788_buck1_dvs {
|
||||
int gpio;
|
||||
enum lp8788_dvs_sel vsel;
|
||||
};
|
||||
|
||||
/*
|
||||
* lp8788_buck2_dvs
|
||||
* @gpio : two gpio pin numbers are used for dvs
|
||||
* @vsel : dvs selector for buck v2 register
|
||||
*/
|
||||
struct lp8788_buck2_dvs {
|
||||
int gpio[LP8788_NUM_BUCK2_DVS];
|
||||
enum lp8788_dvs_sel vsel;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct lp8788_ldo_enable_pin
|
||||
*
|
||||
* Basically, all LDOs are enabled through the I2C commands.
|
||||
* But ALDO 1 ~ 5, 7, DLDO 7, 9, 11 can be enabled by external gpio pins.
|
||||
*
|
||||
* @gpio : gpio number which is used for enabling ldos
|
||||
* @init_state : initial gpio state (ex. GPIOF_OUT_INIT_LOW)
|
||||
*/
|
||||
struct lp8788_ldo_enable_pin {
|
||||
int gpio;
|
||||
int init_state;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct lp8788_chg_param
|
||||
* @addr : charging control register address (range : 0x11 ~ 0x1C)
|
||||
* @val : charging parameter value
|
||||
*/
|
||||
struct lp8788_chg_param {
|
||||
u8 addr;
|
||||
u8 val;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct lp8788_charger_platform_data
|
||||
* @vbatt_adc : adc selection id for battery voltage
|
||||
* @batt_temp_adc : adc selection id for battery temperature
|
||||
* @max_vbatt_mv : used for calculating battery capacity
|
||||
* @chg_params : initial charging parameters
|
||||
* @num_chg_params : numbers of charging parameters
|
||||
* @charger_event : the charger event can be reported to the platform side
|
||||
*/
|
||||
struct lp8788_charger_platform_data {
|
||||
enum lp8788_adc_id vbatt_adc;
|
||||
enum lp8788_adc_id batt_temp_adc;
|
||||
unsigned int max_vbatt_mv;
|
||||
struct lp8788_chg_param *chg_params;
|
||||
int num_chg_params;
|
||||
void (*charger_event) (struct lp8788 *lp,
|
||||
enum lp8788_charger_event event);
|
||||
};
|
||||
|
||||
/*
|
||||
* struct lp8788_bl_pwm_data
|
||||
* @pwm_set_intensity : set duty of pwm
|
||||
* @pwm_get_intensity : get current duty of pwm
|
||||
*/
|
||||
struct lp8788_bl_pwm_data {
|
||||
void (*pwm_set_intensity) (int brightness, int max_brightness);
|
||||
int (*pwm_get_intensity) (int max_brightness);
|
||||
};
|
||||
|
||||
/*
|
||||
* struct lp8788_backlight_platform_data
|
||||
* @name : backlight driver name. (default: "lcd-backlight")
|
||||
* @initial_brightness : initial value of backlight brightness
|
||||
* @bl_mode : brightness control by pwm or lp8788 register
|
||||
* @dim_mode : dimming mode selection
|
||||
* @full_scale : full scale current setting
|
||||
* @rise_time : brightness ramp up step time
|
||||
* @fall_time : brightness ramp down step time
|
||||
* @pwm_pol : pwm polarity setting when bl_mode is pwm based
|
||||
* @pwm_data : platform specific pwm generation functions
|
||||
* only valid when bl_mode is pwm based
|
||||
*/
|
||||
struct lp8788_backlight_platform_data {
|
||||
char *name;
|
||||
int initial_brightness;
|
||||
enum lp8788_bl_ctrl_mode bl_mode;
|
||||
enum lp8788_bl_dim_mode dim_mode;
|
||||
enum lp8788_bl_full_scale_current full_scale;
|
||||
enum lp8788_bl_ramp_step rise_time;
|
||||
enum lp8788_bl_ramp_step fall_time;
|
||||
enum lp8788_bl_pwm_polarity pwm_pol;
|
||||
struct lp8788_bl_pwm_data pwm_data;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct lp8788_led_platform_data
|
||||
* @name : led driver name. (default: "keyboard-backlight")
|
||||
* @scale : current scale
|
||||
* @num : current sink number
|
||||
* @iout_code : current output value (Addr 9Ah ~ 9Bh)
|
||||
*/
|
||||
struct lp8788_led_platform_data {
|
||||
char *name;
|
||||
enum lp8788_isink_scale scale;
|
||||
enum lp8788_isink_number num;
|
||||
int iout_code;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct lp8788_vib_platform_data
|
||||
* @name : vibrator driver name
|
||||
* @scale : current scale
|
||||
* @num : current sink number
|
||||
* @iout_code : current output value (Addr 9Ah ~ 9Bh)
|
||||
* @pwm_code : PWM code value (Addr 9Ch ~ 9Eh)
|
||||
*/
|
||||
struct lp8788_vib_platform_data {
|
||||
char *name;
|
||||
enum lp8788_isink_scale scale;
|
||||
enum lp8788_isink_number num;
|
||||
int iout_code;
|
||||
int pwm_code;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct lp8788_platform_data
|
||||
* @init_func : used for initializing registers
|
||||
* before mfd driver is registered
|
||||
* @buck_data : regulator initial data for buck
|
||||
* @dldo_data : regulator initial data for digital ldo
|
||||
* @aldo_data : regulator initial data for analog ldo
|
||||
* @buck1_dvs : gpio configurations for buck1 dvs
|
||||
* @buck2_dvs : gpio configurations for buck2 dvs
|
||||
* @ldo_pin : gpio configurations for enabling LDOs
|
||||
* @chg_pdata : platform data for charger driver
|
||||
* @alarm_sel : rtc alarm selection (1 or 2)
|
||||
* @bl_pdata : configurable data for backlight driver
|
||||
* @led_pdata : configurable data for led driver
|
||||
* @vib_pdata : configurable data for vibrator driver
|
||||
* @adc_pdata : iio map data for adc driver
|
||||
*/
|
||||
struct lp8788_platform_data {
|
||||
/* general system information */
|
||||
int (*init_func) (struct lp8788 *lp);
|
||||
|
||||
/* regulators */
|
||||
struct regulator_init_data *buck_data[LP8788_NUM_BUCKS];
|
||||
struct regulator_init_data *dldo_data[LP8788_NUM_DLDOS];
|
||||
struct regulator_init_data *aldo_data[LP8788_NUM_ALDOS];
|
||||
struct lp8788_buck1_dvs *buck1_dvs;
|
||||
struct lp8788_buck2_dvs *buck2_dvs;
|
||||
struct lp8788_ldo_enable_pin *ldo_pin[EN_LDOS_MAX];
|
||||
|
||||
/* charger */
|
||||
struct lp8788_charger_platform_data *chg_pdata;
|
||||
|
||||
/* rtc alarm */
|
||||
enum lp8788_alarm_sel alarm_sel;
|
||||
|
||||
/* backlight */
|
||||
struct lp8788_backlight_platform_data *bl_pdata;
|
||||
|
||||
/* current sinks */
|
||||
struct lp8788_led_platform_data *led_pdata;
|
||||
struct lp8788_vib_platform_data *vib_pdata;
|
||||
|
||||
/* adc iio map data */
|
||||
struct iio_map *adc_pdata;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct lp8788
|
||||
* @dev : parent device pointer
|
||||
* @regmap : used for i2c communcation on accessing registers
|
||||
* @irqdm : interrupt domain for handling nested interrupt
|
||||
* @irq : pin number of IRQ_N
|
||||
* @pdata : lp8788 platform specific data
|
||||
*/
|
||||
struct lp8788 {
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
struct irq_domain *irqdm;
|
||||
int irq;
|
||||
struct lp8788_platform_data *pdata;
|
||||
};
|
||||
|
||||
int lp8788_irq_init(struct lp8788 *lp, int chip_irq);
|
||||
void lp8788_irq_exit(struct lp8788 *lp);
|
||||
int lp8788_read_byte(struct lp8788 *lp, u8 reg, u8 *data);
|
||||
int lp8788_read_multi_bytes(struct lp8788 *lp, u8 reg, u8 *data, size_t count);
|
||||
int lp8788_write_byte(struct lp8788 *lp, u8 reg, u8 data);
|
||||
int lp8788_update_bits(struct lp8788 *lp, u8 reg, u8 mask, u8 data);
|
||||
#endif
|
|
@ -43,6 +43,7 @@ struct lpc_ich_info {
|
|||
char name[32];
|
||||
unsigned int iTCO_version;
|
||||
unsigned int gpio_version;
|
||||
u8 use_gpio;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
* Functions to access MAX8907 power management chip.
|
||||
*
|
||||
* Copyright (C) 2010 Gyungoh Yoo <jack.yoo@maxim-ic.com>
|
||||
* Copyright (C) 2012, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_MFD_MAX8907_H
|
||||
#define __LINUX_MFD_MAX8907_H
|
||||
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/pm.h>
|
||||
|
||||
#define MAX8907_GEN_I2C_ADDR (0x78 >> 1)
|
||||
#define MAX8907_ADC_I2C_ADDR (0x8e >> 1)
|
||||
#define MAX8907_RTC_I2C_ADDR (0xd0 >> 1)
|
||||
|
||||
/* MAX8907 register map */
|
||||
#define MAX8907_REG_SYSENSEL 0x00
|
||||
#define MAX8907_REG_ON_OFF_IRQ1 0x01
|
||||
#define MAX8907_REG_ON_OFF_IRQ1_MASK 0x02
|
||||
#define MAX8907_REG_ON_OFF_STAT 0x03
|
||||
#define MAX8907_REG_SDCTL1 0x04
|
||||
#define MAX8907_REG_SDSEQCNT1 0x05
|
||||
#define MAX8907_REG_SDV1 0x06
|
||||
#define MAX8907_REG_SDCTL2 0x07
|
||||
#define MAX8907_REG_SDSEQCNT2 0x08
|
||||
#define MAX8907_REG_SDV2 0x09
|
||||
#define MAX8907_REG_SDCTL3 0x0A
|
||||
#define MAX8907_REG_SDSEQCNT3 0x0B
|
||||
#define MAX8907_REG_SDV3 0x0C
|
||||
#define MAX8907_REG_ON_OFF_IRQ2 0x0D
|
||||
#define MAX8907_REG_ON_OFF_IRQ2_MASK 0x0E
|
||||
#define MAX8907_REG_RESET_CNFG 0x0F
|
||||
#define MAX8907_REG_LDOCTL16 0x10
|
||||
#define MAX8907_REG_LDOSEQCNT16 0x11
|
||||
#define MAX8907_REG_LDO16VOUT 0x12
|
||||
#define MAX8907_REG_SDBYSEQCNT 0x13
|
||||
#define MAX8907_REG_LDOCTL17 0x14
|
||||
#define MAX8907_REG_LDOSEQCNT17 0x15
|
||||
#define MAX8907_REG_LDO17VOUT 0x16
|
||||
#define MAX8907_REG_LDOCTL1 0x18
|
||||
#define MAX8907_REG_LDOSEQCNT1 0x19
|
||||
#define MAX8907_REG_LDO1VOUT 0x1A
|
||||
#define MAX8907_REG_LDOCTL2 0x1C
|
||||
#define MAX8907_REG_LDOSEQCNT2 0x1D
|
||||
#define MAX8907_REG_LDO2VOUT 0x1E
|
||||
#define MAX8907_REG_LDOCTL3 0x20
|
||||
#define MAX8907_REG_LDOSEQCNT3 0x21
|
||||
#define MAX8907_REG_LDO3VOUT 0x22
|
||||
#define MAX8907_REG_LDOCTL4 0x24
|
||||
#define MAX8907_REG_LDOSEQCNT4 0x25
|
||||
#define MAX8907_REG_LDO4VOUT 0x26
|
||||
#define MAX8907_REG_LDOCTL5 0x28
|
||||
#define MAX8907_REG_LDOSEQCNT5 0x29
|
||||
#define MAX8907_REG_LDO5VOUT 0x2A
|
||||
#define MAX8907_REG_LDOCTL6 0x2C
|
||||
#define MAX8907_REG_LDOSEQCNT6 0x2D
|
||||
#define MAX8907_REG_LDO6VOUT 0x2E
|
||||
#define MAX8907_REG_LDOCTL7 0x30
|
||||
#define MAX8907_REG_LDOSEQCNT7 0x31
|
||||
#define MAX8907_REG_LDO7VOUT 0x32
|
||||
#define MAX8907_REG_LDOCTL8 0x34
|
||||
#define MAX8907_REG_LDOSEQCNT8 0x35
|
||||
#define MAX8907_REG_LDO8VOUT 0x36
|
||||
#define MAX8907_REG_LDOCTL9 0x38
|
||||
#define MAX8907_REG_LDOSEQCNT9 0x39
|
||||
#define MAX8907_REG_LDO9VOUT 0x3A
|
||||
#define MAX8907_REG_LDOCTL10 0x3C
|
||||
#define MAX8907_REG_LDOSEQCNT10 0x3D
|
||||
#define MAX8907_REG_LDO10VOUT 0x3E
|
||||
#define MAX8907_REG_LDOCTL11 0x40
|
||||
#define MAX8907_REG_LDOSEQCNT11 0x41
|
||||
#define MAX8907_REG_LDO11VOUT 0x42
|
||||
#define MAX8907_REG_LDOCTL12 0x44
|
||||
#define MAX8907_REG_LDOSEQCNT12 0x45
|
||||
#define MAX8907_REG_LDO12VOUT 0x46
|
||||
#define MAX8907_REG_LDOCTL13 0x48
|
||||
#define MAX8907_REG_LDOSEQCNT13 0x49
|
||||
#define MAX8907_REG_LDO13VOUT 0x4A
|
||||
#define MAX8907_REG_LDOCTL14 0x4C
|
||||
#define MAX8907_REG_LDOSEQCNT14 0x4D
|
||||
#define MAX8907_REG_LDO14VOUT 0x4E
|
||||
#define MAX8907_REG_LDOCTL15 0x50
|
||||
#define MAX8907_REG_LDOSEQCNT15 0x51
|
||||
#define MAX8907_REG_LDO15VOUT 0x52
|
||||
#define MAX8907_REG_OUT5VEN 0x54
|
||||
#define MAX8907_REG_OUT5VSEQ 0x55
|
||||
#define MAX8907_REG_OUT33VEN 0x58
|
||||
#define MAX8907_REG_OUT33VSEQ 0x59
|
||||
#define MAX8907_REG_LDOCTL19 0x5C
|
||||
#define MAX8907_REG_LDOSEQCNT19 0x5D
|
||||
#define MAX8907_REG_LDO19VOUT 0x5E
|
||||
#define MAX8907_REG_LBCNFG 0x60
|
||||
#define MAX8907_REG_SEQ1CNFG 0x64
|
||||
#define MAX8907_REG_SEQ2CNFG 0x65
|
||||
#define MAX8907_REG_SEQ3CNFG 0x66
|
||||
#define MAX8907_REG_SEQ4CNFG 0x67
|
||||
#define MAX8907_REG_SEQ5CNFG 0x68
|
||||
#define MAX8907_REG_SEQ6CNFG 0x69
|
||||
#define MAX8907_REG_SEQ7CNFG 0x6A
|
||||
#define MAX8907_REG_LDOCTL18 0x72
|
||||
#define MAX8907_REG_LDOSEQCNT18 0x73
|
||||
#define MAX8907_REG_LDO18VOUT 0x74
|
||||
#define MAX8907_REG_BBAT_CNFG 0x78
|
||||
#define MAX8907_REG_CHG_CNTL1 0x7C
|
||||
#define MAX8907_REG_CHG_CNTL2 0x7D
|
||||
#define MAX8907_REG_CHG_IRQ1 0x7E
|
||||
#define MAX8907_REG_CHG_IRQ2 0x7F
|
||||
#define MAX8907_REG_CHG_IRQ1_MASK 0x80
|
||||
#define MAX8907_REG_CHG_IRQ2_MASK 0x81
|
||||
#define MAX8907_REG_CHG_STAT 0x82
|
||||
#define MAX8907_REG_WLED_MODE_CNTL 0x84
|
||||
#define MAX8907_REG_ILED_CNTL 0x84
|
||||
#define MAX8907_REG_II1RR 0x8E
|
||||
#define MAX8907_REG_II2RR 0x8F
|
||||
#define MAX8907_REG_LDOCTL20 0x9C
|
||||
#define MAX8907_REG_LDOSEQCNT20 0x9D
|
||||
#define MAX8907_REG_LDO20VOUT 0x9E
|
||||
|
||||
/* RTC register map */
|
||||
#define MAX8907_REG_RTC_SEC 0x00
|
||||
#define MAX8907_REG_RTC_MIN 0x01
|
||||
#define MAX8907_REG_RTC_HOURS 0x02
|
||||
#define MAX8907_REG_RTC_WEEKDAY 0x03
|
||||
#define MAX8907_REG_RTC_DATE 0x04
|
||||
#define MAX8907_REG_RTC_MONTH 0x05
|
||||
#define MAX8907_REG_RTC_YEAR1 0x06
|
||||
#define MAX8907_REG_RTC_YEAR2 0x07
|
||||
#define MAX8907_REG_ALARM0_SEC 0x08
|
||||
#define MAX8907_REG_ALARM0_MIN 0x09
|
||||
#define MAX8907_REG_ALARM0_HOURS 0x0A
|
||||
#define MAX8907_REG_ALARM0_WEEKDAY 0x0B
|
||||
#define MAX8907_REG_ALARM0_DATE 0x0C
|
||||
#define MAX8907_REG_ALARM0_MONTH 0x0D
|
||||
#define MAX8907_REG_ALARM0_YEAR1 0x0E
|
||||
#define MAX8907_REG_ALARM0_YEAR2 0x0F
|
||||
#define MAX8907_REG_ALARM1_SEC 0x10
|
||||
#define MAX8907_REG_ALARM1_MIN 0x11
|
||||
#define MAX8907_REG_ALARM1_HOURS 0x12
|
||||
#define MAX8907_REG_ALARM1_WEEKDAY 0x13
|
||||
#define MAX8907_REG_ALARM1_DATE 0x14
|
||||
#define MAX8907_REG_ALARM1_MONTH 0x15
|
||||
#define MAX8907_REG_ALARM1_YEAR1 0x16
|
||||
#define MAX8907_REG_ALARM1_YEAR2 0x17
|
||||
#define MAX8907_REG_ALARM0_CNTL 0x18
|
||||
#define MAX8907_REG_ALARM1_CNTL 0x19
|
||||
#define MAX8907_REG_RTC_STATUS 0x1A
|
||||
#define MAX8907_REG_RTC_CNTL 0x1B
|
||||
#define MAX8907_REG_RTC_IRQ 0x1C
|
||||
#define MAX8907_REG_RTC_IRQ_MASK 0x1D
|
||||
#define MAX8907_REG_MPL_CNTL 0x1E
|
||||
|
||||
/* ADC and Touch Screen Controller register map */
|
||||
#define MAX8907_CTL 0
|
||||
#define MAX8907_SEQCNT 1
|
||||
#define MAX8907_VOUT 2
|
||||
|
||||
/* mask bit fields */
|
||||
#define MAX8907_MASK_LDO_SEQ 0x1C
|
||||
#define MAX8907_MASK_LDO_EN 0x01
|
||||
#define MAX8907_MASK_VBBATTCV 0x03
|
||||
#define MAX8907_MASK_OUT5V_VINEN 0x10
|
||||
#define MAX8907_MASK_OUT5V_ENSRC 0x0E
|
||||
#define MAX8907_MASK_OUT5V_EN 0x01
|
||||
#define MAX8907_MASK_POWER_OFF 0x40
|
||||
|
||||
/* Regulator IDs */
|
||||
#define MAX8907_MBATT 0
|
||||
#define MAX8907_SD1 1
|
||||
#define MAX8907_SD2 2
|
||||
#define MAX8907_SD3 3
|
||||
#define MAX8907_LDO1 4
|
||||
#define MAX8907_LDO2 5
|
||||
#define MAX8907_LDO3 6
|
||||
#define MAX8907_LDO4 7
|
||||
#define MAX8907_LDO5 8
|
||||
#define MAX8907_LDO6 9
|
||||
#define MAX8907_LDO7 10
|
||||
#define MAX8907_LDO8 11
|
||||
#define MAX8907_LDO9 12
|
||||
#define MAX8907_LDO10 13
|
||||
#define MAX8907_LDO11 14
|
||||
#define MAX8907_LDO12 15
|
||||
#define MAX8907_LDO13 16
|
||||
#define MAX8907_LDO14 17
|
||||
#define MAX8907_LDO15 18
|
||||
#define MAX8907_LDO16 19
|
||||
#define MAX8907_LDO17 20
|
||||
#define MAX8907_LDO18 21
|
||||
#define MAX8907_LDO19 22
|
||||
#define MAX8907_LDO20 23
|
||||
#define MAX8907_OUT5V 24
|
||||
#define MAX8907_OUT33V 25
|
||||
#define MAX8907_BBAT 26
|
||||
#define MAX8907_SDBY 27
|
||||
#define MAX8907_VRTC 28
|
||||
#define MAX8907_NUM_REGULATORS (MAX8907_VRTC + 1)
|
||||
|
||||
/* IRQ definitions */
|
||||
enum {
|
||||
MAX8907_IRQ_VCHG_DC_OVP = 0,
|
||||
MAX8907_IRQ_VCHG_DC_F,
|
||||
MAX8907_IRQ_VCHG_DC_R,
|
||||
MAX8907_IRQ_VCHG_THM_OK_R,
|
||||
MAX8907_IRQ_VCHG_THM_OK_F,
|
||||
MAX8907_IRQ_VCHG_MBATTLOW_F,
|
||||
MAX8907_IRQ_VCHG_MBATTLOW_R,
|
||||
MAX8907_IRQ_VCHG_RST,
|
||||
MAX8907_IRQ_VCHG_DONE,
|
||||
MAX8907_IRQ_VCHG_TOPOFF,
|
||||
MAX8907_IRQ_VCHG_TMR_FAULT,
|
||||
|
||||
MAX8907_IRQ_GPM_RSTIN = 0,
|
||||
MAX8907_IRQ_GPM_MPL,
|
||||
MAX8907_IRQ_GPM_SW_3SEC,
|
||||
MAX8907_IRQ_GPM_EXTON_F,
|
||||
MAX8907_IRQ_GPM_EXTON_R,
|
||||
MAX8907_IRQ_GPM_SW_1SEC,
|
||||
MAX8907_IRQ_GPM_SW_F,
|
||||
MAX8907_IRQ_GPM_SW_R,
|
||||
MAX8907_IRQ_GPM_SYSCKEN_F,
|
||||
MAX8907_IRQ_GPM_SYSCKEN_R,
|
||||
|
||||
MAX8907_IRQ_RTC_ALARM1 = 0,
|
||||
MAX8907_IRQ_RTC_ALARM0,
|
||||
};
|
||||
|
||||
struct max8907_platform_data {
|
||||
struct regulator_init_data *init_data[MAX8907_NUM_REGULATORS];
|
||||
bool pm_off;
|
||||
};
|
||||
|
||||
struct regmap_irq_chips_data;
|
||||
|
||||
struct max8907 {
|
||||
struct device *dev;
|
||||
struct mutex irq_lock;
|
||||
struct i2c_client *i2c_gen;
|
||||
struct i2c_client *i2c_rtc;
|
||||
struct regmap *regmap_gen;
|
||||
struct regmap *regmap_rtc;
|
||||
struct regmap_irq_chip_data *irqc_chg;
|
||||
struct regmap_irq_chip_data *irqc_on_off;
|
||||
struct regmap_irq_chip_data *irqc_rtc;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -158,8 +158,6 @@ enum {
|
|||
#define TSC_IRQ_MASK (0x03)
|
||||
#define RTC_IRQ_MASK (0x0c)
|
||||
|
||||
#define MAX8925_MAX_REGULATOR (23)
|
||||
|
||||
#define MAX8925_NAME_SIZE (32)
|
||||
|
||||
/* IRQ definitions */
|
||||
|
@ -236,7 +234,29 @@ struct max8925_platform_data {
|
|||
struct max8925_backlight_pdata *backlight;
|
||||
struct max8925_touch_pdata *touch;
|
||||
struct max8925_power_pdata *power;
|
||||
struct regulator_init_data *regulator[MAX8925_MAX_REGULATOR];
|
||||
struct regulator_init_data *sd1;
|
||||
struct regulator_init_data *sd2;
|
||||
struct regulator_init_data *sd3;
|
||||
struct regulator_init_data *ldo1;
|
||||
struct regulator_init_data *ldo2;
|
||||
struct regulator_init_data *ldo3;
|
||||
struct regulator_init_data *ldo4;
|
||||
struct regulator_init_data *ldo5;
|
||||
struct regulator_init_data *ldo6;
|
||||
struct regulator_init_data *ldo7;
|
||||
struct regulator_init_data *ldo8;
|
||||
struct regulator_init_data *ldo9;
|
||||
struct regulator_init_data *ldo10;
|
||||
struct regulator_init_data *ldo11;
|
||||
struct regulator_init_data *ldo12;
|
||||
struct regulator_init_data *ldo13;
|
||||
struct regulator_init_data *ldo14;
|
||||
struct regulator_init_data *ldo15;
|
||||
struct regulator_init_data *ldo16;
|
||||
struct regulator_init_data *ldo17;
|
||||
struct regulator_init_data *ldo18;
|
||||
struct regulator_init_data *ldo19;
|
||||
struct regulator_init_data *ldo20;
|
||||
|
||||
int irq_base;
|
||||
int tsc_irq;
|
||||
|
|
|
@ -23,6 +23,9 @@
|
|||
#define PALMAS_NUM_CLIENTS 3
|
||||
|
||||
struct palmas_pmic;
|
||||
struct palmas_gpadc;
|
||||
struct palmas_resource;
|
||||
struct palmas_usb;
|
||||
|
||||
struct palmas {
|
||||
struct device *dev;
|
||||
|
@ -41,6 +44,9 @@ struct palmas {
|
|||
|
||||
/* Child Devices */
|
||||
struct palmas_pmic *pmic;
|
||||
struct palmas_gpadc *gpadc;
|
||||
struct palmas_resource *resource;
|
||||
struct palmas_usb *usb;
|
||||
|
||||
/* GPIO MUXing */
|
||||
u8 gpio_muxed;
|
||||
|
@ -48,6 +54,23 @@ struct palmas {
|
|||
u8 pwm_muxed;
|
||||
};
|
||||
|
||||
struct palmas_gpadc_platform_data {
|
||||
/* Channel 3 current source is only enabled during conversion */
|
||||
int ch3_current;
|
||||
|
||||
/* Channel 0 current source can be used for battery detection.
|
||||
* If used for battery detection this will cause a permanent current
|
||||
* consumption depending on current level set here.
|
||||
*/
|
||||
int ch0_current;
|
||||
|
||||
/* default BAT_REMOVAL_DAT setting on device probe */
|
||||
int bat_removal;
|
||||
|
||||
/* Sets the START_POLARITY bit in the RT_CTRL register */
|
||||
int start_polarity;
|
||||
};
|
||||
|
||||
struct palmas_reg_init {
|
||||
/* warm_rest controls the voltage levels after a warm reset
|
||||
*
|
||||
|
@ -107,21 +130,94 @@ struct palmas_reg_init {
|
|||
|
||||
};
|
||||
|
||||
enum palmas_regulators {
|
||||
/* SMPS regulators */
|
||||
PALMAS_REG_SMPS12,
|
||||
PALMAS_REG_SMPS123,
|
||||
PALMAS_REG_SMPS3,
|
||||
PALMAS_REG_SMPS45,
|
||||
PALMAS_REG_SMPS457,
|
||||
PALMAS_REG_SMPS6,
|
||||
PALMAS_REG_SMPS7,
|
||||
PALMAS_REG_SMPS8,
|
||||
PALMAS_REG_SMPS9,
|
||||
PALMAS_REG_SMPS10,
|
||||
/* LDO regulators */
|
||||
PALMAS_REG_LDO1,
|
||||
PALMAS_REG_LDO2,
|
||||
PALMAS_REG_LDO3,
|
||||
PALMAS_REG_LDO4,
|
||||
PALMAS_REG_LDO5,
|
||||
PALMAS_REG_LDO6,
|
||||
PALMAS_REG_LDO7,
|
||||
PALMAS_REG_LDO8,
|
||||
PALMAS_REG_LDO9,
|
||||
PALMAS_REG_LDOLN,
|
||||
PALMAS_REG_LDOUSB,
|
||||
/* Total number of regulators */
|
||||
PALMAS_NUM_REGS,
|
||||
};
|
||||
|
||||
struct palmas_pmic_platform_data {
|
||||
/* An array of pointers to regulator init data indexed by regulator
|
||||
* ID
|
||||
*/
|
||||
struct regulator_init_data **reg_data;
|
||||
struct regulator_init_data *reg_data[PALMAS_NUM_REGS];
|
||||
|
||||
/* An array of pointers to structures containing sleep mode and DVS
|
||||
* configuration for regulators indexed by ID
|
||||
*/
|
||||
struct palmas_reg_init **reg_init;
|
||||
struct palmas_reg_init *reg_init[PALMAS_NUM_REGS];
|
||||
|
||||
/* use LDO6 for vibrator control */
|
||||
int ldo6_vibrator;
|
||||
};
|
||||
|
||||
struct palmas_usb_platform_data {
|
||||
/* Set this if platform wishes its own vbus control */
|
||||
int no_control_vbus;
|
||||
|
||||
/* Do we enable the wakeup comparator on probe */
|
||||
int wakeup;
|
||||
};
|
||||
|
||||
struct palmas_resource_platform_data {
|
||||
int regen1_mode_sleep;
|
||||
int regen2_mode_sleep;
|
||||
int sysen1_mode_sleep;
|
||||
int sysen2_mode_sleep;
|
||||
|
||||
/* bitfield to be loaded to NSLEEP_RES_ASSIGN */
|
||||
u8 nsleep_res;
|
||||
/* bitfield to be loaded to NSLEEP_SMPS_ASSIGN */
|
||||
u8 nsleep_smps;
|
||||
/* bitfield to be loaded to NSLEEP_LDO_ASSIGN1 */
|
||||
u8 nsleep_ldo1;
|
||||
/* bitfield to be loaded to NSLEEP_LDO_ASSIGN2 */
|
||||
u8 nsleep_ldo2;
|
||||
|
||||
/* bitfield to be loaded to ENABLE1_RES_ASSIGN */
|
||||
u8 enable1_res;
|
||||
/* bitfield to be loaded to ENABLE1_SMPS_ASSIGN */
|
||||
u8 enable1_smps;
|
||||
/* bitfield to be loaded to ENABLE1_LDO_ASSIGN1 */
|
||||
u8 enable1_ldo1;
|
||||
/* bitfield to be loaded to ENABLE1_LDO_ASSIGN2 */
|
||||
u8 enable1_ldo2;
|
||||
|
||||
/* bitfield to be loaded to ENABLE2_RES_ASSIGN */
|
||||
u8 enable2_res;
|
||||
/* bitfield to be loaded to ENABLE2_SMPS_ASSIGN */
|
||||
u8 enable2_smps;
|
||||
/* bitfield to be loaded to ENABLE2_LDO_ASSIGN1 */
|
||||
u8 enable2_ldo1;
|
||||
/* bitfield to be loaded to ENABLE2_LDO_ASSIGN2 */
|
||||
u8 enable2_ldo2;
|
||||
};
|
||||
|
||||
struct palmas_clk_platform_data {
|
||||
int clk32kg_mode_sleep;
|
||||
int clk32kgaudio_mode_sleep;
|
||||
};
|
||||
|
||||
struct palmas_platform_data {
|
||||
|
@ -138,8 +234,49 @@ struct palmas_platform_data {
|
|||
u8 pad1, pad2;
|
||||
|
||||
struct palmas_pmic_platform_data *pmic_pdata;
|
||||
struct palmas_gpadc_platform_data *gpadc_pdata;
|
||||
struct palmas_usb_platform_data *usb_pdata;
|
||||
struct palmas_resource_platform_data *resource_pdata;
|
||||
struct palmas_clk_platform_data *clk_pdata;
|
||||
};
|
||||
|
||||
struct palmas_gpadc_calibration {
|
||||
s32 gain;
|
||||
s32 gain_error;
|
||||
s32 offset_error;
|
||||
};
|
||||
|
||||
struct palmas_gpadc {
|
||||
struct device *dev;
|
||||
struct palmas *palmas;
|
||||
|
||||
int ch3_current;
|
||||
int ch0_current;
|
||||
|
||||
int gpadc_force;
|
||||
|
||||
int bat_removal;
|
||||
|
||||
struct mutex reading_lock;
|
||||
struct completion irq_complete;
|
||||
|
||||
int eoc_sw_irq;
|
||||
|
||||
struct palmas_gpadc_calibration *palmas_cal_tbl;
|
||||
|
||||
int conv0_channel;
|
||||
int conv1_channel;
|
||||
int rt_channel;
|
||||
};
|
||||
|
||||
struct palmas_gpadc_result {
|
||||
s32 raw_code;
|
||||
s32 corrected_code;
|
||||
s32 result;
|
||||
};
|
||||
|
||||
#define PALMAS_MAX_CHANNELS 16
|
||||
|
||||
/* Define the palmas IRQ numbers */
|
||||
enum palmas_irqs {
|
||||
/* INT1 registers */
|
||||
|
@ -182,34 +319,6 @@ enum palmas_irqs {
|
|||
PALMAS_NUM_IRQ,
|
||||
};
|
||||
|
||||
enum palmas_regulators {
|
||||
/* SMPS regulators */
|
||||
PALMAS_REG_SMPS12,
|
||||
PALMAS_REG_SMPS123,
|
||||
PALMAS_REG_SMPS3,
|
||||
PALMAS_REG_SMPS45,
|
||||
PALMAS_REG_SMPS457,
|
||||
PALMAS_REG_SMPS6,
|
||||
PALMAS_REG_SMPS7,
|
||||
PALMAS_REG_SMPS8,
|
||||
PALMAS_REG_SMPS9,
|
||||
PALMAS_REG_SMPS10,
|
||||
/* LDO regulators */
|
||||
PALMAS_REG_LDO1,
|
||||
PALMAS_REG_LDO2,
|
||||
PALMAS_REG_LDO3,
|
||||
PALMAS_REG_LDO4,
|
||||
PALMAS_REG_LDO5,
|
||||
PALMAS_REG_LDO6,
|
||||
PALMAS_REG_LDO7,
|
||||
PALMAS_REG_LDO8,
|
||||
PALMAS_REG_LDO9,
|
||||
PALMAS_REG_LDOLN,
|
||||
PALMAS_REG_LDOUSB,
|
||||
/* Total number of regulators */
|
||||
PALMAS_NUM_REGS,
|
||||
};
|
||||
|
||||
struct palmas_pmic {
|
||||
struct palmas *palmas;
|
||||
struct device *dev;
|
||||
|
@ -223,6 +332,69 @@ struct palmas_pmic {
|
|||
int range[PALMAS_REG_SMPS10];
|
||||
};
|
||||
|
||||
struct palmas_resource {
|
||||
struct palmas *palmas;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
struct palmas_usb {
|
||||
struct palmas *palmas;
|
||||
struct device *dev;
|
||||
|
||||
/* for vbus reporting with irqs disabled */
|
||||
spinlock_t lock;
|
||||
|
||||
struct regulator *vbus_reg;
|
||||
|
||||
/* used to set vbus, in atomic path */
|
||||
struct work_struct set_vbus_work;
|
||||
|
||||
int irq1;
|
||||
int irq2;
|
||||
int irq3;
|
||||
int irq4;
|
||||
|
||||
int vbus_enable;
|
||||
|
||||
u8 linkstat;
|
||||
};
|
||||
|
||||
#define comparator_to_palmas(x) container_of((x), struct palmas_usb, comparator)
|
||||
|
||||
enum usb_irq_events {
|
||||
/* Wakeup events from INT3 */
|
||||
PALMAS_USB_ID_WAKEPUP,
|
||||
PALMAS_USB_VBUS_WAKEUP,
|
||||
|
||||
/* ID_OTG_EVENTS */
|
||||
PALMAS_USB_ID_GND,
|
||||
N_PALMAS_USB_ID_GND,
|
||||
PALMAS_USB_ID_C,
|
||||
N_PALMAS_USB_ID_C,
|
||||
PALMAS_USB_ID_B,
|
||||
N_PALMAS_USB_ID_B,
|
||||
PALMAS_USB_ID_A,
|
||||
N_PALMAS_USB_ID_A,
|
||||
PALMAS_USB_ID_FLOAT,
|
||||
N_PALMAS_USB_ID_FLOAT,
|
||||
|
||||
/* VBUS_OTG_EVENTS */
|
||||
PALMAS_USB_VB_SESS_END,
|
||||
N_PALMAS_USB_VB_SESS_END,
|
||||
PALMAS_USB_VB_SESS_VLD,
|
||||
N_PALMAS_USB_VB_SESS_VLD,
|
||||
PALMAS_USB_VA_SESS_VLD,
|
||||
N_PALMAS_USB_VA_SESS_VLD,
|
||||
PALMAS_USB_VA_VBUS_VLD,
|
||||
N_PALMAS_USB_VA_VBUS_VLD,
|
||||
PALMAS_USB_VADP_SNS,
|
||||
N_PALMAS_USB_VADP_SNS,
|
||||
PALMAS_USB_VADP_PRB,
|
||||
N_PALMAS_USB_VADP_PRB,
|
||||
PALMAS_USB_VOTG_SESS_VLD,
|
||||
N_PALMAS_USB_VOTG_SESS_VLD,
|
||||
};
|
||||
|
||||
/* defines so we can store the mux settings */
|
||||
#define PALMAS_GPIO_0_MUXED (1 << 0)
|
||||
#define PALMAS_GPIO_1_MUXED (1 << 1)
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* SMSC ECE1099
|
||||
*
|
||||
* Copyright 2012 Texas Instruments Inc.
|
||||
*
|
||||
* Author: Sourav Poddar <sourav.poddar@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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_MFD_SMSC_H
|
||||
#define __LINUX_MFD_SMSC_H
|
||||
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define SMSC_ID_ECE1099 1
|
||||
#define SMSC_NUM_CLIENTS 2
|
||||
|
||||
#define SMSC_BASE_ADDR 0x38
|
||||
#define OMAP_GPIO_SMSC_IRQ 151
|
||||
|
||||
#define SMSC_MAXGPIO 32
|
||||
#define SMSC_BANK(offs) ((offs) >> 3)
|
||||
#define SMSC_BIT(offs) (1u << ((offs) & 0x7))
|
||||
|
||||
struct smsc {
|
||||
struct device *dev;
|
||||
struct i2c_client *i2c_clients[SMSC_NUM_CLIENTS];
|
||||
struct regmap *regmap;
|
||||
int clk;
|
||||
/* Stored chip id */
|
||||
int id;
|
||||
};
|
||||
|
||||
struct smsc_gpio;
|
||||
struct smsc_keypad;
|
||||
|
||||
static inline int smsc_read(struct device *child, unsigned int reg,
|
||||
unsigned int *dest)
|
||||
{
|
||||
struct smsc *smsc = dev_get_drvdata(child->parent);
|
||||
|
||||
return regmap_read(smsc->regmap, reg, dest);
|
||||
}
|
||||
|
||||
static inline int smsc_write(struct device *child, unsigned int reg,
|
||||
unsigned int value)
|
||||
{
|
||||
struct smsc *smsc = dev_get_drvdata(child->parent);
|
||||
|
||||
return regmap_write(smsc->regmap, reg, value);
|
||||
}
|
||||
|
||||
/* Registers for SMSC */
|
||||
#define SMSC_RESET 0xF5
|
||||
#define SMSC_GRP_INT 0xF9
|
||||
#define SMSC_CLK_CTRL 0xFA
|
||||
#define SMSC_WKUP_CTRL 0xFB
|
||||
#define SMSC_DEV_ID 0xFC
|
||||
#define SMSC_DEV_REV 0xFD
|
||||
#define SMSC_VEN_ID_L 0xFE
|
||||
#define SMSC_VEN_ID_H 0xFF
|
||||
|
||||
/* CLK VALUE */
|
||||
#define SMSC_CLK_VALUE 0x13
|
||||
|
||||
/* Registers for function GPIO INPUT */
|
||||
#define SMSC_GPIO_DATA_IN_START 0x00
|
||||
|
||||
/* Registers for function GPIO OUPUT */
|
||||
#define SMSC_GPIO_DATA_OUT_START 0x05
|
||||
|
||||
/* Definitions for SMSC GPIO CONFIGURATION REGISTER*/
|
||||
#define SMSC_GPIO_INPUT_LOW 0x01
|
||||
#define SMSC_GPIO_INPUT_RISING 0x09
|
||||
#define SMSC_GPIO_INPUT_FALLING 0x11
|
||||
#define SMSC_GPIO_INPUT_BOTH_EDGE 0x19
|
||||
#define SMSC_GPIO_OUTPUT_PP 0x21
|
||||
#define SMSC_GPIO_OUTPUT_OP 0x31
|
||||
|
||||
#define GRP_INT_STAT 0xf9
|
||||
#define SMSC_GPI_INT 0x0f
|
||||
#define SMSC_CFG_START 0x0A
|
||||
|
||||
/* Registers for SMSC GPIO INTERRUPT STATUS REGISTER*/
|
||||
#define SMSC_GPIO_INT_STAT_START 0x32
|
||||
|
||||
/* Registers for SMSC GPIO INTERRUPT MASK REGISTER*/
|
||||
#define SMSC_GPIO_INT_MASK_START 0x37
|
||||
|
||||
/* Registers for SMSC function KEYPAD*/
|
||||
#define SMSC_KP_OUT 0x40
|
||||
#define SMSC_KP_IN 0x41
|
||||
#define SMSC_KP_INT_STAT 0x42
|
||||
#define SMSC_KP_INT_MASK 0x43
|
||||
|
||||
/* Definitions for keypad */
|
||||
#define SMSC_KP_KSO 0x70
|
||||
#define SMSC_KP_KSI 0x51
|
||||
#define SMSC_KSO_ALL_LOW 0x20
|
||||
#define SMSC_KP_SET_LOW_PWR 0x0B
|
||||
#define SMSC_KP_SET_HIGH 0xFF
|
||||
#define SMSC_KSO_EVAL 0x00
|
||||
|
||||
#endif /* __LINUX_MFD_SMSC_H */
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* System Control Driver
|
||||
*
|
||||
* Copyright (C) 2012 Freescale Semiconductor, Inc.
|
||||
* Copyright (C) 2012 Linaro Ltd.
|
||||
*
|
||||
* Author: Dong Aisheng <dong.aisheng@linaro.org>
|
||||
*
|
||||
* 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 __LINUX_MFD_SYSCON_H__
|
||||
#define __LINUX_MFD_SYSCON_H__
|
||||
|
||||
extern struct regmap *syscon_node_to_regmap(struct device_node *np);
|
||||
extern struct regmap *syscon_regmap_lookup_by_compatible(const char *s);
|
||||
extern struct regmap *syscon_regmap_lookup_by_phandle(
|
||||
struct device_node *np,
|
||||
const char *property);
|
||||
#endif /* __LINUX_MFD_SYSCON_H__ */
|
|
@ -0,0 +1,319 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_IMX6Q_IOMUXC_GPR_H
|
||||
#define __LINUX_IMX6Q_IOMUXC_GPR_H
|
||||
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#define IOMUXC_GPR0 0x00
|
||||
#define IOMUXC_GPR1 0x04
|
||||
#define IOMUXC_GPR2 0x08
|
||||
#define IOMUXC_GPR3 0x0c
|
||||
#define IOMUXC_GPR4 0x10
|
||||
#define IOMUXC_GPR5 0x14
|
||||
#define IOMUXC_GPR6 0x18
|
||||
#define IOMUXC_GPR7 0x1c
|
||||
#define IOMUXC_GPR8 0x20
|
||||
#define IOMUXC_GPR9 0x24
|
||||
#define IOMUXC_GPR10 0x28
|
||||
#define IOMUXC_GPR11 0x2c
|
||||
#define IOMUXC_GPR12 0x30
|
||||
#define IOMUXC_GPR13 0x34
|
||||
|
||||
#define IMX6Q_GPR0_CLOCK_8_MUX_SEL_MASK (0x3 << 30)
|
||||
#define IMX6Q_GPR0_CLOCK_8_MUX_SEL_AUDMUX_RXCLK_P7_MUXED (0x0 << 30)
|
||||
#define IMX6Q_GPR0_CLOCK_8_MUX_SEL_AUDMUX_RXCLK_P7 (0x1 << 30)
|
||||
#define IMX6Q_GPR0_CLOCK_8_MUX_SEL_SSI3_SSI_SRCK (0x2 << 30)
|
||||
#define IMX6Q_GPR0_CLOCK_8_MUX_SEL_SSI3_RX_BIT_CLK (0x3 << 30)
|
||||
#define IMX6Q_GPR0_CLOCK_0_MUX_SEL_MASK (0x3 << 28)
|
||||
#define IMX6Q_GPR0_CLOCK_0_MUX_SEL_ESAI1_IPP_IND_SCKR_MUXED (0x0 << 28)
|
||||
#define IMX6Q_GPR0_CLOCK_0_MUX_SEL_ESAI1_IPP_IND_SCKR (0x1 << 28)
|
||||
#define IMX6Q_GPR0_CLOCK_0_MUX_SEL_ESAI1_IPP_DO_SCKR (0x2 << 28)
|
||||
#define IMX6Q_GPR0_CLOCK_B_MUX_SEL_MASK (0x3 << 26)
|
||||
#define IMX6Q_GPR0_CLOCK_B_MUX_SEL_AUDMUX_TXCLK_P7_MUXED (0x0 << 26)
|
||||
#define IMX6Q_GPR0_CLOCK_B_MUX_SEL_AUDMUX_TXCLK_P7 (0x1 << 26)
|
||||
#define IMX6Q_GPR0_CLOCK_B_MUX_SEL_SSI3_SSI_STCK (0x2 << 26)
|
||||
#define IMX6Q_GPR0_CLOCK_B_MUX_SEL_SSI3_TX_BIT_CLK (0x3 << 26)
|
||||
#define IMX6Q_GPR0_CLOCK_3_MUX_SEL_MASK (0x3 << 24)
|
||||
#define IMX6Q_GPR0_CLOCK_3_MUX_SEL_AUDMUX_RXCLK_P7_MUXED (0x3 << 24)
|
||||
#define IMX6Q_GPR0_CLOCK_3_MUX_SEL_AUDMUX_RXCLK_P7 (0x3 << 24)
|
||||
#define IMX6Q_GPR0_CLOCK_3_MUX_SEL_SSI3_SSI_SRCK (0x3 << 24)
|
||||
#define IMX6Q_GPR0_CLOCK_3_MUX_SEL_SSI3_RX_BIT_CLK (0x3 << 24)
|
||||
#define IMX6Q_GPR0_CLOCK_A_MUX_SEL_MASK (0x3 << 22)
|
||||
#define IMX6Q_GPR0_CLOCK_A_MUX_SEL_AUDMUX_TXCLK_P2_MUXED (0x0 << 22)
|
||||
#define IMX6Q_GPR0_CLOCK_A_MUX_SEL_AUDMUX_TXCLK_P2 (0x1 << 22)
|
||||
#define IMX6Q_GPR0_CLOCK_A_MUX_SEL_SSI2_SSI_STCK (0x2 << 22)
|
||||
#define IMX6Q_GPR0_CLOCK_A_MUX_SEL_SSI2_TX_BIT_CLK (0x3 << 22)
|
||||
#define IMX6Q_GPR0_CLOCK_2_MUX_SEL_MASK (0x3 << 20)
|
||||
#define IMX6Q_GPR0_CLOCK_2_MUX_SEL_AUDMUX_RXCLK_P2_MUXED (0x0 << 20)
|
||||
#define IMX6Q_GPR0_CLOCK_2_MUX_SEL_AUDMUX_RXCLK_P2 (0x1 << 20)
|
||||
#define IMX6Q_GPR0_CLOCK_2_MUX_SEL_SSI2_SSI_SRCK (0x2 << 20)
|
||||
#define IMX6Q_GPR0_CLOCK_2_MUX_SEL_SSI2_RX_BIT_CLK (0x3 << 20)
|
||||
#define IMX6Q_GPR0_CLOCK_9_MUX_SEL_MASK (0x3 << 18)
|
||||
#define IMX6Q_GPR0_CLOCK_9_MUX_SEL_AUDMUX_TXCLK_P1_MUXED (0x0 << 18)
|
||||
#define IMX6Q_GPR0_CLOCK_9_MUX_SEL_AUDMUX_TXCLK_P1 (0x1 << 18)
|
||||
#define IMX6Q_GPR0_CLOCK_9_MUX_SEL_SSI1_SSI_STCK (0x2 << 18)
|
||||
#define IMX6Q_GPR0_CLOCK_9_MUX_SEL_SSI1_SSI_TX_BIT_CLK (0x3 << 18)
|
||||
#define IMX6Q_GPR0_CLOCK_1_MUX_SEL_MASK (0x3 << 16)
|
||||
#define IMX6Q_GPR0_CLOCK_1_MUX_SEL_AUDMUX_RXCLK_P1_MUXED (0x0 << 16)
|
||||
#define IMX6Q_GPR0_CLOCK_1_MUX_SEL_AUDMUX_RXCLK_P1 (0x1 << 16)
|
||||
#define IMX6Q_GPR0_CLOCK_1_MUX_SEL_SSI1_SSI_SRCK (0x2 << 16)
|
||||
#define IMX6Q_GPR0_CLOCK_1_MUX_SEL_SSI1_SSI_RX_BIT_CLK (0x3 << 16)
|
||||
#define IMX6Q_GPR0_TX_CLK2_MUX_SEL_MASK (0x3 << 14)
|
||||
#define IMX6Q_GPR0_TX_CLK2_MUX_SEL_ASRCK_CLK1 (0x0 << 14)
|
||||
#define IMX6Q_GPR0_TX_CLK2_MUX_SEL_ASRCK_CLK2 (0x1 << 14)
|
||||
#define IMX6Q_GPR0_TX_CLK2_MUX_SEL_ASRCK_CLK3 (0x2 << 14)
|
||||
#define IMX6Q_GPR0_DMAREQ_MUX_SEL7_MASK BIT(7)
|
||||
#define IMX6Q_GPR0_DMAREQ_MUX_SEL7_SPDIF 0x0
|
||||
#define IMX6Q_GPR0_DMAREQ_MUX_SEL7_IOMUX BIT(7)
|
||||
#define IMX6Q_GPR0_DMAREQ_MUX_SEL6_MASK BIT(6)
|
||||
#define IMX6Q_GPR0_DMAREQ_MUX_SEL6_ESAI 0x0
|
||||
#define IMX6Q_GPR0_DMAREQ_MUX_SEL6_I2C3 BIT(6)
|
||||
#define IMX6Q_GPR0_DMAREQ_MUX_SEL5_MASK BIT(5)
|
||||
#define IMX6Q_GPR0_DMAREQ_MUX_SEL5_ECSPI4 0x0
|
||||
#define IMX6Q_GPR0_DMAREQ_MUX_SEL5_EPIT2 BIT(5)
|
||||
#define IMX6Q_GPR0_DMAREQ_MUX_SEL4_MASK BIT(4)
|
||||
#define IMX6Q_GPR0_DMAREQ_MUX_SEL4_ECSPI4 0x0
|
||||
#define IMX6Q_GPR0_DMAREQ_MUX_SEL4_I2C1 BIT(4)
|
||||
#define IMX6Q_GPR0_DMAREQ_MUX_SEL3_MASK BIT(3)
|
||||
#define IMX6Q_GPR0_DMAREQ_MUX_SEL3_ECSPI2 0x0
|
||||
#define IMX6Q_GPR0_DMAREQ_MUX_SEL3_I2C1 BIT(3)
|
||||
#define IMX6Q_GPR0_DMAREQ_MUX_SEL2_MASK BIT(2)
|
||||
#define IMX6Q_GPR0_DMAREQ_MUX_SEL2_ECSPI1 0x0
|
||||
#define IMX6Q_GPR0_DMAREQ_MUX_SEL2_I2C2 BIT(2)
|
||||
#define IMX6Q_GPR0_DMAREQ_MUX_SEL1_MASK BIT(1)
|
||||
#define IMX6Q_GPR0_DMAREQ_MUX_SEL1_ECSPI1 0x0
|
||||
#define IMX6Q_GPR0_DMAREQ_MUX_SEL1_I2C3 BIT(1)
|
||||
#define IMX6Q_GPR0_DMAREQ_MUX_SEL0_MASK BIT(0)
|
||||
#define IMX6Q_GPR0_DMAREQ_MUX_SEL0_IPU1 0x0
|
||||
#define IMX6Q_GPR0_DMAREQ_MUX_SEL0_IOMUX BIT(0)
|
||||
|
||||
#define IMX6Q_GPR1_PCIE_REQ_MASK (0x3 << 30)
|
||||
#define IMX6Q_GPR1_PCIE_EXIT_L1 BIT(28)
|
||||
#define IMX6Q_GPR1_PCIE_RDY_L23 BIT(27)
|
||||
#define IMX6Q_GPR1_PCIE_ENTER_L1 BIT(26)
|
||||
#define IMX6Q_GPR1_MIPI_COLOR_SW BIT(25)
|
||||
#define IMX6Q_GPR1_DPI_OFF BIT(24)
|
||||
#define IMX6Q_GPR1_EXC_MON_MASK BIT(22)
|
||||
#define IMX6Q_GPR1_EXC_MON_OKAY 0x0
|
||||
#define IMX6Q_GPR1_EXC_MON_SLVE BIT(22)
|
||||
#define IMX6Q_GPR1_MIPI_IPU2_SEL_MASK BIT(21)
|
||||
#define IMX6Q_GPR1_MIPI_IPU2_SEL_GASKET 0x0
|
||||
#define IMX6Q_GPR1_MIPI_IPU2_SEL_IOMUX BIT(21)
|
||||
#define IMX6Q_GPR1_MIPI_IPU1_MUX_MASK BIT(20)
|
||||
#define IMX6Q_GPR1_MIPI_IPU1_MUX_GASKET 0x0
|
||||
#define IMX6Q_GPR1_MIPI_IPU1_MUX_IOMUX BIT(20)
|
||||
#define IMX6Q_GPR1_MIPI_IPU2_MUX_MASK BIT(19)
|
||||
#define IMX6Q_GPR1_MIPI_IPU2_MUX_GASKET 0x0
|
||||
#define IMX6Q_GPR1_MIPI_IPU2_MUX_IOMUX BIT(19)
|
||||
#define IMX6Q_GPR1_PCIE_TEST_PD BIT(18)
|
||||
#define IMX6Q_GPR1_IPU_VPU_MUX_MASK BIT(17)
|
||||
#define IMX6Q_GPR1_IPU_VPU_MUX_IPU1 0x0
|
||||
#define IMX6Q_GPR1_IPU_VPU_MUX_IPU2 BIT(17)
|
||||
#define IMX6Q_GPR1_PCIE_REF_CLK_EN BIT(16)
|
||||
#define IMX6Q_GPR1_USB_EXP_MODE BIT(15)
|
||||
#define IMX6Q_GPR1_PCIE_INT BIT(14)
|
||||
#define IMX6Q_GPR1_USB_OTG_ID_SEL_MASK BIT(13)
|
||||
#define IMX6Q_GPR1_USB_OTG_ID_SEL_ENET_RX_ER 0x0
|
||||
#define IMX6Q_GPR1_USB_OTG_ID_SEL_GPIO_1 BIT(13)
|
||||
#define IMX6Q_GPR1_GINT BIT(12)
|
||||
#define IMX6Q_GPR1_ADDRS3_MASK (0x3 << 10)
|
||||
#define IMX6Q_GPR1_ADDRS3_32MB (0x0 << 10)
|
||||
#define IMX6Q_GPR1_ADDRS3_64MB (0x1 << 10)
|
||||
#define IMX6Q_GPR1_ADDRS3_128MB (0x2 << 10)
|
||||
#define IMX6Q_GPR1_ACT_CS3 BIT(9)
|
||||
#define IMX6Q_GPR1_ADDRS2_MASK (0x3 << 7)
|
||||
#define IMX6Q_GPR1_ACT_CS2 BIT(6)
|
||||
#define IMX6Q_GPR1_ADDRS1_MASK (0x3 << 4)
|
||||
#define IMX6Q_GPR1_ACT_CS1 BIT(3)
|
||||
#define IMX6Q_GPR1_ADDRS0_MASK (0x3 << 1)
|
||||
#define IMX6Q_GPR1_ACT_CS0 BIT(0)
|
||||
|
||||
#define IMX6Q_GPR2_COUNTER_RESET_VAL_MASK (0x3 << 20)
|
||||
#define IMX6Q_GPR2_COUNTER_RESET_VAL_5 (0x0 << 20)
|
||||
#define IMX6Q_GPR2_COUNTER_RESET_VAL_3 (0x1 << 20)
|
||||
#define IMX6Q_GPR2_COUNTER_RESET_VAL_4 (0x2 << 20)
|
||||
#define IMX6Q_GPR2_COUNTER_RESET_VAL_6 (0x3 << 20)
|
||||
#define IMX6Q_GPR2_LVDS_CLK_SHIFT_MASK (0x7 << 16)
|
||||
#define IMX6Q_GPR2_LVDS_CLK_SHIFT_0 (0x0 << 16)
|
||||
#define IMX6Q_GPR2_LVDS_CLK_SHIFT_1 (0x1 << 16)
|
||||
#define IMX6Q_GPR2_LVDS_CLK_SHIFT_2 (0x2 << 16)
|
||||
#define IMX6Q_GPR2_LVDS_CLK_SHIFT_3 (0x3 << 16)
|
||||
#define IMX6Q_GPR2_LVDS_CLK_SHIFT_4 (0x4 << 16)
|
||||
#define IMX6Q_GPR2_LVDS_CLK_SHIFT_5 (0x5 << 16)
|
||||
#define IMX6Q_GPR2_LVDS_CLK_SHIFT_6 (0x6 << 16)
|
||||
#define IMX6Q_GPR2_LVDS_CLK_SHIFT_7 (0x7 << 16)
|
||||
#define IMX6Q_GPR2_BGREF_RRMODE_MASK BIT(15)
|
||||
#define IMX6Q_GPR2_BGREF_RRMODE_EXT_RESISTOR 0x0
|
||||
#define IMX6Q_GPR2_BGREF_RRMODE_INT_RESISTOR BIT(15)
|
||||
#define IMX6Q_GPR2_DI1_VS_POLARITY_MASK BIT(10)
|
||||
#define IMX6Q_GPR2_DI1_VS_POLARITY_ACTIVE_H 0x0
|
||||
#define IMX6Q_GPR2_DI1_VS_POLARITY_ACTIVE_L BIT(10)
|
||||
#define IMX6Q_GPR2_DI0_VS_POLARITY_MASK BIT(9)
|
||||
#define IMX6Q_GPR2_DI0_VS_POLARITY_ACTIVE_H 0x0
|
||||
#define IMX6Q_GPR2_DI0_VS_POLARITY_ACTIVE_L BIT(9)
|
||||
#define IMX6Q_GPR2_BIT_MAPPING_CH1_MASK BIT(8)
|
||||
#define IMX6Q_GPR2_BIT_MAPPING_CH1_SPWG 0x0
|
||||
#define IMX6Q_GPR2_BIT_MAPPING_CH1_JEIDA BIT(8)
|
||||
#define IMX6Q_GPR2_DATA_WIDTH_CH1_MASK BIT(7)
|
||||
#define IMX6Q_GPR2_DATA_WIDTH_CH1_18BIT 0x0
|
||||
#define IMX6Q_GPR2_DATA_WIDTH_CH1_24BIT BIT(7)
|
||||
#define IMX6Q_GPR2_BIT_MAPPING_CH0_MASK BIT(6)
|
||||
#define IMX6Q_GPR2_BIT_MAPPING_CH0_SPWG 0x0
|
||||
#define IMX6Q_GPR2_BIT_MAPPING_CH0_JEIDA BIT(6)
|
||||
#define IMX6Q_GPR2_DATA_WIDTH_CH0_MASK BIT(5)
|
||||
#define IMX6Q_GPR2_DATA_WIDTH_CH0_18BIT 0x0
|
||||
#define IMX6Q_GPR2_DATA_WIDTH_CH0_24BIT BIT(5)
|
||||
#define IMX6Q_GPR2_SPLIT_MODE_EN BIT(4)
|
||||
#define IMX6Q_GPR2_CH1_MODE_MASK (0x3 << 2)
|
||||
#define IMX6Q_GPR2_CH1_MODE_DISABLE (0x0 << 2)
|
||||
#define IMX6Q_GPR2_CH1_MODE_EN_ROUTE_DI0 (0x1 << 2)
|
||||
#define IMX6Q_GPR2_CH1_MODE_EN_ROUTE_DI1 (0x3 << 2)
|
||||
#define IMX6Q_GPR2_CH0_MODE_MASK (0x3 << 0)
|
||||
#define IMX6Q_GPR2_CH0_MODE_DISABLE (0x0 << 0)
|
||||
#define IMX6Q_GPR2_CH0_MODE_EN_ROUTE_DI0 (0x1 << 0)
|
||||
#define IMX6Q_GPR2_CH0_MODE_EN_ROUTE_DI1 (0x3 << 0)
|
||||
|
||||
#define IMX6Q_GPR3_GPU_DBG_MASK (0x3 << 29)
|
||||
#define IMX6Q_GPR3_GPU_DBG_GPU3D (0x0 << 29)
|
||||
#define IMX6Q_GPR3_GPU_DBG_GPU2D (0x1 << 29)
|
||||
#define IMX6Q_GPR3_GPU_DBG_OPENVG (0x2 << 29)
|
||||
#define IMX6Q_GPR3_BCH_WR_CACHE_CTL BIT(28)
|
||||
#define IMX6Q_GPR3_BCH_RD_CACHE_CTL BIT(27)
|
||||
#define IMX6Q_GPR3_USDHCX_WR_CACHE_CTL BIT(26)
|
||||
#define IMX6Q_GPR3_USDHCX_RD_CACHE_CTL BIT(25)
|
||||
#define IMX6Q_GPR3_OCRAM_CTL_MASK (0xf << 21)
|
||||
#define IMX6Q_GPR3_OCRAM_STATUS_MASK (0xf << 17)
|
||||
#define IMX6Q_GPR3_CORE3_DBG_ACK_EN BIT(16)
|
||||
#define IMX6Q_GPR3_CORE2_DBG_ACK_EN BIT(15)
|
||||
#define IMX6Q_GPR3_CORE1_DBG_ACK_EN BIT(14)
|
||||
#define IMX6Q_GPR3_CORE0_DBG_ACK_EN BIT(13)
|
||||
#define IMX6Q_GPR3_TZASC2_BOOT_LOCK BIT(12)
|
||||
#define IMX6Q_GPR3_TZASC1_BOOT_LOCK BIT(11)
|
||||
#define IMX6Q_GPR3_IPU_DIAG_MASK BIT(10)
|
||||
#define IMX6Q_GPR3_LVDS1_MUX_CTL_MASK (0x3 << 8)
|
||||
#define IMX6Q_GPR3_LVDS1_MUX_CTL_IPU1_DI0 (0x0 << 8)
|
||||
#define IMX6Q_GPR3_LVDS1_MUX_CTL_IPU1_DI1 (0x1 << 8)
|
||||
#define IMX6Q_GPR3_LVDS1_MUX_CTL_IPU2_DI0 (0x2 << 8)
|
||||
#define IMX6Q_GPR3_LVDS1_MUX_CTL_IPU2_DI1 (0x3 << 8)
|
||||
#define IMX6Q_GPR3_LVDS0_MUX_CTL_MASK (0x3 << 6)
|
||||
#define IMX6Q_GPR3_LVDS0_MUX_CTL_IPU1_DI0 (0x0 << 6)
|
||||
#define IMX6Q_GPR3_LVDS0_MUX_CTL_IPU1_DI1 (0x1 << 6)
|
||||
#define IMX6Q_GPR3_LVDS0_MUX_CTL_IPU2_DI0 (0x2 << 6)
|
||||
#define IMX6Q_GPR3_LVDS0_MUX_CTL_IPU2_DI1 (0x3 << 6)
|
||||
#define IMX6Q_GPR3_MIPI_MUX_CTL_MASK (0x3 << 4)
|
||||
#define IMX6Q_GPR3_MIPI_MUX_CTL_IPU1_DI0 (0x0 << 4)
|
||||
#define IMX6Q_GPR3_MIPI_MUX_CTL_IPU1_DI1 (0x1 << 4)
|
||||
#define IMX6Q_GPR3_MIPI_MUX_CTL_IPU2_DI0 (0x2 << 4)
|
||||
#define IMX6Q_GPR3_MIPI_MUX_CTL_IPU2_DI1 (0x3 << 4)
|
||||
#define IMX6Q_GPR3_HDMI_MUX_CTL_MASK (0x3 << 2)
|
||||
#define IMX6Q_GPR3_HDMI_MUX_CTL_IPU1_DI0 (0x0 << 2)
|
||||
#define IMX6Q_GPR3_HDMI_MUX_CTL_IPU1_DI1 (0x1 << 2)
|
||||
#define IMX6Q_GPR3_HDMI_MUX_CTL_IPU2_DI0 (0x2 << 2)
|
||||
#define IMX6Q_GPR3_HDMI_MUX_CTL_IPU2_DI1 (0x3 << 2)
|
||||
|
||||
#define IMX6Q_GPR4_VDOA_WR_CACHE_SEL BIT(31)
|
||||
#define IMX6Q_GPR4_VDOA_RD_CACHE_SEL BIT(30)
|
||||
#define IMX6Q_GPR4_VDOA_WR_CACHE_VAL BIT(29)
|
||||
#define IMX6Q_GPR4_VDOA_RD_CACHE_VAL BIT(28)
|
||||
#define IMX6Q_GPR4_PCIE_WR_CACHE_SEL BIT(27)
|
||||
#define IMX6Q_GPR4_PCIE_RD_CACHE_SEL BIT(26)
|
||||
#define IMX6Q_GPR4_PCIE_WR_CACHE_VAL BIT(25)
|
||||
#define IMX6Q_GPR4_PCIE_RD_CACHE_VAL BIT(24)
|
||||
#define IMX6Q_GPR4_SDMA_STOP_ACK BIT(19)
|
||||
#define IMX6Q_GPR4_CAN2_STOP_ACK BIT(18)
|
||||
#define IMX6Q_GPR4_CAN1_STOP_ACK BIT(17)
|
||||
#define IMX6Q_GPR4_ENET_STOP_ACK BIT(16)
|
||||
#define IMX6Q_GPR4_SOC_VERSION_MASK (0xff << 8)
|
||||
#define IMX6Q_GPR4_SOC_VERSION_OFF 0x8
|
||||
#define IMX6Q_GPR4_VPU_WR_CACHE_SEL BIT(7)
|
||||
#define IMX6Q_GPR4_VPU_RD_CACHE_SEL BIT(6)
|
||||
#define IMX6Q_GPR4_VPU_P_WR_CACHE_VAL BIT(3)
|
||||
#define IMX6Q_GPR4_VPU_P_RD_CACHE_VAL_MASK BIT(2)
|
||||
#define IMX6Q_GPR4_IPU_WR_CACHE_CTL BIT(1)
|
||||
#define IMX6Q_GPR4_IPU_RD_CACHE_CTL BIT(0)
|
||||
|
||||
#define IMX6Q_GPR5_L2_CLK_STOP BIT(8)
|
||||
|
||||
#define IMX6Q_GPR9_TZASC2_BYP BIT(1)
|
||||
#define IMX6Q_GPR9_TZASC1_BYP BIT(0)
|
||||
|
||||
#define IMX6Q_GPR10_LOCK_DBG_EN BIT(29)
|
||||
#define IMX6Q_GPR10_LOCK_DBG_CLK_EN BIT(28)
|
||||
#define IMX6Q_GPR10_LOCK_SEC_ERR_RESP BIT(27)
|
||||
#define IMX6Q_GPR10_LOCK_OCRAM_TZ_ADDR (0x3f << 21)
|
||||
#define IMX6Q_GPR10_LOCK_OCRAM_TZ_EN BIT(20)
|
||||
#define IMX6Q_GPR10_LOCK_DCIC2_MUX_MASK (0x3 << 18)
|
||||
#define IMX6Q_GPR10_LOCK_DCIC1_MUX_MASK (0x3 << 16)
|
||||
#define IMX6Q_GPR10_DBG_EN BIT(13)
|
||||
#define IMX6Q_GPR10_DBG_CLK_EN BIT(12)
|
||||
#define IMX6Q_GPR10_SEC_ERR_RESP_MASK BIT(11)
|
||||
#define IMX6Q_GPR10_SEC_ERR_RESP_OKEY 0x0
|
||||
#define IMX6Q_GPR10_SEC_ERR_RESP_SLVE BIT(11)
|
||||
#define IMX6Q_GPR10_OCRAM_TZ_ADDR_MASK (0x3f << 5)
|
||||
#define IMX6Q_GPR10_OCRAM_TZ_EN_MASK BIT(4)
|
||||
#define IMX6Q_GPR10_DCIC2_MUX_CTL_MASK (0x3 << 2)
|
||||
#define IMX6Q_GPR10_DCIC2_MUX_CTL_IPU1_DI0 (0x0 << 2)
|
||||
#define IMX6Q_GPR10_DCIC2_MUX_CTL_IPU1_DI1 (0x1 << 2)
|
||||
#define IMX6Q_GPR10_DCIC2_MUX_CTL_IPU2_DI0 (0x2 << 2)
|
||||
#define IMX6Q_GPR10_DCIC2_MUX_CTL_IPU2_DI1 (0x3 << 2)
|
||||
#define IMX6Q_GPR10_DCIC1_MUX_CTL_MASK (0x3 << 0)
|
||||
#define IMX6Q_GPR10_DCIC1_MUX_CTL_IPU1_DI0 (0x0 << 0)
|
||||
#define IMX6Q_GPR10_DCIC1_MUX_CTL_IPU1_DI1 (0x1 << 0)
|
||||
#define IMX6Q_GPR10_DCIC1_MUX_CTL_IPU2_DI0 (0x2 << 0)
|
||||
#define IMX6Q_GPR10_DCIC1_MUX_CTL_IPU2_DI1 (0x3 << 0)
|
||||
|
||||
#define IMX6Q_GPR12_ARMP_IPG_CLK_EN BIT(27)
|
||||
#define IMX6Q_GPR12_ARMP_AHB_CLK_EN BIT(26)
|
||||
#define IMX6Q_GPR12_ARMP_ATB_CLK_EN BIT(25)
|
||||
#define IMX6Q_GPR12_ARMP_APB_CLK_EN BIT(24)
|
||||
#define IMX6Q_GPR12_PCIE_CTL_2 BIT(10)
|
||||
|
||||
#define IMX6Q_GPR13_SDMA_STOP_REQ BIT(30)
|
||||
#define IMX6Q_GPR13_CAN2_STOP_REQ BIT(29)
|
||||
#define IMX6Q_GPR13_CAN1_STOP_REQ BIT(28)
|
||||
#define IMX6Q_GPR13_ENET_STOP_REQ BIT(27)
|
||||
#define IMX6Q_GPR13_SATA_PHY_8_MASK (0x7 << 24)
|
||||
#define IMX6Q_GPR13_SATA_PHY_8_0_5_DB (0x0 << 24)
|
||||
#define IMX6Q_GPR13_SATA_PHY_8_1_0_DB (0x1 << 24)
|
||||
#define IMX6Q_GPR13_SATA_PHY_8_1_5_DB (0x2 << 24)
|
||||
#define IMX6Q_GPR13_SATA_PHY_8_2_0_DB (0x3 << 24)
|
||||
#define IMX6Q_GPR13_SATA_PHY_8_2_5_DB (0x4 << 24)
|
||||
#define IMX6Q_GPR13_SATA_PHY_8_3_0_DB (0x5 << 24)
|
||||
#define IMX6Q_GPR13_SATA_PHY_8_3_5_DB (0x6 << 24)
|
||||
#define IMX6Q_GPR13_SATA_PHY_8_4_0_DB (0x7 << 24)
|
||||
#define IMX6Q_GPR13_SATA_PHY_7_MASK (0x1f << 19)
|
||||
#define IMX6Q_GPR13_SATA_PHY_7_SATA1I (0x10 << 19)
|
||||
#define IMX6Q_GPR13_SATA_PHY_7_SATA1M (0x10 << 19)
|
||||
#define IMX6Q_GPR13_SATA_PHY_7_SATA1X (0x1a << 19)
|
||||
#define IMX6Q_GPR13_SATA_PHY_7_SATA2I (0x12 << 19)
|
||||
#define IMX6Q_GPR13_SATA_PHY_7_SATA2M (0x12 << 19)
|
||||
#define IMX6Q_GPR13_SATA_PHY_7_SATA2X (0x1a << 19)
|
||||
#define IMX6Q_GPR13_SATA_PHY_6_MASK (0x7 << 16)
|
||||
#define IMX6Q_GPR13_SATA_SPEED_MASK BIT(15)
|
||||
#define IMX6Q_GPR13_SATA_SPEED_1P5G 0x0
|
||||
#define IMX6Q_GPR13_SATA_SPEED_3P0G BIT(15)
|
||||
#define IMX6Q_GPR13_SATA_PHY_5 BIT(14)
|
||||
#define IMX6Q_GPR13_SATA_PHY_4_MASK (0x7 << 11)
|
||||
#define IMX6Q_GPR13_SATA_PHY_4_16_16 (0x0 << 11)
|
||||
#define IMX6Q_GPR13_SATA_PHY_4_14_16 (0x1 << 11)
|
||||
#define IMX6Q_GPR13_SATA_PHY_4_12_16 (0x2 << 11)
|
||||
#define IMX6Q_GPR13_SATA_PHY_4_10_16 (0x3 << 11)
|
||||
#define IMX6Q_GPR13_SATA_PHY_4_9_16 (0x4 << 11)
|
||||
#define IMX6Q_GPR13_SATA_PHY_4_8_16 (0x5 << 11)
|
||||
#define IMX6Q_GPR13_SATA_PHY_3_MASK (0xf << 7)
|
||||
#define IMX6Q_GPR13_SATA_PHY_3_OFF 0x7
|
||||
#define IMX6Q_GPR13_SATA_PHY_2_MASK (0x1f << 2)
|
||||
#define IMX6Q_GPR13_SATA_PHY_2_OFF 0x2
|
||||
#define IMX6Q_GPR13_SATA_PHY_1_MASK (0x3 << 0)
|
||||
#define IMX6Q_GPR13_SATA_PHY_1_FAST (0x0 << 0)
|
||||
#define IMX6Q_GPR13_SATA_PHY_1_MED (0x1 << 0)
|
||||
#define IMX6Q_GPR13_SATA_PHY_1_SLOW (0x2 << 0)
|
||||
|
||||
#endif /* __LINUX_IMX6Q_IOMUXC_GPR_H */
|
|
@ -117,6 +117,7 @@ struct tc3589x {
|
|||
struct mutex lock;
|
||||
struct device *dev;
|
||||
struct i2c_client *i2c;
|
||||
struct irq_domain *domain;
|
||||
|
||||
int irq_base;
|
||||
int num_gpio;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue