mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-24 17:20:50 +07:00
This is the MFD pull request for the 3.9 merge window.
No new drivers this time, but a bunch of fairly big cleanups: - Roger Quadros worked on a OMAP USBHS and TLL platform data consolidation, OMAP5 support and clock management code cleanup. - The first step of a major sync for the ab8500 driver from Lee Jones. In particular, the debugfs and the sysct interfaces got extended and improved. - Peter Ujfalusi sent a nice patchset for cleaning and fixing the twl-core driver, with a much needed module id lookup code improvement. - The regular wm5102 and arizona cleanups and fixes from Mark Brown. - Laxman Dewangan extended the palmas APIs in order to implement the palmas GPIO and rt drivers. - Laxman also added DT support for the tps65090 driver. - The Intel SCH and ICH drivers got a couple fixes from Aaron Sierra and Darren Hart. - Linus Walleij patchset for the ab8500 driver allowed ab8500 and ab9540 based devices to switch to the new abx500 pin-ctrl driver. - The max8925 now has device tree and irqdomain support thanks to Qing Xu. - The recently added rtsx driver got a few cleanups and fixes for a better card detection code path and now also supports the RTS5227 chipset, thanks to Wei Wang and Roger Tseng. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQIcBAABAgAGBQJRJWtoAAoJEIqAPN1PVmxKHvEP/2B0uUJQpRjTjc9lgrzaUdFO QdSyj8Vpz1fZPF3cDuik/Be91U1nICyJWZZ7Yvngih3kbqiGw8nbp9AATwdF4Anl +QEtPS9YIpu1w5NS4r01q+cx3NxFsaR5yfNPKLWWnLtN8zHq4qQS8SF8jjdrsgkz zUJrjn1GfPPeuyR6Fuko9Mxk6oQ6TUazWJwmxzSCcrKKQ7GlAnbRWcwv2Qnv3GTg xi9S85xmLtVhLmMIQ2OR4JP56Vc49OL2/+hv1uShtFVDR4JLeZ5l8j0IPjgXJTrv ZbcrzEfJkV+zkY5RmDQrZzNLIWQmH9lj0bzitrS8Ii622J/mfnvQEgnC5fObphjg sYKJuBtO9o7XtFJxH7/oXdwM2gC5jDy43FmRv9J2mIDVoX8kNZMzY/sqmL8jm7KD MZU0D7liOyF3/1VbZHGSplKp+HKd5XYXCDQEesG/urkDr2edYHdb52iUVYGC32yV MaTqXnRMGURdjhCorAZPV8hoQOSWV8pj6oskk+E3upCmWjQWdhKMw3/HzasDLO9B eoQSgwZXJLTV8hJjAdgPUjZbxyOyW+9jKA12nyqwX3noq0NseSSJaeZUWmLecmbF vXcg4LAwSUycNJ0DxtWC2oEUV9jv4B+dOE7avVT6BDSvth4nzDlO9gOTtxBLcgTz JKrAPxY1nS4AUXJbsYTq =BhC1 -----END PGP SIGNATURE----- Merge tag 'mfd-3.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6 Pull MFS updates from Samuel Ortiz: "This is the MFD pull request for the 3.9 merge window. No new drivers this time, but a bunch of fairly big cleanups: - Roger Quadros worked on a OMAP USBHS and TLL platform data consolidation, OMAP5 support and clock management code cleanup. - The first step of a major sync for the ab8500 driver from Lee Jones. In particular, the debugfs and the sysct interfaces got extended and improved. - Peter Ujfalusi sent a nice patchset for cleaning and fixing the twl-core driver, with a much needed module id lookup code improvement. - The regular wm5102 and arizona cleanups and fixes from Mark Brown. - Laxman Dewangan extended the palmas APIs in order to implement the palmas GPIO and rt drivers. - Laxman also added DT support for the tps65090 driver. - The Intel SCH and ICH drivers got a couple fixes from Aaron Sierra and Darren Hart. - Linus Walleij patchset for the ab8500 driver allowed ab8500 and ab9540 based devices to switch to the new abx500 pin-ctrl driver. - The max8925 now has device tree and irqdomain support thanks to Qing Xu. - The recently added rtsx driver got a few cleanups and fixes for a better card detection code path and now also supports the RTS5227 chipset, thanks to Wei Wang and Roger Tseng." * tag 'mfd-3.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6: (109 commits) mfd: lpc_ich: Use devres API to allocate private data mfd: lpc_ich: Add Device IDs for Intel Wellsburg PCH mfd: lpc_sch: Accomodate partial population of the MFD devices mfd: da9052-i2c: Staticize da9052_i2c_fix() mfd: syscon: Fix sparse warning mfd: twl-core: Fix kernel panic on boot mfd: rtsx: Fix issue that booting OS with SD card inserted mfd: ab8500: Fix compile error mfd: Add missing GENERIC_HARDIRQS dependecies Documentation: Add docs for max8925 dt mfd: max8925: Add dts mfd: max8925: Support dt for backlight mfd: max8925: Fix onkey driver irq base mfd: max8925: Fix mfd device register failure mfd: max8925: Add irqdomain for dt mfd: vexpress: Allow vexpress-sysreg to self-initialise mfd: rtsx: Support RTS5227 mfd: rtsx: Implement driving adjustment to device-dependent callbacks mfd: vexpress: Add pseudo-GPIO based LEDs mfd: ab8500: Rename ab8500 to abx500 for hwmon driver ...
This commit is contained in:
commit
ab7826595e
64
Documentation/devicetree/bindings/mfd/max8925.txt
Normal file
64
Documentation/devicetree/bindings/mfd/max8925.txt
Normal file
@ -0,0 +1,64 @@
|
||||
* Maxim max8925 Power Management IC
|
||||
|
||||
Required parent device properties:
|
||||
- compatible : "maxim,max8925"
|
||||
- reg : the I2C slave address for the max8925 chip
|
||||
- interrupts : IRQ line for the max8925 chip
|
||||
- interrupt-controller: describes the max8925 as an interrupt
|
||||
controller (has its own domain)
|
||||
- #interrupt-cells : should be 1.
|
||||
- The cell is the max8925 local IRQ number
|
||||
|
||||
Optional parent device properties:
|
||||
- maxim,tsc-irq: there are 2 IRQ lines for max8925, one is indicated in
|
||||
interrupts property, the other is indicated here.
|
||||
|
||||
max8925 consists of a large and varied group of sub-devices:
|
||||
|
||||
Device Supply Names Description
|
||||
------ ------------ -----------
|
||||
max8925-onkey : : On key
|
||||
max8925-rtc : : RTC
|
||||
max8925-regulator : : Regulators
|
||||
max8925-backlight : : Backlight
|
||||
max8925-touch : : Touchscreen
|
||||
max8925-power : : Charger
|
||||
|
||||
Example:
|
||||
|
||||
pmic: max8925@3c {
|
||||
compatible = "maxim,max8925";
|
||||
reg = <0x3c>;
|
||||
interrupts = <1>;
|
||||
interrupt-parent = <&intcmux4>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <1>;
|
||||
maxim,tsc-irq = <0>;
|
||||
|
||||
regulators {
|
||||
SDV1 {
|
||||
regulator-min-microvolt = <637500>;
|
||||
regulator-max-microvolt = <1425000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
LDO1 {
|
||||
regulator-min-microvolt = <750000>;
|
||||
regulator-max-microvolt = <3900000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
};
|
||||
backlight {
|
||||
maxim,max8925-dual-string = <0>;
|
||||
};
|
||||
charger {
|
||||
batt-detect = <0>;
|
||||
topoff-threshold = <1>;
|
||||
fast-charge = <7>;
|
||||
no-temp-support = <0>;
|
||||
no-insert-detect = <0>;
|
||||
};
|
||||
};
|
@ -0,0 +1,18 @@
|
||||
max8925-battery bindings
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
Optional properties :
|
||||
- batt-detect: whether support battery detect
|
||||
- topoff-threshold: set charging current in topoff mode
|
||||
- fast-charge: set charging current in fast mode
|
||||
- no-temp-support: whether support temperature protection detect
|
||||
- no-insert-detect: whether support insert detect
|
||||
|
||||
Example:
|
||||
charger {
|
||||
batt-detect = <0>;
|
||||
topoff-threshold = <1>;
|
||||
fast-charge = <7>;
|
||||
no-temp-support = <0>;
|
||||
no-insert-detect = <0>;
|
||||
};
|
122
Documentation/devicetree/bindings/regulator/tps65090.txt
Normal file
122
Documentation/devicetree/bindings/regulator/tps65090.txt
Normal file
@ -0,0 +1,122 @@
|
||||
TPS65090 regulators
|
||||
|
||||
Required properties:
|
||||
- compatible: "ti,tps65090"
|
||||
- reg: I2C slave address
|
||||
- interrupts: the interrupt outputs of the controller
|
||||
- regulators: A node that houses a sub-node for each regulator within the
|
||||
device. Each sub-node is identified using the node's name, with valid
|
||||
values listed below. The content of each sub-node is defined by the
|
||||
standard binding for regulators; see regulator.txt.
|
||||
dcdc[1-3], fet[1-7] and ldo[1-2] respectively.
|
||||
- vsys[1-3]-supply: The input supply for DCDC[1-3] respectively.
|
||||
- infet[1-7]-supply: The input supply for FET[1-7] respectively.
|
||||
- vsys-l[1-2]-supply: The input supply for LDO[1-2] respectively.
|
||||
|
||||
Optional properties:
|
||||
- ti,enable-ext-control: This is applicable for DCDC1, DCDC2 and DCDC3.
|
||||
If DCDCs are externally controlled then this property should be there.
|
||||
- "dcdc-ext-control-gpios: This is applicable for DCDC1, DCDC2 and DCDC3.
|
||||
If DCDCs are externally controlled and if it is from GPIO then GPIO
|
||||
number should be provided. If it is externally controlled and no GPIO
|
||||
entry then driver will just configure this rails as external control
|
||||
and will not provide any enable/disable APIs.
|
||||
|
||||
Each regulator is defined using the standard binding for regulators.
|
||||
|
||||
Example:
|
||||
|
||||
tps65090@48 {
|
||||
compatible = "ti,tps65090";
|
||||
reg = <0x48>;
|
||||
interrupts = <0 88 0x4>;
|
||||
|
||||
vsys1-supply = <&some_reg>;
|
||||
vsys2-supply = <&some_reg>;
|
||||
vsys3-supply = <&some_reg>;
|
||||
infet1-supply = <&some_reg>;
|
||||
infet2-supply = <&some_reg>;
|
||||
infet3-supply = <&some_reg>;
|
||||
infet4-supply = <&some_reg>;
|
||||
infet5-supply = <&some_reg>;
|
||||
infet6-supply = <&some_reg>;
|
||||
infet7-supply = <&some_reg>;
|
||||
vsys_l1-supply = <&some_reg>;
|
||||
vsys_l2-supply = <&some_reg>;
|
||||
|
||||
regulators {
|
||||
dcdc1 {
|
||||
regulator-name = "dcdc1";
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
ti,enable-ext-control;
|
||||
dcdc-ext-control-gpios = <&gpio 10 0>;
|
||||
};
|
||||
|
||||
dcdc2 {
|
||||
regulator-name = "dcdc2";
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
dcdc3 {
|
||||
regulator-name = "dcdc3";
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
fet1 {
|
||||
regulator-name = "fet1";
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
fet2 {
|
||||
regulator-name = "fet2";
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
fet3 {
|
||||
regulator-name = "fet3";
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
fet4 {
|
||||
regulator-name = "fet4";
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
fet5 {
|
||||
regulator-name = "fet5";
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
fet6 {
|
||||
regulator-name = "fet6";
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
fet7 {
|
||||
regulator-name = "fet7";
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
ldo1 {
|
||||
regulator-name = "ldo1";
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
ldo2 {
|
||||
regulator-name = "ldo2";
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
};
|
||||
};
|
@ -0,0 +1,10 @@
|
||||
88pm860x-backlight bindings
|
||||
|
||||
Optional properties:
|
||||
- maxim,max8925-dual-string: whether support dual string
|
||||
|
||||
Example:
|
||||
|
||||
backlights {
|
||||
maxim,max8925-dual-string = <0>;
|
||||
};
|
@ -29,6 +29,164 @@ uart3: uart@d4018000 {
|
||||
};
|
||||
twsi1: i2c@d4011000 {
|
||||
status = "okay";
|
||||
pmic: max8925@3c {
|
||||
compatible = "maxium,max8925";
|
||||
reg = <0x3c>;
|
||||
interrupts = <1>;
|
||||
interrupt-parent = <&intcmux4>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <1>;
|
||||
maxim,tsc-irq = <0>;
|
||||
|
||||
regulators {
|
||||
SDV1 {
|
||||
regulator-min-microvolt = <637500>;
|
||||
regulator-max-microvolt = <1425000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
SDV2 {
|
||||
regulator-min-microvolt = <650000>;
|
||||
regulator-max-microvolt = <2225000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
SDV3 {
|
||||
regulator-min-microvolt = <750000>;
|
||||
regulator-max-microvolt = <3900000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
LDO1 {
|
||||
regulator-min-microvolt = <750000>;
|
||||
regulator-max-microvolt = <3900000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
LDO2 {
|
||||
regulator-min-microvolt = <650000>;
|
||||
regulator-max-microvolt = <2250000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
LDO3 {
|
||||
regulator-min-microvolt = <650000>;
|
||||
regulator-max-microvolt = <2250000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
LDO4 {
|
||||
regulator-min-microvolt = <750000>;
|
||||
regulator-max-microvolt = <3900000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
LDO5 {
|
||||
regulator-min-microvolt = <750000>;
|
||||
regulator-max-microvolt = <3900000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
LDO6 {
|
||||
regulator-min-microvolt = <750000>;
|
||||
regulator-max-microvolt = <3900000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
LDO7 {
|
||||
regulator-min-microvolt = <750000>;
|
||||
regulator-max-microvolt = <3900000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
LDO8 {
|
||||
regulator-min-microvolt = <750000>;
|
||||
regulator-max-microvolt = <3900000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
LDO9 {
|
||||
regulator-min-microvolt = <750000>;
|
||||
regulator-max-microvolt = <3900000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
LDO10 {
|
||||
regulator-min-microvolt = <750000>;
|
||||
regulator-max-microvolt = <3900000>;
|
||||
};
|
||||
LDO11 {
|
||||
regulator-min-microvolt = <750000>;
|
||||
regulator-max-microvolt = <3900000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
LDO12 {
|
||||
regulator-min-microvolt = <750000>;
|
||||
regulator-max-microvolt = <3900000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
LDO13 {
|
||||
regulator-min-microvolt = <750000>;
|
||||
regulator-max-microvolt = <3900000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
LDO14 {
|
||||
regulator-min-microvolt = <750000>;
|
||||
regulator-max-microvolt = <3900000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
LDO15 {
|
||||
regulator-min-microvolt = <750000>;
|
||||
regulator-max-microvolt = <3900000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
LDO16 {
|
||||
regulator-min-microvolt = <750000>;
|
||||
regulator-max-microvolt = <3900000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
LDO17 {
|
||||
regulator-min-microvolt = <650000>;
|
||||
regulator-max-microvolt = <2250000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
LDO18 {
|
||||
regulator-min-microvolt = <650000>;
|
||||
regulator-max-microvolt = <2250000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
LDO19 {
|
||||
regulator-min-microvolt = <750000>;
|
||||
regulator-max-microvolt = <3900000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
LDO20 {
|
||||
regulator-min-microvolt = <750000>;
|
||||
regulator-max-microvolt = <3900000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
};
|
||||
backlight {
|
||||
maxim,max8925-dual-string = <0>;
|
||||
};
|
||||
charger {
|
||||
batt-detect = <0>;
|
||||
topoff-threshold = <1>;
|
||||
fast-charge = <7>;
|
||||
no-temp-support = <0>;
|
||||
no-insert-detect = <0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
rtc: rtc@d4010000 {
|
||||
status = "okay";
|
||||
|
@ -46,7 +46,7 @@ intc: interrupt-controller@d4282000 {
|
||||
mrvl,intc-nr-irqs = <64>;
|
||||
};
|
||||
|
||||
intcmux4@d4282150 {
|
||||
intcmux4: interrupt-controller@d4282150 {
|
||||
compatible = "mrvl,mmp2-mux-intc";
|
||||
interrupts = <4>;
|
||||
interrupt-controller;
|
||||
@ -201,6 +201,8 @@ twsi1: i2c@d4011000 {
|
||||
compatible = "mrvl,mmp-twsi";
|
||||
reg = <0xd4011000 0x1000>;
|
||||
interrupts = <7>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
mrvl,i2c-fast-mode;
|
||||
status = "disabled";
|
||||
};
|
||||
|
@ -49,13 +49,13 @@ static void zoom_panel_disable_lcd(struct omap_dss_device *dssdev)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* PWMA/B register offsets (TWL4030_MODULE_PWMA)
|
||||
*/
|
||||
/* Register offsets in TWL4030_MODULE_INTBR */
|
||||
#define TWL_INTBR_PMBR1 0xD
|
||||
#define TWL_INTBR_GPBR1 0xC
|
||||
#define TWL_LED_PWMON 0x0
|
||||
#define TWL_LED_PWMOFF 0x1
|
||||
|
||||
/* Register offsets in TWL_MODULE_PWM */
|
||||
#define TWL_LED_PWMON 0x3
|
||||
#define TWL_LED_PWMOFF 0x4
|
||||
|
||||
static int zoom_set_bl_intensity(struct omap_dss_device *dssdev, int level)
|
||||
{
|
||||
@ -93,8 +93,8 @@ static int zoom_set_bl_intensity(struct omap_dss_device *dssdev, int level)
|
||||
}
|
||||
|
||||
c = ((50 * (100 - level)) / 100) + 1;
|
||||
twl_i2c_write_u8(TWL4030_MODULE_PWM1, 0x7F, TWL_LED_PWMOFF);
|
||||
twl_i2c_write_u8(TWL4030_MODULE_PWM1, c, TWL_LED_PWMON);
|
||||
twl_i2c_write_u8(TWL_MODULE_PWM, 0x7F, TWL_LED_PWMOFF);
|
||||
twl_i2c_write_u8(TWL_MODULE_PWM, c, TWL_LED_PWMON);
|
||||
#else
|
||||
pr_warn("Backlight not enabled\n");
|
||||
#endif
|
||||
|
@ -657,6 +657,13 @@ config GPIO_JANZ_TTL
|
||||
This driver provides support for driving the pins in output
|
||||
mode only. Input mode is not supported.
|
||||
|
||||
config GPIO_PALMAS
|
||||
bool "TI PALMAS series PMICs GPIO"
|
||||
depends on MFD_PALMAS
|
||||
help
|
||||
Select this option to enable GPIO driver for the TI PALMAS
|
||||
series chip family.
|
||||
|
||||
config GPIO_TPS6586X
|
||||
bool "TPS6586X GPIO"
|
||||
depends on MFD_TPS6586X
|
||||
|
@ -68,6 +68,7 @@ obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o
|
||||
obj-$(CONFIG_ARCH_TEGRA) += gpio-tegra.o
|
||||
obj-$(CONFIG_GPIO_TIMBERDALE) += gpio-timberdale.o
|
||||
obj-$(CONFIG_ARCH_DAVINCI_TNETV107X) += gpio-tnetv107x.o
|
||||
obj-$(CONFIG_GPIO_PALMAS) += gpio-palmas.o
|
||||
obj-$(CONFIG_GPIO_TPS6586X) += gpio-tps6586x.o
|
||||
obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o
|
||||
obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o
|
||||
|
184
drivers/gpio/gpio-palmas.c
Normal file
184
drivers/gpio/gpio-palmas.c
Normal file
@ -0,0 +1,184 @@
|
||||
/*
|
||||
* TI Palma series PMIC's GPIO driver.
|
||||
*
|
||||
* Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Author: Laxman Dewangan <ldewangan@nvidia.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mfd/palmas.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
struct palmas_gpio {
|
||||
struct gpio_chip gpio_chip;
|
||||
struct palmas *palmas;
|
||||
};
|
||||
|
||||
static inline struct palmas_gpio *to_palmas_gpio(struct gpio_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct palmas_gpio, gpio_chip);
|
||||
}
|
||||
|
||||
static int palmas_gpio_get(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
struct palmas_gpio *pg = to_palmas_gpio(gc);
|
||||
struct palmas *palmas = pg->palmas;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
ret = palmas_read(palmas, PALMAS_GPIO_BASE, PALMAS_GPIO_DATA_IN, &val);
|
||||
if (ret < 0) {
|
||||
dev_err(gc->dev, "GPIO_DATA_IN read failed, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
return !!(val & BIT(offset));
|
||||
}
|
||||
|
||||
static void palmas_gpio_set(struct gpio_chip *gc, unsigned offset,
|
||||
int value)
|
||||
{
|
||||
struct palmas_gpio *pg = to_palmas_gpio(gc);
|
||||
struct palmas *palmas = pg->palmas;
|
||||
int ret;
|
||||
|
||||
if (value)
|
||||
ret = palmas_write(palmas, PALMAS_GPIO_BASE,
|
||||
PALMAS_GPIO_SET_DATA_OUT, BIT(offset));
|
||||
else
|
||||
ret = palmas_write(palmas, PALMAS_GPIO_BASE,
|
||||
PALMAS_GPIO_CLEAR_DATA_OUT, BIT(offset));
|
||||
if (ret < 0)
|
||||
dev_err(gc->dev, "%s write failed, err = %d\n",
|
||||
(value) ? "GPIO_SET_DATA_OUT" : "GPIO_CLEAR_DATA_OUT",
|
||||
ret);
|
||||
}
|
||||
|
||||
static int palmas_gpio_output(struct gpio_chip *gc, unsigned offset,
|
||||
int value)
|
||||
{
|
||||
struct palmas_gpio *pg = to_palmas_gpio(gc);
|
||||
struct palmas *palmas = pg->palmas;
|
||||
int ret;
|
||||
|
||||
/* Set the initial value */
|
||||
palmas_gpio_set(gc, offset, value);
|
||||
|
||||
ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE,
|
||||
PALMAS_GPIO_DATA_DIR, BIT(offset), BIT(offset));
|
||||
if (ret < 0)
|
||||
dev_err(gc->dev, "GPIO_DATA_DIR write failed, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int palmas_gpio_input(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
struct palmas_gpio *pg = to_palmas_gpio(gc);
|
||||
struct palmas *palmas = pg->palmas;
|
||||
int ret;
|
||||
|
||||
ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE,
|
||||
PALMAS_GPIO_DATA_DIR, BIT(offset), 0);
|
||||
if (ret < 0)
|
||||
dev_err(gc->dev, "GPIO_DATA_DIR write failed, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int palmas_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
struct palmas_gpio *pg = to_palmas_gpio(gc);
|
||||
struct palmas *palmas = pg->palmas;
|
||||
|
||||
return palmas_irq_get_virq(palmas, PALMAS_GPIO_0_IRQ + offset);
|
||||
}
|
||||
|
||||
static int palmas_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);
|
||||
struct palmas_platform_data *palmas_pdata;
|
||||
struct palmas_gpio *palmas_gpio;
|
||||
int ret;
|
||||
|
||||
palmas_gpio = devm_kzalloc(&pdev->dev,
|
||||
sizeof(*palmas_gpio), GFP_KERNEL);
|
||||
if (!palmas_gpio) {
|
||||
dev_err(&pdev->dev, "Could not allocate palmas_gpio\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
palmas_gpio->palmas = palmas;
|
||||
palmas_gpio->gpio_chip.owner = THIS_MODULE;
|
||||
palmas_gpio->gpio_chip.label = dev_name(&pdev->dev);
|
||||
palmas_gpio->gpio_chip.ngpio = 8;
|
||||
palmas_gpio->gpio_chip.can_sleep = 1;
|
||||
palmas_gpio->gpio_chip.direction_input = palmas_gpio_input;
|
||||
palmas_gpio->gpio_chip.direction_output = palmas_gpio_output;
|
||||
palmas_gpio->gpio_chip.to_irq = palmas_gpio_to_irq;
|
||||
palmas_gpio->gpio_chip.set = palmas_gpio_set;
|
||||
palmas_gpio->gpio_chip.get = palmas_gpio_get;
|
||||
palmas_gpio->gpio_chip.dev = &pdev->dev;
|
||||
#ifdef CONFIG_OF_GPIO
|
||||
palmas_gpio->gpio_chip.of_node = palmas->dev->of_node;
|
||||
#endif
|
||||
palmas_pdata = dev_get_platdata(palmas->dev);
|
||||
if (palmas_pdata && palmas_pdata->gpio_base)
|
||||
palmas_gpio->gpio_chip.base = palmas_pdata->gpio_base;
|
||||
else
|
||||
palmas_gpio->gpio_chip.base = -1;
|
||||
|
||||
ret = gpiochip_add(&palmas_gpio->gpio_chip);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, palmas_gpio);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int palmas_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct palmas_gpio *palmas_gpio = platform_get_drvdata(pdev);
|
||||
|
||||
return gpiochip_remove(&palmas_gpio->gpio_chip);
|
||||
}
|
||||
|
||||
static struct platform_driver palmas_gpio_driver = {
|
||||
.driver.name = "palmas-gpio",
|
||||
.driver.owner = THIS_MODULE,
|
||||
.probe = palmas_gpio_probe,
|
||||
.remove = palmas_gpio_remove,
|
||||
};
|
||||
|
||||
static int __init palmas_gpio_init(void)
|
||||
{
|
||||
return platform_driver_register(&palmas_gpio_driver);
|
||||
}
|
||||
subsys_initcall(palmas_gpio_init);
|
||||
|
||||
static void __exit palmas_gpio_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&palmas_gpio_driver);
|
||||
}
|
||||
module_exit(palmas_gpio_exit);
|
||||
|
||||
MODULE_ALIAS("platform:palmas-gpio");
|
||||
MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
|
||||
MODULE_DESCRIPTION("GPIO driver for TI Palmas series PMICs");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -100,9 +100,6 @@ static int max8925_onkey_probe(struct platform_device *pdev)
|
||||
input->dev.parent = &pdev->dev;
|
||||
input_set_capability(input, EV_KEY, KEY_POWER);
|
||||
|
||||
irq[0] += chip->irq_base;
|
||||
irq[1] += chip->irq_base;
|
||||
|
||||
error = request_threaded_irq(irq[0], NULL, max8925_onkey_handler,
|
||||
IRQF_ONESHOT, "onkey-down", info);
|
||||
if (error < 0) {
|
||||
|
@ -426,6 +426,9 @@ static void rtsx_pci_ms_request(struct memstick_host *msh)
|
||||
|
||||
dev_dbg(ms_dev(host), "--> %s\n", __func__);
|
||||
|
||||
if (rtsx_pci_card_exclusive_check(host->pcr, RTSX_MS_CARD))
|
||||
return;
|
||||
|
||||
schedule_work(&host->handle_req);
|
||||
}
|
||||
|
||||
@ -441,6 +444,10 @@ static int rtsx_pci_ms_set_param(struct memstick_host *msh,
|
||||
dev_dbg(ms_dev(host), "%s: param = %d, value = %d\n",
|
||||
__func__, param, value);
|
||||
|
||||
err = rtsx_pci_card_exclusive_check(host->pcr, RTSX_MS_CARD);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
switch (param) {
|
||||
case MEMSTICK_POWER:
|
||||
if (value == MEMSTICK_POWER_ON)
|
||||
|
@ -531,7 +531,7 @@ static int pm800_probe(struct i2c_client *client,
|
||||
ret = device_800_init(chip, pdata);
|
||||
if (ret) {
|
||||
dev_err(chip->dev, "%s id 0x%x failed!\n", __func__, chip->id);
|
||||
goto err_800_init;
|
||||
goto err_subchip_alloc;
|
||||
}
|
||||
|
||||
ret = pm800_pages_init(chip);
|
||||
@ -546,10 +546,8 @@ static int pm800_probe(struct i2c_client *client,
|
||||
err_page_init:
|
||||
mfd_remove_devices(chip->dev);
|
||||
device_irq_exit_800(chip);
|
||||
err_800_init:
|
||||
devm_kfree(&client->dev, subchip);
|
||||
err_subchip_alloc:
|
||||
pm80x_deinit(client);
|
||||
pm80x_deinit();
|
||||
out_init:
|
||||
return ret;
|
||||
}
|
||||
@ -562,9 +560,7 @@ static int pm800_remove(struct i2c_client *client)
|
||||
device_irq_exit_800(chip);
|
||||
|
||||
pm800_pages_exit(chip);
|
||||
devm_kfree(&client->dev, chip->subchip);
|
||||
|
||||
pm80x_deinit(client);
|
||||
pm80x_deinit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -257,7 +257,7 @@ static int pm805_probe(struct i2c_client *client,
|
||||
pdata->plat_config(chip, pdata);
|
||||
|
||||
err_805_init:
|
||||
pm80x_deinit(client);
|
||||
pm80x_deinit();
|
||||
out_init:
|
||||
return ret;
|
||||
}
|
||||
@ -269,7 +269,7 @@ static int pm805_remove(struct i2c_client *client)
|
||||
mfd_remove_devices(chip->dev);
|
||||
device_irq_exit_805(chip);
|
||||
|
||||
pm80x_deinit(client);
|
||||
pm80x_deinit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -48,14 +48,12 @@ int pm80x_init(struct i2c_client *client,
|
||||
ret = PTR_ERR(map);
|
||||
dev_err(&client->dev, "Failed to allocate register map: %d\n",
|
||||
ret);
|
||||
goto err_regmap_init;
|
||||
return ret;
|
||||
}
|
||||
|
||||
chip->id = id->driver_data;
|
||||
if (chip->id < CHIP_PM800 || chip->id > CHIP_PM805) {
|
||||
ret = -EINVAL;
|
||||
goto err_chip_id;
|
||||
}
|
||||
if (chip->id < CHIP_PM800 || chip->id > CHIP_PM805)
|
||||
return -EINVAL;
|
||||
|
||||
chip->client = client;
|
||||
chip->regmap = map;
|
||||
@ -82,19 +80,11 @@ int pm80x_init(struct i2c_client *client,
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_chip_id:
|
||||
regmap_exit(map);
|
||||
err_regmap_init:
|
||||
devm_kfree(&client->dev, chip);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pm80x_init);
|
||||
|
||||
int pm80x_deinit(struct i2c_client *client)
|
||||
int pm80x_deinit(void)
|
||||
{
|
||||
struct pm80x_chip *chip = i2c_get_clientdata(client);
|
||||
|
||||
/*
|
||||
* workaround: clear the dependency between pm800 and pm805.
|
||||
* would remove it after HW chip fixes the issue.
|
||||
@ -103,10 +93,6 @@ int pm80x_deinit(struct i2c_client *client)
|
||||
g_pm80x_chip->companion = NULL;
|
||||
else
|
||||
g_pm80x_chip = NULL;
|
||||
|
||||
regmap_exit(chip->regmap);
|
||||
devm_kfree(&client->dev, chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pm80x_deinit);
|
||||
|
@ -65,7 +65,7 @@ config MFD_SM501_GPIO
|
||||
|
||||
config MFD_RTSX_PCI
|
||||
tristate "Support for Realtek PCI-E card reader"
|
||||
depends on PCI
|
||||
depends on PCI && GENERIC_HARDIRQS
|
||||
select MFD_CORE
|
||||
help
|
||||
This supports for Realtek PCI-Express card reader including rts5209,
|
||||
@ -95,7 +95,7 @@ config MFD_DM355EVM_MSP
|
||||
|
||||
config MFD_TI_SSP
|
||||
tristate "TI Sequencer Serial Port support"
|
||||
depends on ARCH_DAVINCI_TNETV107X
|
||||
depends on ARCH_DAVINCI_TNETV107X && GENERIC_HARDIRQS
|
||||
select MFD_CORE
|
||||
---help---
|
||||
Say Y here if you want support for the Sequencer Serial Port
|
||||
@ -109,6 +109,7 @@ config MFD_TI_AM335X_TSCADC
|
||||
select MFD_CORE
|
||||
select REGMAP
|
||||
select REGMAP_MMIO
|
||||
depends on GENERIC_HARDIRQS
|
||||
help
|
||||
If you say yes here you get support for Texas Instruments series
|
||||
of Touch Screen /ADC chips.
|
||||
@ -126,6 +127,7 @@ config HTC_EGPIO
|
||||
config HTC_PASIC3
|
||||
tristate "HTC PASIC3 LED/DS1WM chip support"
|
||||
select MFD_CORE
|
||||
depends on GENERIC_HARDIRQS
|
||||
help
|
||||
This core driver provides register access for the LED/DS1WM
|
||||
chips labeled "AIC2" and "AIC3", found on HTC Blueangel and
|
||||
@ -157,6 +159,7 @@ config MFD_LM3533
|
||||
depends on I2C
|
||||
select MFD_CORE
|
||||
select REGMAP_I2C
|
||||
depends on GENERIC_HARDIRQS
|
||||
help
|
||||
Say yes here to enable support for National Semiconductor / TI
|
||||
LM3533 Lighting Power chips.
|
||||
@ -171,6 +174,7 @@ config TPS6105X
|
||||
select REGULATOR
|
||||
select MFD_CORE
|
||||
select REGULATOR_FIXED_VOLTAGE
|
||||
depends on GENERIC_HARDIRQS
|
||||
help
|
||||
This option enables a driver for the TP61050/TPS61052
|
||||
high-power "white LED driver". This boost converter is
|
||||
@ -193,7 +197,7 @@ config TPS65010
|
||||
config TPS6507X
|
||||
tristate "TPS6507x Power Management / Touch Screen chips"
|
||||
select MFD_CORE
|
||||
depends on I2C
|
||||
depends on I2C && GENERIC_HARDIRQS
|
||||
help
|
||||
If you say yes here you get support for the TPS6507x series of
|
||||
Power Management / Touch Screen chips. These include voltage
|
||||
@ -204,7 +208,7 @@ config TPS6507X
|
||||
|
||||
config MFD_TPS65217
|
||||
tristate "TPS65217 Power Management / White LED chips"
|
||||
depends on I2C
|
||||
depends on I2C && GENERIC_HARDIRQS
|
||||
select MFD_CORE
|
||||
select REGMAP_I2C
|
||||
help
|
||||
@ -234,7 +238,7 @@ config MFD_TPS6586X
|
||||
|
||||
config MFD_TPS65910
|
||||
bool "TPS65910 Power Management chip"
|
||||
depends on I2C=y && GPIOLIB
|
||||
depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS
|
||||
select MFD_CORE
|
||||
select REGMAP_I2C
|
||||
select REGMAP_IRQ
|
||||
@ -251,7 +255,7 @@ config MFD_TPS65912_I2C
|
||||
bool "TPS65912 Power Management chip with I2C"
|
||||
select MFD_CORE
|
||||
select MFD_TPS65912
|
||||
depends on I2C=y && GPIOLIB
|
||||
depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS
|
||||
help
|
||||
If you say yes here you get support for the TPS65912 series of
|
||||
PM chips with I2C interface.
|
||||
@ -260,7 +264,7 @@ config MFD_TPS65912_SPI
|
||||
bool "TPS65912 Power Management chip with SPI"
|
||||
select MFD_CORE
|
||||
select MFD_TPS65912
|
||||
depends on SPI_MASTER && GPIOLIB
|
||||
depends on SPI_MASTER && GPIOLIB && GENERIC_HARDIRQS
|
||||
help
|
||||
If you say yes here you get support for the TPS65912 series of
|
||||
PM chips with SPI interface.
|
||||
@ -330,13 +334,13 @@ config TWL4030_POWER
|
||||
|
||||
config MFD_TWL4030_AUDIO
|
||||
bool
|
||||
depends on TWL4030_CORE
|
||||
depends on TWL4030_CORE && GENERIC_HARDIRQS
|
||||
select MFD_CORE
|
||||
default n
|
||||
|
||||
config TWL6040_CORE
|
||||
bool "Support for TWL6040 audio codec"
|
||||
depends on I2C=y
|
||||
depends on I2C=y && GENERIC_HARDIRQS
|
||||
select MFD_CORE
|
||||
select REGMAP_I2C
|
||||
select REGMAP_IRQ
|
||||
@ -405,7 +409,7 @@ config MFD_TMIO
|
||||
|
||||
config MFD_T7L66XB
|
||||
bool "Support Toshiba T7L66XB"
|
||||
depends on ARM && HAVE_CLK
|
||||
depends on ARM && HAVE_CLK && GENERIC_HARDIRQS
|
||||
select MFD_CORE
|
||||
select MFD_TMIO
|
||||
help
|
||||
@ -413,7 +417,7 @@ config MFD_T7L66XB
|
||||
|
||||
config MFD_SMSC
|
||||
bool "Support for the SMSC ECE1099 series chips"
|
||||
depends on I2C=y
|
||||
depends on I2C=y && GENERIC_HARDIRQS
|
||||
select MFD_CORE
|
||||
select REGMAP_I2C
|
||||
help
|
||||
@ -460,7 +464,7 @@ config MFD_DA9052_SPI
|
||||
select REGMAP_SPI
|
||||
select REGMAP_IRQ
|
||||
select PMIC_DA9052
|
||||
depends on SPI_MASTER=y
|
||||
depends on SPI_MASTER=y && GENERIC_HARDIRQS
|
||||
help
|
||||
Support for the Dialog Semiconductor DA9052 PMIC
|
||||
when controlled using SPI. This driver provides common support
|
||||
@ -472,7 +476,7 @@ config MFD_DA9052_I2C
|
||||
select REGMAP_I2C
|
||||
select REGMAP_IRQ
|
||||
select PMIC_DA9052
|
||||
depends on I2C=y
|
||||
depends on I2C=y && GENERIC_HARDIRQS
|
||||
help
|
||||
Support for the Dialog Semiconductor DA9052 PMIC
|
||||
when controlled using I2C. This driver provides common support
|
||||
@ -485,7 +489,7 @@ config MFD_DA9055
|
||||
select REGMAP_IRQ
|
||||
select PMIC_DA9055
|
||||
select MFD_CORE
|
||||
depends on I2C=y
|
||||
depends on I2C=y && GENERIC_HARDIRQS
|
||||
help
|
||||
Say yes here for support of Dialog Semiconductor DA9055. This is
|
||||
a Power Management IC. This driver provides common support for
|
||||
@ -508,7 +512,7 @@ config PMIC_ADP5520
|
||||
|
||||
config MFD_LP8788
|
||||
bool "Texas Instruments LP8788 Power Management Unit Driver"
|
||||
depends on I2C=y
|
||||
depends on I2C=y && GENERIC_HARDIRQS
|
||||
select MFD_CORE
|
||||
select REGMAP_I2C
|
||||
select IRQ_DOMAIN
|
||||
@ -611,7 +615,7 @@ config MFD_ARIZONA_I2C
|
||||
select MFD_ARIZONA
|
||||
select MFD_CORE
|
||||
select REGMAP_I2C
|
||||
depends on I2C
|
||||
depends on I2C && GENERIC_HARDIRQS
|
||||
help
|
||||
Support for the Wolfson Microelectronics Arizona platform audio SoC
|
||||
core functionality controlled via I2C.
|
||||
@ -621,7 +625,7 @@ config MFD_ARIZONA_SPI
|
||||
select MFD_ARIZONA
|
||||
select MFD_CORE
|
||||
select REGMAP_SPI
|
||||
depends on SPI_MASTER
|
||||
depends on SPI_MASTER && GENERIC_HARDIRQS
|
||||
help
|
||||
Support for the Wolfson Microelectronics Arizona platform audio SoC
|
||||
core functionality controlled via I2C.
|
||||
@ -641,7 +645,7 @@ config MFD_WM5110
|
||||
config MFD_WM8400
|
||||
bool "Support Wolfson Microelectronics WM8400"
|
||||
select MFD_CORE
|
||||
depends on I2C=y
|
||||
depends on I2C=y && GENERIC_HARDIRQS
|
||||
select REGMAP_I2C
|
||||
help
|
||||
Support for the Wolfson Microelecronics WM8400 PMIC and audio
|
||||
@ -785,7 +789,7 @@ config MFD_MC13783
|
||||
|
||||
config MFD_MC13XXX
|
||||
tristate
|
||||
depends on SPI_MASTER || I2C
|
||||
depends on (SPI_MASTER || I2C) && GENERIC_HARDIRQS
|
||||
select MFD_CORE
|
||||
select MFD_MC13783
|
||||
help
|
||||
@ -796,7 +800,7 @@ config MFD_MC13XXX
|
||||
|
||||
config MFD_MC13XXX_SPI
|
||||
tristate "Freescale MC13783 and MC13892 SPI interface"
|
||||
depends on SPI_MASTER
|
||||
depends on SPI_MASTER && GENERIC_HARDIRQS
|
||||
select REGMAP_SPI
|
||||
select MFD_MC13XXX
|
||||
help
|
||||
@ -804,7 +808,7 @@ config MFD_MC13XXX_SPI
|
||||
|
||||
config MFD_MC13XXX_I2C
|
||||
tristate "Freescale MC13892 I2C interface"
|
||||
depends on I2C
|
||||
depends on I2C && GENERIC_HARDIRQS
|
||||
select REGMAP_I2C
|
||||
select MFD_MC13XXX
|
||||
help
|
||||
@ -822,7 +826,7 @@ config ABX500_CORE
|
||||
|
||||
config AB3100_CORE
|
||||
bool "ST-Ericsson AB3100 Mixed Signal Circuit core functions"
|
||||
depends on I2C=y && ABX500_CORE
|
||||
depends on I2C=y && ABX500_CORE && GENERIC_HARDIRQS
|
||||
select MFD_CORE
|
||||
default y if ARCH_U300
|
||||
help
|
||||
@ -909,7 +913,7 @@ config MFD_TIMBERDALE
|
||||
|
||||
config LPC_SCH
|
||||
tristate "Intel SCH LPC"
|
||||
depends on PCI
|
||||
depends on PCI && GENERIC_HARDIRQS
|
||||
select MFD_CORE
|
||||
help
|
||||
LPC bridge function of the Intel SCH provides support for
|
||||
@ -917,7 +921,7 @@ config LPC_SCH
|
||||
|
||||
config LPC_ICH
|
||||
tristate "Intel ICH LPC"
|
||||
depends on PCI
|
||||
depends on PCI && GENERIC_HARDIRQS
|
||||
select MFD_CORE
|
||||
help
|
||||
The LPC bridge function of the Intel ICH provides support for
|
||||
@ -928,7 +932,7 @@ config LPC_ICH
|
||||
config MFD_RDC321X
|
||||
tristate "Support for RDC-R321x southbridge"
|
||||
select MFD_CORE
|
||||
depends on PCI
|
||||
depends on PCI && GENERIC_HARDIRQS
|
||||
help
|
||||
Say yes here if you want to have support for the RDC R-321x SoC
|
||||
southbridge which provides access to GPIOs and Watchdog using the
|
||||
@ -937,7 +941,7 @@ config MFD_RDC321X
|
||||
config MFD_JANZ_CMODIO
|
||||
tristate "Support for Janz CMOD-IO PCI MODULbus Carrier Board"
|
||||
select MFD_CORE
|
||||
depends on PCI
|
||||
depends on PCI && GENERIC_HARDIRQS
|
||||
help
|
||||
This is the core driver for the Janz CMOD-IO PCI MODULbus
|
||||
carrier board. This device is a PCI to MODULbus bridge which may
|
||||
@ -955,7 +959,7 @@ config MFD_JZ4740_ADC
|
||||
|
||||
config MFD_VX855
|
||||
tristate "Support for VIA VX855/VX875 integrated south bridge"
|
||||
depends on PCI
|
||||
depends on PCI && GENERIC_HARDIRQS
|
||||
select MFD_CORE
|
||||
help
|
||||
Say yes here to enable support for various functions of the
|
||||
@ -964,7 +968,7 @@ config MFD_VX855
|
||||
|
||||
config MFD_WL1273_CORE
|
||||
tristate "Support for TI WL1273 FM radio."
|
||||
depends on I2C
|
||||
depends on I2C && GENERIC_HARDIRQS
|
||||
select MFD_CORE
|
||||
default n
|
||||
help
|
||||
@ -1028,7 +1032,7 @@ config MFD_TPS65090
|
||||
config MFD_AAT2870_CORE
|
||||
bool "Support for the AnalogicTech AAT2870"
|
||||
select MFD_CORE
|
||||
depends on I2C=y && GPIOLIB
|
||||
depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS
|
||||
help
|
||||
If you say yes here you get support for the AAT2870.
|
||||
This driver provides common support for accessing the device,
|
||||
@ -1060,7 +1064,7 @@ config MFD_RC5T583
|
||||
|
||||
config MFD_STA2X11
|
||||
bool "STA2X11 multi function device support"
|
||||
depends on STA2X11
|
||||
depends on STA2X11 && GENERIC_HARDIRQS
|
||||
select MFD_CORE
|
||||
select REGMAP_MMIO
|
||||
|
||||
@ -1077,7 +1081,7 @@ config MFD_PALMAS
|
||||
select MFD_CORE
|
||||
select REGMAP_I2C
|
||||
select REGMAP_IRQ
|
||||
depends on I2C=y
|
||||
depends on I2C=y && GENERIC_HARDIRQS
|
||||
help
|
||||
If you say yes here you get support for the Palmas
|
||||
series of PMIC chips from Texas Instruments.
|
||||
@ -1085,7 +1089,7 @@ config MFD_PALMAS
|
||||
config MFD_VIPERBOARD
|
||||
tristate "Support for Nano River Technologies Viperboard"
|
||||
select MFD_CORE
|
||||
depends on USB
|
||||
depends on USB && GENERIC_HARDIRQS
|
||||
default n
|
||||
help
|
||||
Say yes here if you want support for Nano River Technologies
|
||||
@ -1099,7 +1103,7 @@ config MFD_VIPERBOARD
|
||||
config MFD_RETU
|
||||
tristate "Support for Retu multi-function device"
|
||||
select MFD_CORE
|
||||
depends on I2C
|
||||
depends on I2C && GENERIC_HARDIRQS
|
||||
select REGMAP_IRQ
|
||||
help
|
||||
Retu is a multi-function device found on Nokia Internet Tablets
|
||||
@ -1110,7 +1114,7 @@ config MFD_AS3711
|
||||
select MFD_CORE
|
||||
select REGMAP_I2C
|
||||
select REGMAP_IRQ
|
||||
depends on I2C=y
|
||||
depends on I2C=y && GENERIC_HARDIRQS
|
||||
help
|
||||
Support for the AS3711 PMIC from AMS
|
||||
|
||||
|
@ -9,7 +9,7 @@ obj-$(CONFIG_MFD_88PM805) += 88pm805.o 88pm80x.o
|
||||
obj-$(CONFIG_MFD_SM501) += sm501.o
|
||||
obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o
|
||||
|
||||
rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o
|
||||
rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o
|
||||
obj-$(CONFIG_MFD_RTSX_PCI) += rtsx_pci.o
|
||||
|
||||
obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o
|
||||
|
@ -320,6 +320,7 @@ static struct abx500_ops ab8500_ops = {
|
||||
.mask_and_set_register = ab8500_mask_and_set_register,
|
||||
.event_registers_startup_state_get = NULL,
|
||||
.startup_irq_enabled = NULL,
|
||||
.dump_all_banks = ab8500_dump_all_banks,
|
||||
};
|
||||
|
||||
static void ab8500_irq_lock(struct irq_data *data)
|
||||
@ -368,16 +369,48 @@ static void ab8500_irq_mask(struct irq_data *data)
|
||||
int mask = 1 << (offset % 8);
|
||||
|
||||
ab8500->mask[index] |= mask;
|
||||
|
||||
/* The AB8500 GPIOs have two interrupts each (rising & falling). */
|
||||
if (offset >= AB8500_INT_GPIO6R && offset <= AB8500_INT_GPIO41R)
|
||||
ab8500->mask[index + 2] |= mask;
|
||||
if (offset >= AB9540_INT_GPIO50R && offset <= AB9540_INT_GPIO54R)
|
||||
ab8500->mask[index + 1] |= mask;
|
||||
if (offset == AB8540_INT_GPIO43R || offset == AB8540_INT_GPIO44R)
|
||||
/* Here the falling IRQ is one bit lower */
|
||||
ab8500->mask[index] |= (mask << 1);
|
||||
}
|
||||
|
||||
static void ab8500_irq_unmask(struct irq_data *data)
|
||||
{
|
||||
struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
|
||||
unsigned int type = irqd_get_trigger_type(data);
|
||||
int offset = data->hwirq;
|
||||
int index = offset / 8;
|
||||
int mask = 1 << (offset % 8);
|
||||
|
||||
ab8500->mask[index] &= ~mask;
|
||||
if (type & IRQ_TYPE_EDGE_RISING)
|
||||
ab8500->mask[index] &= ~mask;
|
||||
|
||||
/* The AB8500 GPIOs have two interrupts each (rising & falling). */
|
||||
if (type & IRQ_TYPE_EDGE_FALLING) {
|
||||
if (offset >= AB8500_INT_GPIO6R && offset <= AB8500_INT_GPIO41R)
|
||||
ab8500->mask[index + 2] &= ~mask;
|
||||
else if (offset >= AB9540_INT_GPIO50R && offset <= AB9540_INT_GPIO54R)
|
||||
ab8500->mask[index + 1] &= ~mask;
|
||||
else if (offset == AB8540_INT_GPIO43R || offset == AB8540_INT_GPIO44R)
|
||||
/* Here the falling IRQ is one bit lower */
|
||||
ab8500->mask[index] &= ~(mask << 1);
|
||||
else
|
||||
ab8500->mask[index] &= ~mask;
|
||||
} else {
|
||||
/* Satisfies the case where type is not set. */
|
||||
ab8500->mask[index] &= ~mask;
|
||||
}
|
||||
}
|
||||
|
||||
static int ab8500_irq_set_type(struct irq_data *data, unsigned int type)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct irq_chip ab8500_irq_chip = {
|
||||
@ -387,6 +420,7 @@ static struct irq_chip ab8500_irq_chip = {
|
||||
.irq_mask = ab8500_irq_mask,
|
||||
.irq_disable = ab8500_irq_mask,
|
||||
.irq_unmask = ab8500_irq_unmask,
|
||||
.irq_set_type = ab8500_irq_set_type,
|
||||
};
|
||||
|
||||
static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500,
|
||||
@ -411,6 +445,19 @@ static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500,
|
||||
line = (i << 3) + int_bit;
|
||||
latch_val &= ~(1 << int_bit);
|
||||
|
||||
/*
|
||||
* This handles the falling edge hwirqs from the GPIO
|
||||
* lines. Route them back to the line registered for the
|
||||
* rising IRQ, as this is merely a flag for the same IRQ
|
||||
* in linux terms.
|
||||
*/
|
||||
if (line >= AB8500_INT_GPIO6F && line <= AB8500_INT_GPIO41F)
|
||||
line -= 16;
|
||||
if (line >= AB9540_INT_GPIO50F && line <= AB9540_INT_GPIO54F)
|
||||
line -= 8;
|
||||
if (line == AB8540_INT_GPIO43F || line == AB8540_INT_GPIO44F)
|
||||
line += 1;
|
||||
|
||||
handle_nested_irq(ab8500->irq_base + line);
|
||||
} while (latch_val);
|
||||
|
||||
@ -521,6 +568,7 @@ static irqreturn_t ab8500_irq(int irq, void *dev)
|
||||
int virq = ab8500_irq_get_virq(ab8500, line);
|
||||
|
||||
handle_nested_irq(virq);
|
||||
ab8500_debug_register_interrupt(line);
|
||||
value &= ~(1 << bit);
|
||||
|
||||
} while (value);
|
||||
@ -929,7 +977,7 @@ static struct resource ab8505_iddet_resources[] = {
|
||||
|
||||
static struct resource ab8500_temp_resources[] = {
|
||||
{
|
||||
.name = "AB8500_TEMP_WARM",
|
||||
.name = "ABX500_TEMP_WARM",
|
||||
.start = AB8500_INT_TEMP_WARM,
|
||||
.end = AB8500_INT_TEMP_WARM,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
@ -1005,8 +1053,8 @@ static struct mfd_cell abx500_common_devs[] = {
|
||||
.of_compatible = "stericsson,ab8500-denc",
|
||||
},
|
||||
{
|
||||
.name = "ab8500-temp",
|
||||
.of_compatible = "stericsson,ab8500-temp",
|
||||
.name = "abx500-temp",
|
||||
.of_compatible = "stericsson,abx500-temp",
|
||||
.num_resources = ARRAY_SIZE(ab8500_temp_resources),
|
||||
.resources = ab8500_temp_resources,
|
||||
},
|
||||
@ -1049,7 +1097,7 @@ static struct mfd_cell ab8500_bm_devs[] = {
|
||||
|
||||
static struct mfd_cell ab8500_devs[] = {
|
||||
{
|
||||
.name = "ab8500-gpio",
|
||||
.name = "pinctrl-ab8500",
|
||||
.of_compatible = "stericsson,ab8500-gpio",
|
||||
},
|
||||
{
|
||||
@ -1066,7 +1114,8 @@ static struct mfd_cell ab8500_devs[] = {
|
||||
|
||||
static struct mfd_cell ab9540_devs[] = {
|
||||
{
|
||||
.name = "ab8500-gpio",
|
||||
.name = "pinctrl-ab9540",
|
||||
.of_compatible = "stericsson,ab9540-gpio",
|
||||
},
|
||||
{
|
||||
.name = "ab9540-usb",
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -12,6 +12,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
@ -82,6 +83,11 @@
|
||||
/* This is used to not lose precision when dividing to get gain and offset */
|
||||
#define CALIB_SCALE 1000
|
||||
|
||||
/* Time in ms before disabling regulator */
|
||||
#define GPADC_AUDOSUSPEND_DELAY 1
|
||||
|
||||
#define CONVERSION_TIME 500 /* ms */
|
||||
|
||||
enum cal_channels {
|
||||
ADC_INPUT_VMAIN = 0,
|
||||
ADC_INPUT_BTEMP,
|
||||
@ -102,10 +108,10 @@ struct adc_cal_data {
|
||||
|
||||
/**
|
||||
* struct ab8500_gpadc - AB8500 GPADC device information
|
||||
* @chip_id ABB chip id
|
||||
* @dev: pointer to the struct device
|
||||
* @node: a list of AB8500 GPADCs, hence prepared for
|
||||
reentrance
|
||||
* @parent: pointer to the struct ab8500
|
||||
* @ab8500_gpadc_complete: pointer to the struct completion, to indicate
|
||||
* the completion of gpadc conversion
|
||||
* @ab8500_gpadc_lock: structure of type mutex
|
||||
@ -114,9 +120,9 @@ struct adc_cal_data {
|
||||
* @cal_data array of ADC calibration data structs
|
||||
*/
|
||||
struct ab8500_gpadc {
|
||||
u8 chip_id;
|
||||
struct device *dev;
|
||||
struct list_head node;
|
||||
struct ab8500 *parent;
|
||||
struct completion ab8500_gpadc_complete;
|
||||
struct mutex ab8500_gpadc_lock;
|
||||
struct regulator *regu;
|
||||
@ -282,8 +288,9 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
|
||||
return -ENODEV;
|
||||
|
||||
mutex_lock(&gpadc->ab8500_gpadc_lock);
|
||||
|
||||
/* Enable VTVout LDO this is required for GPADC */
|
||||
regulator_enable(gpadc->regu);
|
||||
pm_runtime_get_sync(gpadc->dev);
|
||||
|
||||
/* Check if ADC is not busy, lock and proceed */
|
||||
do {
|
||||
@ -332,7 +339,7 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
|
||||
EN_BUF | EN_ICHAR);
|
||||
break;
|
||||
case BTEMP_BALL:
|
||||
if (gpadc->chip_id >= AB8500_CUT3P0) {
|
||||
if (!is_ab8500_2p0_or_earlier(gpadc->parent)) {
|
||||
/* Turn on btemp pull-up on ABB 3.0 */
|
||||
ret = abx500_mask_and_set_register_interruptible(
|
||||
gpadc->dev,
|
||||
@ -344,7 +351,7 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
|
||||
* Delay might be needed for ABB8500 cut 3.0, if not, remove
|
||||
* when hardware will be available
|
||||
*/
|
||||
msleep(1);
|
||||
usleep_range(1000, 1000);
|
||||
break;
|
||||
}
|
||||
/* Intentional fallthrough */
|
||||
@ -367,7 +374,8 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
|
||||
goto out;
|
||||
}
|
||||
/* wait for completion of conversion */
|
||||
if (!wait_for_completion_timeout(&gpadc->ab8500_gpadc_complete, 2*HZ)) {
|
||||
if (!wait_for_completion_timeout(&gpadc->ab8500_gpadc_complete,
|
||||
msecs_to_jiffies(CONVERSION_TIME))) {
|
||||
dev_err(gpadc->dev,
|
||||
"timeout: didn't receive GPADC conversion interrupt\n");
|
||||
ret = -EINVAL;
|
||||
@ -397,8 +405,10 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
|
||||
dev_err(gpadc->dev, "gpadc_conversion: disable gpadc failed\n");
|
||||
goto out;
|
||||
}
|
||||
/* Disable VTVout LDO this is required for GPADC */
|
||||
regulator_disable(gpadc->regu);
|
||||
|
||||
pm_runtime_mark_last_busy(gpadc->dev);
|
||||
pm_runtime_put_autosuspend(gpadc->dev);
|
||||
|
||||
mutex_unlock(&gpadc->ab8500_gpadc_lock);
|
||||
|
||||
return (high_data << 8) | low_data;
|
||||
@ -412,7 +422,9 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
|
||||
*/
|
||||
(void) abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC,
|
||||
AB8500_GPADC_CTRL1_REG, DIS_GPADC);
|
||||
regulator_disable(gpadc->regu);
|
||||
|
||||
pm_runtime_put(gpadc->dev);
|
||||
|
||||
mutex_unlock(&gpadc->ab8500_gpadc_lock);
|
||||
dev_err(gpadc->dev,
|
||||
"gpadc_conversion: Failed to AD convert channel %d\n", channel);
|
||||
@ -571,6 +583,28 @@ static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc)
|
||||
gpadc->cal_data[ADC_INPUT_VBAT].offset);
|
||||
}
|
||||
|
||||
static int ab8500_gpadc_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct ab8500_gpadc *gpadc = dev_get_drvdata(dev);
|
||||
|
||||
regulator_disable(gpadc->regu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ab8500_gpadc_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct ab8500_gpadc *gpadc = dev_get_drvdata(dev);
|
||||
|
||||
regulator_enable(gpadc->regu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ab8500_gpadc_runtime_idle(struct device *dev)
|
||||
{
|
||||
pm_runtime_suspend(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ab8500_gpadc_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret = 0;
|
||||
@ -591,6 +625,7 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
gpadc->dev = &pdev->dev;
|
||||
gpadc->parent = dev_get_drvdata(pdev->dev.parent);
|
||||
mutex_init(&gpadc->ab8500_gpadc_lock);
|
||||
|
||||
/* Initialize completion used to notify completion of conversion */
|
||||
@ -607,14 +642,6 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Get Chip ID of the ABB ASIC */
|
||||
ret = abx500_get_chip_id(gpadc->dev);
|
||||
if (ret < 0) {
|
||||
dev_err(gpadc->dev, "failed to get chip ID\n");
|
||||
goto fail_irq;
|
||||
}
|
||||
gpadc->chip_id = (u8) ret;
|
||||
|
||||
/* VTVout LDO used to power up ab8500-GPADC */
|
||||
gpadc->regu = regulator_get(&pdev->dev, "vddadc");
|
||||
if (IS_ERR(gpadc->regu)) {
|
||||
@ -622,6 +649,16 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
|
||||
dev_err(gpadc->dev, "failed to get vtvout LDO\n");
|
||||
goto fail_irq;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, gpadc);
|
||||
|
||||
regulator_enable(gpadc->regu);
|
||||
|
||||
pm_runtime_set_autosuspend_delay(gpadc->dev, GPADC_AUDOSUSPEND_DELAY);
|
||||
pm_runtime_use_autosuspend(gpadc->dev);
|
||||
pm_runtime_set_active(gpadc->dev);
|
||||
pm_runtime_enable(gpadc->dev);
|
||||
|
||||
ab8500_gpadc_read_calibration_data(gpadc);
|
||||
list_add_tail(&gpadc->node, &ab8500_gpadc_list);
|
||||
dev_dbg(gpadc->dev, "probe success\n");
|
||||
@ -642,19 +679,34 @@ static int ab8500_gpadc_remove(struct platform_device *pdev)
|
||||
list_del(&gpadc->node);
|
||||
/* remove interrupt - completion of Sw ADC conversion */
|
||||
free_irq(gpadc->irq, gpadc);
|
||||
/* disable VTVout LDO that is being used by GPADC */
|
||||
regulator_put(gpadc->regu);
|
||||
|
||||
pm_runtime_get_sync(gpadc->dev);
|
||||
pm_runtime_disable(gpadc->dev);
|
||||
|
||||
regulator_disable(gpadc->regu);
|
||||
|
||||
pm_runtime_set_suspended(gpadc->dev);
|
||||
|
||||
pm_runtime_put_noidle(gpadc->dev);
|
||||
|
||||
kfree(gpadc);
|
||||
gpadc = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops ab8500_gpadc_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(ab8500_gpadc_runtime_suspend,
|
||||
ab8500_gpadc_runtime_resume,
|
||||
ab8500_gpadc_runtime_idle)
|
||||
};
|
||||
|
||||
static struct platform_driver ab8500_gpadc_driver = {
|
||||
.probe = ab8500_gpadc_probe,
|
||||
.remove = ab8500_gpadc_remove,
|
||||
.driver = {
|
||||
.name = "ab8500-gpadc",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &ab8500_gpadc_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -7,12 +7,73 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/mfd/abx500.h>
|
||||
#include <linux/mfd/abx500/ab8500.h>
|
||||
#include <linux/mfd/abx500/ab8500-sysctrl.h>
|
||||
|
||||
static struct device *sysctrl_dev;
|
||||
|
||||
void ab8500_power_off(void)
|
||||
{
|
||||
sigset_t old;
|
||||
sigset_t all;
|
||||
static char *pss[] = {"ab8500_ac", "ab8500_usb"};
|
||||
int i;
|
||||
bool charger_present = false;
|
||||
union power_supply_propval val;
|
||||
struct power_supply *psy;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* If we have a charger connected and we're powering off,
|
||||
* reboot into charge-only mode.
|
||||
*/
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pss); i++) {
|
||||
psy = power_supply_get_by_name(pss[i]);
|
||||
if (!psy)
|
||||
continue;
|
||||
|
||||
ret = psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &val);
|
||||
|
||||
if (!ret && val.intval) {
|
||||
charger_present = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!charger_present)
|
||||
goto shutdown;
|
||||
|
||||
/* Check if battery is known */
|
||||
psy = power_supply_get_by_name("ab8500_btemp");
|
||||
if (psy) {
|
||||
ret = psy->get_property(psy, POWER_SUPPLY_PROP_TECHNOLOGY,
|
||||
&val);
|
||||
if (!ret && val.intval != POWER_SUPPLY_TECHNOLOGY_UNKNOWN) {
|
||||
printk(KERN_INFO
|
||||
"Charger \"%s\" is connected with known battery."
|
||||
" Rebooting.\n",
|
||||
pss[i]);
|
||||
machine_restart("charging");
|
||||
}
|
||||
}
|
||||
|
||||
shutdown:
|
||||
sigfillset(&all);
|
||||
|
||||
if (!sigprocmask(SIG_BLOCK, &all, &old)) {
|
||||
(void)ab8500_sysctrl_set(AB8500_STW4500CTRL1,
|
||||
AB8500_STW4500CTRL1_SWOFF |
|
||||
AB8500_STW4500CTRL1_SWRESET4500N);
|
||||
(void)sigprocmask(SIG_SETMASK, &old, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool valid_bank(u8 bank)
|
||||
{
|
||||
return ((bank == AB8500_SYS_CTRL1_BLOCK) ||
|
||||
@ -33,6 +94,7 @@ int ab8500_sysctrl_read(u16 reg, u8 *value)
|
||||
return abx500_get_register_interruptible(sysctrl_dev, bank,
|
||||
(u8)(reg & 0xFF), value);
|
||||
}
|
||||
EXPORT_SYMBOL(ab8500_sysctrl_read);
|
||||
|
||||
int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value)
|
||||
{
|
||||
@ -48,10 +110,40 @@ int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value)
|
||||
return abx500_mask_and_set_register_interruptible(sysctrl_dev, bank,
|
||||
(u8)(reg & 0xFF), mask, value);
|
||||
}
|
||||
EXPORT_SYMBOL(ab8500_sysctrl_write);
|
||||
|
||||
static int ab8500_sysctrl_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ab8500_platform_data *plat;
|
||||
struct ab8500_sysctrl_platform_data *pdata;
|
||||
|
||||
sysctrl_dev = &pdev->dev;
|
||||
plat = dev_get_platdata(pdev->dev.parent);
|
||||
if (plat->pm_power_off)
|
||||
pm_power_off = ab8500_power_off;
|
||||
|
||||
pdata = plat->sysctrl;
|
||||
|
||||
if (pdata) {
|
||||
int ret, i, j;
|
||||
|
||||
for (i = AB8500_SYSCLKREQ1RFCLKBUF;
|
||||
i <= AB8500_SYSCLKREQ8RFCLKBUF; i++) {
|
||||
j = i - AB8500_SYSCLKREQ1RFCLKBUF;
|
||||
ret = ab8500_sysctrl_write(i, 0xff,
|
||||
pdata->initial_req_buf_config[j]);
|
||||
dev_dbg(&pdev->dev,
|
||||
"Setting SysClkReq%dRfClkBuf 0x%X\n",
|
||||
j + 1,
|
||||
pdata->initial_req_buf_config[j]);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"unable to set sysClkReq%dRfClkBuf: "
|
||||
"%d\n", j + 1, ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -153,6 +153,22 @@ int abx500_startup_irq_enabled(struct device *dev, unsigned int irq)
|
||||
}
|
||||
EXPORT_SYMBOL(abx500_startup_irq_enabled);
|
||||
|
||||
void abx500_dump_all_banks(void)
|
||||
{
|
||||
struct abx500_ops *ops;
|
||||
struct device dummy_child = {0};
|
||||
struct abx500_device_entry *dev_entry;
|
||||
|
||||
list_for_each_entry(dev_entry, &abx500_list, list) {
|
||||
dummy_child.parent = dev_entry->dev;
|
||||
ops = &dev_entry->ops;
|
||||
|
||||
if ((ops != NULL) && (ops->dump_all_banks != NULL))
|
||||
ops->dump_all_banks(&dummy_child);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(abx500_dump_all_banks);
|
||||
|
||||
MODULE_AUTHOR("Mattias Wallin <mattias.wallin@stericsson.com>");
|
||||
MODULE_DESCRIPTION("ABX500 core driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -115,7 +115,7 @@ static irqreturn_t arizona_underclocked(int irq, void *data)
|
||||
if (val & ARIZONA_ADC_UNDERCLOCKED_STS)
|
||||
dev_err(arizona->dev, "ADC underclocked\n");
|
||||
if (val & ARIZONA_MIXER_UNDERCLOCKED_STS)
|
||||
dev_err(arizona->dev, "Mixer underclocked\n");
|
||||
dev_err(arizona->dev, "Mixer dropped sample\n");
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@ -263,10 +263,36 @@ static int arizona_runtime_suspend(struct device *dev)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int arizona_resume_noirq(struct device *dev)
|
||||
{
|
||||
struct arizona *arizona = dev_get_drvdata(dev);
|
||||
|
||||
dev_dbg(arizona->dev, "Early resume, disabling IRQ\n");
|
||||
disable_irq(arizona->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int arizona_resume(struct device *dev)
|
||||
{
|
||||
struct arizona *arizona = dev_get_drvdata(dev);
|
||||
|
||||
dev_dbg(arizona->dev, "Late resume, reenabling IRQ\n");
|
||||
enable_irq(arizona->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
const struct dev_pm_ops arizona_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(arizona_runtime_suspend,
|
||||
arizona_runtime_resume,
|
||||
NULL)
|
||||
SET_SYSTEM_SLEEP_PM_OPS(NULL, arizona_resume)
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
.resume_noirq = arizona_resume_noirq,
|
||||
#endif
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(arizona_pm_ops);
|
||||
|
||||
@ -275,19 +301,19 @@ static struct mfd_cell early_devs[] = {
|
||||
};
|
||||
|
||||
static struct mfd_cell wm5102_devs[] = {
|
||||
{ .name = "arizona-micsupp" },
|
||||
{ .name = "arizona-extcon" },
|
||||
{ .name = "arizona-gpio" },
|
||||
{ .name = "arizona-haptics" },
|
||||
{ .name = "arizona-micsupp" },
|
||||
{ .name = "arizona-pwm" },
|
||||
{ .name = "wm5102-codec" },
|
||||
};
|
||||
|
||||
static struct mfd_cell wm5110_devs[] = {
|
||||
{ .name = "arizona-micsupp" },
|
||||
{ .name = "arizona-extcon" },
|
||||
{ .name = "arizona-gpio" },
|
||||
{ .name = "arizona-haptics" },
|
||||
{ .name = "arizona-micsupp" },
|
||||
{ .name = "arizona-pwm" },
|
||||
{ .name = "wm5110-codec" },
|
||||
};
|
||||
@ -484,6 +510,29 @@ int arizona_dev_init(struct arizona *arizona)
|
||||
goto err_reset;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARIZONA_MAX_MICBIAS; i++) {
|
||||
if (!arizona->pdata.micbias[i].mV)
|
||||
continue;
|
||||
|
||||
val = (arizona->pdata.micbias[i].mV - 1500) / 100;
|
||||
val <<= ARIZONA_MICB1_LVL_SHIFT;
|
||||
|
||||
if (arizona->pdata.micbias[i].ext_cap)
|
||||
val |= ARIZONA_MICB1_EXT_CAP;
|
||||
|
||||
if (arizona->pdata.micbias[i].discharge)
|
||||
val |= ARIZONA_MICB1_DISCH;
|
||||
|
||||
if (arizona->pdata.micbias[i].fast_start)
|
||||
val |= ARIZONA_MICB1_RATE;
|
||||
|
||||
regmap_update_bits(arizona->regmap,
|
||||
ARIZONA_MIC_BIAS_CTRL_1 + i,
|
||||
ARIZONA_MICB1_LVL_MASK |
|
||||
ARIZONA_MICB1_DISCH |
|
||||
ARIZONA_MICB1_RATE, val);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARIZONA_MAX_INPUT; i++) {
|
||||
/* Default for both is 0 so noop with defaults */
|
||||
val = arizona->pdata.dmic_ref[i]
|
||||
|
@ -60,7 +60,7 @@ static inline bool i2c_safe_reg(unsigned char reg)
|
||||
* This fix is to follow any read or write with a dummy read to a safe
|
||||
* register.
|
||||
*/
|
||||
int da9052_i2c_fix(struct da9052 *da9052, unsigned char reg)
|
||||
static int da9052_i2c_fix(struct da9052 *da9052, unsigned char reg)
|
||||
{
|
||||
int val;
|
||||
|
||||
@ -85,7 +85,6 @@ int da9052_i2c_fix(struct da9052 *da9052, unsigned char reg)
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(da9052_i2c_fix);
|
||||
|
||||
static int da9052_i2c_enable_multiwrite(struct da9052 *da9052)
|
||||
{
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include <linux/regulator/db8500-prcmu.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/platform_data/ux500_wdt.h>
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/irqs.h>
|
||||
#include <mach/db8500-regs.h>
|
||||
@ -2207,21 +2208,25 @@ int db8500_prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
|
||||
sleep_auto_off ? A9WDOG_AUTO_OFF_EN :
|
||||
A9WDOG_AUTO_OFF_DIS);
|
||||
}
|
||||
EXPORT_SYMBOL(db8500_prcmu_config_a9wdog);
|
||||
|
||||
int db8500_prcmu_enable_a9wdog(u8 id)
|
||||
{
|
||||
return prcmu_a9wdog(MB4H_A9WDOG_EN, id, 0, 0, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(db8500_prcmu_enable_a9wdog);
|
||||
|
||||
int db8500_prcmu_disable_a9wdog(u8 id)
|
||||
{
|
||||
return prcmu_a9wdog(MB4H_A9WDOG_DIS, id, 0, 0, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(db8500_prcmu_disable_a9wdog);
|
||||
|
||||
int db8500_prcmu_kick_a9wdog(u8 id)
|
||||
{
|
||||
return prcmu_a9wdog(MB4H_A9WDOG_KICK, id, 0, 0, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(db8500_prcmu_kick_a9wdog);
|
||||
|
||||
/*
|
||||
* timeout is 28 bit, in ms.
|
||||
@ -2239,6 +2244,7 @@ int db8500_prcmu_load_a9wdog(u8 id, u32 timeout)
|
||||
(u8)((timeout >> 12) & 0xff),
|
||||
(u8)((timeout >> 20) & 0xff));
|
||||
}
|
||||
EXPORT_SYMBOL(db8500_prcmu_load_a9wdog);
|
||||
|
||||
/**
|
||||
* prcmu_abb_read() - Read register value(s) from the ABB.
|
||||
@ -3094,6 +3100,11 @@ static struct resource ab8500_resources[] = {
|
||||
}
|
||||
};
|
||||
|
||||
static struct ux500_wdt_data db8500_wdt_pdata = {
|
||||
.timeout = 600, /* 10 minutes */
|
||||
.has_28_bits_resolution = true,
|
||||
};
|
||||
|
||||
static struct mfd_cell db8500_prcmu_devs[] = {
|
||||
{
|
||||
.name = "db8500-prcmu-regulators",
|
||||
@ -3107,6 +3118,12 @@ static struct mfd_cell db8500_prcmu_devs[] = {
|
||||
.platform_data = &db8500_cpufreq_table,
|
||||
.pdata_size = sizeof(db8500_cpufreq_table),
|
||||
},
|
||||
{
|
||||
.name = "ux500_wdt",
|
||||
.platform_data = &db8500_wdt_pdata,
|
||||
.pdata_size = sizeof(db8500_wdt_pdata),
|
||||
.id = -1,
|
||||
},
|
||||
{
|
||||
.name = "ab8500-core",
|
||||
.of_compatible = "stericsson,ab8500",
|
||||
|
@ -50,6 +50,7 @@
|
||||
* document number TBD : Panther Point
|
||||
* document number TBD : Lynx Point
|
||||
* document number TBD : Lynx Point-LP
|
||||
* document number TBD : Wellsburg
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
@ -75,8 +76,10 @@
|
||||
#define ACPIBASE_GCS_OFF 0x3410
|
||||
#define ACPIBASE_GCS_END 0x3414
|
||||
|
||||
#define GPIOBASE 0x48
|
||||
#define GPIOCTRL 0x4C
|
||||
#define GPIOBASE_ICH0 0x58
|
||||
#define GPIOCTRL_ICH0 0x5C
|
||||
#define GPIOBASE_ICH6 0x48
|
||||
#define GPIOCTRL_ICH6 0x4C
|
||||
|
||||
#define RCBABASE 0xf0
|
||||
|
||||
@ -84,8 +87,17 @@
|
||||
#define wdt_mem_res(i) wdt_res(ICH_RES_MEM_OFF, i)
|
||||
#define wdt_res(b, i) (&wdt_ich_res[(b) + (i)])
|
||||
|
||||
static int lpc_ich_acpi_save = -1;
|
||||
static int lpc_ich_gpio_save = -1;
|
||||
struct lpc_ich_cfg {
|
||||
int base;
|
||||
int ctrl;
|
||||
int save;
|
||||
};
|
||||
|
||||
struct lpc_ich_priv {
|
||||
int chipset;
|
||||
struct lpc_ich_cfg acpi;
|
||||
struct lpc_ich_cfg gpio;
|
||||
};
|
||||
|
||||
static struct resource wdt_ich_res[] = {
|
||||
/* ACPI - TCO */
|
||||
@ -194,6 +206,7 @@ enum lpc_chipsets {
|
||||
LPC_PPT, /* Panther Point */
|
||||
LPC_LPT, /* Lynx Point */
|
||||
LPC_LPT_LP, /* Lynx Point-LP */
|
||||
LPC_WBG, /* Wellsburg */
|
||||
};
|
||||
|
||||
struct lpc_ich_info lpc_chipset_info[] = {
|
||||
@ -474,6 +487,10 @@ struct lpc_ich_info lpc_chipset_info[] = {
|
||||
.name = "Lynx Point_LP",
|
||||
.iTCO_version = 2,
|
||||
},
|
||||
[LPC_WBG] = {
|
||||
.name = "Wellsburg",
|
||||
.iTCO_version = 2,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
@ -655,45 +672,82 @@ static DEFINE_PCI_DEVICE_TABLE(lpc_ich_ids) = {
|
||||
{ PCI_VDEVICE(INTEL, 0x9c45), LPC_LPT_LP},
|
||||
{ PCI_VDEVICE(INTEL, 0x9c46), LPC_LPT_LP},
|
||||
{ PCI_VDEVICE(INTEL, 0x9c47), LPC_LPT_LP},
|
||||
{ PCI_VDEVICE(INTEL, 0x8d40), LPC_WBG},
|
||||
{ PCI_VDEVICE(INTEL, 0x8d41), LPC_WBG},
|
||||
{ PCI_VDEVICE(INTEL, 0x8d42), LPC_WBG},
|
||||
{ PCI_VDEVICE(INTEL, 0x8d43), LPC_WBG},
|
||||
{ PCI_VDEVICE(INTEL, 0x8d44), LPC_WBG},
|
||||
{ PCI_VDEVICE(INTEL, 0x8d45), LPC_WBG},
|
||||
{ PCI_VDEVICE(INTEL, 0x8d46), LPC_WBG},
|
||||
{ PCI_VDEVICE(INTEL, 0x8d47), LPC_WBG},
|
||||
{ PCI_VDEVICE(INTEL, 0x8d48), LPC_WBG},
|
||||
{ PCI_VDEVICE(INTEL, 0x8d49), LPC_WBG},
|
||||
{ PCI_VDEVICE(INTEL, 0x8d4a), LPC_WBG},
|
||||
{ PCI_VDEVICE(INTEL, 0x8d4b), LPC_WBG},
|
||||
{ PCI_VDEVICE(INTEL, 0x8d4c), LPC_WBG},
|
||||
{ PCI_VDEVICE(INTEL, 0x8d4d), LPC_WBG},
|
||||
{ PCI_VDEVICE(INTEL, 0x8d4e), LPC_WBG},
|
||||
{ PCI_VDEVICE(INTEL, 0x8d4f), LPC_WBG},
|
||||
{ PCI_VDEVICE(INTEL, 0x8d50), LPC_WBG},
|
||||
{ PCI_VDEVICE(INTEL, 0x8d51), LPC_WBG},
|
||||
{ PCI_VDEVICE(INTEL, 0x8d52), LPC_WBG},
|
||||
{ PCI_VDEVICE(INTEL, 0x8d53), LPC_WBG},
|
||||
{ PCI_VDEVICE(INTEL, 0x8d54), LPC_WBG},
|
||||
{ PCI_VDEVICE(INTEL, 0x8d55), LPC_WBG},
|
||||
{ PCI_VDEVICE(INTEL, 0x8d56), LPC_WBG},
|
||||
{ PCI_VDEVICE(INTEL, 0x8d57), LPC_WBG},
|
||||
{ PCI_VDEVICE(INTEL, 0x8d58), LPC_WBG},
|
||||
{ PCI_VDEVICE(INTEL, 0x8d59), LPC_WBG},
|
||||
{ PCI_VDEVICE(INTEL, 0x8d5a), LPC_WBG},
|
||||
{ PCI_VDEVICE(INTEL, 0x8d5b), LPC_WBG},
|
||||
{ PCI_VDEVICE(INTEL, 0x8d5c), LPC_WBG},
|
||||
{ PCI_VDEVICE(INTEL, 0x8d5d), LPC_WBG},
|
||||
{ PCI_VDEVICE(INTEL, 0x8d5e), LPC_WBG},
|
||||
{ PCI_VDEVICE(INTEL, 0x8d5f), LPC_WBG},
|
||||
{ 0, }, /* End of list */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, lpc_ich_ids);
|
||||
|
||||
static void lpc_ich_restore_config_space(struct pci_dev *dev)
|
||||
{
|
||||
if (lpc_ich_acpi_save >= 0) {
|
||||
pci_write_config_byte(dev, ACPICTRL, lpc_ich_acpi_save);
|
||||
lpc_ich_acpi_save = -1;
|
||||
struct lpc_ich_priv *priv = pci_get_drvdata(dev);
|
||||
|
||||
if (priv->acpi.save >= 0) {
|
||||
pci_write_config_byte(dev, priv->acpi.ctrl, priv->acpi.save);
|
||||
priv->acpi.save = -1;
|
||||
}
|
||||
|
||||
if (lpc_ich_gpio_save >= 0) {
|
||||
pci_write_config_byte(dev, GPIOCTRL, lpc_ich_gpio_save);
|
||||
lpc_ich_gpio_save = -1;
|
||||
if (priv->gpio.save >= 0) {
|
||||
pci_write_config_byte(dev, priv->gpio.ctrl, priv->gpio.save);
|
||||
priv->gpio.save = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void lpc_ich_enable_acpi_space(struct pci_dev *dev)
|
||||
{
|
||||
struct lpc_ich_priv *priv = pci_get_drvdata(dev);
|
||||
u8 reg_save;
|
||||
|
||||
pci_read_config_byte(dev, ACPICTRL, ®_save);
|
||||
pci_write_config_byte(dev, ACPICTRL, reg_save | 0x10);
|
||||
lpc_ich_acpi_save = reg_save;
|
||||
pci_read_config_byte(dev, priv->acpi.ctrl, ®_save);
|
||||
pci_write_config_byte(dev, priv->acpi.ctrl, reg_save | 0x10);
|
||||
priv->acpi.save = reg_save;
|
||||
}
|
||||
|
||||
static void lpc_ich_enable_gpio_space(struct pci_dev *dev)
|
||||
{
|
||||
struct lpc_ich_priv *priv = pci_get_drvdata(dev);
|
||||
u8 reg_save;
|
||||
|
||||
pci_read_config_byte(dev, GPIOCTRL, ®_save);
|
||||
pci_write_config_byte(dev, GPIOCTRL, reg_save | 0x10);
|
||||
lpc_ich_gpio_save = reg_save;
|
||||
pci_read_config_byte(dev, priv->gpio.ctrl, ®_save);
|
||||
pci_write_config_byte(dev, priv->gpio.ctrl, reg_save | 0x10);
|
||||
priv->gpio.save = reg_save;
|
||||
}
|
||||
|
||||
static void lpc_ich_finalize_cell(struct mfd_cell *cell,
|
||||
const struct pci_device_id *id)
|
||||
static void lpc_ich_finalize_cell(struct pci_dev *dev, struct mfd_cell *cell)
|
||||
{
|
||||
cell->platform_data = &lpc_chipset_info[id->driver_data];
|
||||
struct lpc_ich_priv *priv = pci_get_drvdata(dev);
|
||||
|
||||
cell->platform_data = &lpc_chipset_info[priv->chipset];
|
||||
cell->pdata_size = sizeof(struct lpc_ich_info);
|
||||
}
|
||||
|
||||
@ -721,9 +775,9 @@ static int lpc_ich_check_conflict_gpio(struct resource *res)
|
||||
return use_gpio ? use_gpio : ret;
|
||||
}
|
||||
|
||||
static int lpc_ich_init_gpio(struct pci_dev *dev,
|
||||
const struct pci_device_id *id)
|
||||
static int lpc_ich_init_gpio(struct pci_dev *dev)
|
||||
{
|
||||
struct lpc_ich_priv *priv = pci_get_drvdata(dev);
|
||||
u32 base_addr_cfg;
|
||||
u32 base_addr;
|
||||
int ret;
|
||||
@ -731,7 +785,7 @@ static int lpc_ich_init_gpio(struct pci_dev *dev,
|
||||
struct resource *res;
|
||||
|
||||
/* Setup power management base register */
|
||||
pci_read_config_dword(dev, ACPIBASE, &base_addr_cfg);
|
||||
pci_read_config_dword(dev, priv->acpi.base, &base_addr_cfg);
|
||||
base_addr = base_addr_cfg & 0x0000ff80;
|
||||
if (!base_addr) {
|
||||
dev_notice(&dev->dev, "I/O space for ACPI uninitialized\n");
|
||||
@ -757,7 +811,7 @@ static int lpc_ich_init_gpio(struct pci_dev *dev,
|
||||
|
||||
gpe0_done:
|
||||
/* Setup GPIO base register */
|
||||
pci_read_config_dword(dev, GPIOBASE, &base_addr_cfg);
|
||||
pci_read_config_dword(dev, priv->gpio.base, &base_addr_cfg);
|
||||
base_addr = base_addr_cfg & 0x0000ff80;
|
||||
if (!base_addr) {
|
||||
dev_notice(&dev->dev, "I/O space for GPIO uninitialized\n");
|
||||
@ -768,7 +822,7 @@ static int lpc_ich_init_gpio(struct pci_dev *dev,
|
||||
/* Older devices provide fewer GPIO and have a smaller resource size. */
|
||||
res = &gpio_ich_res[ICH_RES_GPIO];
|
||||
res->start = base_addr;
|
||||
switch (lpc_chipset_info[id->driver_data].gpio_version) {
|
||||
switch (lpc_chipset_info[priv->chipset].gpio_version) {
|
||||
case ICH_V5_GPIO:
|
||||
case ICH_V10CORP_GPIO:
|
||||
res->end = res->start + 128 - 1;
|
||||
@ -784,10 +838,10 @@ static int lpc_ich_init_gpio(struct pci_dev *dev,
|
||||
acpi_conflict = true;
|
||||
goto gpio_done;
|
||||
}
|
||||
lpc_chipset_info[id->driver_data].use_gpio = ret;
|
||||
lpc_chipset_info[priv->chipset].use_gpio = ret;
|
||||
lpc_ich_enable_gpio_space(dev);
|
||||
|
||||
lpc_ich_finalize_cell(&lpc_ich_cells[LPC_GPIO], id);
|
||||
lpc_ich_finalize_cell(dev, &lpc_ich_cells[LPC_GPIO]);
|
||||
ret = mfd_add_devices(&dev->dev, -1, &lpc_ich_cells[LPC_GPIO],
|
||||
1, NULL, 0, NULL);
|
||||
|
||||
@ -798,16 +852,16 @@ static int lpc_ich_init_gpio(struct pci_dev *dev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int lpc_ich_init_wdt(struct pci_dev *dev,
|
||||
const struct pci_device_id *id)
|
||||
static int lpc_ich_init_wdt(struct pci_dev *dev)
|
||||
{
|
||||
struct lpc_ich_priv *priv = pci_get_drvdata(dev);
|
||||
u32 base_addr_cfg;
|
||||
u32 base_addr;
|
||||
int ret;
|
||||
struct resource *res;
|
||||
|
||||
/* Setup power management base register */
|
||||
pci_read_config_dword(dev, ACPIBASE, &base_addr_cfg);
|
||||
pci_read_config_dword(dev, priv->acpi.base, &base_addr_cfg);
|
||||
base_addr = base_addr_cfg & 0x0000ff80;
|
||||
if (!base_addr) {
|
||||
dev_notice(&dev->dev, "I/O space for ACPI uninitialized\n");
|
||||
@ -830,7 +884,7 @@ static int lpc_ich_init_wdt(struct pci_dev *dev,
|
||||
* we have to read RCBA from PCI Config space 0xf0 and use
|
||||
* it as base. GCS = RCBA + ICH6_GCS(0x3410).
|
||||
*/
|
||||
if (lpc_chipset_info[id->driver_data].iTCO_version == 1) {
|
||||
if (lpc_chipset_info[priv->chipset].iTCO_version == 1) {
|
||||
/* Don't register iomem for TCO ver 1 */
|
||||
lpc_ich_cells[LPC_WDT].num_resources--;
|
||||
} else {
|
||||
@ -847,7 +901,7 @@ static int lpc_ich_init_wdt(struct pci_dev *dev,
|
||||
res->end = base_addr + ACPIBASE_GCS_END;
|
||||
}
|
||||
|
||||
lpc_ich_finalize_cell(&lpc_ich_cells[LPC_WDT], id);
|
||||
lpc_ich_finalize_cell(dev, &lpc_ich_cells[LPC_WDT]);
|
||||
ret = mfd_add_devices(&dev->dev, -1, &lpc_ich_cells[LPC_WDT],
|
||||
1, NULL, 0, NULL);
|
||||
|
||||
@ -858,14 +912,36 @@ static int lpc_ich_init_wdt(struct pci_dev *dev,
|
||||
static int lpc_ich_probe(struct pci_dev *dev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
struct lpc_ich_priv *priv;
|
||||
int ret;
|
||||
bool cell_added = false;
|
||||
|
||||
ret = lpc_ich_init_wdt(dev, id);
|
||||
priv = devm_kzalloc(&dev->dev,
|
||||
sizeof(struct lpc_ich_priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->chipset = id->driver_data;
|
||||
priv->acpi.save = -1;
|
||||
priv->acpi.base = ACPIBASE;
|
||||
priv->acpi.ctrl = ACPICTRL;
|
||||
|
||||
priv->gpio.save = -1;
|
||||
if (priv->chipset <= LPC_ICH5) {
|
||||
priv->gpio.base = GPIOBASE_ICH0;
|
||||
priv->gpio.ctrl = GPIOCTRL_ICH0;
|
||||
} else {
|
||||
priv->gpio.base = GPIOBASE_ICH6;
|
||||
priv->gpio.ctrl = GPIOCTRL_ICH6;
|
||||
}
|
||||
|
||||
pci_set_drvdata(dev, priv);
|
||||
|
||||
ret = lpc_ich_init_wdt(dev);
|
||||
if (!ret)
|
||||
cell_added = true;
|
||||
|
||||
ret = lpc_ich_init_gpio(dev, id);
|
||||
ret = lpc_ich_init_gpio(dev);
|
||||
if (!ret)
|
||||
cell_added = true;
|
||||
|
||||
@ -876,6 +952,7 @@ static int lpc_ich_probe(struct pci_dev *dev,
|
||||
if (!cell_added) {
|
||||
dev_warn(&dev->dev, "No MFD cells added\n");
|
||||
lpc_ich_restore_config_space(dev);
|
||||
pci_set_drvdata(dev, NULL);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
@ -886,6 +963,7 @@ static void lpc_ich_remove(struct pci_dev *dev)
|
||||
{
|
||||
mfd_remove_devices(&dev->dev);
|
||||
lpc_ich_restore_config_space(dev);
|
||||
pci_set_drvdata(dev, NULL);
|
||||
}
|
||||
|
||||
static struct pci_driver lpc_ich_driver = {
|
||||
|
@ -45,34 +45,32 @@ static struct resource smbus_sch_resource = {
|
||||
.flags = IORESOURCE_IO,
|
||||
};
|
||||
|
||||
|
||||
static struct resource gpio_sch_resource = {
|
||||
.flags = IORESOURCE_IO,
|
||||
};
|
||||
|
||||
static struct mfd_cell lpc_sch_cells[] = {
|
||||
{
|
||||
.name = "isch_smbus",
|
||||
.num_resources = 1,
|
||||
.resources = &smbus_sch_resource,
|
||||
},
|
||||
{
|
||||
.name = "sch_gpio",
|
||||
.num_resources = 1,
|
||||
.resources = &gpio_sch_resource,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource wdt_sch_resource = {
|
||||
.flags = IORESOURCE_IO,
|
||||
};
|
||||
|
||||
static struct mfd_cell tunnelcreek_cells[] = {
|
||||
{
|
||||
.name = "ie6xx_wdt",
|
||||
.num_resources = 1,
|
||||
.resources = &wdt_sch_resource,
|
||||
},
|
||||
static struct mfd_cell lpc_sch_cells[3];
|
||||
|
||||
static struct mfd_cell isch_smbus_cell = {
|
||||
.name = "isch_smbus",
|
||||
.num_resources = 1,
|
||||
.resources = &smbus_sch_resource,
|
||||
};
|
||||
|
||||
static struct mfd_cell sch_gpio_cell = {
|
||||
.name = "sch_gpio",
|
||||
.num_resources = 1,
|
||||
.resources = &gpio_sch_resource,
|
||||
};
|
||||
|
||||
static struct mfd_cell wdt_sch_cell = {
|
||||
.name = "ie6xx_wdt",
|
||||
.num_resources = 1,
|
||||
.resources = &wdt_sch_resource,
|
||||
};
|
||||
|
||||
static DEFINE_PCI_DEVICE_TABLE(lpc_sch_ids) = {
|
||||
@ -88,79 +86,76 @@ static int lpc_sch_probe(struct pci_dev *dev,
|
||||
{
|
||||
unsigned int base_addr_cfg;
|
||||
unsigned short base_addr;
|
||||
int i;
|
||||
int i, cells = 0;
|
||||
int ret;
|
||||
|
||||
pci_read_config_dword(dev, SMBASE, &base_addr_cfg);
|
||||
if (!(base_addr_cfg & (1 << 31))) {
|
||||
dev_err(&dev->dev, "Decode of the SMBus I/O range disabled\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
base_addr = (unsigned short)base_addr_cfg;
|
||||
if (base_addr == 0) {
|
||||
dev_err(&dev->dev, "I/O space for SMBus uninitialized\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
base_addr = 0;
|
||||
if (!(base_addr_cfg & (1 << 31)))
|
||||
dev_warn(&dev->dev, "Decode of the SMBus I/O range disabled\n");
|
||||
else
|
||||
base_addr = (unsigned short)base_addr_cfg;
|
||||
|
||||
smbus_sch_resource.start = base_addr;
|
||||
smbus_sch_resource.end = base_addr + SMBUS_IO_SIZE - 1;
|
||||
if (base_addr == 0) {
|
||||
dev_warn(&dev->dev, "I/O space for SMBus uninitialized\n");
|
||||
} else {
|
||||
lpc_sch_cells[cells++] = isch_smbus_cell;
|
||||
smbus_sch_resource.start = base_addr;
|
||||
smbus_sch_resource.end = base_addr + SMBUS_IO_SIZE - 1;
|
||||
}
|
||||
|
||||
pci_read_config_dword(dev, GPIOBASE, &base_addr_cfg);
|
||||
if (!(base_addr_cfg & (1 << 31))) {
|
||||
dev_err(&dev->dev, "Decode of the GPIO I/O range disabled\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
base_addr = (unsigned short)base_addr_cfg;
|
||||
if (base_addr == 0) {
|
||||
dev_err(&dev->dev, "I/O space for GPIO uninitialized\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
gpio_sch_resource.start = base_addr;
|
||||
|
||||
if (id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB)
|
||||
gpio_sch_resource.end = base_addr + GPIO_IO_SIZE_CENTERTON - 1;
|
||||
base_addr = 0;
|
||||
if (!(base_addr_cfg & (1 << 31)))
|
||||
dev_warn(&dev->dev, "Decode of the GPIO I/O range disabled\n");
|
||||
else
|
||||
gpio_sch_resource.end = base_addr + GPIO_IO_SIZE - 1;
|
||||
base_addr = (unsigned short)base_addr_cfg;
|
||||
|
||||
for (i=0; i < ARRAY_SIZE(lpc_sch_cells); i++)
|
||||
lpc_sch_cells[i].id = id->device;
|
||||
|
||||
ret = mfd_add_devices(&dev->dev, 0,
|
||||
lpc_sch_cells, ARRAY_SIZE(lpc_sch_cells), NULL,
|
||||
0, NULL);
|
||||
if (ret)
|
||||
goto out_dev;
|
||||
if (base_addr == 0) {
|
||||
dev_warn(&dev->dev, "I/O space for GPIO uninitialized\n");
|
||||
} else {
|
||||
lpc_sch_cells[cells++] = sch_gpio_cell;
|
||||
gpio_sch_resource.start = base_addr;
|
||||
if (id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB)
|
||||
gpio_sch_resource.end = base_addr + GPIO_IO_SIZE_CENTERTON - 1;
|
||||
else
|
||||
gpio_sch_resource.end = base_addr + GPIO_IO_SIZE - 1;
|
||||
}
|
||||
|
||||
if (id->device == PCI_DEVICE_ID_INTEL_ITC_LPC
|
||||
|| id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB) {
|
||||
|| id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB) {
|
||||
pci_read_config_dword(dev, WDTBASE, &base_addr_cfg);
|
||||
if (!(base_addr_cfg & (1 << 31))) {
|
||||
dev_err(&dev->dev, "Decode of the WDT I/O range disabled\n");
|
||||
ret = -ENODEV;
|
||||
goto out_dev;
|
||||
base_addr = 0;
|
||||
if (!(base_addr_cfg & (1 << 31)))
|
||||
dev_warn(&dev->dev, "Decode of the WDT I/O range disabled\n");
|
||||
else
|
||||
base_addr = (unsigned short)base_addr_cfg;
|
||||
if (base_addr == 0)
|
||||
dev_warn(&dev->dev, "I/O space for WDT uninitialized\n");
|
||||
else {
|
||||
lpc_sch_cells[cells++] = wdt_sch_cell;
|
||||
wdt_sch_resource.start = base_addr;
|
||||
wdt_sch_resource.end = base_addr + WDT_IO_SIZE - 1;
|
||||
}
|
||||
base_addr = (unsigned short)base_addr_cfg;
|
||||
if (base_addr == 0) {
|
||||
dev_err(&dev->dev, "I/O space for WDT uninitialized\n");
|
||||
ret = -ENODEV;
|
||||
goto out_dev;
|
||||
}
|
||||
|
||||
wdt_sch_resource.start = base_addr;
|
||||
wdt_sch_resource.end = base_addr + WDT_IO_SIZE - 1;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tunnelcreek_cells); i++)
|
||||
tunnelcreek_cells[i].id = id->device;
|
||||
|
||||
ret = mfd_add_devices(&dev->dev, 0, tunnelcreek_cells,
|
||||
ARRAY_SIZE(tunnelcreek_cells), NULL,
|
||||
0, NULL);
|
||||
}
|
||||
|
||||
return ret;
|
||||
out_dev:
|
||||
mfd_remove_devices(&dev->dev);
|
||||
if (WARN_ON(cells > ARRAY_SIZE(lpc_sch_cells))) {
|
||||
dev_err(&dev->dev, "Cell count exceeds array size");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (cells == 0) {
|
||||
dev_err(&dev->dev, "All decode registers disabled.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
for (i = 0; i < cells; i++)
|
||||
lpc_sch_cells[i].id = id->device;
|
||||
|
||||
ret = mfd_add_devices(&dev->dev, 0, lpc_sch_cells, cells, NULL, 0, NULL);
|
||||
if (ret)
|
||||
mfd_remove_devices(&dev->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -14,10 +14,13 @@
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/max8925.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
static struct resource bk_resources[] = {
|
||||
{ 0x84, 0x84, "mode control", IORESOURCE_REG, },
|
||||
@ -639,17 +642,33 @@ static struct irq_chip max8925_irq_chip = {
|
||||
.irq_disable = max8925_irq_disable,
|
||||
};
|
||||
|
||||
static int max8925_irq_domain_map(struct irq_domain *d, unsigned int virq,
|
||||
irq_hw_number_t hw)
|
||||
{
|
||||
irq_set_chip_data(virq, d->host_data);
|
||||
irq_set_chip_and_handler(virq, &max8925_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 max8925_irq_domain_ops = {
|
||||
.map = max8925_irq_domain_map,
|
||||
.xlate = irq_domain_xlate_onetwocell,
|
||||
};
|
||||
|
||||
|
||||
static int max8925_irq_init(struct max8925_chip *chip, int irq,
|
||||
struct max8925_platform_data *pdata)
|
||||
{
|
||||
unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
|
||||
int i, ret;
|
||||
int __irq;
|
||||
int ret;
|
||||
struct device_node *node = chip->dev->of_node;
|
||||
|
||||
if (!pdata || !pdata->irq_base) {
|
||||
dev_warn(chip->dev, "No interrupt support on IRQ base\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
/* clear all interrupts */
|
||||
max8925_reg_read(chip->i2c, MAX8925_CHG_IRQ1);
|
||||
max8925_reg_read(chip->i2c, MAX8925_CHG_IRQ2);
|
||||
@ -667,35 +686,30 @@ static int max8925_irq_init(struct max8925_chip *chip, int irq,
|
||||
max8925_reg_write(chip->rtc, MAX8925_RTC_IRQ_MASK, 0xff);
|
||||
|
||||
mutex_init(&chip->irq_lock);
|
||||
chip->irq_base = irq_alloc_descs(-1, 0, MAX8925_NR_IRQS, 0);
|
||||
if (chip->irq_base < 0) {
|
||||
dev_err(chip->dev, "Failed to allocate interrupts, ret:%d\n",
|
||||
chip->irq_base);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
irq_domain_add_legacy(node, MAX8925_NR_IRQS, chip->irq_base, 0,
|
||||
&max8925_irq_domain_ops, chip);
|
||||
|
||||
/* request irq handler for pmic main irq*/
|
||||
chip->core_irq = irq;
|
||||
chip->irq_base = pdata->irq_base;
|
||||
|
||||
/* register with genirq */
|
||||
for (i = 0; i < ARRAY_SIZE(max8925_irqs); i++) {
|
||||
__irq = i + chip->irq_base;
|
||||
irq_set_chip_data(__irq, chip);
|
||||
irq_set_chip_and_handler(__irq, &max8925_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
|
||||
}
|
||||
if (!irq) {
|
||||
dev_warn(chip->dev, "No interrupt support on core IRQ\n");
|
||||
goto tsc_irq;
|
||||
}
|
||||
|
||||
if (!chip->core_irq)
|
||||
return -EBUSY;
|
||||
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);
|
||||
chip->core_irq = 0;
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
tsc_irq:
|
||||
/* request irq handler for pmic tsc irq*/
|
||||
|
||||
/* mask TSC interrupt */
|
||||
max8925_reg_write(chip->adc, MAX8925_TSC_IRQ_MASK, 0x0f);
|
||||
|
||||
@ -704,7 +718,6 @@ static int max8925_irq_init(struct max8925_chip *chip, int irq,
|
||||
return 0;
|
||||
}
|
||||
chip->tsc_irq = pdata->tsc_irq;
|
||||
|
||||
ret = request_threaded_irq(chip->tsc_irq, NULL, max8925_tsc_irq,
|
||||
flags | IRQF_ONESHOT, "max8925-tsc", chip);
|
||||
if (ret) {
|
||||
@ -846,7 +859,7 @@ int max8925_device_init(struct max8925_chip *chip,
|
||||
|
||||
ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0],
|
||||
ARRAY_SIZE(rtc_devs),
|
||||
&rtc_resources[0], chip->irq_base, NULL);
|
||||
NULL, chip->irq_base, NULL);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "Failed to add rtc subdev\n");
|
||||
goto out;
|
||||
@ -854,7 +867,7 @@ int max8925_device_init(struct max8925_chip *chip,
|
||||
|
||||
ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0],
|
||||
ARRAY_SIZE(onkey_devs),
|
||||
&onkey_resources[0], 0, NULL);
|
||||
NULL, chip->irq_base, NULL);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "Failed to add onkey subdev\n");
|
||||
goto out_dev;
|
||||
@ -873,21 +886,19 @@ int max8925_device_init(struct max8925_chip *chip,
|
||||
goto out_dev;
|
||||
}
|
||||
|
||||
if (pdata && pdata->power) {
|
||||
ret = mfd_add_devices(chip->dev, 0, &power_devs[0],
|
||||
ARRAY_SIZE(power_devs),
|
||||
&power_supply_resources[0], 0, NULL);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "Failed to add power supply "
|
||||
"subdev\n");
|
||||
goto out_dev;
|
||||
}
|
||||
ret = mfd_add_devices(chip->dev, 0, &power_devs[0],
|
||||
ARRAY_SIZE(power_devs),
|
||||
NULL, 0, NULL);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev,
|
||||
"Failed to add power supply subdev, err = %d\n", ret);
|
||||
goto out_dev;
|
||||
}
|
||||
|
||||
if (pdata && pdata->touch) {
|
||||
ret = mfd_add_devices(chip->dev, 0, &touch_devs[0],
|
||||
ARRAY_SIZE(touch_devs),
|
||||
&touch_resources[0], 0, NULL);
|
||||
NULL, chip->tsc_irq, NULL);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "Failed to add touch subdev\n");
|
||||
goto out_dev;
|
||||
|
@ -135,13 +135,37 @@ static const struct i2c_device_id max8925_id_table[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, max8925_id_table);
|
||||
|
||||
static int max8925_dt_init(struct device_node *np, struct device *dev,
|
||||
struct max8925_platform_data *pdata)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = of_property_read_u32(np, "maxim,tsc-irq", &pdata->tsc_irq);
|
||||
if (ret) {
|
||||
dev_err(dev, "Not found maxim,tsc-irq property\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max8925_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct max8925_platform_data *pdata = client->dev.platform_data;
|
||||
static struct max8925_chip *chip;
|
||||
struct device_node *node = client->dev.of_node;
|
||||
|
||||
if (!pdata) {
|
||||
if (node && !pdata) {
|
||||
/* parse DT to get platform data */
|
||||
pdata = devm_kzalloc(&client->dev,
|
||||
sizeof(struct max8925_platform_data),
|
||||
GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return -ENOMEM;
|
||||
|
||||
if (max8925_dt_init(node, &client->dev, pdata))
|
||||
return -EINVAL;
|
||||
} else if (!pdata) {
|
||||
pr_info("%s: platform data is missing\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -203,11 +227,18 @@ static int max8925_resume(struct device *dev)
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(max8925_pm_ops, max8925_suspend, max8925_resume);
|
||||
|
||||
static const struct of_device_id max8925_dt_ids[] = {
|
||||
{ .compatible = "maxim,max8925", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, max8925_dt_ids);
|
||||
|
||||
static struct i2c_driver max8925_driver = {
|
||||
.driver = {
|
||||
.name = "max8925",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &max8925_pm_ops,
|
||||
.of_match_table = of_match_ptr(max8925_dt_ids),
|
||||
},
|
||||
.probe = max8925_probe,
|
||||
.remove = max8925_remove,
|
||||
@ -217,7 +248,6 @@ static struct i2c_driver max8925_driver = {
|
||||
static int __init max8925_i2c_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = i2c_add_driver(&max8925_driver);
|
||||
if (ret != 0)
|
||||
pr_err("Failed to register MAX8925 I2C driver: %d\n", ret);
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/platform_data/usb-omap.h>
|
||||
@ -91,21 +90,23 @@
|
||||
|
||||
|
||||
struct usbhs_hcd_omap {
|
||||
int nports;
|
||||
struct clk **utmi_clk;
|
||||
struct clk **hsic60m_clk;
|
||||
struct clk **hsic480m_clk;
|
||||
|
||||
struct clk *xclk60mhsp1_ck;
|
||||
struct clk *xclk60mhsp2_ck;
|
||||
struct clk *utmi_p1_fck;
|
||||
struct clk *usbhost_p1_fck;
|
||||
struct clk *utmi_p2_fck;
|
||||
struct clk *usbhost_p2_fck;
|
||||
struct clk *utmi_p1_gfclk;
|
||||
struct clk *utmi_p2_gfclk;
|
||||
struct clk *init_60m_fclk;
|
||||
struct clk *ehci_logic_fck;
|
||||
|
||||
void __iomem *uhh_base;
|
||||
|
||||
struct usbhs_omap_platform_data platdata;
|
||||
struct usbhs_omap_platform_data *pdata;
|
||||
|
||||
u32 usbhs_rev;
|
||||
spinlock_t lock;
|
||||
};
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
@ -184,19 +185,13 @@ static struct platform_device *omap_usbhs_alloc_child(const char *name,
|
||||
static int omap_usbhs_alloc_children(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct usbhs_hcd_omap *omap;
|
||||
struct ehci_hcd_omap_platform_data *ehci_data;
|
||||
struct ohci_hcd_omap_platform_data *ohci_data;
|
||||
struct usbhs_omap_platform_data *pdata = dev->platform_data;
|
||||
struct platform_device *ehci;
|
||||
struct platform_device *ohci;
|
||||
struct resource *res;
|
||||
struct resource resources[2];
|
||||
int ret;
|
||||
|
||||
omap = platform_get_drvdata(pdev);
|
||||
ehci_data = omap->platdata.ehci_data;
|
||||
ohci_data = omap->platdata.ohci_data;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ehci");
|
||||
if (!res) {
|
||||
dev_err(dev, "EHCI get resource IORESOURCE_MEM failed\n");
|
||||
@ -213,8 +208,8 @@ static int omap_usbhs_alloc_children(struct platform_device *pdev)
|
||||
}
|
||||
resources[1] = *res;
|
||||
|
||||
ehci = omap_usbhs_alloc_child(OMAP_EHCI_DEVICE, resources, 2, ehci_data,
|
||||
sizeof(*ehci_data), dev);
|
||||
ehci = omap_usbhs_alloc_child(OMAP_EHCI_DEVICE, resources, 2, pdata,
|
||||
sizeof(*pdata), dev);
|
||||
|
||||
if (!ehci) {
|
||||
dev_err(dev, "omap_usbhs_alloc_child failed\n");
|
||||
@ -238,8 +233,8 @@ static int omap_usbhs_alloc_children(struct platform_device *pdev)
|
||||
}
|
||||
resources[1] = *res;
|
||||
|
||||
ohci = omap_usbhs_alloc_child(OMAP_OHCI_DEVICE, resources, 2, ohci_data,
|
||||
sizeof(*ohci_data), dev);
|
||||
ohci = omap_usbhs_alloc_child(OMAP_OHCI_DEVICE, resources, 2, pdata,
|
||||
sizeof(*pdata), dev);
|
||||
if (!ohci) {
|
||||
dev_err(dev, "omap_usbhs_alloc_child failed\n");
|
||||
ret = -ENOMEM;
|
||||
@ -278,31 +273,52 @@ static bool is_ohci_port(enum usbhs_omap_port_mode pmode)
|
||||
static int usbhs_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
|
||||
struct usbhs_omap_platform_data *pdata = &omap->platdata;
|
||||
unsigned long flags;
|
||||
struct usbhs_omap_platform_data *pdata = omap->pdata;
|
||||
int i, r;
|
||||
|
||||
dev_dbg(dev, "usbhs_runtime_resume\n");
|
||||
|
||||
if (!pdata) {
|
||||
dev_dbg(dev, "missing platform_data\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
omap_tll_enable();
|
||||
spin_lock_irqsave(&omap->lock, flags);
|
||||
|
||||
if (omap->ehci_logic_fck && !IS_ERR(omap->ehci_logic_fck))
|
||||
if (!IS_ERR(omap->ehci_logic_fck))
|
||||
clk_enable(omap->ehci_logic_fck);
|
||||
|
||||
if (is_ehci_tll_mode(pdata->port_mode[0]))
|
||||
clk_enable(omap->usbhost_p1_fck);
|
||||
if (is_ehci_tll_mode(pdata->port_mode[1]))
|
||||
clk_enable(omap->usbhost_p2_fck);
|
||||
for (i = 0; i < omap->nports; i++) {
|
||||
switch (pdata->port_mode[i]) {
|
||||
case OMAP_EHCI_PORT_MODE_HSIC:
|
||||
if (!IS_ERR(omap->hsic60m_clk[i])) {
|
||||
r = clk_enable(omap->hsic60m_clk[i]);
|
||||
if (r) {
|
||||
dev_err(dev,
|
||||
"Can't enable port %d hsic60m clk:%d\n",
|
||||
i, r);
|
||||
}
|
||||
}
|
||||
|
||||
clk_enable(omap->utmi_p1_fck);
|
||||
clk_enable(omap->utmi_p2_fck);
|
||||
if (!IS_ERR(omap->hsic480m_clk[i])) {
|
||||
r = clk_enable(omap->hsic480m_clk[i]);
|
||||
if (r) {
|
||||
dev_err(dev,
|
||||
"Can't enable port %d hsic480m clk:%d\n",
|
||||
i, r);
|
||||
}
|
||||
}
|
||||
/* Fall through as HSIC mode needs utmi_clk */
|
||||
|
||||
spin_unlock_irqrestore(&omap->lock, flags);
|
||||
case OMAP_EHCI_PORT_MODE_TLL:
|
||||
if (!IS_ERR(omap->utmi_clk[i])) {
|
||||
r = clk_enable(omap->utmi_clk[i]);
|
||||
if (r) {
|
||||
dev_err(dev,
|
||||
"Can't enable port %d clk : %d\n",
|
||||
i, r);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -310,51 +326,122 @@ static int usbhs_runtime_resume(struct device *dev)
|
||||
static int usbhs_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
|
||||
struct usbhs_omap_platform_data *pdata = &omap->platdata;
|
||||
unsigned long flags;
|
||||
struct usbhs_omap_platform_data *pdata = omap->pdata;
|
||||
int i;
|
||||
|
||||
dev_dbg(dev, "usbhs_runtime_suspend\n");
|
||||
|
||||
if (!pdata) {
|
||||
dev_dbg(dev, "missing platform_data\n");
|
||||
return -ENODEV;
|
||||
for (i = 0; i < omap->nports; i++) {
|
||||
switch (pdata->port_mode[i]) {
|
||||
case OMAP_EHCI_PORT_MODE_HSIC:
|
||||
if (!IS_ERR(omap->hsic60m_clk[i]))
|
||||
clk_disable(omap->hsic60m_clk[i]);
|
||||
|
||||
if (!IS_ERR(omap->hsic480m_clk[i]))
|
||||
clk_disable(omap->hsic480m_clk[i]);
|
||||
/* Fall through as utmi_clks were used in HSIC mode */
|
||||
|
||||
case OMAP_EHCI_PORT_MODE_TLL:
|
||||
if (!IS_ERR(omap->utmi_clk[i]))
|
||||
clk_disable(omap->utmi_clk[i]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&omap->lock, flags);
|
||||
|
||||
if (is_ehci_tll_mode(pdata->port_mode[0]))
|
||||
clk_disable(omap->usbhost_p1_fck);
|
||||
if (is_ehci_tll_mode(pdata->port_mode[1]))
|
||||
clk_disable(omap->usbhost_p2_fck);
|
||||
|
||||
clk_disable(omap->utmi_p2_fck);
|
||||
clk_disable(omap->utmi_p1_fck);
|
||||
|
||||
if (omap->ehci_logic_fck && !IS_ERR(omap->ehci_logic_fck))
|
||||
if (!IS_ERR(omap->ehci_logic_fck))
|
||||
clk_disable(omap->ehci_logic_fck);
|
||||
|
||||
spin_unlock_irqrestore(&omap->lock, flags);
|
||||
omap_tll_disable();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned omap_usbhs_rev1_hostconfig(struct usbhs_hcd_omap *omap,
|
||||
unsigned reg)
|
||||
{
|
||||
struct usbhs_omap_platform_data *pdata = omap->pdata;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < omap->nports; i++) {
|
||||
switch (pdata->port_mode[i]) {
|
||||
case OMAP_USBHS_PORT_MODE_UNUSED:
|
||||
reg &= ~(OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS << i);
|
||||
break;
|
||||
case OMAP_EHCI_PORT_MODE_PHY:
|
||||
if (pdata->single_ulpi_bypass)
|
||||
break;
|
||||
|
||||
if (i == 0)
|
||||
reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
|
||||
else
|
||||
reg &= ~(OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS
|
||||
<< (i-1));
|
||||
break;
|
||||
default:
|
||||
if (pdata->single_ulpi_bypass)
|
||||
break;
|
||||
|
||||
if (i == 0)
|
||||
reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
|
||||
else
|
||||
reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS
|
||||
<< (i-1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pdata->single_ulpi_bypass) {
|
||||
/* bypass ULPI only if none of the ports use PHY mode */
|
||||
reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
|
||||
|
||||
for (i = 0; i < omap->nports; i++) {
|
||||
if (is_ehci_phy_mode(pdata->port_mode[i])) {
|
||||
reg &= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return reg;
|
||||
}
|
||||
|
||||
static unsigned omap_usbhs_rev2_hostconfig(struct usbhs_hcd_omap *omap,
|
||||
unsigned reg)
|
||||
{
|
||||
struct usbhs_omap_platform_data *pdata = omap->pdata;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < omap->nports; i++) {
|
||||
/* Clear port mode fields for PHY mode */
|
||||
reg &= ~(OMAP4_P1_MODE_CLEAR << 2 * i);
|
||||
|
||||
if (is_ehci_tll_mode(pdata->port_mode[i]) ||
|
||||
(is_ohci_port(pdata->port_mode[i])))
|
||||
reg |= OMAP4_P1_MODE_TLL << 2 * i;
|
||||
else if (is_ehci_hsic_mode(pdata->port_mode[i]))
|
||||
reg |= OMAP4_P1_MODE_HSIC << 2 * i;
|
||||
}
|
||||
|
||||
return reg;
|
||||
}
|
||||
|
||||
static void omap_usbhs_init(struct device *dev)
|
||||
{
|
||||
struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
|
||||
struct usbhs_omap_platform_data *pdata = &omap->platdata;
|
||||
unsigned long flags;
|
||||
struct usbhs_omap_platform_data *pdata = omap->pdata;
|
||||
unsigned reg;
|
||||
|
||||
dev_dbg(dev, "starting TI HSUSB Controller\n");
|
||||
|
||||
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],
|
||||
if (pdata->phy_reset) {
|
||||
if (gpio_is_valid(pdata->reset_gpio_port[0]))
|
||||
gpio_request_one(pdata->reset_gpio_port[0],
|
||||
GPIOF_OUT_INIT_LOW, "USB1 PHY reset");
|
||||
|
||||
if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
|
||||
gpio_request_one(pdata->ehci_data->reset_gpio_port[1],
|
||||
if (gpio_is_valid(pdata->reset_gpio_port[1]))
|
||||
gpio_request_one(pdata->reset_gpio_port[1],
|
||||
GPIOF_OUT_INIT_LOW, "USB2 PHY reset");
|
||||
|
||||
/* Hold the PHY in RESET for enough time till DIR is high */
|
||||
@ -362,9 +449,6 @@ static void omap_usbhs_init(struct device *dev)
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG);
|
||||
/* setup ULPI bypass and burst configurations */
|
||||
@ -374,89 +458,51 @@ static void omap_usbhs_init(struct device *dev)
|
||||
reg |= OMAP4_UHH_HOSTCONFIG_APP_START_CLK;
|
||||
reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN;
|
||||
|
||||
if (is_omap_usbhs_rev1(omap)) {
|
||||
if (pdata->port_mode[0] == OMAP_USBHS_PORT_MODE_UNUSED)
|
||||
reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS;
|
||||
if (pdata->port_mode[1] == OMAP_USBHS_PORT_MODE_UNUSED)
|
||||
reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS;
|
||||
if (pdata->port_mode[2] == OMAP_USBHS_PORT_MODE_UNUSED)
|
||||
reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS;
|
||||
switch (omap->usbhs_rev) {
|
||||
case OMAP_USBHS_REV1:
|
||||
omap_usbhs_rev1_hostconfig(omap, reg);
|
||||
break;
|
||||
|
||||
/* Bypass the TLL module for PHY mode operation */
|
||||
if (pdata->single_ulpi_bypass) {
|
||||
dev_dbg(dev, "OMAP3 ES version <= ES2.1\n");
|
||||
if (is_ehci_phy_mode(pdata->port_mode[0]) ||
|
||||
is_ehci_phy_mode(pdata->port_mode[1]) ||
|
||||
is_ehci_phy_mode(pdata->port_mode[2]))
|
||||
reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
|
||||
else
|
||||
reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
|
||||
} else {
|
||||
dev_dbg(dev, "OMAP3 ES version > ES2.1\n");
|
||||
if (is_ehci_phy_mode(pdata->port_mode[0]))
|
||||
reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
|
||||
else
|
||||
reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
|
||||
if (is_ehci_phy_mode(pdata->port_mode[1]))
|
||||
reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;
|
||||
else
|
||||
reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;
|
||||
if (is_ehci_phy_mode(pdata->port_mode[2]))
|
||||
reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
|
||||
else
|
||||
reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
|
||||
}
|
||||
} else if (is_omap_usbhs_rev2(omap)) {
|
||||
/* Clear port mode fields for PHY mode*/
|
||||
reg &= ~OMAP4_P1_MODE_CLEAR;
|
||||
reg &= ~OMAP4_P2_MODE_CLEAR;
|
||||
case OMAP_USBHS_REV2:
|
||||
omap_usbhs_rev2_hostconfig(omap, reg);
|
||||
break;
|
||||
|
||||
if (is_ehci_tll_mode(pdata->port_mode[0]) ||
|
||||
(is_ohci_port(pdata->port_mode[0])))
|
||||
reg |= OMAP4_P1_MODE_TLL;
|
||||
else if (is_ehci_hsic_mode(pdata->port_mode[0]))
|
||||
reg |= OMAP4_P1_MODE_HSIC;
|
||||
|
||||
if (is_ehci_tll_mode(pdata->port_mode[1]) ||
|
||||
(is_ohci_port(pdata->port_mode[1])))
|
||||
reg |= OMAP4_P2_MODE_TLL;
|
||||
else if (is_ehci_hsic_mode(pdata->port_mode[1]))
|
||||
reg |= OMAP4_P2_MODE_HSIC;
|
||||
default: /* newer revisions */
|
||||
omap_usbhs_rev2_hostconfig(omap, reg);
|
||||
break;
|
||||
}
|
||||
|
||||
usbhs_write(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg);
|
||||
dev_dbg(dev, "UHH setup done, uhh_hostconfig=%x\n", reg);
|
||||
|
||||
spin_unlock_irqrestore(&omap->lock, flags);
|
||||
|
||||
pm_runtime_put_sync(dev);
|
||||
if (pdata->ehci_data->phy_reset) {
|
||||
if (pdata->phy_reset) {
|
||||
/* Hold the PHY in RESET for enough time till
|
||||
* PHY is settled and ready
|
||||
*/
|
||||
udelay(10);
|
||||
|
||||
if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
|
||||
if (gpio_is_valid(pdata->reset_gpio_port[0]))
|
||||
gpio_set_value_cansleep
|
||||
(pdata->ehci_data->reset_gpio_port[0], 1);
|
||||
(pdata->reset_gpio_port[0], 1);
|
||||
|
||||
if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
|
||||
if (gpio_is_valid(pdata->reset_gpio_port[1]))
|
||||
gpio_set_value_cansleep
|
||||
(pdata->ehci_data->reset_gpio_port[1], 1);
|
||||
(pdata->reset_gpio_port[1], 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void omap_usbhs_deinit(struct device *dev)
|
||||
{
|
||||
struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
|
||||
struct usbhs_omap_platform_data *pdata = &omap->platdata;
|
||||
struct usbhs_omap_platform_data *pdata = omap->pdata;
|
||||
|
||||
if (pdata->ehci_data->phy_reset) {
|
||||
if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
|
||||
gpio_free(pdata->ehci_data->reset_gpio_port[0]);
|
||||
if (pdata->phy_reset) {
|
||||
if (gpio_is_valid(pdata->reset_gpio_port[0]))
|
||||
gpio_free(pdata->reset_gpio_port[0]);
|
||||
|
||||
if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
|
||||
gpio_free(pdata->ehci_data->reset_gpio_port[1]);
|
||||
if (gpio_is_valid(pdata->reset_gpio_port[1]))
|
||||
gpio_free(pdata->reset_gpio_port[1]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -474,137 +520,185 @@ static int usbhs_omap_probe(struct platform_device *pdev)
|
||||
struct resource *res;
|
||||
int ret = 0;
|
||||
int i;
|
||||
bool need_logic_fck;
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(dev, "Missing platform data\n");
|
||||
ret = -ENOMEM;
|
||||
goto end_probe;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
omap = kzalloc(sizeof(*omap), GFP_KERNEL);
|
||||
omap = devm_kzalloc(dev, sizeof(*omap), GFP_KERNEL);
|
||||
if (!omap) {
|
||||
dev_err(dev, "Memory allocation failed\n");
|
||||
ret = -ENOMEM;
|
||||
goto end_probe;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
spin_lock_init(&omap->lock);
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "uhh");
|
||||
omap->uhh_base = devm_request_and_ioremap(dev, res);
|
||||
if (!omap->uhh_base) {
|
||||
dev_err(dev, "Resource request/ioremap failed\n");
|
||||
return -EADDRNOTAVAIL;
|
||||
}
|
||||
|
||||
for (i = 0; i < OMAP3_HS_USB_PORTS; i++)
|
||||
omap->platdata.port_mode[i] = pdata->port_mode[i];
|
||||
|
||||
omap->platdata.ehci_data = pdata->ehci_data;
|
||||
omap->platdata.ohci_data = pdata->ohci_data;
|
||||
omap->pdata = pdata;
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
platform_set_drvdata(pdev, omap);
|
||||
pm_runtime_get_sync(dev);
|
||||
|
||||
for (i = 0; i < OMAP3_HS_USB_PORTS; i++)
|
||||
if (is_ehci_phy_mode(i) || is_ehci_tll_mode(i) ||
|
||||
is_ehci_hsic_mode(i)) {
|
||||
omap->ehci_logic_fck = clk_get(dev, "ehci_logic_fck");
|
||||
if (IS_ERR(omap->ehci_logic_fck)) {
|
||||
ret = PTR_ERR(omap->ehci_logic_fck);
|
||||
dev_warn(dev, "ehci_logic_fck failed:%d\n",
|
||||
ret);
|
||||
}
|
||||
omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION);
|
||||
|
||||
/* we need to call runtime suspend before we update omap->nports
|
||||
* to prevent unbalanced clk_disable()
|
||||
*/
|
||||
pm_runtime_put_sync(dev);
|
||||
|
||||
/*
|
||||
* If platform data contains nports then use that
|
||||
* else make out number of ports from USBHS revision
|
||||
*/
|
||||
if (pdata->nports) {
|
||||
omap->nports = pdata->nports;
|
||||
} else {
|
||||
switch (omap->usbhs_rev) {
|
||||
case OMAP_USBHS_REV1:
|
||||
omap->nports = 3;
|
||||
break;
|
||||
case OMAP_USBHS_REV2:
|
||||
omap->nports = 2;
|
||||
break;
|
||||
default:
|
||||
omap->nports = OMAP3_HS_USB_PORTS;
|
||||
dev_dbg(dev,
|
||||
"USB HOST Rev:0x%d not recognized, assuming %d ports\n",
|
||||
omap->usbhs_rev, omap->nports);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
omap->utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk");
|
||||
if (IS_ERR(omap->utmi_p1_fck)) {
|
||||
ret = PTR_ERR(omap->utmi_p1_fck);
|
||||
dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret);
|
||||
goto err_end;
|
||||
i = sizeof(struct clk *) * omap->nports;
|
||||
omap->utmi_clk = devm_kzalloc(dev, i, GFP_KERNEL);
|
||||
omap->hsic480m_clk = devm_kzalloc(dev, i, GFP_KERNEL);
|
||||
omap->hsic60m_clk = devm_kzalloc(dev, i, GFP_KERNEL);
|
||||
|
||||
if (!omap->utmi_clk || !omap->hsic480m_clk || !omap->hsic60m_clk) {
|
||||
dev_err(dev, "Memory allocation failed\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_mem;
|
||||
}
|
||||
|
||||
need_logic_fck = false;
|
||||
for (i = 0; i < omap->nports; i++) {
|
||||
if (is_ehci_phy_mode(i) || is_ehci_tll_mode(i) ||
|
||||
is_ehci_hsic_mode(i))
|
||||
need_logic_fck |= true;
|
||||
}
|
||||
|
||||
omap->ehci_logic_fck = ERR_PTR(-EINVAL);
|
||||
if (need_logic_fck) {
|
||||
omap->ehci_logic_fck = clk_get(dev, "ehci_logic_fck");
|
||||
if (IS_ERR(omap->ehci_logic_fck)) {
|
||||
ret = PTR_ERR(omap->ehci_logic_fck);
|
||||
dev_dbg(dev, "ehci_logic_fck failed:%d\n", ret);
|
||||
}
|
||||
}
|
||||
|
||||
omap->utmi_p1_gfclk = clk_get(dev, "utmi_p1_gfclk");
|
||||
if (IS_ERR(omap->utmi_p1_gfclk)) {
|
||||
ret = PTR_ERR(omap->utmi_p1_gfclk);
|
||||
dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret);
|
||||
goto err_p1_gfclk;
|
||||
}
|
||||
|
||||
omap->utmi_p2_gfclk = clk_get(dev, "utmi_p2_gfclk");
|
||||
if (IS_ERR(omap->utmi_p2_gfclk)) {
|
||||
ret = PTR_ERR(omap->utmi_p2_gfclk);
|
||||
dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret);
|
||||
goto err_p2_gfclk;
|
||||
}
|
||||
|
||||
omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck");
|
||||
if (IS_ERR(omap->xclk60mhsp1_ck)) {
|
||||
ret = PTR_ERR(omap->xclk60mhsp1_ck);
|
||||
dev_err(dev, "xclk60mhsp1_ck failed error:%d\n", ret);
|
||||
goto err_utmi_p1_fck;
|
||||
}
|
||||
|
||||
omap->utmi_p2_fck = clk_get(dev, "utmi_p2_gfclk");
|
||||
if (IS_ERR(omap->utmi_p2_fck)) {
|
||||
ret = PTR_ERR(omap->utmi_p2_fck);
|
||||
dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret);
|
||||
goto err_xclk60mhsp1_ck;
|
||||
goto err_xclk60mhsp1;
|
||||
}
|
||||
|
||||
omap->xclk60mhsp2_ck = clk_get(dev, "xclk60mhsp2_ck");
|
||||
if (IS_ERR(omap->xclk60mhsp2_ck)) {
|
||||
ret = PTR_ERR(omap->xclk60mhsp2_ck);
|
||||
dev_err(dev, "xclk60mhsp2_ck failed error:%d\n", ret);
|
||||
goto err_utmi_p2_fck;
|
||||
}
|
||||
|
||||
omap->usbhost_p1_fck = clk_get(dev, "usb_host_hs_utmi_p1_clk");
|
||||
if (IS_ERR(omap->usbhost_p1_fck)) {
|
||||
ret = PTR_ERR(omap->usbhost_p1_fck);
|
||||
dev_err(dev, "usbhost_p1_fck failed error:%d\n", ret);
|
||||
goto err_xclk60mhsp2_ck;
|
||||
}
|
||||
|
||||
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_usbhost_p1_fck;
|
||||
goto err_xclk60mhsp2;
|
||||
}
|
||||
|
||||
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_usbhost_p2_fck;
|
||||
goto err_init60m;
|
||||
}
|
||||
|
||||
for (i = 0; i < omap->nports; i++) {
|
||||
char clkname[30];
|
||||
|
||||
/* clock names are indexed from 1*/
|
||||
snprintf(clkname, sizeof(clkname),
|
||||
"usb_host_hs_utmi_p%d_clk", i + 1);
|
||||
|
||||
/* If a clock is not found we won't bail out as not all
|
||||
* platforms have all clocks and we can function without
|
||||
* them
|
||||
*/
|
||||
omap->utmi_clk[i] = clk_get(dev, clkname);
|
||||
if (IS_ERR(omap->utmi_clk[i]))
|
||||
dev_dbg(dev, "Failed to get clock : %s : %ld\n",
|
||||
clkname, PTR_ERR(omap->utmi_clk[i]));
|
||||
|
||||
snprintf(clkname, sizeof(clkname),
|
||||
"usb_host_hs_hsic480m_p%d_clk", i + 1);
|
||||
omap->hsic480m_clk[i] = clk_get(dev, clkname);
|
||||
if (IS_ERR(omap->hsic480m_clk[i]))
|
||||
dev_dbg(dev, "Failed to get clock : %s : %ld\n",
|
||||
clkname, PTR_ERR(omap->hsic480m_clk[i]));
|
||||
|
||||
snprintf(clkname, sizeof(clkname),
|
||||
"usb_host_hs_hsic60m_p%d_clk", i + 1);
|
||||
omap->hsic60m_clk[i] = clk_get(dev, clkname);
|
||||
if (IS_ERR(omap->hsic60m_clk[i]))
|
||||
dev_dbg(dev, "Failed to get clock : %s : %ld\n",
|
||||
clkname, PTR_ERR(omap->hsic60m_clk[i]));
|
||||
}
|
||||
|
||||
if (is_ehci_phy_mode(pdata->port_mode[0])) {
|
||||
/* for OMAP3 , the clk set paretn fails */
|
||||
ret = clk_set_parent(omap->utmi_p1_fck,
|
||||
/* for OMAP3, clk_set_parent fails */
|
||||
ret = clk_set_parent(omap->utmi_p1_gfclk,
|
||||
omap->xclk60mhsp1_ck);
|
||||
if (ret != 0)
|
||||
dev_err(dev, "xclk60mhsp1_ck set parent"
|
||||
"failed error:%d\n", ret);
|
||||
dev_dbg(dev, "xclk60mhsp1_ck set parent failed: %d\n",
|
||||
ret);
|
||||
} else if (is_ehci_tll_mode(pdata->port_mode[0])) {
|
||||
ret = clk_set_parent(omap->utmi_p1_fck,
|
||||
ret = clk_set_parent(omap->utmi_p1_gfclk,
|
||||
omap->init_60m_fclk);
|
||||
if (ret != 0)
|
||||
dev_err(dev, "init_60m_fclk set parent"
|
||||
"failed error:%d\n", ret);
|
||||
dev_dbg(dev, "P0 init_60m_fclk set parent failed: %d\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
if (is_ehci_phy_mode(pdata->port_mode[1])) {
|
||||
ret = clk_set_parent(omap->utmi_p2_fck,
|
||||
ret = clk_set_parent(omap->utmi_p2_gfclk,
|
||||
omap->xclk60mhsp2_ck);
|
||||
if (ret != 0)
|
||||
dev_err(dev, "xclk60mhsp2_ck set parent"
|
||||
"failed error:%d\n", ret);
|
||||
dev_dbg(dev, "xclk60mhsp2_ck set parent failed: %d\n",
|
||||
ret);
|
||||
} else if (is_ehci_tll_mode(pdata->port_mode[1])) {
|
||||
ret = clk_set_parent(omap->utmi_p2_fck,
|
||||
ret = clk_set_parent(omap->utmi_p2_gfclk,
|
||||
omap->init_60m_fclk);
|
||||
if (ret != 0)
|
||||
dev_err(dev, "init_60m_fclk set parent"
|
||||
"failed error:%d\n", ret);
|
||||
dev_dbg(dev, "P1 init_60m_fclk set parent failed: %d\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "uhh");
|
||||
if (!res) {
|
||||
dev_err(dev, "UHH EHCI get resource failed\n");
|
||||
ret = -ENODEV;
|
||||
goto err_init_60m_fclk;
|
||||
}
|
||||
|
||||
omap->uhh_base = ioremap(res->start, resource_size(res));
|
||||
if (!omap->uhh_base) {
|
||||
dev_err(dev, "UHH ioremap failed\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_init_60m_fclk;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, omap);
|
||||
|
||||
omap_usbhs_init(dev);
|
||||
ret = omap_usbhs_alloc_children(pdev);
|
||||
if (ret) {
|
||||
@ -612,39 +706,41 @@ static int usbhs_omap_probe(struct platform_device *pdev)
|
||||
goto err_alloc;
|
||||
}
|
||||
|
||||
goto end_probe;
|
||||
return 0;
|
||||
|
||||
err_alloc:
|
||||
omap_usbhs_deinit(&pdev->dev);
|
||||
iounmap(omap->uhh_base);
|
||||
|
||||
err_init_60m_fclk:
|
||||
for (i = 0; i < omap->nports; i++) {
|
||||
if (!IS_ERR(omap->utmi_clk[i]))
|
||||
clk_put(omap->utmi_clk[i]);
|
||||
if (!IS_ERR(omap->hsic60m_clk[i]))
|
||||
clk_put(omap->hsic60m_clk[i]);
|
||||
if (!IS_ERR(omap->hsic480m_clk[i]))
|
||||
clk_put(omap->hsic480m_clk[i]);
|
||||
}
|
||||
|
||||
clk_put(omap->init_60m_fclk);
|
||||
|
||||
err_usbhost_p2_fck:
|
||||
clk_put(omap->usbhost_p2_fck);
|
||||
|
||||
err_usbhost_p1_fck:
|
||||
clk_put(omap->usbhost_p1_fck);
|
||||
|
||||
err_xclk60mhsp2_ck:
|
||||
err_init60m:
|
||||
clk_put(omap->xclk60mhsp2_ck);
|
||||
|
||||
err_utmi_p2_fck:
|
||||
clk_put(omap->utmi_p2_fck);
|
||||
|
||||
err_xclk60mhsp1_ck:
|
||||
err_xclk60mhsp2:
|
||||
clk_put(omap->xclk60mhsp1_ck);
|
||||
|
||||
err_utmi_p1_fck:
|
||||
clk_put(omap->utmi_p1_fck);
|
||||
err_xclk60mhsp1:
|
||||
clk_put(omap->utmi_p2_gfclk);
|
||||
|
||||
err_end:
|
||||
clk_put(omap->ehci_logic_fck);
|
||||
err_p2_gfclk:
|
||||
clk_put(omap->utmi_p1_gfclk);
|
||||
|
||||
err_p1_gfclk:
|
||||
if (!IS_ERR(omap->ehci_logic_fck))
|
||||
clk_put(omap->ehci_logic_fck);
|
||||
|
||||
err_mem:
|
||||
pm_runtime_disable(dev);
|
||||
kfree(omap);
|
||||
|
||||
end_probe:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -657,19 +753,29 @@ static int usbhs_omap_probe(struct platform_device *pdev)
|
||||
static int usbhs_omap_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev);
|
||||
int i;
|
||||
|
||||
omap_usbhs_deinit(&pdev->dev);
|
||||
iounmap(omap->uhh_base);
|
||||
|
||||
for (i = 0; i < omap->nports; i++) {
|
||||
if (!IS_ERR(omap->utmi_clk[i]))
|
||||
clk_put(omap->utmi_clk[i]);
|
||||
if (!IS_ERR(omap->hsic60m_clk[i]))
|
||||
clk_put(omap->hsic60m_clk[i]);
|
||||
if (!IS_ERR(omap->hsic480m_clk[i]))
|
||||
clk_put(omap->hsic480m_clk[i]);
|
||||
}
|
||||
|
||||
clk_put(omap->init_60m_fclk);
|
||||
clk_put(omap->usbhost_p2_fck);
|
||||
clk_put(omap->usbhost_p1_fck);
|
||||
clk_put(omap->utmi_p1_gfclk);
|
||||
clk_put(omap->utmi_p2_gfclk);
|
||||
clk_put(omap->xclk60mhsp2_ck);
|
||||
clk_put(omap->utmi_p2_fck);
|
||||
clk_put(omap->xclk60mhsp1_ck);
|
||||
clk_put(omap->utmi_p1_fck);
|
||||
clk_put(omap->ehci_logic_fck);
|
||||
|
||||
if (!IS_ERR(omap->ehci_logic_fck))
|
||||
clk_put(omap->ehci_logic_fck);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
kfree(omap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -685,7 +791,7 @@ static struct platform_driver usbhs_omap_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &usbhsomap_dev_pm_ops,
|
||||
},
|
||||
.remove = __exit_p(usbhs_omap_remove),
|
||||
.remove = usbhs_omap_remove,
|
||||
};
|
||||
|
||||
MODULE_AUTHOR("Keshava Munegowda <keshava_mgowda@ti.com>");
|
||||
|
@ -54,10 +54,13 @@
|
||||
|
||||
#define OMAP_TLL_CHANNEL_CONF(num) (0x040 + 0x004 * num)
|
||||
#define OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT 24
|
||||
#define OMAP_TLL_CHANNEL_CONF_DRVVBUS (1 << 16)
|
||||
#define OMAP_TLL_CHANNEL_CONF_CHRGVBUS (1 << 15)
|
||||
#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_MODE_TRANSPARENT_UTMI (2 << 1)
|
||||
#define OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS (1 << 1)
|
||||
#define OMAP_TLL_CHANNEL_CONF_CHANEN (1 << 0)
|
||||
|
||||
@ -92,21 +95,25 @@
|
||||
#define OMAP_USBTLL_REV1 0x00000015 /* OMAP3 */
|
||||
#define OMAP_USBTLL_REV2 0x00000018 /* OMAP 3630 */
|
||||
#define OMAP_USBTLL_REV3 0x00000004 /* OMAP4 */
|
||||
#define OMAP_USBTLL_REV4 0x00000006 /* OMAP5 */
|
||||
|
||||
#define is_ehci_tll_mode(x) (x == OMAP_EHCI_PORT_MODE_TLL)
|
||||
|
||||
/* only PHY and UNUSED modes don't need TLL */
|
||||
#define omap_usb_mode_needs_tll(x) ((x) != OMAP_USBHS_PORT_MODE_UNUSED &&\
|
||||
(x) != OMAP_EHCI_PORT_MODE_PHY)
|
||||
|
||||
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;
|
||||
int nch; /* num. of channels */
|
||||
struct usbhs_omap_platform_data *pdata;
|
||||
struct clk **ch_clk;
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
const char usbtll_driver_name[] = USBTLL_DRIVER_NAME;
|
||||
struct platform_device *tll_pdev;
|
||||
static const char usbtll_driver_name[] = USBTLL_DRIVER_NAME;
|
||||
static struct device *tll_dev;
|
||||
static DEFINE_SPINLOCK(tll_lock); /* serialize access to tll_dev */
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
@ -203,84 +210,84 @@ static unsigned ohci_omap3_fslsmode(enum usbhs_omap_port_mode mode)
|
||||
static int usbtll_omap_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct usbtll_omap_platform_data *pdata = dev->platform_data;
|
||||
struct usbhs_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;
|
||||
int i, ver;
|
||||
bool needs_tll;
|
||||
|
||||
dev_dbg(dev, "starting TI HSUSB TLL Controller\n");
|
||||
|
||||
tll = kzalloc(sizeof(struct usbtll_omap), GFP_KERNEL);
|
||||
tll = devm_kzalloc(dev, sizeof(struct usbtll_omap), GFP_KERNEL);
|
||||
if (!tll) {
|
||||
dev_err(dev, "Memory allocation failed\n");
|
||||
ret = -ENOMEM;
|
||||
goto end;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
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;
|
||||
if (!pdata) {
|
||||
dev_err(dev, "Platform data missing\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
tll->pdata = pdata;
|
||||
|
||||
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));
|
||||
base = devm_request_and_ioremap(dev, res);
|
||||
if (!base) {
|
||||
dev_err(dev, "TLL ioremap failed\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_usbtll_p2_fck;
|
||||
ret = -EADDRNOTAVAIL;
|
||||
dev_err(dev, "Resource request/ioremap failed:%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
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;
|
||||
case OMAP_USBTLL_REV4:
|
||||
tll->nch = OMAP_TLL_CHANNEL_COUNT;
|
||||
break;
|
||||
case OMAP_USBTLL_REV2:
|
||||
case OMAP_USBTLL_REV3:
|
||||
count = OMAP_REV2_TLL_CHANNEL_COUNT;
|
||||
tll->nch = OMAP_REV2_TLL_CHANNEL_COUNT;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "TLL version failed\n");
|
||||
ret = -ENODEV;
|
||||
goto err_ioremap;
|
||||
tll->nch = OMAP_TLL_CHANNEL_COUNT;
|
||||
dev_dbg(dev,
|
||||
"USB TLL Rev : 0x%x not recognized, assuming %d channels\n",
|
||||
ver, tll->nch);
|
||||
break;
|
||||
}
|
||||
|
||||
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])) {
|
||||
tll->ch_clk = devm_kzalloc(dev, sizeof(struct clk * [tll->nch]),
|
||||
GFP_KERNEL);
|
||||
if (!tll->ch_clk) {
|
||||
ret = -ENOMEM;
|
||||
dev_err(dev, "Couldn't allocate memory for channel clocks\n");
|
||||
goto err_clk_alloc;
|
||||
}
|
||||
|
||||
for (i = 0; i < tll->nch; i++) {
|
||||
char clkname[] = "usb_tll_hs_usb_chx_clk";
|
||||
|
||||
snprintf(clkname, sizeof(clkname),
|
||||
"usb_tll_hs_usb_ch%d_clk", i);
|
||||
tll->ch_clk[i] = clk_get(dev, clkname);
|
||||
|
||||
if (IS_ERR(tll->ch_clk[i]))
|
||||
dev_dbg(dev, "can't get clock : %s\n", clkname);
|
||||
}
|
||||
|
||||
needs_tll = false;
|
||||
for (i = 0; i < tll->nch; i++)
|
||||
needs_tll |= omap_usb_mode_needs_tll(pdata->port_mode[i]);
|
||||
|
||||
if (needs_tll) {
|
||||
|
||||
/* Program Common TLL register */
|
||||
reg = usbtll_read(base, OMAP_TLL_SHARED_CONF);
|
||||
@ -292,7 +299,7 @@ static int usbtll_omap_probe(struct platform_device *pdev)
|
||||
usbtll_write(base, OMAP_TLL_SHARED_CONF, reg);
|
||||
|
||||
/* Enable channels now */
|
||||
for (i = 0; i < count; i++) {
|
||||
for (i = 0; i < tll->nch; i++) {
|
||||
reg = usbtll_read(base, OMAP_TLL_CHANNEL_CONF(i));
|
||||
|
||||
if (is_ohci_port(pdata->port_mode[i])) {
|
||||
@ -308,6 +315,15 @@ static int usbtll_omap_probe(struct platform_device *pdev)
|
||||
reg &= ~(OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE
|
||||
| OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF
|
||||
| OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE);
|
||||
} else if (pdata->port_mode[i] ==
|
||||
OMAP_EHCI_PORT_MODE_HSIC) {
|
||||
/*
|
||||
* HSIC Mode requires UTMI port configurations
|
||||
*/
|
||||
reg |= OMAP_TLL_CHANNEL_CONF_DRVVBUS
|
||||
| OMAP_TLL_CHANNEL_CONF_CHRGVBUS
|
||||
| OMAP_TLL_CHANNEL_CONF_MODE_TRANSPARENT_UTMI
|
||||
| OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
@ -320,25 +336,18 @@ static int usbtll_omap_probe(struct platform_device *pdev)
|
||||
}
|
||||
}
|
||||
|
||||
err_ioremap:
|
||||
spin_unlock_irqrestore(&tll->lock, flags);
|
||||
iounmap(base);
|
||||
pm_runtime_put_sync(dev);
|
||||
tll_pdev = pdev;
|
||||
if (!ret)
|
||||
goto end;
|
||||
/* only after this can omap_tll_enable/disable work */
|
||||
spin_lock(&tll_lock);
|
||||
tll_dev = dev;
|
||||
spin_unlock(&tll_lock);
|
||||
|
||||
return 0;
|
||||
|
||||
err_clk_alloc:
|
||||
pm_runtime_put_sync(dev);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -351,63 +360,61 @@ static int usbtll_omap_probe(struct platform_device *pdev)
|
||||
static int usbtll_omap_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct usbtll_omap *tll = platform_get_drvdata(pdev);
|
||||
int i;
|
||||
|
||||
spin_lock(&tll_lock);
|
||||
tll_dev = NULL;
|
||||
spin_unlock(&tll_lock);
|
||||
|
||||
for (i = 0; i < tll->nch; i++)
|
||||
if (!IS_ERR(tll->ch_clk[i]))
|
||||
clk_put(tll->ch_clk[i]);
|
||||
|
||||
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;
|
||||
struct usbhs_omap_platform_data *pdata = tll->pdata;
|
||||
int i;
|
||||
|
||||
dev_dbg(dev, "usbtll_runtime_resume\n");
|
||||
|
||||
if (!pdata) {
|
||||
dev_dbg(dev, "missing platform_data\n");
|
||||
return -ENODEV;
|
||||
for (i = 0; i < tll->nch; i++) {
|
||||
if (omap_usb_mode_needs_tll(pdata->port_mode[i])) {
|
||||
int r;
|
||||
|
||||
if (IS_ERR(tll->ch_clk[i]))
|
||||
continue;
|
||||
|
||||
r = clk_enable(tll->ch_clk[i]);
|
||||
if (r) {
|
||||
dev_err(dev,
|
||||
"Error enabling ch %d clock: %d\n", i, r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
struct usbhs_omap_platform_data *pdata = tll->pdata;
|
||||
int i;
|
||||
|
||||
dev_dbg(dev, "usbtll_runtime_suspend\n");
|
||||
|
||||
if (!pdata) {
|
||||
dev_dbg(dev, "missing platform_data\n");
|
||||
return -ENODEV;
|
||||
for (i = 0; i < tll->nch; i++) {
|
||||
if (omap_usb_mode_needs_tll(pdata->port_mode[i])) {
|
||||
if (!IS_ERR(tll->ch_clk[i]))
|
||||
clk_disable(tll->ch_clk[i]);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -429,21 +436,39 @@ static struct platform_driver usbtll_omap_driver = {
|
||||
|
||||
int omap_tll_enable(void)
|
||||
{
|
||||
if (!tll_pdev) {
|
||||
pr_err("missing omap usbhs tll platform_data\n");
|
||||
return -ENODEV;
|
||||
int ret;
|
||||
|
||||
spin_lock(&tll_lock);
|
||||
|
||||
if (!tll_dev) {
|
||||
pr_err("%s: OMAP USB TLL not initialized\n", __func__);
|
||||
ret = -ENODEV;
|
||||
} else {
|
||||
ret = pm_runtime_get_sync(tll_dev);
|
||||
}
|
||||
return pm_runtime_get_sync(&tll_pdev->dev);
|
||||
|
||||
spin_unlock(&tll_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
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;
|
||||
int ret;
|
||||
|
||||
spin_lock(&tll_lock);
|
||||
|
||||
if (!tll_dev) {
|
||||
pr_err("%s: OMAP USB TLL not initialized\n", __func__);
|
||||
ret = -ENODEV;
|
||||
} else {
|
||||
ret = pm_runtime_put_sync(tll_dev);
|
||||
}
|
||||
return pm_runtime_put_sync(&tll_pdev->dev);
|
||||
|
||||
spin_unlock(&tll_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_tll_disable);
|
||||
|
||||
|
@ -39,6 +39,14 @@ enum palmas_ids {
|
||||
PALMAS_USB_ID,
|
||||
};
|
||||
|
||||
static struct resource palmas_rtc_resources[] = {
|
||||
{
|
||||
.start = PALMAS_RTC_ALARM_IRQ,
|
||||
.end = PALMAS_RTC_ALARM_IRQ,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct mfd_cell palmas_children[] = {
|
||||
{
|
||||
.name = "palmas-pmic",
|
||||
@ -59,6 +67,8 @@ static const struct mfd_cell palmas_children[] = {
|
||||
{
|
||||
.name = "palmas-rtc",
|
||||
.id = PALMAS_RTC_ID,
|
||||
.resources = &palmas_rtc_resources[0],
|
||||
.num_resources = ARRAY_SIZE(palmas_rtc_resources),
|
||||
},
|
||||
{
|
||||
.name = "palmas-pwrbutton",
|
||||
@ -456,8 +466,8 @@ static int palmas_i2c_probe(struct i2c_client *i2c,
|
||||
|
||||
ret = mfd_add_devices(palmas->dev, -1,
|
||||
children, ARRAY_SIZE(palmas_children),
|
||||
NULL, regmap_irq_chip_get_base(palmas->irq_data),
|
||||
NULL);
|
||||
NULL, 0,
|
||||
regmap_irq_get_domain(palmas->irq_data));
|
||||
kfree(children);
|
||||
|
||||
if (ret < 0)
|
||||
|
@ -115,14 +115,24 @@ static int rtl8411_card_power_off(struct rtsx_pcr *pcr, int card)
|
||||
static int rtl8411_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
|
||||
{
|
||||
u8 mask, val;
|
||||
int err;
|
||||
|
||||
mask = (BPP_REG_TUNED18 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_MASK;
|
||||
if (voltage == OUTPUT_3V3)
|
||||
if (voltage == OUTPUT_3V3) {
|
||||
err = rtsx_pci_write_register(pcr,
|
||||
SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_D);
|
||||
if (err < 0)
|
||||
return err;
|
||||
val = (BPP_ASIC_3V3 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_3V3;
|
||||
else if (voltage == OUTPUT_1V8)
|
||||
} else if (voltage == OUTPUT_1V8) {
|
||||
err = rtsx_pci_write_register(pcr,
|
||||
SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_B);
|
||||
if (err < 0)
|
||||
return err;
|
||||
val = (BPP_ASIC_1V8 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_1V8;
|
||||
else
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return rtsx_pci_write_register(pcr, LDO_CTL, mask, val);
|
||||
}
|
||||
|
@ -149,10 +149,18 @@ static int rts5209_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
|
||||
int err;
|
||||
|
||||
if (voltage == OUTPUT_3V3) {
|
||||
err = rtsx_pci_write_register(pcr,
|
||||
SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_D);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24);
|
||||
if (err < 0)
|
||||
return err;
|
||||
} else if (voltage == OUTPUT_1V8) {
|
||||
err = rtsx_pci_write_register(pcr,
|
||||
SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_B);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C40 | 0x24);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
234
drivers/mfd/rts5227.c
Normal file
234
drivers/mfd/rts5227.c
Normal file
@ -0,0 +1,234 @@
|
||||
/* Driver for Realtek PCI-Express card reader
|
||||
*
|
||||
* Copyright(c) 2009 Realtek Semiconductor Corp. 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 as published by the
|
||||
* Free Software Foundation; either version 2, 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author:
|
||||
* Wei WANG <wei_wang@realsil.com.cn>
|
||||
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
|
||||
*
|
||||
* Roger Tseng <rogerable@realtek.com>
|
||||
* No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mfd/rtsx_pci.h>
|
||||
|
||||
#include "rtsx_pcr.h"
|
||||
|
||||
static int rts5227_extra_init_hw(struct rtsx_pcr *pcr)
|
||||
{
|
||||
u16 cap;
|
||||
|
||||
rtsx_pci_init_cmd(pcr);
|
||||
|
||||
/* Configure GPIO as output */
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, GPIO_CTL, 0x02, 0x02);
|
||||
/* Switch LDO3318 source from DV33 to card_3v3 */
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x00);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x01);
|
||||
/* LED shine disabled, set initial shine cycle period */
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OLT_LED_CTL, 0x0F, 0x02);
|
||||
/* Configure LTR */
|
||||
pcie_capability_read_word(pcr->pci, PCI_EXP_DEVCTL2, &cap);
|
||||
if (cap & PCI_EXP_LTR_EN)
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LTR_CTL, 0xFF, 0xA3);
|
||||
/* Configure OBFF */
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OBFF_CFG, 0x03, 0x03);
|
||||
/* Configure force_clock_req
|
||||
* Maybe We should define 0xFF03 as some name
|
||||
*/
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, 0xFF03, 0x08, 0x08);
|
||||
/* Correct driving */
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
|
||||
SD30_CLK_DRIVE_SEL, 0xFF, 0x96);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
|
||||
SD30_CMD_DRIVE_SEL, 0xFF, 0x96);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
|
||||
SD30_DAT_DRIVE_SEL, 0xFF, 0x96);
|
||||
|
||||
return rtsx_pci_send_cmd(pcr, 100);
|
||||
}
|
||||
|
||||
static int rts5227_optimize_phy(struct rtsx_pcr *pcr)
|
||||
{
|
||||
/* Optimize RX sensitivity */
|
||||
return rtsx_pci_write_phy_register(pcr, 0x00, 0xBA42);
|
||||
}
|
||||
|
||||
static int rts5227_turn_on_led(struct rtsx_pcr *pcr)
|
||||
{
|
||||
return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x02);
|
||||
}
|
||||
|
||||
static int rts5227_turn_off_led(struct rtsx_pcr *pcr)
|
||||
{
|
||||
return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x00);
|
||||
}
|
||||
|
||||
static int rts5227_enable_auto_blink(struct rtsx_pcr *pcr)
|
||||
{
|
||||
return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x08);
|
||||
}
|
||||
|
||||
static int rts5227_disable_auto_blink(struct rtsx_pcr *pcr)
|
||||
{
|
||||
return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x00);
|
||||
}
|
||||
|
||||
static int rts5227_card_power_on(struct rtsx_pcr *pcr, int card)
|
||||
{
|
||||
int err;
|
||||
|
||||
rtsx_pci_init_cmd(pcr);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
|
||||
SD_POWER_MASK, SD_PARTIAL_POWER_ON);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
|
||||
LDO3318_PWR_MASK, 0x02);
|
||||
err = rtsx_pci_send_cmd(pcr, 100);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* To avoid too large in-rush current */
|
||||
udelay(150);
|
||||
|
||||
rtsx_pci_init_cmd(pcr);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
|
||||
SD_POWER_MASK, SD_POWER_ON);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
|
||||
LDO3318_PWR_MASK, 0x06);
|
||||
err = rtsx_pci_send_cmd(pcr, 100);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rts5227_card_power_off(struct rtsx_pcr *pcr, int card)
|
||||
{
|
||||
rtsx_pci_init_cmd(pcr);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
|
||||
SD_POWER_MASK | PMOS_STRG_MASK,
|
||||
SD_POWER_OFF | PMOS_STRG_400mA);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
|
||||
LDO3318_PWR_MASK, 0X00);
|
||||
return rtsx_pci_send_cmd(pcr, 100);
|
||||
}
|
||||
|
||||
static int rts5227_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
|
||||
{
|
||||
int err;
|
||||
u8 drive_sel;
|
||||
|
||||
if (voltage == OUTPUT_3V3) {
|
||||
err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24);
|
||||
if (err < 0)
|
||||
return err;
|
||||
drive_sel = 0x96;
|
||||
} else if (voltage == OUTPUT_1V8) {
|
||||
err = rtsx_pci_write_phy_register(pcr, 0x11, 0x3C02);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C80 | 0x24);
|
||||
if (err < 0)
|
||||
return err;
|
||||
drive_sel = 0xB3;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* set pad drive */
|
||||
rtsx_pci_init_cmd(pcr);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CLK_DRIVE_SEL,
|
||||
0xFF, drive_sel);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CMD_DRIVE_SEL,
|
||||
0xFF, drive_sel);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DAT_DRIVE_SEL,
|
||||
0xFF, drive_sel);
|
||||
return rtsx_pci_send_cmd(pcr, 100);
|
||||
}
|
||||
|
||||
static const struct pcr_ops rts5227_pcr_ops = {
|
||||
.extra_init_hw = rts5227_extra_init_hw,
|
||||
.optimize_phy = rts5227_optimize_phy,
|
||||
.turn_on_led = rts5227_turn_on_led,
|
||||
.turn_off_led = rts5227_turn_off_led,
|
||||
.enable_auto_blink = rts5227_enable_auto_blink,
|
||||
.disable_auto_blink = rts5227_disable_auto_blink,
|
||||
.card_power_on = rts5227_card_power_on,
|
||||
.card_power_off = rts5227_card_power_off,
|
||||
.switch_output_voltage = rts5227_switch_output_voltage,
|
||||
.cd_deglitch = NULL,
|
||||
.conv_clk_and_div_n = NULL,
|
||||
};
|
||||
|
||||
/* SD Pull Control Enable:
|
||||
* SD_DAT[3:0] ==> pull up
|
||||
* SD_CD ==> pull up
|
||||
* SD_WP ==> pull up
|
||||
* SD_CMD ==> pull up
|
||||
* SD_CLK ==> pull down
|
||||
*/
|
||||
static const u32 rts5227_sd_pull_ctl_enable_tbl[] = {
|
||||
RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
|
||||
RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE9),
|
||||
0,
|
||||
};
|
||||
|
||||
/* SD Pull Control Disable:
|
||||
* SD_DAT[3:0] ==> pull down
|
||||
* SD_CD ==> pull up
|
||||
* SD_WP ==> pull down
|
||||
* SD_CMD ==> pull down
|
||||
* SD_CLK ==> pull down
|
||||
*/
|
||||
static const u32 rts5227_sd_pull_ctl_disable_tbl[] = {
|
||||
RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
|
||||
RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD5),
|
||||
0,
|
||||
};
|
||||
|
||||
/* MS Pull Control Enable:
|
||||
* MS CD ==> pull up
|
||||
* others ==> pull down
|
||||
*/
|
||||
static const u32 rts5227_ms_pull_ctl_enable_tbl[] = {
|
||||
RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55),
|
||||
RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15),
|
||||
0,
|
||||
};
|
||||
|
||||
/* MS Pull Control Disable:
|
||||
* MS CD ==> pull up
|
||||
* others ==> pull down
|
||||
*/
|
||||
static const u32 rts5227_ms_pull_ctl_disable_tbl[] = {
|
||||
RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55),
|
||||
RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15),
|
||||
0,
|
||||
};
|
||||
|
||||
void rts5227_init_params(struct rtsx_pcr *pcr)
|
||||
{
|
||||
pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104;
|
||||
pcr->num_slots = 2;
|
||||
pcr->ops = &rts5227_pcr_ops;
|
||||
|
||||
pcr->sd_pull_ctl_enable_tbl = rts5227_sd_pull_ctl_enable_tbl;
|
||||
pcr->sd_pull_ctl_disable_tbl = rts5227_sd_pull_ctl_disable_tbl;
|
||||
pcr->ms_pull_ctl_enable_tbl = rts5227_ms_pull_ctl_enable_tbl;
|
||||
pcr->ms_pull_ctl_disable_tbl = rts5227_ms_pull_ctl_disable_tbl;
|
||||
}
|
@ -119,10 +119,18 @@ static int rts5229_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
|
||||
int err;
|
||||
|
||||
if (voltage == OUTPUT_3V3) {
|
||||
err = rtsx_pci_write_register(pcr,
|
||||
SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_D);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24);
|
||||
if (err < 0)
|
||||
return err;
|
||||
} else if (voltage == OUTPUT_1V8) {
|
||||
err = rtsx_pci_write_register(pcr,
|
||||
SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_B);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C40 | 0x24);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
@ -55,6 +55,7 @@ static DEFINE_PCI_DEVICE_TABLE(rtsx_pci_ids) = {
|
||||
{ PCI_DEVICE(0x10EC, 0x5209), PCI_CLASS_OTHERS << 16, 0xFF0000 },
|
||||
{ PCI_DEVICE(0x10EC, 0x5229), PCI_CLASS_OTHERS << 16, 0xFF0000 },
|
||||
{ PCI_DEVICE(0x10EC, 0x5289), PCI_CLASS_OTHERS << 16, 0xFF0000 },
|
||||
{ PCI_DEVICE(0x10EC, 0x5227), PCI_CLASS_OTHERS << 16, 0xFF0000 },
|
||||
{ 0, }
|
||||
};
|
||||
|
||||
@ -325,7 +326,6 @@ static void rtsx_pci_add_sg_tbl(struct rtsx_pcr *pcr,
|
||||
val = ((u64)addr << 32) | ((u64)len << 12) | option;
|
||||
|
||||
put_unaligned_le64(val, ptr);
|
||||
ptr++;
|
||||
pcr->sgi++;
|
||||
}
|
||||
|
||||
@ -591,8 +591,7 @@ int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
|
||||
u8 ssc_depth, bool initial_mode, bool double_clk, bool vpclk)
|
||||
{
|
||||
int err, clk;
|
||||
u8 N, min_N, max_N, clk_divider;
|
||||
u8 mcu_cnt, div, max_div;
|
||||
u8 n, clk_divider, mcu_cnt, div;
|
||||
u8 depth[] = {
|
||||
[RTSX_SSC_DEPTH_4M] = SSC_DEPTH_4M,
|
||||
[RTSX_SSC_DEPTH_2M] = SSC_DEPTH_2M,
|
||||
@ -616,10 +615,6 @@ int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
|
||||
card_clock /= 1000000;
|
||||
dev_dbg(&(pcr->pci->dev), "Switch card clock to %dMHz\n", card_clock);
|
||||
|
||||
min_N = 80;
|
||||
max_N = 208;
|
||||
max_div = CLK_DIV_8;
|
||||
|
||||
clk = card_clock;
|
||||
if (!initial_mode && double_clk)
|
||||
clk = card_clock * 2;
|
||||
@ -631,30 +626,30 @@ int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
|
||||
return 0;
|
||||
|
||||
if (pcr->ops->conv_clk_and_div_n)
|
||||
N = (u8)pcr->ops->conv_clk_and_div_n(clk, CLK_TO_DIV_N);
|
||||
n = (u8)pcr->ops->conv_clk_and_div_n(clk, CLK_TO_DIV_N);
|
||||
else
|
||||
N = (u8)(clk - 2);
|
||||
if ((clk <= 2) || (N > max_N))
|
||||
n = (u8)(clk - 2);
|
||||
if ((clk <= 2) || (n > MAX_DIV_N_PCR))
|
||||
return -EINVAL;
|
||||
|
||||
mcu_cnt = (u8)(125/clk + 3);
|
||||
if (mcu_cnt > 15)
|
||||
mcu_cnt = 15;
|
||||
|
||||
/* Make sure that the SSC clock div_n is equal or greater than min_N */
|
||||
/* Make sure that the SSC clock div_n is not less than MIN_DIV_N_PCR */
|
||||
div = CLK_DIV_1;
|
||||
while ((N < min_N) && (div < max_div)) {
|
||||
while ((n < MIN_DIV_N_PCR) && (div < CLK_DIV_8)) {
|
||||
if (pcr->ops->conv_clk_and_div_n) {
|
||||
int dbl_clk = pcr->ops->conv_clk_and_div_n(N,
|
||||
int dbl_clk = pcr->ops->conv_clk_and_div_n(n,
|
||||
DIV_N_TO_CLK) * 2;
|
||||
N = (u8)pcr->ops->conv_clk_and_div_n(dbl_clk,
|
||||
n = (u8)pcr->ops->conv_clk_and_div_n(dbl_clk,
|
||||
CLK_TO_DIV_N);
|
||||
} else {
|
||||
N = (N + 2) * 2 - 2;
|
||||
n = (n + 2) * 2 - 2;
|
||||
}
|
||||
div++;
|
||||
}
|
||||
dev_dbg(&(pcr->pci->dev), "N = %d, div = %d\n", N, div);
|
||||
dev_dbg(&(pcr->pci->dev), "n = %d, div = %d\n", n, div);
|
||||
|
||||
ssc_depth = depth[ssc_depth];
|
||||
if (double_clk)
|
||||
@ -671,7 +666,7 @@ int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, 0);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL2,
|
||||
SSC_DEPTH_MASK, ssc_depth);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_DIV_N_0, 0xFF, N);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_DIV_N_0, 0xFF, n);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, SSC_RSTB);
|
||||
if (vpclk) {
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL,
|
||||
@ -713,6 +708,25 @@ int rtsx_pci_card_power_off(struct rtsx_pcr *pcr, int card)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rtsx_pci_card_power_off);
|
||||
|
||||
int rtsx_pci_card_exclusive_check(struct rtsx_pcr *pcr, int card)
|
||||
{
|
||||
unsigned int cd_mask[] = {
|
||||
[RTSX_SD_CARD] = SD_EXIST,
|
||||
[RTSX_MS_CARD] = MS_EXIST
|
||||
};
|
||||
|
||||
if (!pcr->ms_pmos) {
|
||||
/* When using single PMOS, accessing card is not permitted
|
||||
* if the existing card is not the designated one.
|
||||
*/
|
||||
if (pcr->card_exist & (~cd_mask[card]))
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rtsx_pci_card_exclusive_check);
|
||||
|
||||
int rtsx_pci_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
|
||||
{
|
||||
if (pcr->ops->switch_output_voltage)
|
||||
@ -758,7 +772,7 @@ static void rtsx_pci_card_detect(struct work_struct *work)
|
||||
struct delayed_work *dwork;
|
||||
struct rtsx_pcr *pcr;
|
||||
unsigned long flags;
|
||||
unsigned int card_detect = 0;
|
||||
unsigned int card_detect = 0, card_inserted, card_removed;
|
||||
u32 irq_status;
|
||||
|
||||
dwork = to_delayed_work(work);
|
||||
@ -766,26 +780,36 @@ static void rtsx_pci_card_detect(struct work_struct *work)
|
||||
|
||||
dev_dbg(&(pcr->pci->dev), "--> %s\n", __func__);
|
||||
|
||||
mutex_lock(&pcr->pcr_mutex);
|
||||
spin_lock_irqsave(&pcr->lock, flags);
|
||||
|
||||
irq_status = rtsx_pci_readl(pcr, RTSX_BIPR);
|
||||
dev_dbg(&(pcr->pci->dev), "irq_status: 0x%08x\n", irq_status);
|
||||
|
||||
if (pcr->card_inserted || pcr->card_removed) {
|
||||
dev_dbg(&(pcr->pci->dev),
|
||||
"card_inserted: 0x%x, card_removed: 0x%x\n",
|
||||
pcr->card_inserted, pcr->card_removed);
|
||||
|
||||
if (pcr->ops->cd_deglitch)
|
||||
pcr->card_inserted = pcr->ops->cd_deglitch(pcr);
|
||||
|
||||
card_detect = pcr->card_inserted | pcr->card_removed;
|
||||
pcr->card_inserted = 0;
|
||||
pcr->card_removed = 0;
|
||||
}
|
||||
irq_status &= CARD_EXIST;
|
||||
card_inserted = pcr->card_inserted & irq_status;
|
||||
card_removed = pcr->card_removed;
|
||||
pcr->card_inserted = 0;
|
||||
pcr->card_removed = 0;
|
||||
|
||||
spin_unlock_irqrestore(&pcr->lock, flags);
|
||||
|
||||
if (card_inserted || card_removed) {
|
||||
dev_dbg(&(pcr->pci->dev),
|
||||
"card_inserted: 0x%x, card_removed: 0x%x\n",
|
||||
card_inserted, card_removed);
|
||||
|
||||
if (pcr->ops->cd_deglitch)
|
||||
card_inserted = pcr->ops->cd_deglitch(pcr);
|
||||
|
||||
card_detect = card_inserted | card_removed;
|
||||
|
||||
pcr->card_exist |= card_inserted;
|
||||
pcr->card_exist &= ~card_removed;
|
||||
}
|
||||
|
||||
mutex_unlock(&pcr->pcr_mutex);
|
||||
|
||||
if ((card_detect & SD_EXIST) && pcr->slots[RTSX_SD_CARD].card_event)
|
||||
pcr->slots[RTSX_SD_CARD].card_event(
|
||||
pcr->slots[RTSX_SD_CARD].p_dev);
|
||||
@ -836,10 +860,6 @@ static irqreturn_t rtsx_pci_isr(int irq, void *dev_id)
|
||||
}
|
||||
}
|
||||
|
||||
if (pcr->card_inserted || pcr->card_removed)
|
||||
schedule_delayed_work(&pcr->carddet_work,
|
||||
msecs_to_jiffies(200));
|
||||
|
||||
if (int_reg & (NEED_COMPLETE_INT | DELINK_INT)) {
|
||||
if (int_reg & (TRANS_FAIL_INT | DELINK_INT)) {
|
||||
pcr->trans_result = TRANS_RESULT_FAIL;
|
||||
@ -852,6 +872,10 @@ static irqreturn_t rtsx_pci_isr(int irq, void *dev_id)
|
||||
}
|
||||
}
|
||||
|
||||
if (pcr->card_inserted || pcr->card_removed)
|
||||
schedule_delayed_work(&pcr->carddet_work,
|
||||
msecs_to_jiffies(200));
|
||||
|
||||
spin_unlock(&pcr->lock);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@ -974,6 +998,14 @@ static int rtsx_pci_init_hw(struct rtsx_pcr *pcr)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* No CD interrupt if probing driver with card inserted.
|
||||
* So we need to initialize pcr->card_exist here.
|
||||
*/
|
||||
if (pcr->ops->cd_deglitch)
|
||||
pcr->card_exist = pcr->ops->cd_deglitch(pcr);
|
||||
else
|
||||
pcr->card_exist = rtsx_pci_readl(pcr, RTSX_BIPR) & CARD_EXIST;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -997,6 +1029,10 @@ static int rtsx_pci_init_chip(struct rtsx_pcr *pcr)
|
||||
case 0x5289:
|
||||
rtl8411_init_params(pcr);
|
||||
break;
|
||||
|
||||
case 0x5227:
|
||||
rts5227_init_params(pcr);
|
||||
break;
|
||||
}
|
||||
|
||||
dev_dbg(&(pcr->pci->dev), "PID: 0x%04x, IC version: 0x%02x\n",
|
||||
@ -1030,6 +1066,10 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
|
||||
pci_name(pcidev), (int)pcidev->vendor, (int)pcidev->device,
|
||||
(int)pcidev->revision);
|
||||
|
||||
ret = pci_set_dma_mask(pcidev, DMA_BIT_MASK(32));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = pci_enable_device(pcidev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -25,8 +25,12 @@
|
||||
|
||||
#include <linux/mfd/rtsx_pci.h>
|
||||
|
||||
#define MIN_DIV_N_PCR 80
|
||||
#define MAX_DIV_N_PCR 208
|
||||
|
||||
void rts5209_init_params(struct rtsx_pcr *pcr);
|
||||
void rts5229_init_params(struct rtsx_pcr *pcr);
|
||||
void rtl8411_init_params(struct rtsx_pcr *pcr);
|
||||
void rts5227_init_params(struct rtsx_pcr *pcr);
|
||||
|
||||
#endif
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
|
||||
static struct platform_driver syscon_driver;
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/tps6507x.h>
|
||||
|
||||
@ -116,11 +117,19 @@ static const struct i2c_device_id tps6507x_i2c_id[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, tps6507x_i2c_id);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct of_device_id tps6507x_of_match[] = {
|
||||
{.compatible = "ti,tps6507x", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tps6507x_of_match);
|
||||
#endif
|
||||
|
||||
static struct i2c_driver tps6507x_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "tps6507x",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(tps6507x_of_match),
|
||||
},
|
||||
.probe = tps6507x_i2c_probe,
|
||||
.remove = tps6507x_i2c_remove,
|
||||
|
@ -25,6 +25,8 @@
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/tps65090.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#define NUM_INT_REG 2
|
||||
@ -148,18 +150,31 @@ static const struct regmap_config tps65090_regmap_config = {
|
||||
.volatile_reg = is_volatile_reg,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id tps65090_of_match[] = {
|
||||
{ .compatible = "ti,tps65090",},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tps65090_of_match);
|
||||
#endif
|
||||
|
||||
static int tps65090_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct tps65090_platform_data *pdata = client->dev.platform_data;
|
||||
int irq_base = 0;
|
||||
struct tps65090 *tps65090;
|
||||
int ret;
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(&client->dev, "tps65090 requires platform data\n");
|
||||
if (!pdata && !client->dev.of_node) {
|
||||
dev_err(&client->dev,
|
||||
"tps65090 requires platform data or of_node\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (pdata)
|
||||
irq_base = pdata->irq_base;
|
||||
|
||||
tps65090 = devm_kzalloc(&client->dev, sizeof(*tps65090), GFP_KERNEL);
|
||||
if (!tps65090) {
|
||||
dev_err(&client->dev, "mem alloc for tps65090 failed\n");
|
||||
@ -178,7 +193,7 @@ static int tps65090_i2c_probe(struct i2c_client *client,
|
||||
|
||||
if (client->irq) {
|
||||
ret = regmap_add_irq_chip(tps65090->rmap, client->irq,
|
||||
IRQF_ONESHOT | IRQF_TRIGGER_LOW, pdata->irq_base,
|
||||
IRQF_ONESHOT | IRQF_TRIGGER_LOW, irq_base,
|
||||
&tps65090_irq_chip, &tps65090->irq_data);
|
||||
if (ret) {
|
||||
dev_err(&client->dev,
|
||||
@ -189,7 +204,7 @@ static int tps65090_i2c_probe(struct i2c_client *client,
|
||||
|
||||
ret = mfd_add_devices(tps65090->dev, -1, tps65090s,
|
||||
ARRAY_SIZE(tps65090s), NULL,
|
||||
regmap_irq_chip_get_base(tps65090->irq_data), NULL);
|
||||
0, regmap_irq_get_domain(tps65090->irq_data));
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "add mfd devices failed with err: %d\n",
|
||||
ret);
|
||||
@ -215,28 +230,6 @@ static int tps65090_i2c_remove(struct i2c_client *client)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int tps65090_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
if (client->irq)
|
||||
disable_irq(client->irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tps65090_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
if (client->irq)
|
||||
enable_irq(client->irq);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops tps65090_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(tps65090_suspend, tps65090_resume)
|
||||
};
|
||||
|
||||
static const struct i2c_device_id tps65090_id_table[] = {
|
||||
{ "tps65090", 0 },
|
||||
{ },
|
||||
@ -247,7 +240,7 @@ static struct i2c_driver tps65090_driver = {
|
||||
.driver = {
|
||||
.name = "tps65090",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &tps65090_pm_ops,
|
||||
.of_match_table = of_match_ptr(tps65090_of_match),
|
||||
},
|
||||
.probe = tps65090_i2c_probe,
|
||||
.remove = tps65090_i2c_remove,
|
||||
|
@ -66,16 +66,6 @@
|
||||
|
||||
/* Triton Core internal information (BEGIN) */
|
||||
|
||||
#define TWL_NUM_SLAVES 4
|
||||
|
||||
#define SUB_CHIP_ID0 0
|
||||
#define SUB_CHIP_ID1 1
|
||||
#define SUB_CHIP_ID2 2
|
||||
#define SUB_CHIP_ID3 3
|
||||
#define SUB_CHIP_ID_INVAL 0xff
|
||||
|
||||
#define TWL_MODULE_LAST TWL4030_MODULE_LAST
|
||||
|
||||
/* Base Address defns for twl4030_map[] */
|
||||
|
||||
/* subchip/slave 0 - USB ID */
|
||||
@ -94,10 +84,7 @@
|
||||
#define TWL4030_BASEADD_MADC 0x0000
|
||||
#define TWL4030_BASEADD_MAIN_CHARGE 0x0074
|
||||
#define TWL4030_BASEADD_PRECHARGE 0x00AA
|
||||
#define TWL4030_BASEADD_PWM0 0x00F8
|
||||
#define TWL4030_BASEADD_PWM1 0x00FB
|
||||
#define TWL4030_BASEADD_PWMA 0x00EF
|
||||
#define TWL4030_BASEADD_PWMB 0x00F1
|
||||
#define TWL4030_BASEADD_PWM 0x00F8
|
||||
#define TWL4030_BASEADD_KEYPAD 0x00D2
|
||||
|
||||
#define TWL5031_BASEADD_ACCESSORY 0x0074 /* Replaces Main Charge */
|
||||
@ -117,7 +104,7 @@
|
||||
|
||||
/* subchip/slave 0 0x48 - POWER */
|
||||
#define TWL6030_BASEADD_RTC 0x0000
|
||||
#define TWL6030_BASEADD_MEM 0x0017
|
||||
#define TWL6030_BASEADD_SECURED_REG 0x0017
|
||||
#define TWL6030_BASEADD_PM_MASTER 0x001F
|
||||
#define TWL6030_BASEADD_PM_SLAVE_MISC 0x0030 /* PM_RECEIVER */
|
||||
#define TWL6030_BASEADD_PM_MISC 0x00E2
|
||||
@ -132,6 +119,7 @@
|
||||
#define TWL6030_BASEADD_PIH 0x00D0
|
||||
#define TWL6030_BASEADD_CHARGER 0x00E0
|
||||
#define TWL6025_BASEADD_CHARGER 0x00DA
|
||||
#define TWL6030_BASEADD_LED 0x00F4
|
||||
|
||||
/* subchip/slave 2 0x4A - DFT */
|
||||
#define TWL6030_BASEADD_DIEID 0x00C0
|
||||
@ -153,33 +141,28 @@
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
/* is driver active, bound to a chip? */
|
||||
static bool inuse;
|
||||
|
||||
/* TWL IDCODE Register value */
|
||||
static u32 twl_idcode;
|
||||
|
||||
static unsigned int twl_id;
|
||||
unsigned int twl_rev(void)
|
||||
{
|
||||
return twl_id;
|
||||
}
|
||||
EXPORT_SYMBOL(twl_rev);
|
||||
|
||||
/* Structure for each TWL4030/TWL6030 Slave */
|
||||
struct twl_client {
|
||||
struct i2c_client *client;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
static struct twl_client twl_modules[TWL_NUM_SLAVES];
|
||||
|
||||
/* mapping the module id to slave id and base address */
|
||||
struct twl_mapping {
|
||||
unsigned char sid; /* Slave ID */
|
||||
unsigned char base; /* base address */
|
||||
};
|
||||
static struct twl_mapping *twl_map;
|
||||
|
||||
struct twl_private {
|
||||
bool ready; /* The core driver is ready to be used */
|
||||
u32 twl_idcode; /* TWL IDCODE Register value */
|
||||
unsigned int twl_id;
|
||||
|
||||
struct twl_mapping *twl_map;
|
||||
struct twl_client *twl_modules;
|
||||
};
|
||||
|
||||
static struct twl_private *twl_priv;
|
||||
|
||||
static struct twl_mapping twl4030_map[] = {
|
||||
/*
|
||||
@ -188,34 +171,33 @@ static struct twl_mapping twl4030_map[] = {
|
||||
* so they continue to match the order in this table.
|
||||
*/
|
||||
|
||||
/* Common IPs */
|
||||
{ 0, TWL4030_BASEADD_USB },
|
||||
{ 1, TWL4030_BASEADD_PIH },
|
||||
{ 2, TWL4030_BASEADD_MAIN_CHARGE },
|
||||
{ 3, TWL4030_BASEADD_PM_MASTER },
|
||||
{ 3, TWL4030_BASEADD_PM_RECEIVER },
|
||||
|
||||
{ 3, TWL4030_BASEADD_RTC },
|
||||
{ 2, TWL4030_BASEADD_PWM },
|
||||
{ 2, TWL4030_BASEADD_LED },
|
||||
{ 3, TWL4030_BASEADD_SECURED_REG },
|
||||
|
||||
/* TWL4030 specific IPs */
|
||||
{ 1, TWL4030_BASEADD_AUDIO_VOICE },
|
||||
{ 1, TWL4030_BASEADD_GPIO },
|
||||
{ 1, TWL4030_BASEADD_INTBR },
|
||||
{ 1, TWL4030_BASEADD_PIH },
|
||||
|
||||
{ 1, TWL4030_BASEADD_TEST },
|
||||
{ 2, TWL4030_BASEADD_KEYPAD },
|
||||
|
||||
{ 2, TWL4030_BASEADD_MADC },
|
||||
{ 2, TWL4030_BASEADD_INTERRUPTS },
|
||||
{ 2, TWL4030_BASEADD_LED },
|
||||
|
||||
{ 2, TWL4030_BASEADD_MAIN_CHARGE },
|
||||
{ 2, TWL4030_BASEADD_PRECHARGE },
|
||||
{ 2, TWL4030_BASEADD_PWM0 },
|
||||
{ 2, TWL4030_BASEADD_PWM1 },
|
||||
{ 2, TWL4030_BASEADD_PWMA },
|
||||
|
||||
{ 2, TWL4030_BASEADD_PWMB },
|
||||
{ 2, TWL5031_BASEADD_ACCESSORY },
|
||||
{ 2, TWL5031_BASEADD_INTERRUPTS },
|
||||
{ 3, TWL4030_BASEADD_BACKUP },
|
||||
{ 3, TWL4030_BASEADD_INT },
|
||||
|
||||
{ 3, TWL4030_BASEADD_PM_MASTER },
|
||||
{ 3, TWL4030_BASEADD_PM_RECEIVER },
|
||||
{ 3, TWL4030_BASEADD_RTC },
|
||||
{ 3, TWL4030_BASEADD_SECURED_REG },
|
||||
{ 2, TWL5031_BASEADD_ACCESSORY },
|
||||
{ 2, TWL5031_BASEADD_INTERRUPTS },
|
||||
};
|
||||
|
||||
static struct regmap_config twl4030_regmap_config[4] = {
|
||||
@ -251,35 +233,25 @@ static struct twl_mapping twl6030_map[] = {
|
||||
* <linux/i2c/twl.h> defines for TWL4030_MODULE_*
|
||||
* so they continue to match the order in this table.
|
||||
*/
|
||||
{ SUB_CHIP_ID1, TWL6030_BASEADD_USB },
|
||||
{ SUB_CHIP_ID_INVAL, TWL6030_BASEADD_AUDIO },
|
||||
{ SUB_CHIP_ID2, TWL6030_BASEADD_DIEID },
|
||||
{ SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
|
||||
{ SUB_CHIP_ID1, TWL6030_BASEADD_PIH },
|
||||
|
||||
{ SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
|
||||
{ SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
|
||||
{ SUB_CHIP_ID1, TWL6030_BASEADD_GPADC_CTRL },
|
||||
{ SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
|
||||
{ SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
|
||||
/* Common IPs */
|
||||
{ 1, TWL6030_BASEADD_USB },
|
||||
{ 1, TWL6030_BASEADD_PIH },
|
||||
{ 1, TWL6030_BASEADD_CHARGER },
|
||||
{ 0, TWL6030_BASEADD_PM_MASTER },
|
||||
{ 0, TWL6030_BASEADD_PM_SLAVE_MISC },
|
||||
|
||||
{ SUB_CHIP_ID1, TWL6030_BASEADD_CHARGER },
|
||||
{ SUB_CHIP_ID1, TWL6030_BASEADD_GASGAUGE },
|
||||
{ SUB_CHIP_ID1, TWL6030_BASEADD_PWM },
|
||||
{ SUB_CHIP_ID0, TWL6030_BASEADD_ZERO },
|
||||
{ SUB_CHIP_ID1, TWL6030_BASEADD_ZERO },
|
||||
{ 0, TWL6030_BASEADD_RTC },
|
||||
{ 1, TWL6030_BASEADD_PWM },
|
||||
{ 1, TWL6030_BASEADD_LED },
|
||||
{ 0, TWL6030_BASEADD_SECURED_REG },
|
||||
|
||||
{ SUB_CHIP_ID2, TWL6030_BASEADD_ZERO },
|
||||
{ SUB_CHIP_ID2, TWL6030_BASEADD_ZERO },
|
||||
{ SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
|
||||
{ SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
|
||||
{ SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
|
||||
|
||||
{ SUB_CHIP_ID0, TWL6030_BASEADD_PM_MASTER },
|
||||
{ SUB_CHIP_ID0, TWL6030_BASEADD_PM_SLAVE_MISC },
|
||||
{ SUB_CHIP_ID0, TWL6030_BASEADD_RTC },
|
||||
{ SUB_CHIP_ID0, TWL6030_BASEADD_MEM },
|
||||
{ SUB_CHIP_ID1, TWL6025_BASEADD_CHARGER },
|
||||
/* TWL6030 specific IPs */
|
||||
{ 0, TWL6030_BASEADD_ZERO },
|
||||
{ 1, TWL6030_BASEADD_ZERO },
|
||||
{ 2, TWL6030_BASEADD_ZERO },
|
||||
{ 1, TWL6030_BASEADD_GPADC_CTRL },
|
||||
{ 1, TWL6030_BASEADD_GASGAUGE },
|
||||
};
|
||||
|
||||
static struct regmap_config twl6030_regmap_config[3] = {
|
||||
@ -305,8 +277,30 @@ static struct regmap_config twl6030_regmap_config[3] = {
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
static inline int twl_get_num_slaves(void)
|
||||
{
|
||||
if (twl_class_is_4030())
|
||||
return 4; /* TWL4030 class have four slave address */
|
||||
else
|
||||
return 3; /* TWL6030 class have three slave address */
|
||||
}
|
||||
|
||||
static inline int twl_get_last_module(void)
|
||||
{
|
||||
if (twl_class_is_4030())
|
||||
return TWL4030_MODULE_LAST;
|
||||
else
|
||||
return TWL6030_MODULE_LAST;
|
||||
}
|
||||
|
||||
/* Exported Functions */
|
||||
|
||||
unsigned int twl_rev(void)
|
||||
{
|
||||
return twl_priv ? twl_priv->twl_id : 0;
|
||||
}
|
||||
EXPORT_SYMBOL(twl_rev);
|
||||
|
||||
/**
|
||||
* twl_i2c_write - Writes a n bit register in TWL4030/TWL5030/TWL60X0
|
||||
* @mod_no: module number
|
||||
@ -314,9 +308,6 @@ static struct regmap_config twl6030_regmap_config[3] = {
|
||||
* @reg: register address (just offset will do)
|
||||
* @num_bytes: number of bytes to transfer
|
||||
*
|
||||
* IMPORTANT: for 'value' parameter: Allocate value num_bytes+1 and
|
||||
* valid data starts at Offset 1.
|
||||
*
|
||||
* Returns the result of operation - 0 is success
|
||||
*/
|
||||
int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
|
||||
@ -325,24 +316,21 @@ int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
|
||||
int sid;
|
||||
struct twl_client *twl;
|
||||
|
||||
if (unlikely(mod_no >= TWL_MODULE_LAST)) {
|
||||
pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no);
|
||||
return -EPERM;
|
||||
}
|
||||
if (unlikely(!inuse)) {
|
||||
if (unlikely(!twl_priv || !twl_priv->ready)) {
|
||||
pr_err("%s: not initialized\n", DRIVER_NAME);
|
||||
return -EPERM;
|
||||
}
|
||||
sid = twl_map[mod_no].sid;
|
||||
if (unlikely(sid == SUB_CHIP_ID_INVAL)) {
|
||||
pr_err("%s: module %d is not part of the pmic\n",
|
||||
DRIVER_NAME, mod_no);
|
||||
return -EINVAL;
|
||||
if (unlikely(mod_no >= twl_get_last_module())) {
|
||||
pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no);
|
||||
return -EPERM;
|
||||
}
|
||||
twl = &twl_modules[sid];
|
||||
|
||||
ret = regmap_bulk_write(twl->regmap, twl_map[mod_no].base + reg,
|
||||
value, num_bytes);
|
||||
sid = twl_priv->twl_map[mod_no].sid;
|
||||
twl = &twl_priv->twl_modules[sid];
|
||||
|
||||
ret = regmap_bulk_write(twl->regmap,
|
||||
twl_priv->twl_map[mod_no].base + reg, value,
|
||||
num_bytes);
|
||||
|
||||
if (ret)
|
||||
pr_err("%s: Write failed (mod %d, reg 0x%02x count %d)\n",
|
||||
@ -367,24 +355,21 @@ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
|
||||
int sid;
|
||||
struct twl_client *twl;
|
||||
|
||||
if (unlikely(mod_no >= TWL_MODULE_LAST)) {
|
||||
pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no);
|
||||
return -EPERM;
|
||||
}
|
||||
if (unlikely(!inuse)) {
|
||||
if (unlikely(!twl_priv || !twl_priv->ready)) {
|
||||
pr_err("%s: not initialized\n", DRIVER_NAME);
|
||||
return -EPERM;
|
||||
}
|
||||
sid = twl_map[mod_no].sid;
|
||||
if (unlikely(sid == SUB_CHIP_ID_INVAL)) {
|
||||
pr_err("%s: module %d is not part of the pmic\n",
|
||||
DRIVER_NAME, mod_no);
|
||||
return -EINVAL;
|
||||
if (unlikely(mod_no >= twl_get_last_module())) {
|
||||
pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no);
|
||||
return -EPERM;
|
||||
}
|
||||
twl = &twl_modules[sid];
|
||||
|
||||
ret = regmap_bulk_read(twl->regmap, twl_map[mod_no].base + reg,
|
||||
value, num_bytes);
|
||||
sid = twl_priv->twl_map[mod_no].sid;
|
||||
twl = &twl_priv->twl_modules[sid];
|
||||
|
||||
ret = regmap_bulk_read(twl->regmap,
|
||||
twl_priv->twl_map[mod_no].base + reg, value,
|
||||
num_bytes);
|
||||
|
||||
if (ret)
|
||||
pr_err("%s: Read failed (mod %d, reg 0x%02x count %d)\n",
|
||||
@ -394,34 +379,6 @@ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
|
||||
}
|
||||
EXPORT_SYMBOL(twl_i2c_read);
|
||||
|
||||
/**
|
||||
* twl_i2c_write_u8 - Writes a 8 bit register in TWL4030/TWL5030/TWL60X0
|
||||
* @mod_no: module number
|
||||
* @value: the value to be written 8 bit
|
||||
* @reg: register address (just offset will do)
|
||||
*
|
||||
* Returns result of operation - 0 is success
|
||||
*/
|
||||
int twl_i2c_write_u8(u8 mod_no, u8 value, u8 reg)
|
||||
{
|
||||
return twl_i2c_write(mod_no, &value, reg, 1);
|
||||
}
|
||||
EXPORT_SYMBOL(twl_i2c_write_u8);
|
||||
|
||||
/**
|
||||
* twl_i2c_read_u8 - Reads a 8 bit register from TWL4030/TWL5030/TWL60X0
|
||||
* @mod_no: module number
|
||||
* @value: the value read 8 bit
|
||||
* @reg: register address (just offset will do)
|
||||
*
|
||||
* Returns result of operation - 0 is success
|
||||
*/
|
||||
int twl_i2c_read_u8(u8 mod_no, u8 *value, u8 reg)
|
||||
{
|
||||
return twl_i2c_read(mod_no, value, reg, 1);
|
||||
}
|
||||
EXPORT_SYMBOL(twl_i2c_read_u8);
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
@ -440,7 +397,7 @@ static int twl_read_idcode_register(void)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
err = twl_i2c_read(TWL4030_MODULE_INTBR, (u8 *)(&twl_idcode),
|
||||
err = twl_i2c_read(TWL4030_MODULE_INTBR, (u8 *)(&twl_priv->twl_idcode),
|
||||
REG_IDCODE_7_0, 4);
|
||||
if (err) {
|
||||
pr_err("TWL4030: unable to read IDCODE -%d\n", err);
|
||||
@ -461,7 +418,7 @@ static int twl_read_idcode_register(void)
|
||||
*/
|
||||
int twl_get_type(void)
|
||||
{
|
||||
return TWL_SIL_TYPE(twl_idcode);
|
||||
return TWL_SIL_TYPE(twl_priv->twl_idcode);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(twl_get_type);
|
||||
|
||||
@ -472,7 +429,7 @@ EXPORT_SYMBOL_GPL(twl_get_type);
|
||||
*/
|
||||
int twl_get_version(void)
|
||||
{
|
||||
return TWL_SIL_REV(twl_idcode);
|
||||
return TWL_SIL_REV(twl_priv->twl_idcode);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(twl_get_version);
|
||||
|
||||
@ -509,13 +466,20 @@ int twl_get_hfclk_rate(void)
|
||||
EXPORT_SYMBOL_GPL(twl_get_hfclk_rate);
|
||||
|
||||
static struct device *
|
||||
add_numbered_child(unsigned chip, const char *name, int num,
|
||||
add_numbered_child(unsigned mod_no, const char *name, int num,
|
||||
void *pdata, unsigned pdata_len,
|
||||
bool can_wakeup, int irq0, int irq1)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
struct twl_client *twl = &twl_modules[chip];
|
||||
int status;
|
||||
struct twl_client *twl;
|
||||
int status, sid;
|
||||
|
||||
if (unlikely(mod_no >= twl_get_last_module())) {
|
||||
pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no);
|
||||
return ERR_PTR(-EPERM);
|
||||
}
|
||||
sid = twl_priv->twl_map[mod_no].sid;
|
||||
twl = &twl_priv->twl_modules[sid];
|
||||
|
||||
pdev = platform_device_alloc(name, num);
|
||||
if (!pdev) {
|
||||
@ -560,11 +524,11 @@ add_numbered_child(unsigned chip, const char *name, int num,
|
||||
return &pdev->dev;
|
||||
}
|
||||
|
||||
static inline struct device *add_child(unsigned chip, const char *name,
|
||||
static inline struct device *add_child(unsigned mod_no, const char *name,
|
||||
void *pdata, unsigned pdata_len,
|
||||
bool can_wakeup, int irq0, int irq1)
|
||||
{
|
||||
return add_numbered_child(chip, name, -1, pdata, pdata_len,
|
||||
return add_numbered_child(mod_no, name, -1, pdata, pdata_len,
|
||||
can_wakeup, irq0, irq1);
|
||||
}
|
||||
|
||||
@ -573,7 +537,6 @@ add_regulator_linked(int num, struct regulator_init_data *pdata,
|
||||
struct regulator_consumer_supply *consumers,
|
||||
unsigned num_consumers, unsigned long features)
|
||||
{
|
||||
unsigned sub_chip_id;
|
||||
struct twl_regulator_driver_data drv_data;
|
||||
|
||||
/* regulator framework demands init_data ... */
|
||||
@ -600,8 +563,7 @@ add_regulator_linked(int num, struct regulator_init_data *pdata,
|
||||
}
|
||||
|
||||
/* NOTE: we currently ignore regulator IRQs, e.g. for short circuits */
|
||||
sub_chip_id = twl_map[TWL_MODULE_PM_MASTER].sid;
|
||||
return add_numbered_child(sub_chip_id, "twl_reg", num,
|
||||
return add_numbered_child(TWL_MODULE_PM_MASTER, "twl_reg", num,
|
||||
pdata, sizeof(*pdata), false, 0, 0);
|
||||
}
|
||||
|
||||
@ -623,10 +585,9 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
|
||||
unsigned long features)
|
||||
{
|
||||
struct device *child;
|
||||
unsigned sub_chip_id;
|
||||
|
||||
if (IS_ENABLED(CONFIG_GPIO_TWL4030) && pdata->gpio) {
|
||||
child = add_child(SUB_CHIP_ID1, "twl4030_gpio",
|
||||
child = add_child(TWL4030_MODULE_GPIO, "twl4030_gpio",
|
||||
pdata->gpio, sizeof(*pdata->gpio),
|
||||
false, irq_base + GPIO_INTR_OFFSET, 0);
|
||||
if (IS_ERR(child))
|
||||
@ -634,7 +595,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_KEYBOARD_TWL4030) && pdata->keypad) {
|
||||
child = add_child(SUB_CHIP_ID2, "twl4030_keypad",
|
||||
child = add_child(TWL4030_MODULE_KEYPAD, "twl4030_keypad",
|
||||
pdata->keypad, sizeof(*pdata->keypad),
|
||||
true, irq_base + KEYPAD_INTR_OFFSET, 0);
|
||||
if (IS_ERR(child))
|
||||
@ -643,7 +604,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
|
||||
|
||||
if (IS_ENABLED(CONFIG_TWL4030_MADC) && pdata->madc &&
|
||||
twl_class_is_4030()) {
|
||||
child = add_child(SUB_CHIP_ID2, "twl4030_madc",
|
||||
child = add_child(TWL4030_MODULE_MADC, "twl4030_madc",
|
||||
pdata->madc, sizeof(*pdata->madc),
|
||||
true, irq_base + MADC_INTR_OFFSET, 0);
|
||||
if (IS_ERR(child))
|
||||
@ -658,22 +619,21 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
|
||||
* Eventually, Linux might become more aware of such
|
||||
* HW security concerns, and "least privilege".
|
||||
*/
|
||||
sub_chip_id = twl_map[TWL_MODULE_RTC].sid;
|
||||
child = add_child(sub_chip_id, "twl_rtc", NULL, 0,
|
||||
child = add_child(TWL_MODULE_RTC, "twl_rtc", NULL, 0,
|
||||
true, irq_base + RTC_INTR_OFFSET, 0);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_PWM_TWL)) {
|
||||
child = add_child(SUB_CHIP_ID1, "twl-pwm", NULL, 0,
|
||||
child = add_child(TWL_MODULE_PWM, "twl-pwm", NULL, 0,
|
||||
false, 0, 0);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_PWM_TWL_LED)) {
|
||||
child = add_child(SUB_CHIP_ID1, "twl-pwmled", NULL, 0,
|
||||
child = add_child(TWL_MODULE_LED, "twl-pwmled", NULL, 0,
|
||||
false, 0, 0);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
@ -725,7 +685,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
|
||||
|
||||
}
|
||||
|
||||
child = add_child(SUB_CHIP_ID0, "twl4030_usb",
|
||||
child = add_child(TWL_MODULE_USB, "twl4030_usb",
|
||||
pdata->usb, sizeof(*pdata->usb), true,
|
||||
/* irq0 = USB_PRES, irq1 = USB */
|
||||
irq_base + USB_PRES_INTR_OFFSET,
|
||||
@ -774,7 +734,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
|
||||
|
||||
pdata->usb->features = features;
|
||||
|
||||
child = add_child(SUB_CHIP_ID0, "twl6030_usb",
|
||||
child = add_child(TWL_MODULE_USB, "twl6030_usb",
|
||||
pdata->usb, sizeof(*pdata->usb), true,
|
||||
/* irq1 = VBUS_PRES, irq0 = USB ID */
|
||||
irq_base + USBOTG_INTR_OFFSET,
|
||||
@ -799,22 +759,22 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_TWL4030_WATCHDOG) && twl_class_is_4030()) {
|
||||
child = add_child(SUB_CHIP_ID3, "twl4030_wdt", NULL, 0,
|
||||
false, 0, 0);
|
||||
child = add_child(TWL_MODULE_PM_RECEIVER, "twl4030_wdt", NULL,
|
||||
0, false, 0, 0);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_INPUT_TWL4030_PWRBUTTON) && twl_class_is_4030()) {
|
||||
child = add_child(SUB_CHIP_ID3, "twl4030_pwrbutton", NULL, 0,
|
||||
true, irq_base + 8 + 0, 0);
|
||||
child = add_child(TWL_MODULE_PM_MASTER, "twl4030_pwrbutton",
|
||||
NULL, 0, true, irq_base + 8 + 0, 0);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_MFD_TWL4030_AUDIO) && pdata->audio &&
|
||||
twl_class_is_4030()) {
|
||||
child = add_child(SUB_CHIP_ID1, "twl4030-audio",
|
||||
child = add_child(TWL4030_MODULE_AUDIO_VOICE, "twl4030-audio",
|
||||
pdata->audio, sizeof(*pdata->audio),
|
||||
false, 0, 0);
|
||||
if (IS_ERR(child))
|
||||
@ -1054,7 +1014,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
|
||||
|
||||
if (IS_ENABLED(CONFIG_CHARGER_TWL4030) && pdata->bci &&
|
||||
!(features & (TPS_SUBSET | TWL5031))) {
|
||||
child = add_child(SUB_CHIP_ID3, "twl4030_bci",
|
||||
child = add_child(TWL_MODULE_MAIN_CHARGE, "twl4030_bci",
|
||||
pdata->bci, sizeof(*pdata->bci), false,
|
||||
/* irq0 = CHG_PRES, irq1 = BCI */
|
||||
irq_base + BCI_PRES_INTR_OFFSET,
|
||||
@ -1145,25 +1105,23 @@ static int twl_remove(struct i2c_client *client)
|
||||
unsigned i, num_slaves;
|
||||
int status;
|
||||
|
||||
if (twl_class_is_4030()) {
|
||||
if (twl_class_is_4030())
|
||||
status = twl4030_exit_irq();
|
||||
num_slaves = TWL_NUM_SLAVES;
|
||||
} else {
|
||||
else
|
||||
status = twl6030_exit_irq();
|
||||
num_slaves = TWL_NUM_SLAVES - 1;
|
||||
}
|
||||
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
num_slaves = twl_get_num_slaves();
|
||||
for (i = 0; i < num_slaves; i++) {
|
||||
struct twl_client *twl = &twl_modules[i];
|
||||
struct twl_client *twl = &twl_priv->twl_modules[i];
|
||||
|
||||
if (twl->client && twl->client != client)
|
||||
i2c_unregister_device(twl->client);
|
||||
twl_modules[i].client = NULL;
|
||||
twl->client = NULL;
|
||||
}
|
||||
inuse = false;
|
||||
twl_priv->ready = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1179,6 +1137,17 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
int status;
|
||||
unsigned i, num_slaves;
|
||||
|
||||
if (!node && !pdata) {
|
||||
dev_err(&client->dev, "no platform data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (twl_priv) {
|
||||
dev_dbg(&client->dev, "only one instance of %s allowed\n",
|
||||
DRIVER_NAME);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
pdev = platform_device_alloc(DRIVER_NAME, -1);
|
||||
if (!pdev) {
|
||||
dev_err(&client->dev, "can't alloc pdev\n");
|
||||
@ -1191,54 +1160,44 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
return status;
|
||||
}
|
||||
|
||||
if (node && !pdata) {
|
||||
/*
|
||||
* XXX: Temporary pdata until the information is correctly
|
||||
* retrieved by every TWL modules from DT.
|
||||
*/
|
||||
pdata = devm_kzalloc(&client->dev,
|
||||
sizeof(struct twl4030_platform_data),
|
||||
GFP_KERNEL);
|
||||
if (!pdata) {
|
||||
status = -ENOMEM;
|
||||
goto free;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pdata) {
|
||||
dev_dbg(&client->dev, "no platform data?\n");
|
||||
status = -EINVAL;
|
||||
goto free;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, pdata);
|
||||
|
||||
if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
|
||||
dev_dbg(&client->dev, "can't talk I2C?\n");
|
||||
status = -EIO;
|
||||
goto free;
|
||||
}
|
||||
|
||||
if (inuse) {
|
||||
dev_dbg(&client->dev, "driver is already in use\n");
|
||||
status = -EBUSY;
|
||||
twl_priv = devm_kzalloc(&client->dev, sizeof(struct twl_private),
|
||||
GFP_KERNEL);
|
||||
if (!twl_priv) {
|
||||
status = -ENOMEM;
|
||||
goto free;
|
||||
}
|
||||
|
||||
if ((id->driver_data) & TWL6030_CLASS) {
|
||||
twl_id = TWL6030_CLASS_ID;
|
||||
twl_map = &twl6030_map[0];
|
||||
twl_priv->twl_id = TWL6030_CLASS_ID;
|
||||
twl_priv->twl_map = &twl6030_map[0];
|
||||
/* The charger base address is different in twl6025 */
|
||||
if ((id->driver_data) & TWL6025_SUBCLASS)
|
||||
twl_priv->twl_map[TWL_MODULE_MAIN_CHARGE].base =
|
||||
TWL6025_BASEADD_CHARGER;
|
||||
twl_regmap_config = twl6030_regmap_config;
|
||||
num_slaves = TWL_NUM_SLAVES - 1;
|
||||
} else {
|
||||
twl_id = TWL4030_CLASS_ID;
|
||||
twl_map = &twl4030_map[0];
|
||||
twl_priv->twl_id = TWL4030_CLASS_ID;
|
||||
twl_priv->twl_map = &twl4030_map[0];
|
||||
twl_regmap_config = twl4030_regmap_config;
|
||||
num_slaves = TWL_NUM_SLAVES;
|
||||
}
|
||||
|
||||
num_slaves = twl_get_num_slaves();
|
||||
twl_priv->twl_modules = devm_kzalloc(&client->dev,
|
||||
sizeof(struct twl_client) * num_slaves,
|
||||
GFP_KERNEL);
|
||||
if (!twl_priv->twl_modules) {
|
||||
status = -ENOMEM;
|
||||
goto free;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_slaves; i++) {
|
||||
struct twl_client *twl = &twl_modules[i];
|
||||
struct twl_client *twl = &twl_priv->twl_modules[i];
|
||||
|
||||
if (i == 0) {
|
||||
twl->client = client;
|
||||
@ -1264,19 +1223,19 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
}
|
||||
}
|
||||
|
||||
inuse = true;
|
||||
twl_priv->ready = true;
|
||||
|
||||
/* setup clock framework */
|
||||
clocks_init(&pdev->dev, pdata->clock);
|
||||
clocks_init(&pdev->dev, pdata ? pdata->clock : NULL);
|
||||
|
||||
/* read TWL IDCODE Register */
|
||||
if (twl_id == TWL4030_CLASS_ID) {
|
||||
if (twl_class_is_4030()) {
|
||||
status = twl_read_idcode_register();
|
||||
WARN(status < 0, "Error: reading twl_idcode register value\n");
|
||||
}
|
||||
|
||||
/* load power event scripts */
|
||||
if (IS_ENABLED(CONFIG_TWL4030_POWER) && pdata->power)
|
||||
if (IS_ENABLED(CONFIG_TWL4030_POWER) && pdata && pdata->power)
|
||||
twl4030_power_init(pdata->power);
|
||||
|
||||
/* Maybe init the T2 Interrupt subsystem */
|
||||
@ -1308,10 +1267,9 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);
|
||||
}
|
||||
|
||||
status = -ENODEV;
|
||||
if (node)
|
||||
status = of_platform_populate(node, NULL, NULL, &client->dev);
|
||||
if (status)
|
||||
else
|
||||
status = add_children(pdata, irq_base, id->driver_data);
|
||||
|
||||
fail:
|
||||
|
@ -49,6 +49,8 @@
|
||||
#define SYS_ID_HBI_SHIFT 16
|
||||
#define SYS_PROCIDx_HBI_SHIFT 0
|
||||
|
||||
#define SYS_LED_LED(n) (1 << (n))
|
||||
|
||||
#define SYS_MCI_CARDIN (1 << 0)
|
||||
#define SYS_MCI_WPROT (1 << 1)
|
||||
|
||||
@ -336,34 +338,40 @@ void __init vexpress_sysreg_early_init(void __iomem *base)
|
||||
|
||||
void __init vexpress_sysreg_of_early_init(void)
|
||||
{
|
||||
struct device_node *node = of_find_compatible_node(NULL, NULL,
|
||||
"arm,vexpress-sysreg");
|
||||
struct device_node *node;
|
||||
|
||||
if (vexpress_sysreg_base)
|
||||
return;
|
||||
|
||||
node = of_find_compatible_node(NULL, NULL, "arm,vexpress-sysreg");
|
||||
if (node) {
|
||||
vexpress_sysreg_base = of_iomap(node, 0);
|
||||
vexpress_sysreg_setup(node);
|
||||
} else {
|
||||
pr_info("vexpress-sysreg: No Device Tree node found.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define VEXPRESS_SYSREG_GPIO(_name, _reg, _value) \
|
||||
[VEXPRESS_GPIO_##_name] = { \
|
||||
.reg = _reg, \
|
||||
.value = _reg##_##_value, \
|
||||
}
|
||||
|
||||
static struct vexpress_sysreg_gpio {
|
||||
unsigned long reg;
|
||||
u32 value;
|
||||
} vexpress_sysreg_gpios[] = {
|
||||
[VEXPRESS_GPIO_MMC_CARDIN] = {
|
||||
.reg = SYS_MCI,
|
||||
.value = SYS_MCI_CARDIN,
|
||||
},
|
||||
[VEXPRESS_GPIO_MMC_WPROT] = {
|
||||
.reg = SYS_MCI,
|
||||
.value = SYS_MCI_WPROT,
|
||||
},
|
||||
[VEXPRESS_GPIO_FLASH_WPn] = {
|
||||
.reg = SYS_FLASH,
|
||||
.value = SYS_FLASH_WPn,
|
||||
},
|
||||
VEXPRESS_SYSREG_GPIO(MMC_CARDIN, SYS_MCI, CARDIN),
|
||||
VEXPRESS_SYSREG_GPIO(MMC_WPROT, SYS_MCI, WPROT),
|
||||
VEXPRESS_SYSREG_GPIO(FLASH_WPn, SYS_FLASH, WPn),
|
||||
VEXPRESS_SYSREG_GPIO(LED0, SYS_LED, LED(0)),
|
||||
VEXPRESS_SYSREG_GPIO(LED1, SYS_LED, LED(1)),
|
||||
VEXPRESS_SYSREG_GPIO(LED2, SYS_LED, LED(2)),
|
||||
VEXPRESS_SYSREG_GPIO(LED3, SYS_LED, LED(3)),
|
||||
VEXPRESS_SYSREG_GPIO(LED4, SYS_LED, LED(4)),
|
||||
VEXPRESS_SYSREG_GPIO(LED5, SYS_LED, LED(5)),
|
||||
VEXPRESS_SYSREG_GPIO(LED6, SYS_LED, LED(6)),
|
||||
VEXPRESS_SYSREG_GPIO(LED7, SYS_LED, LED(7)),
|
||||
};
|
||||
|
||||
static int vexpress_sysreg_gpio_direction_input(struct gpio_chip *chip,
|
||||
@ -372,12 +380,6 @@ static int vexpress_sysreg_gpio_direction_input(struct gpio_chip *chip,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vexpress_sysreg_gpio_direction_output(struct gpio_chip *chip,
|
||||
unsigned offset, int value)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vexpress_sysreg_gpio_get(struct gpio_chip *chip,
|
||||
unsigned offset)
|
||||
{
|
||||
@ -401,6 +403,14 @@ static void vexpress_sysreg_gpio_set(struct gpio_chip *chip,
|
||||
writel(reg_value, vexpress_sysreg_base + gpio->reg);
|
||||
}
|
||||
|
||||
static int vexpress_sysreg_gpio_direction_output(struct gpio_chip *chip,
|
||||
unsigned offset, int value)
|
||||
{
|
||||
vexpress_sysreg_gpio_set(chip, offset, value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct gpio_chip vexpress_sysreg_gpio_chip = {
|
||||
.label = "vexpress-sysreg",
|
||||
.direction_input = vexpress_sysreg_gpio_direction_input,
|
||||
@ -412,6 +422,30 @@ static struct gpio_chip vexpress_sysreg_gpio_chip = {
|
||||
};
|
||||
|
||||
|
||||
#define VEXPRESS_SYSREG_GREEN_LED(_name, _default_trigger, _gpio) \
|
||||
{ \
|
||||
.name = "v2m:green:"_name, \
|
||||
.default_trigger = _default_trigger, \
|
||||
.gpio = VEXPRESS_GPIO_##_gpio, \
|
||||
}
|
||||
|
||||
struct gpio_led vexpress_sysreg_leds[] = {
|
||||
VEXPRESS_SYSREG_GREEN_LED("user1", "heartbeat", LED0),
|
||||
VEXPRESS_SYSREG_GREEN_LED("user2", "mmc0", LED1),
|
||||
VEXPRESS_SYSREG_GREEN_LED("user3", "cpu0", LED2),
|
||||
VEXPRESS_SYSREG_GREEN_LED("user4", "cpu1", LED3),
|
||||
VEXPRESS_SYSREG_GREEN_LED("user5", "cpu2", LED4),
|
||||
VEXPRESS_SYSREG_GREEN_LED("user6", "cpu3", LED5),
|
||||
VEXPRESS_SYSREG_GREEN_LED("user7", "cpu4", LED6),
|
||||
VEXPRESS_SYSREG_GREEN_LED("user8", "cpu5", LED7),
|
||||
};
|
||||
|
||||
struct gpio_led_platform_data vexpress_sysreg_leds_pdata = {
|
||||
.num_leds = ARRAY_SIZE(vexpress_sysreg_leds),
|
||||
.leds = vexpress_sysreg_leds,
|
||||
};
|
||||
|
||||
|
||||
static ssize_t vexpress_sysreg_sys_id_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@ -456,6 +490,10 @@ static int vexpress_sysreg_probe(struct platform_device *pdev)
|
||||
return err;
|
||||
}
|
||||
|
||||
platform_device_register_data(vexpress_sysreg_dev, "leds-gpio",
|
||||
PLATFORM_DEVID_AUTO, &vexpress_sysreg_leds_pdata,
|
||||
sizeof(vexpress_sysreg_leds_pdata));
|
||||
|
||||
vexpress_sysreg_dev = &pdev->dev;
|
||||
|
||||
device_create_file(vexpress_sysreg_dev, &dev_attr_sys_id);
|
||||
@ -478,6 +516,7 @@ static struct platform_driver vexpress_sysreg_driver = {
|
||||
|
||||
static int __init vexpress_sysreg_init(void)
|
||||
{
|
||||
vexpress_sysreg_of_early_init();
|
||||
return platform_driver_register(&vexpress_sysreg_driver);
|
||||
}
|
||||
core_initcall(vexpress_sysreg_init);
|
||||
|
@ -59,12 +59,13 @@ static const struct reg_default wm5102_reva_patch[] = {
|
||||
static const struct reg_default wm5102_revb_patch[] = {
|
||||
{ 0x80, 0x0003 },
|
||||
{ 0x081, 0xE022 },
|
||||
{ 0x410, 0x6080 },
|
||||
{ 0x418, 0x6080 },
|
||||
{ 0x420, 0x6080 },
|
||||
{ 0x410, 0x4080 },
|
||||
{ 0x418, 0x4080 },
|
||||
{ 0x420, 0x4080 },
|
||||
{ 0x428, 0xC000 },
|
||||
{ 0x441, 0x8014 },
|
||||
{ 0x4B0, 0x0066 },
|
||||
{ 0x458, 0x000b },
|
||||
{ 0x212, 0x0000 },
|
||||
{ 0x80, 0x0000 },
|
||||
};
|
||||
|
||||
@ -231,11 +232,9 @@ const struct regmap_irq_chip wm5102_irq = {
|
||||
static const struct reg_default wm5102_reg_default[] = {
|
||||
{ 0x00000008, 0x0019 }, /* R8 - Ctrl IF SPI CFG 1 */
|
||||
{ 0x00000009, 0x0001 }, /* R9 - Ctrl IF I2C1 CFG 1 */
|
||||
{ 0x0000000D, 0x0000 }, /* R13 - Ctrl IF Status 1 */
|
||||
{ 0x00000016, 0x0000 }, /* R22 - Write Sequencer Ctrl 0 */
|
||||
{ 0x00000017, 0x0000 }, /* R23 - Write Sequencer Ctrl 1 */
|
||||
{ 0x00000018, 0x0000 }, /* R24 - Write Sequencer Ctrl 2 */
|
||||
{ 0x0000001A, 0x0000 }, /* R26 - Write Sequencer PROM */
|
||||
{ 0x00000020, 0x0000 }, /* R32 - Tone Generator 1 */
|
||||
{ 0x00000021, 0x1000 }, /* R33 - Tone Generator 2 */
|
||||
{ 0x00000022, 0x0000 }, /* R34 - Tone Generator 3 */
|
||||
@ -250,12 +249,14 @@ static const struct reg_default wm5102_reg_default[] = {
|
||||
{ 0x00000062, 0x01FF }, /* R98 - Sample Rate Sequence Select 2 */
|
||||
{ 0x00000063, 0x01FF }, /* R99 - Sample Rate Sequence Select 3 */
|
||||
{ 0x00000064, 0x01FF }, /* R100 - Sample Rate Sequence Select 4 */
|
||||
{ 0x00000068, 0x01FF }, /* R104 - Always On Triggers Sequence Select 1 */
|
||||
{ 0x00000069, 0x01FF }, /* R105 - Always On Triggers Sequence Select 2 */
|
||||
{ 0x0000006A, 0x01FF }, /* R106 - Always On Triggers Sequence Select 3 */
|
||||
{ 0x0000006B, 0x01FF }, /* R107 - Always On Triggers Sequence Select 4 */
|
||||
{ 0x0000006C, 0x01FF }, /* R108 - Always On Triggers Sequence Select 5 */
|
||||
{ 0x0000006D, 0x01FF }, /* R109 - Always On Triggers Sequence Select 6 */
|
||||
{ 0x00000066, 0x01FF }, /* R102 - Always On Triggers Sequence Select 1 */
|
||||
{ 0x00000067, 0x01FF }, /* R103 - Always On Triggers Sequence Select 2 */
|
||||
{ 0x00000068, 0x01FF }, /* R104 - Always On Triggers Sequence Select 3 */
|
||||
{ 0x00000069, 0x01FF }, /* R105 - Always On Triggers Sequence Select 4 */
|
||||
{ 0x0000006A, 0x01FF }, /* R106 - Always On Triggers Sequence Select 5 */
|
||||
{ 0x0000006B, 0x01FF }, /* R107 - Always On Triggers Sequence Select 6 */
|
||||
{ 0x0000006E, 0x01FF }, /* R110 - Trigger Sequence Select 32 */
|
||||
{ 0x0000006F, 0x01FF }, /* R111 - Trigger Sequence Select 33 */
|
||||
{ 0x00000070, 0x0000 }, /* R112 - Comfort Noise Generator */
|
||||
{ 0x00000090, 0x0000 }, /* R144 - Haptics Control 1 */
|
||||
{ 0x00000091, 0x7FFF }, /* R145 - Haptics Control 2 */
|
||||
@ -265,13 +266,14 @@ static const struct reg_default wm5102_reg_default[] = {
|
||||
{ 0x00000095, 0x0000 }, /* R149 - Haptics phase 2 duration */
|
||||
{ 0x00000096, 0x0000 }, /* R150 - Haptics phase 3 intensity */
|
||||
{ 0x00000097, 0x0000 }, /* R151 - Haptics phase 3 duration */
|
||||
{ 0x00000100, 0x0001 }, /* R256 - Clock 32k 1 */
|
||||
{ 0x00000100, 0x0002 }, /* R256 - Clock 32k 1 */
|
||||
{ 0x00000101, 0x0304 }, /* R257 - System Clock 1 */
|
||||
{ 0x00000102, 0x0011 }, /* R258 - Sample rate 1 */
|
||||
{ 0x00000103, 0x0011 }, /* R259 - Sample rate 2 */
|
||||
{ 0x00000104, 0x0011 }, /* R260 - Sample rate 3 */
|
||||
{ 0x00000112, 0x0305 }, /* R274 - Async clock 1 */
|
||||
{ 0x00000113, 0x0011 }, /* R275 - Async sample rate 1 */
|
||||
{ 0x00000114, 0x0011 }, /* R276 - Async sample rate 2 */
|
||||
{ 0x00000149, 0x0000 }, /* R329 - Output system clock */
|
||||
{ 0x0000014A, 0x0000 }, /* R330 - Output async clock */
|
||||
{ 0x00000152, 0x0000 }, /* R338 - Rate Estimator 1 */
|
||||
@ -280,13 +282,14 @@ static const struct reg_default wm5102_reg_default[] = {
|
||||
{ 0x00000155, 0x0000 }, /* R341 - Rate Estimator 4 */
|
||||
{ 0x00000156, 0x0000 }, /* R342 - Rate Estimator 5 */
|
||||
{ 0x00000161, 0x0000 }, /* R353 - Dynamic Frequency Scaling 1 */
|
||||
{ 0x00000171, 0x0000 }, /* R369 - FLL1 Control 1 */
|
||||
{ 0x00000171, 0x0002 }, /* R369 - FLL1 Control 1 */
|
||||
{ 0x00000172, 0x0008 }, /* R370 - FLL1 Control 2 */
|
||||
{ 0x00000173, 0x0018 }, /* R371 - FLL1 Control 3 */
|
||||
{ 0x00000174, 0x007D }, /* R372 - FLL1 Control 4 */
|
||||
{ 0x00000175, 0x0004 }, /* R373 - FLL1 Control 5 */
|
||||
{ 0x00000176, 0x0000 }, /* R374 - FLL1 Control 6 */
|
||||
{ 0x00000177, 0x0181 }, /* R375 - FLL1 Loop Filter Test 1 */
|
||||
{ 0x00000178, 0x0000 }, /* R376 - FLL1 NCO Test 0 */
|
||||
{ 0x00000181, 0x0000 }, /* R385 - FLL1 Synchroniser 1 */
|
||||
{ 0x00000182, 0x0000 }, /* R386 - FLL1 Synchroniser 2 */
|
||||
{ 0x00000183, 0x0000 }, /* R387 - FLL1 Synchroniser 3 */
|
||||
@ -302,6 +305,7 @@ static const struct reg_default wm5102_reg_default[] = {
|
||||
{ 0x00000195, 0x0004 }, /* R405 - FLL2 Control 5 */
|
||||
{ 0x00000196, 0x0000 }, /* R406 - FLL2 Control 6 */
|
||||
{ 0x00000197, 0x0000 }, /* R407 - FLL2 Loop Filter Test 1 */
|
||||
{ 0x00000198, 0x0000 }, /* R408 - FLL2 NCO Test 0 */
|
||||
{ 0x000001A1, 0x0000 }, /* R417 - FLL2 Synchroniser 1 */
|
||||
{ 0x000001A2, 0x0000 }, /* R418 - FLL2 Synchroniser 2 */
|
||||
{ 0x000001A3, 0x0000 }, /* R419 - FLL2 Synchroniser 3 */
|
||||
@ -317,8 +321,12 @@ static const struct reg_default wm5102_reg_default[] = {
|
||||
{ 0x00000218, 0x01A6 }, /* R536 - Mic Bias Ctrl 1 */
|
||||
{ 0x00000219, 0x01A6 }, /* R537 - Mic Bias Ctrl 2 */
|
||||
{ 0x0000021A, 0x01A6 }, /* R538 - Mic Bias Ctrl 3 */
|
||||
{ 0x00000225, 0x0400 }, /* R549 - HP Ctrl 1L */
|
||||
{ 0x00000226, 0x0400 }, /* R550 - HP Ctrl 1R */
|
||||
{ 0x00000293, 0x0000 }, /* R659 - Accessory Detect Mode 1 */
|
||||
{ 0x0000029B, 0x0020 }, /* R667 - Headphone Detect 1 */
|
||||
{ 0x0000029C, 0x0000 }, /* R668 - Headphone Detect 2 */
|
||||
{ 0x0000029F, 0x0000 }, /* R671 - Headphone Detect Test */
|
||||
{ 0x000002A2, 0x0000 }, /* R674 - Micd clamp control */
|
||||
{ 0x000002A3, 0x1102 }, /* R675 - Mic Detect 1 */
|
||||
{ 0x000002A4, 0x009F }, /* R676 - Mic Detect 2 */
|
||||
@ -350,53 +358,44 @@ static const struct reg_default wm5102_reg_default[] = {
|
||||
{ 0x00000400, 0x0000 }, /* R1024 - Output Enables 1 */
|
||||
{ 0x00000408, 0x0000 }, /* R1032 - Output Rate 1 */
|
||||
{ 0x00000409, 0x0022 }, /* R1033 - Output Volume Ramp */
|
||||
{ 0x00000410, 0x0080 }, /* R1040 - Output Path Config 1L */
|
||||
{ 0x00000410, 0x4080 }, /* R1040 - Output Path Config 1L */
|
||||
{ 0x00000411, 0x0180 }, /* R1041 - DAC Digital Volume 1L */
|
||||
{ 0x00000412, 0x0080 }, /* R1042 - DAC Volume Limit 1L */
|
||||
{ 0x00000412, 0x0081 }, /* R1042 - DAC Volume Limit 1L */
|
||||
{ 0x00000413, 0x0001 }, /* R1043 - Noise Gate Select 1L */
|
||||
{ 0x00000414, 0x0080 }, /* R1044 - Output Path Config 1R */
|
||||
{ 0x00000415, 0x0180 }, /* R1045 - DAC Digital Volume 1R */
|
||||
{ 0x00000416, 0x0080 }, /* R1046 - DAC Volume Limit 1R */
|
||||
{ 0x00000416, 0x0081 }, /* R1046 - DAC Volume Limit 1R */
|
||||
{ 0x00000417, 0x0002 }, /* R1047 - Noise Gate Select 1R */
|
||||
{ 0x00000418, 0x0080 }, /* R1048 - Output Path Config 2L */
|
||||
{ 0x00000418, 0x4080 }, /* R1048 - Output Path Config 2L */
|
||||
{ 0x00000419, 0x0180 }, /* R1049 - DAC Digital Volume 2L */
|
||||
{ 0x0000041A, 0x0080 }, /* R1050 - DAC Volume Limit 2L */
|
||||
{ 0x0000041A, 0x0081 }, /* R1050 - DAC Volume Limit 2L */
|
||||
{ 0x0000041B, 0x0004 }, /* R1051 - Noise Gate Select 2L */
|
||||
{ 0x0000041C, 0x0080 }, /* R1052 - Output Path Config 2R */
|
||||
{ 0x0000041D, 0x0180 }, /* R1053 - DAC Digital Volume 2R */
|
||||
{ 0x0000041E, 0x0080 }, /* R1054 - DAC Volume Limit 2R */
|
||||
{ 0x0000041E, 0x0081 }, /* R1054 - DAC Volume Limit 2R */
|
||||
{ 0x0000041F, 0x0008 }, /* R1055 - Noise Gate Select 2R */
|
||||
{ 0x00000420, 0x0080 }, /* R1056 - Output Path Config 3L */
|
||||
{ 0x00000420, 0x4080 }, /* R1056 - Output Path Config 3L */
|
||||
{ 0x00000421, 0x0180 }, /* R1057 - DAC Digital Volume 3L */
|
||||
{ 0x00000422, 0x0080 }, /* R1058 - DAC Volume Limit 3L */
|
||||
{ 0x00000422, 0x0081 }, /* R1058 - DAC Volume Limit 3L */
|
||||
{ 0x00000423, 0x0010 }, /* R1059 - Noise Gate Select 3L */
|
||||
{ 0x00000424, 0x0080 }, /* R1060 - Output Path Config 3R */
|
||||
{ 0x00000425, 0x0180 }, /* R1061 - DAC Digital Volume 3R */
|
||||
{ 0x00000426, 0x0080 }, /* R1062 - DAC Volume Limit 3R */
|
||||
{ 0x00000428, 0x0000 }, /* R1064 - Output Path Config 4L */
|
||||
{ 0x00000428, 0xC000 }, /* R1064 - Output Path Config 4L */
|
||||
{ 0x00000429, 0x0180 }, /* R1065 - DAC Digital Volume 4L */
|
||||
{ 0x0000042A, 0x0080 }, /* R1066 - Out Volume 4L */
|
||||
{ 0x0000042A, 0x0081 }, /* R1066 - Out Volume 4L */
|
||||
{ 0x0000042B, 0x0040 }, /* R1067 - Noise Gate Select 4L */
|
||||
{ 0x0000042C, 0x0000 }, /* R1068 - Output Path Config 4R */
|
||||
{ 0x0000042D, 0x0180 }, /* R1069 - DAC Digital Volume 4R */
|
||||
{ 0x0000042E, 0x0080 }, /* R1070 - Out Volume 4R */
|
||||
{ 0x0000042E, 0x0081 }, /* R1070 - Out Volume 4R */
|
||||
{ 0x0000042F, 0x0080 }, /* R1071 - Noise Gate Select 4R */
|
||||
{ 0x00000430, 0x0000 }, /* R1072 - Output Path Config 5L */
|
||||
{ 0x00000431, 0x0180 }, /* R1073 - DAC Digital Volume 5L */
|
||||
{ 0x00000432, 0x0080 }, /* R1074 - DAC Volume Limit 5L */
|
||||
{ 0x00000432, 0x0081 }, /* R1074 - DAC Volume Limit 5L */
|
||||
{ 0x00000433, 0x0100 }, /* R1075 - Noise Gate Select 5L */
|
||||
{ 0x00000434, 0x0000 }, /* R1076 - Output Path Config 5R */
|
||||
{ 0x00000435, 0x0180 }, /* R1077 - DAC Digital Volume 5R */
|
||||
{ 0x00000436, 0x0080 }, /* R1078 - DAC Volume Limit 5R */
|
||||
{ 0x00000437, 0x0200 }, /* R1079 - Noise Gate Select 5R */
|
||||
{ 0x00000436, 0x0081 }, /* R1078 - DAC Volume Limit 5R */
|
||||
{ 0x00000437, 0x0200 }, /* R1079 - Noise Gate Select 5R */
|
||||
{ 0x00000450, 0x0000 }, /* R1104 - DAC AEC Control 1 */
|
||||
{ 0x00000458, 0x0001 }, /* R1112 - Noise Gate Control */
|
||||
{ 0x00000490, 0x0069 }, /* R1168 - PDM SPK1 CTRL 1 */
|
||||
{ 0x00000491, 0x0000 }, /* R1169 - PDM SPK1 CTRL 2 */
|
||||
{ 0x000004DC, 0x0000 }, /* R1244 - DAC comp 1 */
|
||||
{ 0x000004DD, 0x0000 }, /* R1245 - DAC comp 2 */
|
||||
{ 0x000004DE, 0x0000 }, /* R1246 - DAC comp 3 */
|
||||
{ 0x000004DF, 0x0000 }, /* R1247 - DAC comp 4 */
|
||||
{ 0x00000500, 0x000C }, /* R1280 - AIF1 BCLK Ctrl */
|
||||
{ 0x00000501, 0x0008 }, /* R1281 - AIF1 Tx Pin Ctrl */
|
||||
{ 0x00000502, 0x0000 }, /* R1282 - AIF1 Rx Pin Ctrl */
|
||||
@ -424,7 +423,6 @@ static const struct reg_default wm5102_reg_default[] = {
|
||||
{ 0x00000518, 0x0007 }, /* R1304 - AIF1 Frame Ctrl 18 */
|
||||
{ 0x00000519, 0x0000 }, /* R1305 - AIF1 Tx Enables */
|
||||
{ 0x0000051A, 0x0000 }, /* R1306 - AIF1 Rx Enables */
|
||||
{ 0x0000051B, 0x0000 }, /* R1307 - AIF1 Force Write */
|
||||
{ 0x00000540, 0x000C }, /* R1344 - AIF2 BCLK Ctrl */
|
||||
{ 0x00000541, 0x0008 }, /* R1345 - AIF2 Tx Pin Ctrl */
|
||||
{ 0x00000542, 0x0000 }, /* R1346 - AIF2 Rx Pin Ctrl */
|
||||
@ -440,7 +438,6 @@ static const struct reg_default wm5102_reg_default[] = {
|
||||
{ 0x00000552, 0x0001 }, /* R1362 - AIF2 Frame Ctrl 12 */
|
||||
{ 0x00000559, 0x0000 }, /* R1369 - AIF2 Tx Enables */
|
||||
{ 0x0000055A, 0x0000 }, /* R1370 - AIF2 Rx Enables */
|
||||
{ 0x0000055B, 0x0000 }, /* R1371 - AIF2 Force Write */
|
||||
{ 0x00000580, 0x000C }, /* R1408 - AIF3 BCLK Ctrl */
|
||||
{ 0x00000581, 0x0008 }, /* R1409 - AIF3 Tx Pin Ctrl */
|
||||
{ 0x00000582, 0x0000 }, /* R1410 - AIF3 Rx Pin Ctrl */
|
||||
@ -456,7 +453,6 @@ static const struct reg_default wm5102_reg_default[] = {
|
||||
{ 0x00000592, 0x0001 }, /* R1426 - AIF3 Frame Ctrl 12 */
|
||||
{ 0x00000599, 0x0000 }, /* R1433 - AIF3 Tx Enables */
|
||||
{ 0x0000059A, 0x0000 }, /* R1434 - AIF3 Rx Enables */
|
||||
{ 0x0000059B, 0x0000 }, /* R1435 - AIF3 Force Write */
|
||||
{ 0x000005E3, 0x0004 }, /* R1507 - SLIMbus Framer Ref Gear */
|
||||
{ 0x000005E5, 0x0000 }, /* R1509 - SLIMbus Rates 1 */
|
||||
{ 0x000005E6, 0x0000 }, /* R1510 - SLIMbus Rates 2 */
|
||||
@ -780,22 +776,6 @@ static const struct reg_default wm5102_reg_default[] = {
|
||||
{ 0x000008CD, 0x0080 }, /* R2253 - DRC1RMIX Input 3 Volume */
|
||||
{ 0x000008CE, 0x0000 }, /* R2254 - DRC1RMIX Input 4 Source */
|
||||
{ 0x000008CF, 0x0080 }, /* R2255 - DRC1RMIX Input 4 Volume */
|
||||
{ 0x000008D0, 0x0000 }, /* R2256 - DRC2LMIX Input 1 Source */
|
||||
{ 0x000008D1, 0x0080 }, /* R2257 - DRC2LMIX Input 1 Volume */
|
||||
{ 0x000008D2, 0x0000 }, /* R2258 - DRC2LMIX Input 2 Source */
|
||||
{ 0x000008D3, 0x0080 }, /* R2259 - DRC2LMIX Input 2 Volume */
|
||||
{ 0x000008D4, 0x0000 }, /* R2260 - DRC2LMIX Input 3 Source */
|
||||
{ 0x000008D5, 0x0080 }, /* R2261 - DRC2LMIX Input 3 Volume */
|
||||
{ 0x000008D6, 0x0000 }, /* R2262 - DRC2LMIX Input 4 Source */
|
||||
{ 0x000008D7, 0x0080 }, /* R2263 - DRC2LMIX Input 4 Volume */
|
||||
{ 0x000008D8, 0x0000 }, /* R2264 - DRC2RMIX Input 1 Source */
|
||||
{ 0x000008D9, 0x0080 }, /* R2265 - DRC2RMIX Input 1 Volume */
|
||||
{ 0x000008DA, 0x0000 }, /* R2266 - DRC2RMIX Input 2 Source */
|
||||
{ 0x000008DB, 0x0080 }, /* R2267 - DRC2RMIX Input 2 Volume */
|
||||
{ 0x000008DC, 0x0000 }, /* R2268 - DRC2RMIX Input 3 Source */
|
||||
{ 0x000008DD, 0x0080 }, /* R2269 - DRC2RMIX Input 3 Volume */
|
||||
{ 0x000008DE, 0x0000 }, /* R2270 - DRC2RMIX Input 4 Source */
|
||||
{ 0x000008DF, 0x0080 }, /* R2271 - DRC2RMIX Input 4 Volume */
|
||||
{ 0x00000900, 0x0000 }, /* R2304 - HPLP1MIX Input 1 Source */
|
||||
{ 0x00000901, 0x0080 }, /* R2305 - HPLP1MIX Input 1 Volume */
|
||||
{ 0x00000902, 0x0000 }, /* R2306 - HPLP1MIX Input 2 Source */
|
||||
@ -887,7 +867,7 @@ static const struct reg_default wm5102_reg_default[] = {
|
||||
{ 0x00000D1B, 0xFFFF }, /* R3355 - IRQ2 Status 4 Mask */
|
||||
{ 0x00000D1C, 0xFFFF }, /* R3356 - IRQ2 Status 5 Mask */
|
||||
{ 0x00000D1F, 0x0000 }, /* R3359 - IRQ2 Control */
|
||||
{ 0x00000D41, 0x0000 }, /* R3393 - ADSP2 IRQ0 */
|
||||
{ 0x00000D50, 0x0000 }, /* R3408 - AOD wkup and trig */
|
||||
{ 0x00000D53, 0xFFFF }, /* R3411 - AOD IRQ Mask IRQ1 */
|
||||
{ 0x00000D54, 0xFFFF }, /* R3412 - AOD IRQ Mask IRQ2 */
|
||||
{ 0x00000D56, 0x0000 }, /* R3414 - Jack detect debounce */
|
||||
@ -982,11 +962,6 @@ static const struct reg_default wm5102_reg_default[] = {
|
||||
{ 0x00000E82, 0x0018 }, /* R3714 - DRC1 ctrl3 */
|
||||
{ 0x00000E83, 0x0000 }, /* R3715 - DRC1 ctrl4 */
|
||||
{ 0x00000E84, 0x0000 }, /* R3716 - DRC1 ctrl5 */
|
||||
{ 0x00000E89, 0x0018 }, /* R3721 - DRC2 ctrl1 */
|
||||
{ 0x00000E8A, 0x0933 }, /* R3722 - DRC2 ctrl2 */
|
||||
{ 0x00000E8B, 0x0018 }, /* R3723 - DRC2 ctrl3 */
|
||||
{ 0x00000E8C, 0x0000 }, /* R3724 - DRC2 ctrl4 */
|
||||
{ 0x00000E8D, 0x0000 }, /* R3725 - DRC2 ctrl5 */
|
||||
{ 0x00000EC0, 0x0000 }, /* R3776 - HPLPF1_1 */
|
||||
{ 0x00000EC1, 0x0000 }, /* R3777 - HPLPF1_2 */
|
||||
{ 0x00000EC4, 0x0000 }, /* R3780 - HPLPF2_1 */
|
||||
@ -997,16 +972,12 @@ static const struct reg_default wm5102_reg_default[] = {
|
||||
{ 0x00000ECD, 0x0000 }, /* R3789 - HPLPF4_2 */
|
||||
{ 0x00000EE0, 0x0000 }, /* R3808 - ASRC_ENABLE */
|
||||
{ 0x00000EE2, 0x0000 }, /* R3810 - ASRC_RATE1 */
|
||||
{ 0x00000EE3, 0x4000 }, /* R3811 - ASRC_RATE2 */
|
||||
{ 0x00000EF0, 0x0000 }, /* R3824 - ISRC 1 CTRL 1 */
|
||||
{ 0x00000EF1, 0x0000 }, /* R3825 - ISRC 1 CTRL 2 */
|
||||
{ 0x00000EF2, 0x0000 }, /* R3826 - ISRC 1 CTRL 3 */
|
||||
{ 0x00000EF3, 0x0000 }, /* R3827 - ISRC 2 CTRL 1 */
|
||||
{ 0x00000EF4, 0x0000 }, /* R3828 - ISRC 2 CTRL 2 */
|
||||
{ 0x00000EF5, 0x0000 }, /* R3829 - ISRC 2 CTRL 3 */
|
||||
{ 0x00000EF6, 0x0000 }, /* R3830 - ISRC 3 CTRL 1 */
|
||||
{ 0x00000EF7, 0x0000 }, /* R3831 - ISRC 3 CTRL 2 */
|
||||
{ 0x00000EF8, 0x0000 }, /* R3832 - ISRC 3 CTRL 3 */
|
||||
{ 0x00001100, 0x0010 }, /* R4352 - DSP1 Control 1 */
|
||||
{ 0x00001101, 0x0000 }, /* R4353 - DSP1 Clocking 1 */
|
||||
};
|
||||
@ -1833,17 +1804,24 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg)
|
||||
case ARIZONA_DSP1_STATUS_1:
|
||||
case ARIZONA_DSP1_STATUS_2:
|
||||
case ARIZONA_DSP1_STATUS_3:
|
||||
case ARIZONA_DSP1_SCRATCH_0:
|
||||
case ARIZONA_DSP1_SCRATCH_1:
|
||||
case ARIZONA_DSP1_SCRATCH_2:
|
||||
case ARIZONA_DSP1_SCRATCH_3:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
if ((reg >= 0x100000 && reg < 0x106000) ||
|
||||
(reg >= 0x180000 && reg < 0x180800) ||
|
||||
(reg >= 0x190000 && reg < 0x194800) ||
|
||||
(reg >= 0x1a8000 && reg < 0x1a9800))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool wm5102_volatile_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
if (reg > 0xffff)
|
||||
return true;
|
||||
|
||||
switch (reg) {
|
||||
case ARIZONA_SOFTWARE_RESET:
|
||||
case ARIZONA_DEVICE_REVISION:
|
||||
@ -1884,12 +1862,22 @@ static bool wm5102_volatile_register(struct device *dev, unsigned int reg)
|
||||
case ARIZONA_DSP1_STATUS_1:
|
||||
case ARIZONA_DSP1_STATUS_2:
|
||||
case ARIZONA_DSP1_STATUS_3:
|
||||
case ARIZONA_DSP1_SCRATCH_0:
|
||||
case ARIZONA_DSP1_SCRATCH_1:
|
||||
case ARIZONA_DSP1_SCRATCH_2:
|
||||
case ARIZONA_DSP1_SCRATCH_3:
|
||||
case ARIZONA_HEADPHONE_DETECT_2:
|
||||
case ARIZONA_HP_DACVAL:
|
||||
case ARIZONA_MIC_DETECT_3:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
if ((reg >= 0x100000 && reg < 0x106000) ||
|
||||
(reg >= 0x180000 && reg < 0x180800) ||
|
||||
(reg >= 0x190000 && reg < 0x194800) ||
|
||||
(reg >= 0x1a8000 && reg < 0x1a9800))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -467,7 +467,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = regulator_bulk_get(wm8994->dev, wm8994->num_supplies,
|
||||
ret = devm_regulator_bulk_get(wm8994->dev, wm8994->num_supplies,
|
||||
wm8994->supplies);
|
||||
if (ret != 0) {
|
||||
dev_err(wm8994->dev, "Failed to get supplies: %d\n", ret);
|
||||
@ -478,7 +478,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
|
||||
wm8994->supplies);
|
||||
if (ret != 0) {
|
||||
dev_err(wm8994->dev, "Failed to enable supplies: %d\n", ret);
|
||||
goto err_get;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = wm8994_reg_read(wm8994, WM8994_SOFTWARE_RESET);
|
||||
@ -658,8 +658,6 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
|
||||
err_enable:
|
||||
regulator_bulk_disable(wm8994->num_supplies,
|
||||
wm8994->supplies);
|
||||
err_get:
|
||||
regulator_bulk_free(wm8994->num_supplies, wm8994->supplies);
|
||||
err:
|
||||
mfd_remove_devices(wm8994->dev);
|
||||
return ret;
|
||||
@ -672,7 +670,6 @@ static void wm8994_device_exit(struct wm8994 *wm8994)
|
||||
wm8994_irq_exit(wm8994);
|
||||
regulator_bulk_disable(wm8994->num_supplies,
|
||||
wm8994->supplies);
|
||||
regulator_bulk_free(wm8994->num_supplies, wm8994->supplies);
|
||||
}
|
||||
|
||||
static const struct of_device_id wm8994_of_match[] = {
|
||||
|
@ -678,12 +678,19 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
||||
struct mmc_command *cmd = mrq->cmd;
|
||||
struct mmc_data *data = mrq->data;
|
||||
unsigned int data_size = 0;
|
||||
int err;
|
||||
|
||||
if (host->eject) {
|
||||
cmd->error = -ENOMEDIUM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
err = rtsx_pci_card_exclusive_check(host->pcr, RTSX_SD_CARD);
|
||||
if (err) {
|
||||
cmd->error = err;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
mutex_lock(&pcr->pcr_mutex);
|
||||
|
||||
rtsx_pci_start_run(pcr);
|
||||
@ -901,6 +908,9 @@ static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
if (host->eject)
|
||||
return;
|
||||
|
||||
if (rtsx_pci_card_exclusive_check(host->pcr, RTSX_SD_CARD))
|
||||
return;
|
||||
|
||||
mutex_lock(&pcr->pcr_mutex);
|
||||
|
||||
rtsx_pci_start_run(pcr);
|
||||
@ -1073,6 +1083,10 @@ static int sdmmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
if (host->eject)
|
||||
return -ENOMEDIUM;
|
||||
|
||||
err = rtsx_pci_card_exclusive_check(host->pcr, RTSX_SD_CARD);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&pcr->pcr_mutex);
|
||||
|
||||
rtsx_pci_start_run(pcr);
|
||||
@ -1122,6 +1136,10 @@ static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
|
||||
if (host->eject)
|
||||
return -ENOMEDIUM;
|
||||
|
||||
err = rtsx_pci_card_exclusive_check(host->pcr, RTSX_SD_CARD);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&pcr->pcr_mutex);
|
||||
|
||||
rtsx_pci_start_run(pcr);
|
||||
|
@ -305,6 +305,16 @@ config RTC_DRV_X1205
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-x1205.
|
||||
|
||||
config RTC_DRV_PALMAS
|
||||
tristate "TI Palmas RTC driver"
|
||||
depends on MFD_PALMAS
|
||||
help
|
||||
If you say yes here you get support for the RTC of TI PALMA series PMIC
|
||||
chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-palma.
|
||||
|
||||
config RTC_DRV_PCF8523
|
||||
tristate "NXP PCF8523"
|
||||
help
|
||||
|
@ -81,6 +81,7 @@ obj-$(CONFIG_RTC_DRV_MPC5121) += rtc-mpc5121.o
|
||||
obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o
|
||||
obj-$(CONFIG_RTC_DRV_NUC900) += rtc-nuc900.o
|
||||
obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o
|
||||
obj-$(CONFIG_RTC_DRV_PALMAS) += rtc-palmas.o
|
||||
obj-$(CONFIG_RTC_DRV_PCAP) += rtc-pcap.o
|
||||
obj-$(CONFIG_RTC_DRV_PCF8523) += rtc-pcf8523.o
|
||||
obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o
|
||||
|
339
drivers/rtc/rtc-palmas.c
Normal file
339
drivers/rtc/rtc-palmas.c
Normal file
@ -0,0 +1,339 @@
|
||||
/*
|
||||
* rtc-palmas.c -- Palmas Real Time Clock driver.
|
||||
|
||||
* RTC driver for TI Palma series devices like TPS65913,
|
||||
* TPS65914 power management IC.
|
||||
*
|
||||
* Copyright (c) 2012, NVIDIA Corporation.
|
||||
*
|
||||
* Author: Laxman Dewangan <ldewangan@nvidia.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 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.
|
||||
*
|
||||
* 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/bcd.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/palmas.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm.h>
|
||||
|
||||
struct palmas_rtc {
|
||||
struct rtc_device *rtc;
|
||||
struct device *dev;
|
||||
unsigned int irq;
|
||||
};
|
||||
|
||||
/* Total number of RTC registers needed to set time*/
|
||||
#define PALMAS_NUM_TIME_REGS (PALMAS_YEARS_REG - PALMAS_SECONDS_REG + 1)
|
||||
|
||||
static int palmas_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
unsigned char rtc_data[PALMAS_NUM_TIME_REGS];
|
||||
struct palmas *palmas = dev_get_drvdata(dev->parent);
|
||||
int ret;
|
||||
|
||||
/* Copy RTC counting registers to static registers or latches */
|
||||
ret = palmas_update_bits(palmas, PALMAS_RTC_BASE, PALMAS_RTC_CTRL_REG,
|
||||
PALMAS_RTC_CTRL_REG_GET_TIME, PALMAS_RTC_CTRL_REG_GET_TIME);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "RTC CTRL reg update failed, err: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = palmas_bulk_read(palmas, PALMAS_RTC_BASE, PALMAS_SECONDS_REG,
|
||||
rtc_data, PALMAS_NUM_TIME_REGS);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "RTC_SECONDS reg read failed, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
tm->tm_sec = bcd2bin(rtc_data[0]);
|
||||
tm->tm_min = bcd2bin(rtc_data[1]);
|
||||
tm->tm_hour = bcd2bin(rtc_data[2]);
|
||||
tm->tm_mday = bcd2bin(rtc_data[3]);
|
||||
tm->tm_mon = bcd2bin(rtc_data[4]) - 1;
|
||||
tm->tm_year = bcd2bin(rtc_data[5]) + 100;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int palmas_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
unsigned char rtc_data[PALMAS_NUM_TIME_REGS];
|
||||
struct palmas *palmas = dev_get_drvdata(dev->parent);
|
||||
int ret;
|
||||
|
||||
rtc_data[0] = bin2bcd(tm->tm_sec);
|
||||
rtc_data[1] = bin2bcd(tm->tm_min);
|
||||
rtc_data[2] = bin2bcd(tm->tm_hour);
|
||||
rtc_data[3] = bin2bcd(tm->tm_mday);
|
||||
rtc_data[4] = bin2bcd(tm->tm_mon + 1);
|
||||
rtc_data[5] = bin2bcd(tm->tm_year - 100);
|
||||
|
||||
/* Stop RTC while updating the RTC time registers */
|
||||
ret = palmas_update_bits(palmas, PALMAS_RTC_BASE, PALMAS_RTC_CTRL_REG,
|
||||
PALMAS_RTC_CTRL_REG_STOP_RTC, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "RTC stop failed, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = palmas_bulk_write(palmas, PALMAS_RTC_BASE, PALMAS_SECONDS_REG,
|
||||
rtc_data, PALMAS_NUM_TIME_REGS);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "RTC_SECONDS reg write failed, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Start back RTC */
|
||||
ret = palmas_update_bits(palmas, PALMAS_RTC_BASE, PALMAS_RTC_CTRL_REG,
|
||||
PALMAS_RTC_CTRL_REG_STOP_RTC, PALMAS_RTC_CTRL_REG_STOP_RTC);
|
||||
if (ret < 0)
|
||||
dev_err(dev, "RTC start failed, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int palmas_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)
|
||||
{
|
||||
struct palmas *palmas = dev_get_drvdata(dev->parent);
|
||||
u8 val;
|
||||
|
||||
val = enabled ? PALMAS_RTC_INTERRUPTS_REG_IT_ALARM : 0;
|
||||
return palmas_write(palmas, PALMAS_RTC_BASE,
|
||||
PALMAS_RTC_INTERRUPTS_REG, val);
|
||||
}
|
||||
|
||||
static int palmas_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
||||
{
|
||||
unsigned char alarm_data[PALMAS_NUM_TIME_REGS];
|
||||
u32 int_val;
|
||||
struct palmas *palmas = dev_get_drvdata(dev->parent);
|
||||
int ret;
|
||||
|
||||
ret = palmas_bulk_read(palmas, PALMAS_RTC_BASE,
|
||||
PALMAS_ALARM_SECONDS_REG,
|
||||
alarm_data, PALMAS_NUM_TIME_REGS);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "RTC_ALARM_SECONDS read failed, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
alm->time.tm_sec = bcd2bin(alarm_data[0]);
|
||||
alm->time.tm_min = bcd2bin(alarm_data[1]);
|
||||
alm->time.tm_hour = bcd2bin(alarm_data[2]);
|
||||
alm->time.tm_mday = bcd2bin(alarm_data[3]);
|
||||
alm->time.tm_mon = bcd2bin(alarm_data[4]) - 1;
|
||||
alm->time.tm_year = bcd2bin(alarm_data[5]) + 100;
|
||||
|
||||
ret = palmas_read(palmas, PALMAS_RTC_BASE, PALMAS_RTC_INTERRUPTS_REG,
|
||||
&int_val);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "RTC_INTERRUPTS reg read failed, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (int_val & PALMAS_RTC_INTERRUPTS_REG_IT_ALARM)
|
||||
alm->enabled = 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int palmas_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
||||
{
|
||||
unsigned char alarm_data[PALMAS_NUM_TIME_REGS];
|
||||
struct palmas *palmas = dev_get_drvdata(dev->parent);
|
||||
int ret;
|
||||
|
||||
ret = palmas_rtc_alarm_irq_enable(dev, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Disable RTC alarm failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
alarm_data[0] = bin2bcd(alm->time.tm_sec);
|
||||
alarm_data[1] = bin2bcd(alm->time.tm_min);
|
||||
alarm_data[2] = bin2bcd(alm->time.tm_hour);
|
||||
alarm_data[3] = bin2bcd(alm->time.tm_mday);
|
||||
alarm_data[4] = bin2bcd(alm->time.tm_mon + 1);
|
||||
alarm_data[5] = bin2bcd(alm->time.tm_year - 100);
|
||||
|
||||
ret = palmas_bulk_write(palmas, PALMAS_RTC_BASE,
|
||||
PALMAS_ALARM_SECONDS_REG, alarm_data, PALMAS_NUM_TIME_REGS);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "ALARM_SECONDS_REG write failed, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (alm->enabled)
|
||||
ret = palmas_rtc_alarm_irq_enable(dev, 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int palmas_clear_interrupts(struct device *dev)
|
||||
{
|
||||
struct palmas *palmas = dev_get_drvdata(dev->parent);
|
||||
unsigned int rtc_reg;
|
||||
int ret;
|
||||
|
||||
ret = palmas_read(palmas, PALMAS_RTC_BASE, PALMAS_RTC_STATUS_REG,
|
||||
&rtc_reg);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "RTC_STATUS read failed, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = palmas_write(palmas, PALMAS_RTC_BASE, PALMAS_RTC_STATUS_REG,
|
||||
rtc_reg);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "RTC_STATUS write failed, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t palmas_rtc_interrupt(int irq, void *context)
|
||||
{
|
||||
struct palmas_rtc *palmas_rtc = context;
|
||||
struct device *dev = palmas_rtc->dev;
|
||||
int ret;
|
||||
|
||||
ret = palmas_clear_interrupts(dev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "RTC interrupt clear failed, err = %d\n", ret);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
rtc_update_irq(palmas_rtc->rtc, 1, RTC_IRQF | RTC_AF);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static struct rtc_class_ops palmas_rtc_ops = {
|
||||
.read_time = palmas_rtc_read_time,
|
||||
.set_time = palmas_rtc_set_time,
|
||||
.read_alarm = palmas_rtc_read_alarm,
|
||||
.set_alarm = palmas_rtc_set_alarm,
|
||||
.alarm_irq_enable = palmas_rtc_alarm_irq_enable,
|
||||
};
|
||||
|
||||
static int palmas_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);
|
||||
struct palmas_rtc *palmas_rtc = NULL;
|
||||
int ret;
|
||||
|
||||
palmas_rtc = devm_kzalloc(&pdev->dev, sizeof(struct palmas_rtc),
|
||||
GFP_KERNEL);
|
||||
if (!palmas_rtc)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Clear pending interrupts */
|
||||
ret = palmas_clear_interrupts(&pdev->dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "clear RTC int failed, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
palmas_rtc->dev = &pdev->dev;
|
||||
platform_set_drvdata(pdev, palmas_rtc);
|
||||
|
||||
/* Start RTC */
|
||||
ret = palmas_update_bits(palmas, PALMAS_RTC_BASE, PALMAS_RTC_CTRL_REG,
|
||||
PALMAS_RTC_CTRL_REG_STOP_RTC,
|
||||
PALMAS_RTC_CTRL_REG_STOP_RTC);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "RTC_CTRL write failed, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
palmas_rtc->irq = platform_get_irq(pdev, 0);
|
||||
|
||||
palmas_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
|
||||
&palmas_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(palmas_rtc->rtc)) {
|
||||
ret = PTR_ERR(palmas_rtc->rtc);
|
||||
dev_err(&pdev->dev, "RTC register failed, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = request_threaded_irq(palmas_rtc->irq, NULL,
|
||||
palmas_rtc_interrupt,
|
||||
IRQF_TRIGGER_LOW | IRQF_ONESHOT |
|
||||
IRQF_EARLY_RESUME,
|
||||
dev_name(&pdev->dev), palmas_rtc);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "IRQ request failed, err = %d\n", ret);
|
||||
rtc_device_unregister(palmas_rtc->rtc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
device_set_wakeup_capable(&pdev->dev, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int palmas_rtc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct palmas_rtc *palmas_rtc = platform_get_drvdata(pdev);
|
||||
|
||||
palmas_rtc_alarm_irq_enable(&pdev->dev, 0);
|
||||
free_irq(palmas_rtc->irq, palmas_rtc);
|
||||
rtc_device_unregister(palmas_rtc->rtc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int palmas_rtc_suspend(struct device *dev)
|
||||
{
|
||||
struct palmas_rtc *palmas_rtc = dev_get_drvdata(dev);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
enable_irq_wake(palmas_rtc->irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int palmas_rtc_resume(struct device *dev)
|
||||
{
|
||||
struct palmas_rtc *palmas_rtc = dev_get_drvdata(dev);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
disable_irq_wake(palmas_rtc->irq);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops palmas_rtc_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(palmas_rtc_suspend, palmas_rtc_resume)
|
||||
};
|
||||
|
||||
static struct platform_driver palmas_rtc_driver = {
|
||||
.probe = palmas_rtc_probe,
|
||||
.remove = palmas_rtc_remove,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "palmas-rtc",
|
||||
.pm = &palmas_rtc_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(palmas_rtc_driver);
|
||||
|
||||
MODULE_ALIAS("platform:palmas_rtc");
|
||||
MODULE_DESCRIPTION("TI PALMAS series RTC driver");
|
||||
MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -107,7 +107,7 @@ static int omap_ehci_init(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
int rc;
|
||||
struct ehci_hcd_omap_platform_data *pdata;
|
||||
struct usbhs_omap_platform_data *pdata;
|
||||
|
||||
pdata = hcd->self.controller->platform_data;
|
||||
|
||||
@ -151,7 +151,7 @@ static int omap_ehci_init(struct usb_hcd *hcd)
|
||||
}
|
||||
|
||||
static void disable_put_regulator(
|
||||
struct ehci_hcd_omap_platform_data *pdata)
|
||||
struct usbhs_omap_platform_data *pdata)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -176,7 +176,7 @@ static void disable_put_regulator(
|
||||
static int ehci_hcd_omap_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct ehci_hcd_omap_platform_data *pdata = dev->platform_data;
|
||||
struct usbhs_omap_platform_data *pdata = dev->platform_data;
|
||||
struct resource *res;
|
||||
struct usb_hcd *hcd;
|
||||
void __iomem *regs;
|
||||
|
@ -101,6 +101,29 @@ static const struct backlight_ops max8925_backlight_ops = {
|
||||
.get_brightness = max8925_backlight_get_brightness,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int max8925_backlight_dt_init(struct platform_device *pdev,
|
||||
struct max8925_backlight_pdata *pdata)
|
||||
{
|
||||
struct device_node *nproot = pdev->dev.parent->of_node, *np;
|
||||
int dual_string;
|
||||
|
||||
if (!nproot)
|
||||
return -ENODEV;
|
||||
np = of_find_node_by_name(nproot, "backlight");
|
||||
if (!np) {
|
||||
dev_err(&pdev->dev, "failed to find backlight node\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
of_property_read_u32(np, "maxim,max8925-dual-string", &dual_string);
|
||||
pdata->dual_string = dual_string;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define max8925_backlight_dt_init(x, y) (-1)
|
||||
#endif
|
||||
|
||||
static int max8925_backlight_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
|
||||
@ -147,6 +170,13 @@ static int max8925_backlight_probe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, bl);
|
||||
|
||||
value = 0;
|
||||
if (pdev->dev.parent->of_node && !pdata) {
|
||||
pdata = devm_kzalloc(&pdev->dev,
|
||||
sizeof(struct max8925_backlight_pdata),
|
||||
GFP_KERNEL);
|
||||
max8925_backlight_dt_init(pdev, pdata);
|
||||
}
|
||||
|
||||
if (pdata) {
|
||||
if (pdata->lxw_scl)
|
||||
value |= (1 << 7);
|
||||
@ -158,7 +188,6 @@ static int max8925_backlight_probe(struct platform_device *pdev)
|
||||
ret = max8925_set_bits(chip->i2c, data->reg_mode_cntl, 0xfe, value);
|
||||
if (ret < 0)
|
||||
goto out_brt;
|
||||
|
||||
backlight_update_status(bl);
|
||||
return 0;
|
||||
out_brt:
|
||||
|
@ -364,6 +364,18 @@ config IMX2_WDT
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called imx2_wdt.
|
||||
|
||||
config UX500_WATCHDOG
|
||||
tristate "ST-Ericsson Ux500 watchdog"
|
||||
depends on MFD_DB8500_PRCMU
|
||||
select WATCHDOG_CORE
|
||||
default y
|
||||
help
|
||||
Say Y here to include Watchdog timer support for the watchdog
|
||||
existing in the prcmu of ST-Ericsson Ux500 series platforms.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called ux500_wdt.
|
||||
|
||||
# AVR32 Architecture
|
||||
|
||||
config AT32AP700X_WDT
|
||||
|
@ -52,6 +52,7 @@ obj-$(CONFIG_STMP3XXX_WATCHDOG) += stmp3xxx_wdt.o
|
||||
obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_wdt.o
|
||||
obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o
|
||||
obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o
|
||||
obj-$(CONFIG_UX500_WATCHDOG) += ux500_wdt.o
|
||||
|
||||
# AVR32 Architecture
|
||||
obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
|
||||
|
171
drivers/watchdog/ux500_wdt.c
Normal file
171
drivers/watchdog/ux500_wdt.c
Normal file
@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright (C) ST-Ericsson SA 2011-2013
|
||||
*
|
||||
* License Terms: GNU General Public License v2
|
||||
*
|
||||
* Author: Mathieu Poirier <mathieu.poirier@linaro.org> for ST-Ericsson
|
||||
* Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/watchdog.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/platform_data/ux500_wdt.h>
|
||||
|
||||
#include <linux/mfd/dbx500-prcmu.h>
|
||||
|
||||
#define WATCHDOG_TIMEOUT 600 /* 10 minutes */
|
||||
|
||||
#define WATCHDOG_MIN 0
|
||||
#define WATCHDOG_MAX28 268435 /* 28 bit resolution in ms == 268435.455 s */
|
||||
#define WATCHDOG_MAX32 4294967 /* 32 bit resolution in ms == 4294967.295 s */
|
||||
|
||||
static unsigned int timeout = WATCHDOG_TIMEOUT;
|
||||
module_param(timeout, uint, 0);
|
||||
MODULE_PARM_DESC(timeout,
|
||||
"Watchdog timeout in seconds. default="
|
||||
__MODULE_STRING(WATCHDOG_TIMEOUT) ".");
|
||||
|
||||
static bool nowayout = WATCHDOG_NOWAYOUT;
|
||||
module_param(nowayout, bool, 0);
|
||||
MODULE_PARM_DESC(nowayout,
|
||||
"Watchdog cannot be stopped once started (default="
|
||||
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
|
||||
|
||||
static int ux500_wdt_start(struct watchdog_device *wdd)
|
||||
{
|
||||
return prcmu_enable_a9wdog(PRCMU_WDOG_ALL);
|
||||
}
|
||||
|
||||
static int ux500_wdt_stop(struct watchdog_device *wdd)
|
||||
{
|
||||
return prcmu_disable_a9wdog(PRCMU_WDOG_ALL);
|
||||
}
|
||||
|
||||
static int ux500_wdt_keepalive(struct watchdog_device *wdd)
|
||||
{
|
||||
return prcmu_kick_a9wdog(PRCMU_WDOG_ALL);
|
||||
}
|
||||
|
||||
static int ux500_wdt_set_timeout(struct watchdog_device *wdd,
|
||||
unsigned int timeout)
|
||||
{
|
||||
ux500_wdt_stop(wdd);
|
||||
prcmu_load_a9wdog(PRCMU_WDOG_ALL, timeout * 1000);
|
||||
ux500_wdt_start(wdd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct watchdog_info ux500_wdt_info = {
|
||||
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
|
||||
.identity = "Ux500 WDT",
|
||||
.firmware_version = 1,
|
||||
};
|
||||
|
||||
static const struct watchdog_ops ux500_wdt_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.start = ux500_wdt_start,
|
||||
.stop = ux500_wdt_stop,
|
||||
.ping = ux500_wdt_keepalive,
|
||||
.set_timeout = ux500_wdt_set_timeout,
|
||||
};
|
||||
|
||||
static struct watchdog_device ux500_wdt = {
|
||||
.info = &ux500_wdt_info,
|
||||
.ops = &ux500_wdt_ops,
|
||||
.min_timeout = WATCHDOG_MIN,
|
||||
.max_timeout = WATCHDOG_MAX32,
|
||||
};
|
||||
|
||||
static int ux500_wdt_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct ux500_wdt_data *pdata = pdev->dev.platform_data;
|
||||
|
||||
if (pdata) {
|
||||
if (pdata->timeout > 0)
|
||||
timeout = pdata->timeout;
|
||||
if (pdata->has_28_bits_resolution)
|
||||
ux500_wdt.max_timeout = WATCHDOG_MAX28;
|
||||
}
|
||||
|
||||
watchdog_set_nowayout(&ux500_wdt, nowayout);
|
||||
|
||||
/* disable auto off on sleep */
|
||||
prcmu_config_a9wdog(PRCMU_WDOG_CPU1, false);
|
||||
|
||||
/* set HW initial value */
|
||||
prcmu_load_a9wdog(PRCMU_WDOG_ALL, timeout * 1000);
|
||||
|
||||
ret = watchdog_register_device(&ux500_wdt);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dev_info(&pdev->dev, "initialized\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ux500_wdt_remove(struct platform_device *dev)
|
||||
{
|
||||
watchdog_unregister_device(&ux500_wdt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int ux500_wdt_suspend(struct platform_device *pdev,
|
||||
pm_message_t state)
|
||||
{
|
||||
if (watchdog_active(&ux500_wdt)) {
|
||||
ux500_wdt_stop(&ux500_wdt);
|
||||
prcmu_config_a9wdog(PRCMU_WDOG_CPU1, true);
|
||||
|
||||
prcmu_load_a9wdog(PRCMU_WDOG_ALL, timeout * 1000);
|
||||
ux500_wdt_start(&ux500_wdt);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ux500_wdt_resume(struct platform_device *pdev)
|
||||
{
|
||||
if (watchdog_active(&ux500_wdt)) {
|
||||
ux500_wdt_stop(&ux500_wdt);
|
||||
prcmu_config_a9wdog(PRCMU_WDOG_CPU1, false);
|
||||
|
||||
prcmu_load_a9wdog(PRCMU_WDOG_ALL, timeout * 1000);
|
||||
ux500_wdt_start(&ux500_wdt);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define ux500_wdt_suspend NULL
|
||||
#define ux500_wdt_resume NULL
|
||||
#endif
|
||||
|
||||
static struct platform_driver ux500_wdt_driver = {
|
||||
.probe = ux500_wdt_probe,
|
||||
.remove = ux500_wdt_remove,
|
||||
.suspend = ux500_wdt_suspend,
|
||||
.resume = ux500_wdt_resume,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "ux500_wdt",
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(ux500_wdt_driver);
|
||||
|
||||
MODULE_AUTHOR("Jonas Aaberg <jonas.aberg@stericsson.com>");
|
||||
MODULE_DESCRIPTION("Ux500 Watchdog Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
|
||||
MODULE_ALIAS("platform:ux500_wdt");
|
@ -39,51 +39,55 @@
|
||||
* address each module uses within a given i2c slave.
|
||||
*/
|
||||
|
||||
/* Module IDs for similar functionalities found in twl4030/twl6030 */
|
||||
enum twl_module_ids {
|
||||
TWL_MODULE_USB,
|
||||
TWL_MODULE_PIH,
|
||||
TWL_MODULE_MAIN_CHARGE,
|
||||
TWL_MODULE_PM_MASTER,
|
||||
TWL_MODULE_PM_RECEIVER,
|
||||
|
||||
TWL_MODULE_RTC,
|
||||
TWL_MODULE_PWM,
|
||||
TWL_MODULE_LED,
|
||||
TWL_MODULE_SECURED_REG,
|
||||
|
||||
TWL_MODULE_LAST,
|
||||
};
|
||||
|
||||
/* Modules only available in twl4030 series */
|
||||
enum twl4030_module_ids {
|
||||
TWL4030_MODULE_USB = 0, /* Slave 0 (i2c address 0x48) */
|
||||
TWL4030_MODULE_AUDIO_VOICE, /* Slave 1 (i2c address 0x49) */
|
||||
TWL4030_MODULE_AUDIO_VOICE = TWL_MODULE_LAST,
|
||||
TWL4030_MODULE_GPIO,
|
||||
TWL4030_MODULE_INTBR,
|
||||
TWL4030_MODULE_PIH,
|
||||
|
||||
TWL4030_MODULE_TEST,
|
||||
TWL4030_MODULE_KEYPAD, /* Slave 2 (i2c address 0x4a) */
|
||||
TWL4030_MODULE_KEYPAD,
|
||||
|
||||
TWL4030_MODULE_MADC,
|
||||
TWL4030_MODULE_INTERRUPTS,
|
||||
TWL4030_MODULE_LED,
|
||||
|
||||
TWL4030_MODULE_MAIN_CHARGE,
|
||||
TWL4030_MODULE_PRECHARGE,
|
||||
TWL4030_MODULE_PWM0,
|
||||
TWL4030_MODULE_PWM1,
|
||||
TWL4030_MODULE_PWMA,
|
||||
|
||||
TWL4030_MODULE_PWMB,
|
||||
TWL5031_MODULE_ACCESSORY,
|
||||
TWL5031_MODULE_INTERRUPTS,
|
||||
TWL4030_MODULE_BACKUP, /* Slave 3 (i2c address 0x4b) */
|
||||
TWL4030_MODULE_BACKUP,
|
||||
TWL4030_MODULE_INT,
|
||||
|
||||
TWL4030_MODULE_PM_MASTER,
|
||||
TWL4030_MODULE_PM_RECEIVER,
|
||||
TWL4030_MODULE_RTC,
|
||||
TWL4030_MODULE_SECURED_REG,
|
||||
TWL5031_MODULE_ACCESSORY,
|
||||
TWL5031_MODULE_INTERRUPTS,
|
||||
|
||||
TWL4030_MODULE_LAST,
|
||||
};
|
||||
|
||||
/* Similar functionalities implemented in TWL4030/6030 */
|
||||
#define TWL_MODULE_USB TWL4030_MODULE_USB
|
||||
#define TWL_MODULE_PIH TWL4030_MODULE_PIH
|
||||
#define TWL_MODULE_MAIN_CHARGE TWL4030_MODULE_MAIN_CHARGE
|
||||
#define TWL_MODULE_PM_MASTER TWL4030_MODULE_PM_MASTER
|
||||
#define TWL_MODULE_PM_RECEIVER TWL4030_MODULE_PM_RECEIVER
|
||||
#define TWL_MODULE_RTC TWL4030_MODULE_RTC
|
||||
#define TWL_MODULE_PWM TWL4030_MODULE_PWM0
|
||||
#define TWL_MODULE_LED TWL4030_MODULE_LED
|
||||
/* Modules only available in twl6030 series */
|
||||
enum twl6030_module_ids {
|
||||
TWL6030_MODULE_ID0 = TWL_MODULE_LAST,
|
||||
TWL6030_MODULE_ID1,
|
||||
TWL6030_MODULE_ID2,
|
||||
TWL6030_MODULE_GPADC,
|
||||
TWL6030_MODULE_GASGAUGE,
|
||||
|
||||
#define TWL6030_MODULE_ID0 13
|
||||
#define TWL6030_MODULE_ID1 14
|
||||
#define TWL6030_MODULE_ID2 15
|
||||
TWL6030_MODULE_LAST,
|
||||
};
|
||||
|
||||
/* Until the clients has been converted to use TWL_MODULE_LED */
|
||||
#define TWL4030_MODULE_LED TWL_MODULE_LED
|
||||
|
||||
#define GPIO_INTR_OFFSET 0
|
||||
#define KEYPAD_INTR_OFFSET 1
|
||||
@ -170,21 +174,23 @@ static inline int twl_class_is_ ##class(void) \
|
||||
TWL_CLASS_IS(4030, TWL4030_CLASS_ID)
|
||||
TWL_CLASS_IS(6030, TWL6030_CLASS_ID)
|
||||
|
||||
/*
|
||||
* Read and write single 8-bit registers
|
||||
*/
|
||||
int twl_i2c_write_u8(u8 mod_no, u8 val, u8 reg);
|
||||
int twl_i2c_read_u8(u8 mod_no, u8 *val, u8 reg);
|
||||
|
||||
/*
|
||||
* Read and write several 8-bit registers at once.
|
||||
*
|
||||
* IMPORTANT: For twl_i2c_write(), allocate num_bytes + 1
|
||||
* for the value, and populate your data starting at offset 1.
|
||||
*/
|
||||
int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes);
|
||||
int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes);
|
||||
|
||||
/*
|
||||
* Read and write single 8-bit registers
|
||||
*/
|
||||
static inline int twl_i2c_write_u8(u8 mod_no, u8 val, u8 reg) {
|
||||
return twl_i2c_write(mod_no, &val, reg, 1);
|
||||
}
|
||||
|
||||
static inline int twl_i2c_read_u8(u8 mod_no, u8 *val, u8 reg) {
|
||||
return twl_i2c_read(mod_no, val, reg, 1);
|
||||
}
|
||||
|
||||
int twl_get_type(void);
|
||||
int twl_get_version(void);
|
||||
int twl_get_hfclk_rate(void);
|
||||
|
@ -365,5 +365,5 @@ static inline int pm80x_dev_resume(struct device *dev)
|
||||
|
||||
extern int pm80x_init(struct i2c_client *client,
|
||||
const struct i2c_device_id *id);
|
||||
extern int pm80x_deinit(struct i2c_client *client);
|
||||
extern int pm80x_deinit(void);
|
||||
#endif /* __LINUX_MFD_88PM80X_H */
|
||||
|
@ -311,6 +311,7 @@ int abx500_mask_and_set_register_interruptible(struct device *dev, u8 bank,
|
||||
int abx500_get_chip_id(struct device *dev);
|
||||
int abx500_event_registers_startup_state_get(struct device *dev, u8 *event);
|
||||
int abx500_startup_irq_enabled(struct device *dev, unsigned int irq);
|
||||
void abx500_dump_all_banks(void);
|
||||
|
||||
struct abx500_ops {
|
||||
int (*get_chip_id) (struct device *);
|
||||
@ -321,6 +322,7 @@ struct abx500_ops {
|
||||
int (*mask_and_set_register) (struct device *, u8, u8, u8, u8);
|
||||
int (*event_registers_startup_state_get) (struct device *, u8 *);
|
||||
int (*startup_irq_enabled) (struct device *, unsigned int);
|
||||
void (*dump_all_banks) (struct device *);
|
||||
};
|
||||
|
||||
int abx500_register_ops(struct device *core_dev, struct abx500_ops *ops);
|
||||
|
@ -37,6 +37,11 @@ static inline int ab8500_sysctrl_clear(u16 reg, u8 bits)
|
||||
return ab8500_sysctrl_write(reg, bits, 0);
|
||||
}
|
||||
|
||||
/* Configuration data for SysClkReq1RfClkBuf - SysClkReq8RfClkBuf */
|
||||
struct ab8500_sysctrl_platform_data {
|
||||
u8 initial_req_buf_config[8];
|
||||
};
|
||||
|
||||
/* Registers */
|
||||
#define AB8500_TURNONSTATUS 0x100
|
||||
#define AB8500_RESETSTATUS 0x101
|
||||
|
@ -368,10 +368,12 @@ struct regulator_reg_init;
|
||||
struct regulator_init_data;
|
||||
struct ab8500_gpio_platform_data;
|
||||
struct ab8500_codec_platform_data;
|
||||
struct ab8500_sysctrl_platform_data;
|
||||
|
||||
/**
|
||||
* struct ab8500_platform_data - AB8500 platform data
|
||||
* @irq_base: start of AB8500 IRQs, AB8500_NR_IRQS will be used
|
||||
* @pm_power_off: Should machine pm power off hook be registered or not
|
||||
* @init: board-specific initialization after detection of ab8500
|
||||
* @num_regulator_reg_init: number of regulator init registers
|
||||
* @regulator_reg_init: regulator init registers
|
||||
@ -380,6 +382,7 @@ struct ab8500_codec_platform_data;
|
||||
*/
|
||||
struct ab8500_platform_data {
|
||||
int irq_base;
|
||||
bool pm_power_off;
|
||||
void (*init) (struct ab8500 *);
|
||||
int num_regulator_reg_init;
|
||||
struct ab8500_regulator_reg_init *regulator_reg_init;
|
||||
@ -387,6 +390,7 @@ struct ab8500_platform_data {
|
||||
struct regulator_init_data *regulator;
|
||||
struct abx500_gpio_platform_data *gpio;
|
||||
struct ab8500_codec_platform_data *codec;
|
||||
struct ab8500_sysctrl_platform_data *sysctrl;
|
||||
};
|
||||
|
||||
extern int ab8500_init(struct ab8500 *ab8500,
|
||||
@ -508,4 +512,12 @@ static inline int is_ab9540_2p0_or_earlier(struct ab8500 *ab)
|
||||
return (is_ab9540(ab) && (ab->chip_id < AB8500_CUT2P0));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_AB8500_DEBUG
|
||||
void ab8500_dump_all_banks(struct device *dev);
|
||||
void ab8500_debug_register_interrupt(int line);
|
||||
#else
|
||||
static inline void ab8500_dump_all_banks(struct device *dev) {}
|
||||
static inline void ab8500_debug_register_interrupt(int line) {}
|
||||
#endif
|
||||
|
||||
#endif /* MFD_AB8500_H */
|
||||
|
@ -56,6 +56,8 @@
|
||||
#define ARIZONA_DMIC_MICBIAS2 2
|
||||
#define ARIZONA_DMIC_MICBIAS3 3
|
||||
|
||||
#define ARIZONA_MAX_MICBIAS 3
|
||||
|
||||
#define ARIZONA_INMODE_DIFF 0
|
||||
#define ARIZONA_INMODE_SE 1
|
||||
#define ARIZONA_INMODE_DMIC 2
|
||||
@ -71,6 +73,13 @@
|
||||
|
||||
struct regulator_init_data;
|
||||
|
||||
struct arizona_micbias {
|
||||
int mV; /** Regulated voltage */
|
||||
unsigned int ext_cap:1; /** External capacitor fitted */
|
||||
unsigned int discharge:1; /** Actively discharge */
|
||||
unsigned int fast_start:1; /** Enable aggressive startup ramp rate */
|
||||
};
|
||||
|
||||
struct arizona_micd_config {
|
||||
unsigned int src;
|
||||
unsigned int bias;
|
||||
@ -136,6 +145,9 @@ struct arizona_pdata {
|
||||
/** Reference voltage for DMIC inputs */
|
||||
int dmic_ref[ARIZONA_MAX_INPUT];
|
||||
|
||||
/** MICBIAS configurations */
|
||||
struct arizona_micbias micbias[ARIZONA_MAX_MICBIAS];
|
||||
|
||||
/** Mode of input structures */
|
||||
int inmode[ARIZONA_MAX_INPUT];
|
||||
|
||||
|
@ -984,18 +984,34 @@
|
||||
#define ARIZONA_DSP1_STATUS_1 0x1104
|
||||
#define ARIZONA_DSP1_STATUS_2 0x1105
|
||||
#define ARIZONA_DSP1_STATUS_3 0x1106
|
||||
#define ARIZONA_DSP1_SCRATCH_0 0x1140
|
||||
#define ARIZONA_DSP1_SCRATCH_1 0x1141
|
||||
#define ARIZONA_DSP1_SCRATCH_2 0x1142
|
||||
#define ARIZONA_DSP1_SCRATCH_3 0x1143
|
||||
#define ARIZONA_DSP2_CONTROL_1 0x1200
|
||||
#define ARIZONA_DSP2_CLOCKING_1 0x1201
|
||||
#define ARIZONA_DSP2_STATUS_1 0x1204
|
||||
#define ARIZONA_DSP2_STATUS_2 0x1205
|
||||
#define ARIZONA_DSP2_SCRATCH_0 0x1240
|
||||
#define ARIZONA_DSP2_SCRATCH_1 0x1241
|
||||
#define ARIZONA_DSP2_SCRATCH_2 0x1242
|
||||
#define ARIZONA_DSP2_SCRATCH_3 0x1243
|
||||
#define ARIZONA_DSP3_CONTROL_1 0x1300
|
||||
#define ARIZONA_DSP3_CLOCKING_1 0x1301
|
||||
#define ARIZONA_DSP3_STATUS_1 0x1304
|
||||
#define ARIZONA_DSP3_STATUS_2 0x1305
|
||||
#define ARIZONA_DSP3_SCRATCH_0 0x1340
|
||||
#define ARIZONA_DSP3_SCRATCH_1 0x1341
|
||||
#define ARIZONA_DSP3_SCRATCH_2 0x1342
|
||||
#define ARIZONA_DSP3_SCRATCH_3 0x1343
|
||||
#define ARIZONA_DSP4_CONTROL_1 0x1400
|
||||
#define ARIZONA_DSP4_CLOCKING_1 0x1401
|
||||
#define ARIZONA_DSP4_STATUS_1 0x1404
|
||||
#define ARIZONA_DSP4_STATUS_2 0x1405
|
||||
#define ARIZONA_DSP4_SCRATCH_0 0x1440
|
||||
#define ARIZONA_DSP4_SCRATCH_1 0x1441
|
||||
#define ARIZONA_DSP4_SCRATCH_2 0x1442
|
||||
#define ARIZONA_DSP4_SCRATCH_3 0x1443
|
||||
|
||||
/*
|
||||
* Field Definitions.
|
||||
|
@ -150,6 +150,18 @@ enum prcmu_clock {
|
||||
PRCMU_DSI2ESCCLK,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum prcmu_wdog_id - PRCMU watchdog IDs
|
||||
* @PRCMU_WDOG_ALL: use all timers
|
||||
* @PRCMU_WDOG_CPU1: use first CPU timer only
|
||||
* @PRCMU_WDOG_CPU2: use second CPU timer conly
|
||||
*/
|
||||
enum prcmu_wdog_id {
|
||||
PRCMU_WDOG_ALL = 0x00,
|
||||
PRCMU_WDOG_CPU1 = 0x01,
|
||||
PRCMU_WDOG_CPU2 = 0x02,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum ape_opp - APE OPP states definition
|
||||
* @APE_OPP_INIT:
|
||||
|
@ -190,6 +190,8 @@ enum {
|
||||
MAX8925_NR_IRQS,
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct max8925_chip {
|
||||
struct device *dev;
|
||||
struct i2c_client *i2c;
|
||||
@ -201,7 +203,6 @@ struct max8925_chip {
|
||||
int irq_base;
|
||||
int core_irq;
|
||||
int tsc_irq;
|
||||
|
||||
unsigned int wakeup_flag;
|
||||
};
|
||||
|
||||
|
@ -2789,4 +2789,56 @@ enum usb_irq_events {
|
||||
#define PALMAS_GPADC_TRIM15 0xE
|
||||
#define PALMAS_GPADC_TRIM16 0xF
|
||||
|
||||
static inline int palmas_read(struct palmas *palmas, unsigned int base,
|
||||
unsigned int reg, unsigned int *val)
|
||||
{
|
||||
unsigned int addr = PALMAS_BASE_TO_REG(base, reg);
|
||||
int slave_id = PALMAS_BASE_TO_SLAVE(base);
|
||||
|
||||
return regmap_read(palmas->regmap[slave_id], addr, val);
|
||||
}
|
||||
|
||||
static inline int palmas_write(struct palmas *palmas, unsigned int base,
|
||||
unsigned int reg, unsigned int value)
|
||||
{
|
||||
unsigned int addr = PALMAS_BASE_TO_REG(base, reg);
|
||||
int slave_id = PALMAS_BASE_TO_SLAVE(base);
|
||||
|
||||
return regmap_write(palmas->regmap[slave_id], addr, value);
|
||||
}
|
||||
|
||||
static inline int palmas_bulk_write(struct palmas *palmas, unsigned int base,
|
||||
unsigned int reg, const void *val, size_t val_count)
|
||||
{
|
||||
unsigned int addr = PALMAS_BASE_TO_REG(base, reg);
|
||||
int slave_id = PALMAS_BASE_TO_SLAVE(base);
|
||||
|
||||
return regmap_bulk_write(palmas->regmap[slave_id], addr,
|
||||
val, val_count);
|
||||
}
|
||||
|
||||
static inline int palmas_bulk_read(struct palmas *palmas, unsigned int base,
|
||||
unsigned int reg, void *val, size_t val_count)
|
||||
{
|
||||
unsigned int addr = PALMAS_BASE_TO_REG(base, reg);
|
||||
int slave_id = PALMAS_BASE_TO_SLAVE(base);
|
||||
|
||||
return regmap_bulk_read(palmas->regmap[slave_id], addr,
|
||||
val, val_count);
|
||||
}
|
||||
|
||||
static inline int palmas_update_bits(struct palmas *palmas, unsigned int base,
|
||||
unsigned int reg, unsigned int mask, unsigned int val)
|
||||
{
|
||||
unsigned int addr = PALMAS_BASE_TO_REG(base, reg);
|
||||
int slave_id = PALMAS_BASE_TO_SLAVE(base);
|
||||
|
||||
return regmap_update_bits(palmas->regmap[slave_id], addr, mask, val);
|
||||
}
|
||||
|
||||
static inline int palmas_irq_get_virq(struct palmas *palmas, int irq)
|
||||
{
|
||||
return regmap_irq_get_virq(palmas->irq_data, irq);
|
||||
}
|
||||
|
||||
#endif /* __LINUX_MFD_PALMAS_H */
|
||||
|
@ -465,7 +465,7 @@
|
||||
#define SD_RSP_TYPE_R6 0x01
|
||||
#define SD_RSP_TYPE_R7 0x01
|
||||
|
||||
/* SD_CONFIURE3 */
|
||||
/* SD_CONFIGURE3 */
|
||||
#define SD_RSP_80CLK_TIMEOUT_EN 0x01
|
||||
|
||||
/* Card Transfer Reset Register */
|
||||
@ -581,8 +581,11 @@
|
||||
#define CARD_GPIO_DIR 0xFD57
|
||||
#define CARD_GPIO 0xFD58
|
||||
#define CARD_DATA_SOURCE 0xFD5B
|
||||
#define SD30_CLK_DRIVE_SEL 0xFD5A
|
||||
#define CARD_SELECT 0xFD5C
|
||||
#define SD30_DRIVE_SEL 0xFD5E
|
||||
#define SD30_CMD_DRIVE_SEL 0xFD5E
|
||||
#define SD30_DAT_DRIVE_SEL 0xFD5F
|
||||
#define CARD_CLK_EN 0xFD69
|
||||
#define SDIO_CTRL 0xFD6B
|
||||
#define CD_PAD_CTL 0xFD73
|
||||
@ -655,6 +658,8 @@
|
||||
#define MSGTXDATA3 0xFE47
|
||||
#define MSGTXCTL 0xFE48
|
||||
#define PETXCFG 0xFE49
|
||||
#define LTR_CTL 0xFE4A
|
||||
#define OBFF_CFG 0xFE4C
|
||||
|
||||
#define CDRESUMECTL 0xFE52
|
||||
#define WAKE_SEL_CTL 0xFE54
|
||||
@ -735,6 +740,7 @@ struct rtsx_pcr {
|
||||
|
||||
unsigned int card_inserted;
|
||||
unsigned int card_removed;
|
||||
unsigned int card_exist;
|
||||
|
||||
struct delayed_work carddet_work;
|
||||
struct delayed_work idle_work;
|
||||
@ -799,6 +805,7 @@ int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
|
||||
u8 ssc_depth, bool initial_mode, bool double_clk, bool vpclk);
|
||||
int rtsx_pci_card_power_on(struct rtsx_pcr *pcr, int card);
|
||||
int rtsx_pci_card_power_off(struct rtsx_pcr *pcr, int card);
|
||||
int rtsx_pci_card_exclusive_check(struct rtsx_pcr *pcr, int card);
|
||||
int rtsx_pci_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage);
|
||||
unsigned int rtsx_pci_card_exist(struct rtsx_pcr *pcr);
|
||||
void rtsx_pci_complete_unfinished_transfer(struct rtsx_pcr *pcr);
|
||||
|
@ -55,6 +55,7 @@ struct ohci_hcd_omap_platform_data {
|
||||
};
|
||||
|
||||
struct usbhs_omap_platform_data {
|
||||
int nports;
|
||||
enum usbhs_omap_port_mode port_mode[OMAP3_HS_USB_PORTS];
|
||||
int reset_gpio_port[OMAP3_HS_USB_PORTS];
|
||||
struct regulator *regulator[OMAP3_HS_USB_PORTS];
|
||||
|
19
include/linux/platform_data/ux500_wdt.h
Normal file
19
include/linux/platform_data/ux500_wdt.h
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) ST Ericsson SA 2011
|
||||
*
|
||||
* License Terms: GNU General Public License v2
|
||||
*
|
||||
* STE Ux500 Watchdog platform data
|
||||
*/
|
||||
#ifndef __UX500_WDT_H
|
||||
#define __UX500_WDT_H
|
||||
|
||||
/**
|
||||
* struct ux500_wdt_data
|
||||
*/
|
||||
struct ux500_wdt_data {
|
||||
unsigned int timeout;
|
||||
bool has_28_bits_resolution;
|
||||
};
|
||||
|
||||
#endif /* __UX500_WDT_H */
|
@ -27,6 +27,14 @@
|
||||
#define VEXPRESS_GPIO_MMC_CARDIN 0
|
||||
#define VEXPRESS_GPIO_MMC_WPROT 1
|
||||
#define VEXPRESS_GPIO_FLASH_WPn 2
|
||||
#define VEXPRESS_GPIO_LED0 3
|
||||
#define VEXPRESS_GPIO_LED1 4
|
||||
#define VEXPRESS_GPIO_LED2 5
|
||||
#define VEXPRESS_GPIO_LED3 6
|
||||
#define VEXPRESS_GPIO_LED4 7
|
||||
#define VEXPRESS_GPIO_LED5 8
|
||||
#define VEXPRESS_GPIO_LED6 9
|
||||
#define VEXPRESS_GPIO_LED7 10
|
||||
|
||||
#define VEXPRESS_RES_FUNC(_site, _func) \
|
||||
{ \
|
||||
|
Loading…
Reference in New Issue
Block a user