mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 03:01:39 -04: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
68 changed files with 4302 additions and 1054 deletions
|
|
@ -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 @@ out:
|
|||
*/
|
||||
(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 <[email protected]>");
|
||||
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 @@ gpe0_done:
|
|||
/* 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 @@ gpe0_done:
|
|||
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 @@ gpio_done:
|
|||
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 @@ wdt_done:
|
|||
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 @@ tsc_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 @@ err_end:
|
|||
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 @@ end_probe:
|
|||
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 <[email protected]>");
|
||||
|
|
|
|||
|
|
@ -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 @@ end:
|
|||
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 @@ fail:
|
|||
*/
|
||||
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 @@ err:
|
|||
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 @@ err_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[] = {
|
||||
|
|
|
|||
Loading…
Reference in a new issue