提交 ab782659 编写于 作者: L Linus Torvalds

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
  ...
* Maxim max8925 Power Management IC
Required parent device properties:
- compatible : "maxim,max8925"
- reg : the I2C slave address for the max8925 chip
- interrupts : IRQ line for the max8925 chip
- interrupt-controller: describes the max8925 as an interrupt
controller (has its own domain)
- #interrupt-cells : should be 1.
- The cell is the max8925 local IRQ number
Optional parent device properties:
- maxim,tsc-irq: there are 2 IRQ lines for max8925, one is indicated in
interrupts property, the other is indicated here.
max8925 consists of a large and varied group of sub-devices:
Device Supply Names Description
------ ------------ -----------
max8925-onkey : : On key
max8925-rtc : : RTC
max8925-regulator : : Regulators
max8925-backlight : : Backlight
max8925-touch : : Touchscreen
max8925-power : : Charger
Example:
pmic: max8925@3c {
compatible = "maxim,max8925";
reg = <0x3c>;
interrupts = <1>;
interrupt-parent = <&intcmux4>;
interrupt-controller;
#interrupt-cells = <1>;
maxim,tsc-irq = <0>;
regulators {
SDV1 {
regulator-min-microvolt = <637500>;
regulator-max-microvolt = <1425000>;
regulator-boot-on;
regulator-always-on;
};
LDO1 {
regulator-min-microvolt = <750000>;
regulator-max-microvolt = <3900000>;
regulator-boot-on;
regulator-always-on;
};
};
backlight {
maxim,max8925-dual-string = <0>;
};
charger {
batt-detect = <0>;
topoff-threshold = <1>;
fast-charge = <7>;
no-temp-support = <0>;
no-insert-detect = <0>;
};
};
max8925-battery bindings
~~~~~~~~~~~~~~~~
Optional properties :
- batt-detect: whether support battery detect
- topoff-threshold: set charging current in topoff mode
- fast-charge: set charging current in fast mode
- no-temp-support: whether support temperature protection detect
- no-insert-detect: whether support insert detect
Example:
charger {
batt-detect = <0>;
topoff-threshold = <1>;
fast-charge = <7>;
no-temp-support = <0>;
no-insert-detect = <0>;
};
TPS65090 regulators
Required properties:
- compatible: "ti,tps65090"
- reg: I2C slave address
- interrupts: the interrupt outputs of the controller
- regulators: A node that houses a sub-node for each regulator within the
device. Each sub-node is identified using the node's name, with valid
values listed below. The content of each sub-node is defined by the
standard binding for regulators; see regulator.txt.
dcdc[1-3], fet[1-7] and ldo[1-2] respectively.
- vsys[1-3]-supply: The input supply for DCDC[1-3] respectively.
- infet[1-7]-supply: The input supply for FET[1-7] respectively.
- vsys-l[1-2]-supply: The input supply for LDO[1-2] respectively.
Optional properties:
- ti,enable-ext-control: This is applicable for DCDC1, DCDC2 and DCDC3.
If DCDCs are externally controlled then this property should be there.
- "dcdc-ext-control-gpios: This is applicable for DCDC1, DCDC2 and DCDC3.
If DCDCs are externally controlled and if it is from GPIO then GPIO
number should be provided. If it is externally controlled and no GPIO
entry then driver will just configure this rails as external control
and will not provide any enable/disable APIs.
Each regulator is defined using the standard binding for regulators.
Example:
tps65090@48 {
compatible = "ti,tps65090";
reg = <0x48>;
interrupts = <0 88 0x4>;
vsys1-supply = <&some_reg>;
vsys2-supply = <&some_reg>;
vsys3-supply = <&some_reg>;
infet1-supply = <&some_reg>;
infet2-supply = <&some_reg>;
infet3-supply = <&some_reg>;
infet4-supply = <&some_reg>;
infet5-supply = <&some_reg>;
infet6-supply = <&some_reg>;
infet7-supply = <&some_reg>;
vsys_l1-supply = <&some_reg>;
vsys_l2-supply = <&some_reg>;
regulators {
dcdc1 {
regulator-name = "dcdc1";
regulator-boot-on;
regulator-always-on;
ti,enable-ext-control;
dcdc-ext-control-gpios = <&gpio 10 0>;
};
dcdc2 {
regulator-name = "dcdc2";
regulator-boot-on;
regulator-always-on;
};
dcdc3 {
regulator-name = "dcdc3";
regulator-boot-on;
regulator-always-on;
};
fet1 {
regulator-name = "fet1";
regulator-boot-on;
regulator-always-on;
};
fet2 {
regulator-name = "fet2";
regulator-boot-on;
regulator-always-on;
};
fet3 {
regulator-name = "fet3";
regulator-boot-on;
regulator-always-on;
};
fet4 {
regulator-name = "fet4";
regulator-boot-on;
regulator-always-on;
};
fet5 {
regulator-name = "fet5";
regulator-boot-on;
regulator-always-on;
};
fet6 {
regulator-name = "fet6";
regulator-boot-on;
regulator-always-on;
};
fet7 {
regulator-name = "fet7";
regulator-boot-on;
regulator-always-on;
};
ldo1 {
regulator-name = "ldo1";
regulator-boot-on;
regulator-always-on;
};
ldo2 {
regulator-name = "ldo2";
regulator-boot-on;
regulator-always-on;
};
};
};
88pm860x-backlight bindings
Optional properties:
- maxim,max8925-dual-string: whether support dual string
Example:
backlights {
maxim,max8925-dual-string = <0>;
};
......@@ -29,6 +29,164 @@
};
twsi1: i2c@d4011000 {
status = "okay";
pmic: max8925@3c {
compatible = "maxium,max8925";
reg = <0x3c>;
interrupts = <1>;
interrupt-parent = <&intcmux4>;
interrupt-controller;
#interrupt-cells = <1>;
maxim,tsc-irq = <0>;
regulators {
SDV1 {
regulator-min-microvolt = <637500>;
regulator-max-microvolt = <1425000>;
regulator-boot-on;
regulator-always-on;
};
SDV2 {
regulator-min-microvolt = <650000>;
regulator-max-microvolt = <2225000>;
regulator-boot-on;
regulator-always-on;
};
SDV3 {
regulator-min-microvolt = <750000>;
regulator-max-microvolt = <3900000>;
regulator-boot-on;
regulator-always-on;
};
LDO1 {
regulator-min-microvolt = <750000>;
regulator-max-microvolt = <3900000>;
regulator-boot-on;
regulator-always-on;
};
LDO2 {
regulator-min-microvolt = <650000>;
regulator-max-microvolt = <2250000>;
regulator-boot-on;
regulator-always-on;
};
LDO3 {
regulator-min-microvolt = <650000>;
regulator-max-microvolt = <2250000>;
regulator-boot-on;
regulator-always-on;
};
LDO4 {
regulator-min-microvolt = <750000>;
regulator-max-microvolt = <3900000>;
regulator-boot-on;
regulator-always-on;
};
LDO5 {
regulator-min-microvolt = <750000>;
regulator-max-microvolt = <3900000>;
regulator-boot-on;
regulator-always-on;
};
LDO6 {
regulator-min-microvolt = <750000>;
regulator-max-microvolt = <3900000>;
regulator-boot-on;
regulator-always-on;
};
LDO7 {
regulator-min-microvolt = <750000>;
regulator-max-microvolt = <3900000>;
regulator-boot-on;
regulator-always-on;
};
LDO8 {
regulator-min-microvolt = <750000>;
regulator-max-microvolt = <3900000>;
regulator-boot-on;
regulator-always-on;
};
LDO9 {
regulator-min-microvolt = <750000>;
regulator-max-microvolt = <3900000>;
regulator-boot-on;
regulator-always-on;
};
LDO10 {
regulator-min-microvolt = <750000>;
regulator-max-microvolt = <3900000>;
};
LDO11 {
regulator-min-microvolt = <750000>;
regulator-max-microvolt = <3900000>;
regulator-boot-on;
regulator-always-on;
};
LDO12 {
regulator-min-microvolt = <750000>;
regulator-max-microvolt = <3900000>;
regulator-boot-on;
regulator-always-on;
};
LDO13 {
regulator-min-microvolt = <750000>;
regulator-max-microvolt = <3900000>;
regulator-boot-on;
regulator-always-on;
};
LDO14 {
regulator-min-microvolt = <750000>;
regulator-max-microvolt = <3900000>;
regulator-boot-on;
regulator-always-on;
};
LDO15 {
regulator-min-microvolt = <750000>;
regulator-max-microvolt = <3900000>;
regulator-boot-on;
regulator-always-on;
};
LDO16 {
regulator-min-microvolt = <750000>;
regulator-max-microvolt = <3900000>;
regulator-boot-on;
regulator-always-on;
};
LDO17 {
regulator-min-microvolt = <650000>;
regulator-max-microvolt = <2250000>;
regulator-boot-on;
regulator-always-on;
};
LDO18 {
regulator-min-microvolt = <650000>;
regulator-max-microvolt = <2250000>;
regulator-boot-on;
regulator-always-on;
};
LDO19 {
regulator-min-microvolt = <750000>;
regulator-max-microvolt = <3900000>;
regulator-boot-on;
regulator-always-on;
};
LDO20 {
regulator-min-microvolt = <750000>;
regulator-max-microvolt = <3900000>;
regulator-boot-on;
regulator-always-on;
};
};
backlight {
maxim,max8925-dual-string = <0>;
};
charger {
batt-detect = <0>;
topoff-threshold = <1>;
fast-charge = <7>;
no-temp-support = <0>;
no-insert-detect = <0>;
};
};
};
rtc: rtc@d4010000 {
status = "okay";
......
......@@ -46,7 +46,7 @@
mrvl,intc-nr-irqs = <64>;
};
intcmux4@d4282150 {
intcmux4: interrupt-controller@d4282150 {
compatible = "mrvl,mmp2-mux-intc";
interrupts = <4>;
interrupt-controller;
......@@ -201,6 +201,8 @@
compatible = "mrvl,mmp-twsi";
reg = <0xd4011000 0x1000>;
interrupts = <7>;
#address-cells = <1>;
#size-cells = <0>;
mrvl,i2c-fast-mode;
status = "disabled";
};
......
......@@ -49,13 +49,13 @@ static void zoom_panel_disable_lcd(struct omap_dss_device *dssdev)
{
}
/*
* PWMA/B register offsets (TWL4030_MODULE_PWMA)
*/
/* Register offsets in TWL4030_MODULE_INTBR */
#define TWL_INTBR_PMBR1 0xD
#define TWL_INTBR_GPBR1 0xC
#define TWL_LED_PWMON 0x0
#define TWL_LED_PWMOFF 0x1
/* Register offsets in TWL_MODULE_PWM */
#define TWL_LED_PWMON 0x3
#define TWL_LED_PWMOFF 0x4
static int zoom_set_bl_intensity(struct omap_dss_device *dssdev, int level)
{
......@@ -93,8 +93,8 @@ static int zoom_set_bl_intensity(struct omap_dss_device *dssdev, int level)
}
c = ((50 * (100 - level)) / 100) + 1;
twl_i2c_write_u8(TWL4030_MODULE_PWM1, 0x7F, TWL_LED_PWMOFF);
twl_i2c_write_u8(TWL4030_MODULE_PWM1, c, TWL_LED_PWMON);
twl_i2c_write_u8(TWL_MODULE_PWM, 0x7F, TWL_LED_PWMOFF);
twl_i2c_write_u8(TWL_MODULE_PWM, c, TWL_LED_PWMON);
#else
pr_warn("Backlight not enabled\n");
#endif
......
......@@ -657,6 +657,13 @@ config GPIO_JANZ_TTL
This driver provides support for driving the pins in output
mode only. Input mode is not supported.
config GPIO_PALMAS
bool "TI PALMAS series PMICs GPIO"
depends on MFD_PALMAS
help
Select this option to enable GPIO driver for the TI PALMAS
series chip family.
config GPIO_TPS6586X
bool "TPS6586X GPIO"
depends on MFD_TPS6586X
......
......@@ -68,6 +68,7 @@ obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o
obj-$(CONFIG_ARCH_TEGRA) += gpio-tegra.o
obj-$(CONFIG_GPIO_TIMBERDALE) += gpio-timberdale.o
obj-$(CONFIG_ARCH_DAVINCI_TNETV107X) += gpio-tnetv107x.o
obj-$(CONFIG_GPIO_PALMAS) += gpio-palmas.o
obj-$(CONFIG_GPIO_TPS6586X) += gpio-tps6586x.o
obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o
obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o
......
/*
* TI Palma series PMIC's GPIO driver.
*
* Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
*
* Author: Laxman Dewangan <ldewangan@nvidia.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/gpio.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mfd/palmas.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
struct palmas_gpio {
struct gpio_chip gpio_chip;
struct palmas *palmas;
};
static inline struct palmas_gpio *to_palmas_gpio(struct gpio_chip *chip)
{
return container_of(chip, struct palmas_gpio, gpio_chip);
}
static int palmas_gpio_get(struct gpio_chip *gc, unsigned offset)
{
struct palmas_gpio *pg = to_palmas_gpio(gc);
struct palmas *palmas = pg->palmas;
unsigned int val;
int ret;
ret = palmas_read(palmas, PALMAS_GPIO_BASE, PALMAS_GPIO_DATA_IN, &val);
if (ret < 0) {
dev_err(gc->dev, "GPIO_DATA_IN read failed, err = %d\n", ret);
return ret;
}
return !!(val & BIT(offset));
}
static void palmas_gpio_set(struct gpio_chip *gc, unsigned offset,
int value)
{
struct palmas_gpio *pg = to_palmas_gpio(gc);
struct palmas *palmas = pg->palmas;
int ret;
if (value)
ret = palmas_write(palmas, PALMAS_GPIO_BASE,
PALMAS_GPIO_SET_DATA_OUT, BIT(offset));
else
ret = palmas_write(palmas, PALMAS_GPIO_BASE,
PALMAS_GPIO_CLEAR_DATA_OUT, BIT(offset));
if (ret < 0)
dev_err(gc->dev, "%s write failed, err = %d\n",
(value) ? "GPIO_SET_DATA_OUT" : "GPIO_CLEAR_DATA_OUT",
ret);
}
static int palmas_gpio_output(struct gpio_chip *gc, unsigned offset,
int value)
{
struct palmas_gpio *pg = to_palmas_gpio(gc);
struct palmas *palmas = pg->palmas;
int ret;
/* Set the initial value */
palmas_gpio_set(gc, offset, value);
ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE,
PALMAS_GPIO_DATA_DIR, BIT(offset), BIT(offset));
if (ret < 0)
dev_err(gc->dev, "GPIO_DATA_DIR write failed, err = %d\n", ret);
return ret;
}
static int palmas_gpio_input(struct gpio_chip *gc, unsigned offset)
{
struct palmas_gpio *pg = to_palmas_gpio(gc);
struct palmas *palmas = pg->palmas;
int ret;
ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE,
PALMAS_GPIO_DATA_DIR, BIT(offset), 0);
if (ret < 0)
dev_err(gc->dev, "GPIO_DATA_DIR write failed, err = %d\n", ret);
return ret;
}
static int palmas_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
{
struct palmas_gpio *pg = to_palmas_gpio(gc);
struct palmas *palmas = pg->palmas;
return palmas_irq_get_virq(palmas, PALMAS_GPIO_0_IRQ + offset);
}
static int palmas_gpio_probe(struct platform_device *pdev)
{
struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);
struct palmas_platform_data *palmas_pdata;
struct palmas_gpio *palmas_gpio;
int ret;
palmas_gpio = devm_kzalloc(&pdev->dev,
sizeof(*palmas_gpio), GFP_KERNEL);
if (!palmas_gpio) {
dev_err(&pdev->dev, "Could not allocate palmas_gpio\n");
return -ENOMEM;
}
palmas_gpio->palmas = palmas;
palmas_gpio->gpio_chip.owner = THIS_MODULE;
palmas_gpio->gpio_chip.label = dev_name(&pdev->dev);
palmas_gpio->gpio_chip.ngpio = 8;
palmas_gpio->gpio_chip.can_sleep = 1;
palmas_gpio->gpio_chip.direction_input = palmas_gpio_input;
palmas_gpio->gpio_chip.direction_output = palmas_gpio_output;
palmas_gpio->gpio_chip.to_irq = palmas_gpio_to_irq;
palmas_gpio->gpio_chip.set = palmas_gpio_set;
palmas_gpio->gpio_chip.get = palmas_gpio_get;
palmas_gpio->gpio_chip.dev = &pdev->dev;
#ifdef CONFIG_OF_GPIO
palmas_gpio->gpio_chip.of_node = palmas->dev->of_node;
#endif
palmas_pdata = dev_get_platdata(palmas->dev);
if (palmas_pdata && palmas_pdata->gpio_base)
palmas_gpio->gpio_chip.base = palmas_pdata->gpio_base;
else
palmas_gpio->gpio_chip.base = -1;
ret = gpiochip_add(&palmas_gpio->gpio_chip);
if (ret < 0) {
dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
return ret;
}
platform_set_drvdata(pdev, palmas_gpio);
return ret;
}
static int palmas_gpio_remove(struct platform_device *pdev)
{
struct palmas_gpio *palmas_gpio = platform_get_drvdata(pdev);
return gpiochip_remove(&palmas_gpio->gpio_chip);
}
static struct platform_driver palmas_gpio_driver = {
.driver.name = "palmas-gpio",
.driver.owner = THIS_MODULE,
.probe = palmas_gpio_probe,
.remove = palmas_gpio_remove,
};
static int __init palmas_gpio_init(void)
{
return platform_driver_register(&palmas_gpio_driver);
}
subsys_initcall(palmas_gpio_init);
static void __exit palmas_gpio_exit(void)
{
platform_driver_unregister(&palmas_gpio_driver);
}
module_exit(palmas_gpio_exit);
MODULE_ALIAS("platform:palmas-gpio");
MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
MODULE_DESCRIPTION("GPIO driver for TI Palmas series PMICs");
MODULE_LICENSE("GPL v2");
......@@ -100,9 +100,6 @@ static int max8925_onkey_probe(struct platform_device *pdev)
input->dev.parent = &pdev->dev;
input_set_capability(input, EV_KEY, KEY_POWER);
irq[0] += chip->irq_base;
irq[1] += chip->irq_base;
error = request_threaded_irq(irq[0], NULL, max8925_onkey_handler,
IRQF_ONESHOT, "onkey-down", info);
if (error < 0) {
......
......@@ -426,6 +426,9 @@ static void rtsx_pci_ms_request(struct memstick_host *msh)
dev_dbg(ms_dev(host), "--> %s\n", __func__);
if (rtsx_pci_card_exclusive_check(host->pcr, RTSX_MS_CARD))
return;
schedule_work(&host->handle_req);
}
......@@ -441,6 +444,10 @@ static int rtsx_pci_ms_set_param(struct memstick_host *msh,
dev_dbg(ms_dev(host), "%s: param = %d, value = %d\n",
__func__, param, value);
err = rtsx_pci_card_exclusive_check(host->pcr, RTSX_MS_CARD);
if (err)
return err;
switch (param) {
case MEMSTICK_POWER:
if (value == MEMSTICK_POWER_ON)
......
......@@ -531,7 +531,7 @@ static int pm800_probe(struct i2c_client *client,
ret = device_800_init(chip, pdata);
if (ret) {
dev_err(chip->dev, "%s id 0x%x failed!\n", __func__, chip->id);
goto err_800_init;
goto err_subchip_alloc;
}
ret = pm800_pages_init(chip);
......@@ -546,10 +546,8 @@ static int pm800_probe(struct i2c_client *client,
err_page_init:
mfd_remove_devices(chip->dev);
device_irq_exit_800(chip);
err_800_init:
devm_kfree(&client->dev, subchip);
err_subchip_alloc:
pm80x_deinit(client);
pm80x_deinit();
out_init:
return ret;
}
......@@ -562,9 +560,7 @@ static int pm800_remove(struct i2c_client *client)
device_irq_exit_800(chip);
pm800_pages_exit(chip);
devm_kfree(&client->dev, chip->subchip);
pm80x_deinit(client);
pm80x_deinit();
return 0;
}
......
......@@ -257,7 +257,7 @@ static int pm805_probe(struct i2c_client *client,
pdata->plat_config(chip, pdata);
err_805_init:
pm80x_deinit(client);
pm80x_deinit();
out_init:
return ret;
}
......@@ -269,7 +269,7 @@ static int pm805_remove(struct i2c_client *client)
mfd_remove_devices(chip->dev);
device_irq_exit_805(chip);
pm80x_deinit(client);
pm80x_deinit();
return 0;
}
......
......@@ -48,14 +48,12 @@ int pm80x_init(struct i2c_client *client,
ret = PTR_ERR(map);
dev_err(&client->dev, "Failed to allocate register map: %d\n",
ret);
goto err_regmap_init;
return ret;
}
chip->id = id->driver_data;
if (chip->id < CHIP_PM800 || chip->id > CHIP_PM805) {
ret = -EINVAL;
goto err_chip_id;
}
if (chip->id < CHIP_PM800 || chip->id > CHIP_PM805)
return -EINVAL;
chip->client = client;
chip->regmap = map;
......@@ -82,19 +80,11 @@ int pm80x_init(struct i2c_client *client,
}
return 0;
err_chip_id:
regmap_exit(map);
err_regmap_init:
devm_kfree(&client->dev, chip);
return ret;
}
EXPORT_SYMBOL_GPL(pm80x_init);
int pm80x_deinit(struct i2c_client *client)
int pm80x_deinit(void)
{
struct pm80x_chip *chip = i2c_get_clientdata(client);
/*
* workaround: clear the dependency between pm800 and pm805.
* would remove it after HW chip fixes the issue.
......@@ -103,10 +93,6 @@ int pm80x_deinit(struct i2c_client *client)
g_pm80x_chip->companion = NULL;
else
g_pm80x_chip = NULL;
regmap_exit(chip->regmap);
devm_kfree(&client->dev, chip);
return 0;
}
EXPORT_SYMBOL_GPL(pm80x_deinit);
......
......@@ -65,7 +65,7 @@ config MFD_SM501_GPIO
config MFD_RTSX_PCI
tristate "Support for Realtek PCI-E card reader"
depends on PCI
depends on PCI && GENERIC_HARDIRQS
select MFD_CORE
help
This supports for Realtek PCI-Express card reader including rts5209,
......@@ -95,7 +95,7 @@ config MFD_DM355EVM_MSP
config MFD_TI_SSP
tristate "TI Sequencer Serial Port support"
depends on ARCH_DAVINCI_TNETV107X
depends on ARCH_DAVINCI_TNETV107X && GENERIC_HARDIRQS
select MFD_CORE
---help---
Say Y here if you want support for the Sequencer Serial Port
......@@ -109,6 +109,7 @@ config MFD_TI_AM335X_TSCADC
select MFD_CORE
select REGMAP
select REGMAP_MMIO
depends on GENERIC_HARDIRQS
help
If you say yes here you get support for Texas Instruments series
of Touch Screen /ADC chips.
......@@ -126,6 +127,7 @@ config HTC_EGPIO
config HTC_PASIC3
tristate "HTC PASIC3 LED/DS1WM chip support"
select MFD_CORE
depends on GENERIC_HARDIRQS
help
This core driver provides register access for the LED/DS1WM
chips labeled "AIC2" and "AIC3", found on HTC Blueangel and
......@@ -157,6 +159,7 @@ config MFD_LM3533
depends on I2C
select MFD_CORE
select REGMAP_I2C
depends on GENERIC_HARDIRQS
help
Say yes here to enable support for National Semiconductor / TI
LM3533 Lighting Power chips.
......@@ -171,6 +174,7 @@ config TPS6105X
select REGULATOR
select MFD_CORE
select REGULATOR_FIXED_VOLTAGE
depends on GENERIC_HARDIRQS
help
This option enables a driver for the TP61050/TPS61052
high-power "white LED driver". This boost converter is
......@@ -193,7 +197,7 @@ config TPS65010
config TPS6507X
tristate "TPS6507x Power Management / Touch Screen chips"
select MFD_CORE
depends on I2C
depends on I2C && GENERIC_HARDIRQS
help
If you say yes here you get support for the TPS6507x series of
Power Management / Touch Screen chips. These include voltage
......@@ -204,7 +208,7 @@ config TPS6507X
config MFD_TPS65217
tristate "TPS65217 Power Management / White LED chips"
depends on I2C
depends on I2C && GENERIC_HARDIRQS
select MFD_CORE
select REGMAP_I2C
help
......@@ -234,7 +238,7 @@ config MFD_TPS6586X
config MFD_TPS65910
bool "TPS65910 Power Management chip"
depends on I2C=y && GPIOLIB
depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
......@@ -251,7 +255,7 @@ config MFD_TPS65912_I2C
bool "TPS65912 Power Management chip with I2C"
select MFD_CORE
select MFD_TPS65912
depends on I2C=y && GPIOLIB
depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS
help
If you say yes here you get support for the TPS65912 series of
PM chips with I2C interface.
......@@ -260,7 +264,7 @@ config MFD_TPS65912_SPI
bool "TPS65912 Power Management chip with SPI"
select MFD_CORE
select MFD_TPS65912
depends on SPI_MASTER && GPIOLIB
depends on SPI_MASTER && GPIOLIB && GENERIC_HARDIRQS
help
If you say yes here you get support for the TPS65912 series of
PM chips with SPI interface.
......@@ -330,13 +334,13 @@ config TWL4030_POWER
config MFD_TWL4030_AUDIO
bool
depends on TWL4030_CORE
depends on TWL4030_CORE && GENERIC_HARDIRQS
select MFD_CORE
default n
config TWL6040_CORE
bool "Support for TWL6040 audio codec"
depends on I2C=y
depends on I2C=y && GENERIC_HARDIRQS
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
......@@ -405,7 +409,7 @@ config MFD_TMIO
config MFD_T7L66XB
bool "Support Toshiba T7L66XB"
depends on ARM && HAVE_CLK
depends on ARM && HAVE_CLK && GENERIC_HARDIRQS
select MFD_CORE
select MFD_TMIO
help
......@@ -413,7 +417,7 @@ config MFD_T7L66XB
config MFD_SMSC
bool "Support for the SMSC ECE1099 series chips"
depends on I2C=y
depends on I2C=y && GENERIC_HARDIRQS
select MFD_CORE
select REGMAP_I2C
help
......@@ -460,7 +464,7 @@ config MFD_DA9052_SPI
select REGMAP_SPI
select REGMAP_IRQ
select PMIC_DA9052
depends on SPI_MASTER=y
depends on SPI_MASTER=y && GENERIC_HARDIRQS
help
Support for the Dialog Semiconductor DA9052 PMIC
when controlled using SPI. This driver provides common support
......@@ -472,7 +476,7 @@ config MFD_DA9052_I2C
select REGMAP_I2C
select REGMAP_IRQ
select PMIC_DA9052
depends on I2C=y
depends on I2C=y && GENERIC_HARDIRQS
help
Support for the Dialog Semiconductor DA9052 PMIC
when controlled using I2C. This driver provides common support
......@@ -485,7 +489,7 @@ config MFD_DA9055
select REGMAP_IRQ
select PMIC_DA9055
select MFD_CORE
depends on I2C=y
depends on I2C=y && GENERIC_HARDIRQS
help
Say yes here for support of Dialog Semiconductor DA9055. This is
a Power Management IC. This driver provides common support for
......@@ -508,7 +512,7 @@ config PMIC_ADP5520
config MFD_LP8788
bool "Texas Instruments LP8788 Power Management Unit Driver"
depends on I2C=y
depends on I2C=y && GENERIC_HARDIRQS
select MFD_CORE
select REGMAP_I2C
select IRQ_DOMAIN
......@@ -611,7 +615,7 @@ config MFD_ARIZONA_I2C
select MFD_ARIZONA
select MFD_CORE
select REGMAP_I2C
depends on I2C
depends on I2C && GENERIC_HARDIRQS
help
Support for the Wolfson Microelectronics Arizona platform audio SoC
core functionality controlled via I2C.
......@@ -621,7 +625,7 @@ config MFD_ARIZONA_SPI
select MFD_ARIZONA
select MFD_CORE
select REGMAP_SPI
depends on SPI_MASTER
depends on SPI_MASTER && GENERIC_HARDIRQS
help
Support for the Wolfson Microelectronics Arizona platform audio SoC
core functionality controlled via I2C.
......@@ -641,7 +645,7 @@ config MFD_WM5110
config MFD_WM8400
bool "Support Wolfson Microelectronics WM8400"
select MFD_CORE
depends on I2C=y
depends on I2C=y && GENERIC_HARDIRQS
select REGMAP_I2C
help
Support for the Wolfson Microelecronics WM8400 PMIC and audio
......@@ -785,7 +789,7 @@ config MFD_MC13783
config MFD_MC13XXX
tristate
depends on SPI_MASTER || I2C
depends on (SPI_MASTER || I2C) && GENERIC_HARDIRQS
select MFD_CORE
select MFD_MC13783
help
......@@ -796,7 +800,7 @@ config MFD_MC13XXX
config MFD_MC13XXX_SPI
tristate "Freescale MC13783 and MC13892 SPI interface"
depends on SPI_MASTER
depends on SPI_MASTER && GENERIC_HARDIRQS
select REGMAP_SPI
select MFD_MC13XXX
help
......@@ -804,7 +808,7 @@ config MFD_MC13XXX_SPI
config MFD_MC13XXX_I2C
tristate "Freescale MC13892 I2C interface"
depends on I2C
depends on I2C && GENERIC_HARDIRQS
select REGMAP_I2C
select MFD_MC13XXX
help
......@@ -822,7 +826,7 @@ config ABX500_CORE
config AB3100_CORE
bool "ST-Ericsson AB3100 Mixed Signal Circuit core functions"
depends on I2C=y && ABX500_CORE
depends on I2C=y && ABX500_CORE && GENERIC_HARDIRQS
select MFD_CORE
default y if ARCH_U300
help
......@@ -909,7 +913,7 @@ config MFD_TIMBERDALE
config LPC_SCH
tristate "Intel SCH LPC"
depends on PCI
depends on PCI && GENERIC_HARDIRQS
select MFD_CORE
help
LPC bridge function of the Intel SCH provides support for
......@@ -917,7 +921,7 @@ config LPC_SCH
config LPC_ICH
tristate "Intel ICH LPC"
depends on PCI
depends on PCI && GENERIC_HARDIRQS
select MFD_CORE
help
The LPC bridge function of the Intel ICH provides support for
......@@ -928,7 +932,7 @@ config LPC_ICH
config MFD_RDC321X
tristate "Support for RDC-R321x southbridge"
select MFD_CORE
depends on PCI
depends on PCI && GENERIC_HARDIRQS
help
Say yes here if you want to have support for the RDC R-321x SoC
southbridge which provides access to GPIOs and Watchdog using the
......@@ -937,7 +941,7 @@ config MFD_RDC321X
config MFD_JANZ_CMODIO
tristate "Support for Janz CMOD-IO PCI MODULbus Carrier Board"
select MFD_CORE
depends on PCI
depends on PCI && GENERIC_HARDIRQS
help
This is the core driver for the Janz CMOD-IO PCI MODULbus
carrier board. This device is a PCI to MODULbus bridge which may
......@@ -955,7 +959,7 @@ config MFD_JZ4740_ADC
config MFD_VX855
tristate "Support for VIA VX855/VX875 integrated south bridge"
depends on PCI
depends on PCI && GENERIC_HARDIRQS
select MFD_CORE
help
Say yes here to enable support for various functions of the
......@@ -964,7 +968,7 @@ config MFD_VX855
config MFD_WL1273_CORE
tristate "Support for TI WL1273 FM radio."
depends on I2C
depends on I2C && GENERIC_HARDIRQS
select MFD_CORE
default n
help
......@@ -1028,7 +1032,7 @@ config MFD_TPS65090
config MFD_AAT2870_CORE
bool "Support for the AnalogicTech AAT2870"
select MFD_CORE
depends on I2C=y && GPIOLIB
depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS
help
If you say yes here you get support for the AAT2870.
This driver provides common support for accessing the device,
......@@ -1060,7 +1064,7 @@ config MFD_RC5T583
config MFD_STA2X11
bool "STA2X11 multi function device support"
depends on STA2X11
depends on STA2X11 && GENERIC_HARDIRQS
select MFD_CORE
select REGMAP_MMIO
......@@ -1077,7 +1081,7 @@ config MFD_PALMAS
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
depends on I2C=y
depends on I2C=y && GENERIC_HARDIRQS
help
If you say yes here you get support for the Palmas
series of PMIC chips from Texas Instruments.
......@@ -1085,7 +1089,7 @@ config MFD_PALMAS
config MFD_VIPERBOARD
tristate "Support for Nano River Technologies Viperboard"
select MFD_CORE
depends on USB
depends on USB && GENERIC_HARDIRQS
default n
help
Say yes here if you want support for Nano River Technologies
......@@ -1099,7 +1103,7 @@ config MFD_VIPERBOARD
config MFD_RETU
tristate "Support for Retu multi-function device"
select MFD_CORE
depends on I2C
depends on I2C && GENERIC_HARDIRQS
select REGMAP_IRQ
help
Retu is a multi-function device found on Nokia Internet Tablets
......@@ -1110,7 +1114,7 @@ config MFD_AS3711
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
depends on I2C=y
depends on I2C=y && GENERIC_HARDIRQS
help
Support for the AS3711 PMIC from AMS
......
......@@ -9,7 +9,7 @@ obj-$(CONFIG_MFD_88PM805) += 88pm805.o 88pm80x.o
obj-$(CONFIG_MFD_SM501) += sm501.o
obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o
rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o
rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o
obj-$(CONFIG_MFD_RTSX_PCI) += rtsx_pci.o
obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o
......
......@@ -320,6 +320,7 @@ static struct abx500_ops ab8500_ops = {
.mask_and_set_register = ab8500_mask_and_set_register,
.event_registers_startup_state_get = NULL,
.startup_irq_enabled = NULL,
.dump_all_banks = ab8500_dump_all_banks,
};
static void ab8500_irq_lock(struct irq_data *data)
......@@ -368,16 +369,48 @@ static void ab8500_irq_mask(struct irq_data *data)
int mask = 1 << (offset % 8);
ab8500->mask[index] |= mask;
/* The AB8500 GPIOs have two interrupts each (rising & falling). */
if (offset >= AB8500_INT_GPIO6R && offset <= AB8500_INT_GPIO41R)
ab8500->mask[index + 2] |= mask;
if (offset >= AB9540_INT_GPIO50R && offset <= AB9540_INT_GPIO54R)
ab8500->mask[index + 1] |= mask;
if (offset == AB8540_INT_GPIO43R || offset == AB8540_INT_GPIO44R)
/* Here the falling IRQ is one bit lower */
ab8500->mask[index] |= (mask << 1);
}
static void ab8500_irq_unmask(struct irq_data *data)
{
struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
unsigned int type = irqd_get_trigger_type(data);
int offset = data->hwirq;
int index = offset / 8;
int mask = 1 << (offset % 8);
ab8500->mask[index] &= ~mask;
if (type & IRQ_TYPE_EDGE_RISING)
ab8500->mask[index] &= ~mask;
/* The AB8500 GPIOs have two interrupts each (rising & falling). */
if (type & IRQ_TYPE_EDGE_FALLING) {
if (offset >= AB8500_INT_GPIO6R && offset <= AB8500_INT_GPIO41R)
ab8500->mask[index + 2] &= ~mask;
else if (offset >= AB9540_INT_GPIO50R && offset <= AB9540_INT_GPIO54R)
ab8500->mask[index + 1] &= ~mask;
else if (offset == AB8540_INT_GPIO43R || offset == AB8540_INT_GPIO44R)
/* Here the falling IRQ is one bit lower */
ab8500->mask[index] &= ~(mask << 1);
else
ab8500->mask[index] &= ~mask;
} else {
/* Satisfies the case where type is not set. */
ab8500->mask[index] &= ~mask;
}
}
static int ab8500_irq_set_type(struct irq_data *data, unsigned int type)
{
return 0;
}
static struct irq_chip ab8500_irq_chip = {
......@@ -387,6 +420,7 @@ static struct irq_chip ab8500_irq_chip = {
.irq_mask = ab8500_irq_mask,
.irq_disable = ab8500_irq_mask,
.irq_unmask = ab8500_irq_unmask,
.irq_set_type = ab8500_irq_set_type,
};
static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500,
......@@ -411,6 +445,19 @@ static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500,
line = (i << 3) + int_bit;
latch_val &= ~(1 << int_bit);
/*
* This handles the falling edge hwirqs from the GPIO
* lines. Route them back to the line registered for the
* rising IRQ, as this is merely a flag for the same IRQ
* in linux terms.
*/
if (line >= AB8500_INT_GPIO6F && line <= AB8500_INT_GPIO41F)
line -= 16;
if (line >= AB9540_INT_GPIO50F && line <= AB9540_INT_GPIO54F)
line -= 8;
if (line == AB8540_INT_GPIO43F || line == AB8540_INT_GPIO44F)
line += 1;
handle_nested_irq(ab8500->irq_base + line);
} while (latch_val);
......@@ -521,6 +568,7 @@ static irqreturn_t ab8500_irq(int irq, void *dev)
int virq = ab8500_irq_get_virq(ab8500, line);
handle_nested_irq(virq);
ab8500_debug_register_interrupt(line);
value &= ~(1 << bit);
} while (value);
......@@ -929,7 +977,7 @@ static struct resource ab8505_iddet_resources[] = {
static struct resource ab8500_temp_resources[] = {
{
.name = "AB8500_TEMP_WARM",
.name = "ABX500_TEMP_WARM",
.start = AB8500_INT_TEMP_WARM,
.end = AB8500_INT_TEMP_WARM,
.flags = IORESOURCE_IRQ,
......@@ -1005,8 +1053,8 @@ static struct mfd_cell abx500_common_devs[] = {
.of_compatible = "stericsson,ab8500-denc",
},
{
.name = "ab8500-temp",
.of_compatible = "stericsson,ab8500-temp",
.name = "abx500-temp",
.of_compatible = "stericsson,abx500-temp",
.num_resources = ARRAY_SIZE(ab8500_temp_resources),
.resources = ab8500_temp_resources,
},
......@@ -1049,7 +1097,7 @@ static struct mfd_cell ab8500_bm_devs[] = {
static struct mfd_cell ab8500_devs[] = {
{
.name = "ab8500-gpio",
.name = "pinctrl-ab8500",
.of_compatible = "stericsson,ab8500-gpio",
},
{
......@@ -1066,7 +1114,8 @@ static struct mfd_cell ab8500_devs[] = {
static struct mfd_cell ab9540_devs[] = {
{
.name = "ab8500-gpio",
.name = "pinctrl-ab9540",
.of_compatible = "stericsson,ab9540-gpio",
},
{
.name = "ab9540-usb",
......
此差异已折叠。
......@@ -12,6 +12,7 @@
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/pm_runtime.h>
#include <linux/platform_device.h>
#include <linux/completion.h>
#include <linux/regulator/consumer.h>
......@@ -82,6 +83,11 @@
/* This is used to not lose precision when dividing to get gain and offset */
#define CALIB_SCALE 1000
/* Time in ms before disabling regulator */
#define GPADC_AUDOSUSPEND_DELAY 1
#define CONVERSION_TIME 500 /* ms */
enum cal_channels {
ADC_INPUT_VMAIN = 0,
ADC_INPUT_BTEMP,
......@@ -102,10 +108,10 @@ struct adc_cal_data {
/**
* struct ab8500_gpadc - AB8500 GPADC device information
* @chip_id ABB chip id
* @dev: pointer to the struct device
* @node: a list of AB8500 GPADCs, hence prepared for
reentrance
* @parent: pointer to the struct ab8500
* @ab8500_gpadc_complete: pointer to the struct completion, to indicate
* the completion of gpadc conversion
* @ab8500_gpadc_lock: structure of type mutex
......@@ -114,9 +120,9 @@ struct adc_cal_data {
* @cal_data array of ADC calibration data structs
*/
struct ab8500_gpadc {
u8 chip_id;
struct device *dev;
struct list_head node;
struct ab8500 *parent;
struct completion ab8500_gpadc_complete;
struct mutex ab8500_gpadc_lock;
struct regulator *regu;
......@@ -282,8 +288,9 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
return -ENODEV;
mutex_lock(&gpadc->ab8500_gpadc_lock);
/* Enable VTVout LDO this is required for GPADC */
regulator_enable(gpadc->regu);
pm_runtime_get_sync(gpadc->dev);
/* Check if ADC is not busy, lock and proceed */
do {
......@@ -332,7 +339,7 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
EN_BUF | EN_ICHAR);
break;
case BTEMP_BALL:
if (gpadc->chip_id >= AB8500_CUT3P0) {
if (!is_ab8500_2p0_or_earlier(gpadc->parent)) {
/* Turn on btemp pull-up on ABB 3.0 */
ret = abx500_mask_and_set_register_interruptible(
gpadc->dev,
......@@ -344,7 +351,7 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
* Delay might be needed for ABB8500 cut 3.0, if not, remove
* when hardware will be available
*/
msleep(1);
usleep_range(1000, 1000);
break;
}
/* Intentional fallthrough */
......@@ -367,7 +374,8 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
goto out;
}
/* wait for completion of conversion */
if (!wait_for_completion_timeout(&gpadc->ab8500_gpadc_complete, 2*HZ)) {
if (!wait_for_completion_timeout(&gpadc->ab8500_gpadc_complete,
msecs_to_jiffies(CONVERSION_TIME))) {
dev_err(gpadc->dev,
"timeout: didn't receive GPADC conversion interrupt\n");
ret = -EINVAL;
......@@ -397,8 +405,10 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
dev_err(gpadc->dev, "gpadc_conversion: disable gpadc failed\n");
goto out;
}
/* Disable VTVout LDO this is required for GPADC */
regulator_disable(gpadc->regu);
pm_runtime_mark_last_busy(gpadc->dev);
pm_runtime_put_autosuspend(gpadc->dev);
mutex_unlock(&gpadc->ab8500_gpadc_lock);
return (high_data << 8) | low_data;
......@@ -412,7 +422,9 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
*/
(void) abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC,
AB8500_GPADC_CTRL1_REG, DIS_GPADC);
regulator_disable(gpadc->regu);
pm_runtime_put(gpadc->dev);
mutex_unlock(&gpadc->ab8500_gpadc_lock);
dev_err(gpadc->dev,
"gpadc_conversion: Failed to AD convert channel %d\n", channel);
......@@ -571,6 +583,28 @@ static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc)
gpadc->cal_data[ADC_INPUT_VBAT].offset);
}
static int ab8500_gpadc_runtime_suspend(struct device *dev)
{
struct ab8500_gpadc *gpadc = dev_get_drvdata(dev);
regulator_disable(gpadc->regu);
return 0;
}
static int ab8500_gpadc_runtime_resume(struct device *dev)
{
struct ab8500_gpadc *gpadc = dev_get_drvdata(dev);
regulator_enable(gpadc->regu);
return 0;
}
static int ab8500_gpadc_runtime_idle(struct device *dev)
{
pm_runtime_suspend(dev);
return 0;
}
static int ab8500_gpadc_probe(struct platform_device *pdev)
{
int ret = 0;
......@@ -591,6 +625,7 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
}
gpadc->dev = &pdev->dev;
gpadc->parent = dev_get_drvdata(pdev->dev.parent);
mutex_init(&gpadc->ab8500_gpadc_lock);
/* Initialize completion used to notify completion of conversion */
......@@ -607,14 +642,6 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
goto fail;
}
/* Get Chip ID of the ABB ASIC */
ret = abx500_get_chip_id(gpadc->dev);
if (ret < 0) {
dev_err(gpadc->dev, "failed to get chip ID\n");
goto fail_irq;
}
gpadc->chip_id = (u8) ret;
/* VTVout LDO used to power up ab8500-GPADC */
gpadc->regu = regulator_get(&pdev->dev, "vddadc");
if (IS_ERR(gpadc->regu)) {
......@@ -622,6 +649,16 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
dev_err(gpadc->dev, "failed to get vtvout LDO\n");
goto fail_irq;
}
platform_set_drvdata(pdev, gpadc);
regulator_enable(gpadc->regu);
pm_runtime_set_autosuspend_delay(gpadc->dev, GPADC_AUDOSUSPEND_DELAY);
pm_runtime_use_autosuspend(gpadc->dev);
pm_runtime_set_active(gpadc->dev);
pm_runtime_enable(gpadc->dev);
ab8500_gpadc_read_calibration_data(gpadc);
list_add_tail(&gpadc->node, &ab8500_gpadc_list);
dev_dbg(gpadc->dev, "probe success\n");
......@@ -642,19 +679,34 @@ static int ab8500_gpadc_remove(struct platform_device *pdev)
list_del(&gpadc->node);
/* remove interrupt - completion of Sw ADC conversion */
free_irq(gpadc->irq, gpadc);
/* disable VTVout LDO that is being used by GPADC */
regulator_put(gpadc->regu);
pm_runtime_get_sync(gpadc->dev);
pm_runtime_disable(gpadc->dev);
regulator_disable(gpadc->regu);
pm_runtime_set_suspended(gpadc->dev);
pm_runtime_put_noidle(gpadc->dev);
kfree(gpadc);
gpadc = NULL;
return 0;
}
static const struct dev_pm_ops ab8500_gpadc_pm_ops = {
SET_RUNTIME_PM_OPS(ab8500_gpadc_runtime_suspend,
ab8500_gpadc_runtime_resume,
ab8500_gpadc_runtime_idle)
};
static struct platform_driver ab8500_gpadc_driver = {
.probe = ab8500_gpadc_probe,
.remove = ab8500_gpadc_remove,
.driver = {
.name = "ab8500-gpadc",
.owner = THIS_MODULE,
.pm = &ab8500_gpadc_pm_ops,
},
};
......
......@@ -7,12 +7,73 @@
#include <linux/err.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/reboot.h>
#include <linux/signal.h>
#include <linux/power_supply.h>
#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500/ab8500.h>
#include <linux/mfd/abx500/ab8500-sysctrl.h>
static struct device *sysctrl_dev;
void ab8500_power_off(void)
{
sigset_t old;
sigset_t all;
static char *pss[] = {"ab8500_ac", "ab8500_usb"};
int i;
bool charger_present = false;
union power_supply_propval val;
struct power_supply *psy;
int ret;
/*
* If we have a charger connected and we're powering off,
* reboot into charge-only mode.
*/
for (i = 0; i < ARRAY_SIZE(pss); i++) {
psy = power_supply_get_by_name(pss[i]);
if (!psy)
continue;
ret = psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &val);
if (!ret && val.intval) {
charger_present = true;
break;
}
}
if (!charger_present)
goto shutdown;
/* Check if battery is known */
psy = power_supply_get_by_name("ab8500_btemp");
if (psy) {
ret = psy->get_property(psy, POWER_SUPPLY_PROP_TECHNOLOGY,
&val);
if (!ret && val.intval != POWER_SUPPLY_TECHNOLOGY_UNKNOWN) {
printk(KERN_INFO
"Charger \"%s\" is connected with known battery."
" Rebooting.\n",
pss[i]);
machine_restart("charging");
}
}
shutdown:
sigfillset(&all);
if (!sigprocmask(SIG_BLOCK, &all, &old)) {
(void)ab8500_sysctrl_set(AB8500_STW4500CTRL1,
AB8500_STW4500CTRL1_SWOFF |
AB8500_STW4500CTRL1_SWRESET4500N);
(void)sigprocmask(SIG_SETMASK, &old, NULL);
}
}
static inline bool valid_bank(u8 bank)
{
return ((bank == AB8500_SYS_CTRL1_BLOCK) ||
......@@ -33,6 +94,7 @@ int ab8500_sysctrl_read(u16 reg, u8 *value)
return abx500_get_register_interruptible(sysctrl_dev, bank,
(u8)(reg & 0xFF), value);
}
EXPORT_SYMBOL(ab8500_sysctrl_read);
int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value)
{
......@@ -48,10 +110,40 @@ int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value)
return abx500_mask_and_set_register_interruptible(sysctrl_dev, bank,
(u8)(reg & 0xFF), mask, value);
}
EXPORT_SYMBOL(ab8500_sysctrl_write);
static int ab8500_sysctrl_probe(struct platform_device *pdev)
{
struct ab8500_platform_data *plat;
struct ab8500_sysctrl_platform_data *pdata;
sysctrl_dev = &pdev->dev;
plat = dev_get_platdata(pdev->dev.parent);
if (plat->pm_power_off)
pm_power_off = ab8500_power_off;
pdata = plat->sysctrl;
if (pdata) {
int ret, i, j;
for (i = AB8500_SYSCLKREQ1RFCLKBUF;
i <= AB8500_SYSCLKREQ8RFCLKBUF; i++) {
j = i - AB8500_SYSCLKREQ1RFCLKBUF;
ret = ab8500_sysctrl_write(i, 0xff,
pdata->initial_req_buf_config[j]);
dev_dbg(&pdev->dev,
"Setting SysClkReq%dRfClkBuf 0x%X\n",
j + 1,
pdata->initial_req_buf_config[j]);
if (ret < 0) {
dev_err(&pdev->dev,
"unable to set sysClkReq%dRfClkBuf: "
"%d\n", j + 1, ret);
}
}
}
return 0;
}
......
......@@ -153,6 +153,22 @@ int abx500_startup_irq_enabled(struct device *dev, unsigned int irq)
}
EXPORT_SYMBOL(abx500_startup_irq_enabled);
void abx500_dump_all_banks(void)
{
struct abx500_ops *ops;
struct device dummy_child = {0};
struct abx500_device_entry *dev_entry;
list_for_each_entry(dev_entry, &abx500_list, list) {
dummy_child.parent = dev_entry->dev;
ops = &dev_entry->ops;
if ((ops != NULL) && (ops->dump_all_banks != NULL))
ops->dump_all_banks(&dummy_child);
}
}
EXPORT_SYMBOL(abx500_dump_all_banks);
MODULE_AUTHOR("Mattias Wallin <mattias.wallin@stericsson.com>");
MODULE_DESCRIPTION("ABX500 core driver");
MODULE_LICENSE("GPL");
......@@ -115,7 +115,7 @@ static irqreturn_t arizona_underclocked(int irq, void *data)
if (val & ARIZONA_ADC_UNDERCLOCKED_STS)
dev_err(arizona->dev, "ADC underclocked\n");
if (val & ARIZONA_MIXER_UNDERCLOCKED_STS)
dev_err(arizona->dev, "Mixer underclocked\n");
dev_err(arizona->dev, "Mixer dropped sample\n");
return IRQ_HANDLED;
}
......@@ -263,10 +263,36 @@ static int arizona_runtime_suspend(struct device *dev)
}
#endif
#ifdef CONFIG_PM_SLEEP
static int arizona_resume_noirq(struct device *dev)
{
struct arizona *arizona = dev_get_drvdata(dev);
dev_dbg(arizona->dev, "Early resume, disabling IRQ\n");
disable_irq(arizona->irq);
return 0;
}
static int arizona_resume(struct device *dev)
{
struct arizona *arizona = dev_get_drvdata(dev);
dev_dbg(arizona->dev, "Late resume, reenabling IRQ\n");
enable_irq(arizona->irq);
return 0;
}
#endif
const struct dev_pm_ops arizona_pm_ops = {
SET_RUNTIME_PM_OPS(arizona_runtime_suspend,
arizona_runtime_resume,
NULL)
SET_SYSTEM_SLEEP_PM_OPS(NULL, arizona_resume)
#ifdef CONFIG_PM_SLEEP
.resume_noirq = arizona_resume_noirq,
#endif
};
EXPORT_SYMBOL_GPL(arizona_pm_ops);
......@@ -275,19 +301,19 @@ static struct mfd_cell early_devs[] = {
};
static struct mfd_cell wm5102_devs[] = {
{ .name = "arizona-micsupp" },
{ .name = "arizona-extcon" },
{ .name = "arizona-gpio" },
{ .name = "arizona-haptics" },
{ .name = "arizona-micsupp" },
{ .name = "arizona-pwm" },
{ .name = "wm5102-codec" },
};
static struct mfd_cell wm5110_devs[] = {
{ .name = "arizona-micsupp" },
{ .name = "arizona-extcon" },
{ .name = "arizona-gpio" },
{ .name = "arizona-haptics" },
{ .name = "arizona-micsupp" },
{ .name = "arizona-pwm" },
{ .name = "wm5110-codec" },
};
......@@ -484,6 +510,29 @@ int arizona_dev_init(struct arizona *arizona)
goto err_reset;
}
for (i = 0; i < ARIZONA_MAX_MICBIAS; i++) {
if (!arizona->pdata.micbias[i].mV)
continue;
val = (arizona->pdata.micbias[i].mV - 1500) / 100;
val <<= ARIZONA_MICB1_LVL_SHIFT;
if (arizona->pdata.micbias[i].ext_cap)
val |= ARIZONA_MICB1_EXT_CAP;
if (arizona->pdata.micbias[i].discharge)
val |= ARIZONA_MICB1_DISCH;
if (arizona->pdata.micbias[i].fast_start)
val |= ARIZONA_MICB1_RATE;
regmap_update_bits(arizona->regmap,
ARIZONA_MIC_BIAS_CTRL_1 + i,
ARIZONA_MICB1_LVL_MASK |
ARIZONA_MICB1_DISCH |
ARIZONA_MICB1_RATE, val);
}
for (i = 0; i < ARIZONA_MAX_INPUT; i++) {
/* Default for both is 0 so noop with defaults */
val = arizona->pdata.dmic_ref[i]
......
......@@ -60,7 +60,7 @@ static inline bool i2c_safe_reg(unsigned char reg)
* This fix is to follow any read or write with a dummy read to a safe
* register.
*/
int da9052_i2c_fix(struct da9052 *da9052, unsigned char reg)
static int da9052_i2c_fix(struct da9052 *da9052, unsigned char reg)
{
int val;
......@@ -85,7 +85,6 @@ int da9052_i2c_fix(struct da9052 *da9052, unsigned char reg)
return 0;
}
EXPORT_SYMBOL(da9052_i2c_fix);
static int da9052_i2c_enable_multiwrite(struct da9052 *da9052)
{
......
......@@ -33,6 +33,7 @@
#include <linux/regulator/db8500-prcmu.h>
#include <linux/regulator/machine.h>
#include <linux/cpufreq.h>
#include <linux/platform_data/ux500_wdt.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
#include <mach/db8500-regs.h>
......@@ -2207,21 +2208,25 @@ int db8500_prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
sleep_auto_off ? A9WDOG_AUTO_OFF_EN :
A9WDOG_AUTO_OFF_DIS);
}
EXPORT_SYMBOL(db8500_prcmu_config_a9wdog);
int db8500_prcmu_enable_a9wdog(u8 id)
{
return prcmu_a9wdog(MB4H_A9WDOG_EN, id, 0, 0, 0);
}
EXPORT_SYMBOL(db8500_prcmu_enable_a9wdog);
int db8500_prcmu_disable_a9wdog(u8 id)
{
return prcmu_a9wdog(MB4H_A9WDOG_DIS, id, 0, 0, 0);
}
EXPORT_SYMBOL(db8500_prcmu_disable_a9wdog);
int db8500_prcmu_kick_a9wdog(u8 id)
{
return prcmu_a9wdog(MB4H_A9WDOG_KICK, id, 0, 0, 0);
}
EXPORT_SYMBOL(db8500_prcmu_kick_a9wdog);
/*
* timeout is 28 bit, in ms.
......@@ -2239,6 +2244,7 @@ int db8500_prcmu_load_a9wdog(u8 id, u32 timeout)
(u8)((timeout >> 12) & 0xff),
(u8)((timeout >> 20) & 0xff));
}
EXPORT_SYMBOL(db8500_prcmu_load_a9wdog);
/**
* prcmu_abb_read() - Read register value(s) from the ABB.
......@@ -3094,6 +3100,11 @@ static struct resource ab8500_resources[] = {
}
};
static struct ux500_wdt_data db8500_wdt_pdata = {
.timeout = 600, /* 10 minutes */
.has_28_bits_resolution = true,
};
static struct mfd_cell db8500_prcmu_devs[] = {
{
.name = "db8500-prcmu-regulators",
......@@ -3107,6 +3118,12 @@ static struct mfd_cell db8500_prcmu_devs[] = {
.platform_data = &db8500_cpufreq_table,
.pdata_size = sizeof(db8500_cpufreq_table),
},
{
.name = "ux500_wdt",
.platform_data = &db8500_wdt_pdata,
.pdata_size = sizeof(db8500_wdt_pdata),
.id = -1,
},
{
.name = "ab8500-core",
.of_compatible = "stericsson,ab8500",
......
......@@ -50,6 +50,7 @@
* document number TBD : Panther Point
* document number TBD : Lynx Point
* document number TBD : Lynx Point-LP
* document number TBD : Wellsburg
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
......@@ -75,8 +76,10 @@
#define ACPIBASE_GCS_OFF 0x3410
#define ACPIBASE_GCS_END 0x3414
#define GPIOBASE 0x48
#define GPIOCTRL 0x4C
#define GPIOBASE_ICH0 0x58
#define GPIOCTRL_ICH0 0x5C
#define GPIOBASE_ICH6 0x48
#define GPIOCTRL_ICH6 0x4C
#define RCBABASE 0xf0
......@@ -84,8 +87,17 @@
#define wdt_mem_res(i) wdt_res(ICH_RES_MEM_OFF, i)
#define wdt_res(b, i) (&wdt_ich_res[(b) + (i)])
static int lpc_ich_acpi_save = -1;
static int lpc_ich_gpio_save = -1;
struct lpc_ich_cfg {
int base;
int ctrl;
int save;
};
struct lpc_ich_priv {
int chipset;
struct lpc_ich_cfg acpi;
struct lpc_ich_cfg gpio;
};
static struct resource wdt_ich_res[] = {
/* ACPI - TCO */
......@@ -194,6 +206,7 @@ enum lpc_chipsets {
LPC_PPT, /* Panther Point */
LPC_LPT, /* Lynx Point */
LPC_LPT_LP, /* Lynx Point-LP */
LPC_WBG, /* Wellsburg */
};
struct lpc_ich_info lpc_chipset_info[] = {
......@@ -474,6 +487,10 @@ struct lpc_ich_info lpc_chipset_info[] = {
.name = "Lynx Point_LP",
.iTCO_version = 2,
},
[LPC_WBG] = {
.name = "Wellsburg",
.iTCO_version = 2,
},
};
/*
......@@ -655,45 +672,82 @@ static DEFINE_PCI_DEVICE_TABLE(lpc_ich_ids) = {
{ PCI_VDEVICE(INTEL, 0x9c45), LPC_LPT_LP},
{ PCI_VDEVICE(INTEL, 0x9c46), LPC_LPT_LP},
{ PCI_VDEVICE(INTEL, 0x9c47), LPC_LPT_LP},
{ PCI_VDEVICE(INTEL, 0x8d40), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x8d41), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x8d42), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x8d43), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x8d44), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x8d45), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x8d46), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x8d47), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x8d48), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x8d49), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x8d4a), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x8d4b), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x8d4c), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x8d4d), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x8d4e), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x8d4f), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x8d50), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x8d51), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x8d52), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x8d53), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x8d54), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x8d55), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x8d56), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x8d57), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x8d58), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x8d59), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x8d5a), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x8d5b), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x8d5c), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x8d5d), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x8d5e), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x8d5f), LPC_WBG},
{ 0, }, /* End of list */
};
MODULE_DEVICE_TABLE(pci, lpc_ich_ids);
static void lpc_ich_restore_config_space(struct pci_dev *dev)
{
if (lpc_ich_acpi_save >= 0) {
pci_write_config_byte(dev, ACPICTRL, lpc_ich_acpi_save);
lpc_ich_acpi_save = -1;
struct lpc_ich_priv *priv = pci_get_drvdata(dev);
if (priv->acpi.save >= 0) {
pci_write_config_byte(dev, priv->acpi.ctrl, priv->acpi.save);
priv->acpi.save = -1;
}
if (lpc_ich_gpio_save >= 0) {
pci_write_config_byte(dev, GPIOCTRL, lpc_ich_gpio_save);
lpc_ich_gpio_save = -1;
if (priv->gpio.save >= 0) {
pci_write_config_byte(dev, priv->gpio.ctrl, priv->gpio.save);
priv->gpio.save = -1;
}
}
static void lpc_ich_enable_acpi_space(struct pci_dev *dev)
{
struct lpc_ich_priv *priv = pci_get_drvdata(dev);
u8 reg_save;
pci_read_config_byte(dev, ACPICTRL, &reg_save);
pci_write_config_byte(dev, ACPICTRL, reg_save | 0x10);
lpc_ich_acpi_save = reg_save;
pci_read_config_byte(dev, priv->acpi.ctrl, &reg_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, &reg_save);
pci_write_config_byte(dev, GPIOCTRL, reg_save | 0x10);
lpc_ich_gpio_save = reg_save;
pci_read_config_byte(dev, priv->gpio.ctrl, &reg_save);
pci_write_config_byte(dev, priv->gpio.ctrl, reg_save | 0x10);
priv->gpio.save = reg_save;
}
static void lpc_ich_finalize_cell(struct mfd_cell *cell,
const struct pci_device_id *id)
static void lpc_ich_finalize_cell(struct pci_dev *dev, struct mfd_cell *cell)
{
cell->platform_data = &lpc_chipset_info[id->driver_data];
struct lpc_ich_priv *priv = pci_get_drvdata(dev);
cell->platform_data = &lpc_chipset_info[priv->chipset];
cell->pdata_size = sizeof(struct lpc_ich_info);
}
......@@ -721,9 +775,9 @@ static int lpc_ich_check_conflict_gpio(struct resource *res)
return use_gpio ? use_gpio : ret;
}
static int lpc_ich_init_gpio(struct pci_dev *dev,
const struct pci_device_id *id)
static int lpc_ich_init_gpio(struct pci_dev *dev)
{
struct lpc_ich_priv *priv = pci_get_drvdata(dev);
u32 base_addr_cfg;
u32 base_addr;
int ret;
......@@ -731,7 +785,7 @@ static int lpc_ich_init_gpio(struct pci_dev *dev,
struct resource *res;
/* Setup power management base register */
pci_read_config_dword(dev, ACPIBASE, &base_addr_cfg);
pci_read_config_dword(dev, priv->acpi.base, &base_addr_cfg);
base_addr = base_addr_cfg & 0x0000ff80;
if (!base_addr) {
dev_notice(&dev->dev, "I/O space for ACPI uninitialized\n");
......@@ -757,7 +811,7 @@ static int lpc_ich_init_gpio(struct pci_dev *dev,
gpe0_done:
/* Setup GPIO base register */
pci_read_config_dword(dev, GPIOBASE, &base_addr_cfg);
pci_read_config_dword(dev, priv->gpio.base, &base_addr_cfg);
base_addr = base_addr_cfg & 0x0000ff80;
if (!base_addr) {
dev_notice(&dev->dev, "I/O space for GPIO uninitialized\n");
......@@ -768,7 +822,7 @@ static int lpc_ich_init_gpio(struct pci_dev *dev,
/* Older devices provide fewer GPIO and have a smaller resource size. */
res = &gpio_ich_res[ICH_RES_GPIO];
res->start = base_addr;
switch (lpc_chipset_info[id->driver_data].gpio_version) {
switch (lpc_chipset_info[priv->chipset].gpio_version) {
case ICH_V5_GPIO:
case ICH_V10CORP_GPIO:
res->end = res->start + 128 - 1;
......@@ -784,10 +838,10 @@ static int lpc_ich_init_gpio(struct pci_dev *dev,
acpi_conflict = true;
goto gpio_done;
}
lpc_chipset_info[id->driver_data].use_gpio = ret;
lpc_chipset_info[priv->chipset].use_gpio = ret;
lpc_ich_enable_gpio_space(dev);
lpc_ich_finalize_cell(&lpc_ich_cells[LPC_GPIO], id);
lpc_ich_finalize_cell(dev, &lpc_ich_cells[LPC_GPIO]);
ret = mfd_add_devices(&dev->dev, -1, &lpc_ich_cells[LPC_GPIO],
1, NULL, 0, NULL);
......@@ -798,16 +852,16 @@ static int lpc_ich_init_gpio(struct pci_dev *dev,
return ret;
}
static int lpc_ich_init_wdt(struct pci_dev *dev,
const struct pci_device_id *id)
static int lpc_ich_init_wdt(struct pci_dev *dev)
{
struct lpc_ich_priv *priv = pci_get_drvdata(dev);
u32 base_addr_cfg;
u32 base_addr;
int ret;
struct resource *res;
/* Setup power management base register */
pci_read_config_dword(dev, ACPIBASE, &base_addr_cfg);
pci_read_config_dword(dev, priv->acpi.base, &base_addr_cfg);
base_addr = base_addr_cfg & 0x0000ff80;
if (!base_addr) {
dev_notice(&dev->dev, "I/O space for ACPI uninitialized\n");
......@@ -830,7 +884,7 @@ static int lpc_ich_init_wdt(struct pci_dev *dev,
* we have to read RCBA from PCI Config space 0xf0 and use
* it as base. GCS = RCBA + ICH6_GCS(0x3410).
*/
if (lpc_chipset_info[id->driver_data].iTCO_version == 1) {
if (lpc_chipset_info[priv->chipset].iTCO_version == 1) {
/* Don't register iomem for TCO ver 1 */
lpc_ich_cells[LPC_WDT].num_resources--;
} else {
......@@ -847,7 +901,7 @@ static int lpc_ich_init_wdt(struct pci_dev *dev,
res->end = base_addr + ACPIBASE_GCS_END;
}
lpc_ich_finalize_cell(&lpc_ich_cells[LPC_WDT], id);
lpc_ich_finalize_cell(dev, &lpc_ich_cells[LPC_WDT]);
ret = mfd_add_devices(&dev->dev, -1, &lpc_ich_cells[LPC_WDT],
1, NULL, 0, NULL);
......@@ -858,14 +912,36 @@ static int lpc_ich_init_wdt(struct pci_dev *dev,
static int lpc_ich_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
struct lpc_ich_priv *priv;
int ret;
bool cell_added = false;
ret = lpc_ich_init_wdt(dev, id);
priv = devm_kzalloc(&dev->dev,
sizeof(struct lpc_ich_priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->chipset = id->driver_data;
priv->acpi.save = -1;
priv->acpi.base = ACPIBASE;
priv->acpi.ctrl = ACPICTRL;
priv->gpio.save = -1;
if (priv->chipset <= LPC_ICH5) {
priv->gpio.base = GPIOBASE_ICH0;
priv->gpio.ctrl = GPIOCTRL_ICH0;
} else {
priv->gpio.base = GPIOBASE_ICH6;
priv->gpio.ctrl = GPIOCTRL_ICH6;
}
pci_set_drvdata(dev, priv);
ret = lpc_ich_init_wdt(dev);
if (!ret)
cell_added = true;
ret = lpc_ich_init_gpio(dev, id);
ret = lpc_ich_init_gpio(dev);
if (!ret)
cell_added = true;
......@@ -876,6 +952,7 @@ static int lpc_ich_probe(struct pci_dev *dev,
if (!cell_added) {
dev_warn(&dev->dev, "No MFD cells added\n");
lpc_ich_restore_config_space(dev);
pci_set_drvdata(dev, NULL);
return -ENODEV;
}
......@@ -886,6 +963,7 @@ static void lpc_ich_remove(struct pci_dev *dev)
{
mfd_remove_devices(&dev->dev);
lpc_ich_restore_config_space(dev);
pci_set_drvdata(dev, NULL);
}
static struct pci_driver lpc_ich_driver = {
......
......@@ -45,34 +45,32 @@ static struct resource smbus_sch_resource = {
.flags = IORESOURCE_IO,
};
static struct resource gpio_sch_resource = {
.flags = IORESOURCE_IO,
};
static struct mfd_cell lpc_sch_cells[] = {
{
.name = "isch_smbus",
.num_resources = 1,
.resources = &smbus_sch_resource,
},
{
.name = "sch_gpio",
.num_resources = 1,
.resources = &gpio_sch_resource,
},
};
static struct resource wdt_sch_resource = {
.flags = IORESOURCE_IO,
};
static struct mfd_cell tunnelcreek_cells[] = {
{
.name = "ie6xx_wdt",
.num_resources = 1,
.resources = &wdt_sch_resource,
},
static struct mfd_cell lpc_sch_cells[3];
static struct mfd_cell isch_smbus_cell = {
.name = "isch_smbus",
.num_resources = 1,
.resources = &smbus_sch_resource,
};
static struct mfd_cell sch_gpio_cell = {
.name = "sch_gpio",
.num_resources = 1,
.resources = &gpio_sch_resource,
};
static struct mfd_cell wdt_sch_cell = {
.name = "ie6xx_wdt",
.num_resources = 1,
.resources = &wdt_sch_resource,
};
static DEFINE_PCI_DEVICE_TABLE(lpc_sch_ids) = {
......@@ -88,79 +86,76 @@ static int lpc_sch_probe(struct pci_dev *dev,
{
unsigned int base_addr_cfg;
unsigned short base_addr;
int i;
int i, cells = 0;
int ret;
pci_read_config_dword(dev, SMBASE, &base_addr_cfg);
if (!(base_addr_cfg & (1 << 31))) {
dev_err(&dev->dev, "Decode of the SMBus I/O range disabled\n");
return -ENODEV;
}
base_addr = (unsigned short)base_addr_cfg;
if (base_addr == 0) {
dev_err(&dev->dev, "I/O space for SMBus uninitialized\n");
return -ENODEV;
}
smbus_sch_resource.start = base_addr;
smbus_sch_resource.end = base_addr + SMBUS_IO_SIZE - 1;
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;
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;
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;
}
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;
pci_read_config_dword(dev, GPIOBASE, &base_addr_cfg);
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;
for (i=0; i < ARRAY_SIZE(lpc_sch_cells); i++)
lpc_sch_cells[i].id = id->device;
base_addr = (unsigned short)base_addr_cfg;
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;
if (WARN_ON(cells > ARRAY_SIZE(lpc_sch_cells))) {
dev_err(&dev->dev, "Cell count exceeds array size");
return -ENODEV;
}
ret = mfd_add_devices(&dev->dev, 0, tunnelcreek_cells,
ARRAY_SIZE(tunnelcreek_cells), NULL,
0, NULL);
if (cells == 0) {
dev_err(&dev->dev, "All decode registers disabled.\n");
return -ENODEV;
}
return ret;
out_dev:
mfd_remove_devices(&dev->dev);
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->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;
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;
if (!chip->core_irq)
return -EBUSY;
ret = request_threaded_irq(irq, NULL, max8925_irq, flags | IRQF_ONESHOT,
"max8925", chip);
if (ret) {
dev_err(chip->dev, "Failed to request core IRQ: %d\n", ret);
chip->core_irq = 0;
return -EBUSY;
}
tsc_irq:
/* request irq handler for pmic tsc irq*/
/* mask TSC interrupt */
max8925_reg_write(chip->adc, MAX8925_TSC_IRQ_MASK, 0x0f);
......@@ -704,7 +718,6 @@ static int max8925_irq_init(struct max8925_chip *chip, int irq,
return 0;
}
chip->tsc_irq = pdata->tsc_irq;
ret = request_threaded_irq(chip->tsc_irq, NULL, max8925_tsc_irq,
flags | IRQF_ONESHOT, "max8925-tsc", chip);
if (ret) {
......@@ -846,7 +859,7 @@ int max8925_device_init(struct max8925_chip *chip,
ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0],
ARRAY_SIZE(rtc_devs),
&rtc_resources[0], chip->irq_base, NULL);
NULL, chip->irq_base, NULL);
if (ret < 0) {
dev_err(chip->dev, "Failed to add rtc subdev\n");
goto out;
......@@ -854,7 +867,7 @@ int max8925_device_init(struct max8925_chip *chip,
ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0],
ARRAY_SIZE(onkey_devs),
&onkey_resources[0], 0, NULL);
NULL, chip->irq_base, NULL);
if (ret < 0) {
dev_err(chip->dev, "Failed to add onkey subdev\n");
goto out_dev;
......@@ -873,21 +886,19 @@ int max8925_device_init(struct max8925_chip *chip,
goto out_dev;
}
if (pdata && pdata->power) {
ret = mfd_add_devices(chip->dev, 0, &power_devs[0],
ARRAY_SIZE(power_devs),
&power_supply_resources[0], 0, NULL);
if (ret < 0) {
dev_err(chip->dev, "Failed to add power supply "
"subdev\n");
goto out_dev;
}
ret = mfd_add_devices(chip->dev, 0, &power_devs[0],
ARRAY_SIZE(power_devs),
NULL, 0, NULL);
if (ret < 0) {
dev_err(chip->dev,
"Failed to add power supply subdev, err = %d\n", ret);
goto out_dev;
}
if (pdata && pdata->touch) {
ret = mfd_add_devices(chip->dev, 0, &touch_devs[0],
ARRAY_SIZE(touch_devs),
&touch_resources[0], 0, NULL);
NULL, chip->tsc_irq, NULL);
if (ret < 0) {
dev_err(chip->dev, "Failed to add touch subdev\n");
goto out_dev;
......
......@@ -135,13 +135,37 @@ static const struct i2c_device_id max8925_id_table[] = {
};
MODULE_DEVICE_TABLE(i2c, max8925_id_table);
static int max8925_dt_init(struct device_node *np, struct device *dev,
struct max8925_platform_data *pdata)
{
int ret;
ret = of_property_read_u32(np, "maxim,tsc-irq", &pdata->tsc_irq);
if (ret) {
dev_err(dev, "Not found maxim,tsc-irq property\n");
return -EINVAL;
}
return 0;
}
static int max8925_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct max8925_platform_data *pdata = client->dev.platform_data;
static struct max8925_chip *chip;
if (!pdata) {
struct device_node *node = client->dev.of_node;
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);
......
此差异已折叠。
......@@ -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;
pm_runtime_disable(dev);
/* only after this can omap_tll_enable/disable work */
spin_lock(&tll_lock);
tll_dev = dev;
spin_unlock(&tll_lock);
err_usbtll_p2_fck:
clk_put(tll->usbtll_p2_fck);
err_usbtll_p1_fck:
clk_put(tll->usbtll_p1_fck);
return 0;
err_tll:
kfree(tll);
err_clk_alloc:
pm_runtime_put_sync(dev);
pm_runtime_disable(dev);
end:
return ret;
}
......@@ -351,36 +360,42 @@ static int usbtll_omap_probe(struct platform_device *pdev)
static int usbtll_omap_remove(struct platform_device *pdev)
{
struct usbtll_omap *tll = platform_get_drvdata(pdev);
int i;
spin_lock(&tll_lock);
tll_dev = NULL;
spin_unlock(&tll_lock);
for (i = 0; i < tll->nch; i++)
if (!IS_ERR(tll->ch_clk[i]))
clk_put(tll->ch_clk[i]);
clk_put(tll->usbtll_p2_fck);
clk_put(tll->usbtll_p1_fck);
pm_runtime_disable(&pdev->dev);
kfree(tll);
return 0;
}
static int usbtll_runtime_resume(struct device *dev)
{
struct usbtll_omap *tll = dev_get_drvdata(dev);
struct usbtll_omap_platform_data *pdata = &tll->platdata;
unsigned long flags;
struct usbhs_omap_platform_data *pdata = tll->pdata;
int i;
dev_dbg(dev, "usbtll_runtime_resume\n");
if (!pdata) {
dev_dbg(dev, "missing platform_data\n");
return -ENODEV;
}
spin_lock_irqsave(&tll->lock, flags);
for (i = 0; i < tll->nch; i++) {
if (omap_usb_mode_needs_tll(pdata->port_mode[i])) {
int r;
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);
if (IS_ERR(tll->ch_clk[i]))
continue;
spin_unlock_irqrestore(&tll->lock, flags);
r = clk_enable(tll->ch_clk[i]);
if (r) {
dev_err(dev,
"Error enabling ch %d clock: %d\n", i, r);
}
}
}
return 0;
}
......@@ -388,26 +403,18 @@ static int usbtll_runtime_resume(struct device *dev)
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;
......
此差异已折叠。
......@@ -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;
......
此差异已折叠。
......@@ -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;
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册