diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-30 12:41:17 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-30 12:41:17 -0700 |
commit | 3e701cdfe601306817604ca7f79f1d1c1088007c (patch) | |
tree | 1b0a4088a091f035d8be06758a604ca449223fc0 /drivers/mfd/88pm80x.c | |
parent | 7d3d09b01a028e9dd1282149fdcd2a6e0edd73e4 (diff) | |
parent | 3c1534c7ecffeb4330bba4c55d17f301528195b6 (diff) |
Merge tag 'mfd-3.6-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6
Pull MFD bits from Samuel Ortiz:
"We have support for a few new drivers:
- Samsung s2mps11
- Wolfson Microelectronics wm5102 and wm5110
- Marvell 88PM800 and 88PM805
- TI twl6041
We also have our regular driver improvements:
- Device tree and IRQ domain support for STE AB8500
- Regmap and devm_* API conversion for TI tps6586x
- Device tree support for Samsung max77686
- devm_* API conversion for STE AB3100
Besides that, quite a lot of fixing and cleanup for mc13xxx, tps65910,
tps65090, da9052 and twl-core."
Fix up mostly trivial conflicts, with the exception of
drivers/usb/host/ehci-omap.c in particular, which had some
re-organization of the reset sequence (commit 1a49e2ac9651: "EHCI:
centralize controller initialization") that clashed with commit
2761a6394516 ("mfd: USB: Fix the omap-usb EHCI ULPI PHY reset fix
issues").
In particular, commit 2761a6394516 moved the usb_add_hcd() to the
*middle* of the reset sequence, which clashes fairly badly with the
reset sequence re-organization (although it could have been done inside
the new omap_ehci_init() function).
I left that part of commit 2761a6394516 just undone.
* tag 'mfd-3.6-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6: (110 commits)
mfd: Ensure AB8500 platform data is passed through db8500-prcmu to MFD Core
mfd: Arizone core should select MFD_CORE
mfd: Fix arizona-irq.c build by selecting REGMAP_IRQ
mfd: Add debug trace on entering and leaving arizone runtime suspend
mfd: Correct tps65090 cell names
mfd: Remove gpio support from tps6586x core driver
ARM: tegra: defconfig: Enable tps6586x gpio
gpio: tps6586x: Add gpio support through platform driver
mfd: Cache tps6586x register through regmap
mfd: Use regmap for tps6586x register access.
mfd: Use devm managed resources for tps6586x
input: Add onkey support for 88PM80X PMIC
mfd: Add support for twl6041
mfd: Fix twl6040 revision information
mfd: Matches should be NULL when populate anatop child devices
input: ab8500-ponkey: Create AB8500 domain IRQ mapping
mfd: Add missing out of memory check for pcf50633
Documentation: Describe the AB8500 Device Tree bindings
mfd: Add tps65910 32-kHz-crystal-input init
mfd: Drop modifying mc13xxx driver's id_table in probe
...
Diffstat (limited to 'drivers/mfd/88pm80x.c')
-rw-r--r-- | drivers/mfd/88pm80x.c | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/drivers/mfd/88pm80x.c b/drivers/mfd/88pm80x.c new file mode 100644 index 00000000000..cd0bf527d76 --- /dev/null +++ b/drivers/mfd/88pm80x.c @@ -0,0 +1,145 @@ +/* + * I2C driver for Marvell 88PM80x + * + * Copyright (C) 2012 Marvell International Ltd. + * Haojian Zhuang <haojian.zhuang@marvell.com> + * Joseph(Yossi) Hanin <yhanin@marvell.com> + * Qiao Zhou <zhouqiao@marvell.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/mfd/88pm80x.h> +#include <linux/slab.h> +#include <linux/uaccess.h> +#include <linux/err.h> + +/* + * workaround: some registers needed by pm805 are defined in pm800, so + * need to use this global variable to maintain the relation between + * pm800 and pm805. would remove it after HW chip fixes the issue. + */ +static struct pm80x_chip *g_pm80x_chip; + +const struct regmap_config pm80x_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; +EXPORT_SYMBOL_GPL(pm80x_regmap_config); + +int __devinit pm80x_init(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct pm80x_chip *chip; + struct regmap *map; + int ret = 0; + + chip = + devm_kzalloc(&client->dev, sizeof(struct pm80x_chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + map = devm_regmap_init_i2c(client, &pm80x_regmap_config); + if (IS_ERR(map)) { + ret = PTR_ERR(map); + dev_err(&client->dev, "Failed to allocate register map: %d\n", + ret); + goto err_regmap_init; + } + + chip->id = id->driver_data; + if (chip->id < CHIP_PM800 || chip->id > CHIP_PM805) { + ret = -EINVAL; + goto err_chip_id; + } + + chip->client = client; + chip->regmap = map; + + chip->irq = client->irq; + + chip->dev = &client->dev; + dev_set_drvdata(chip->dev, chip); + i2c_set_clientdata(chip->client, chip); + + device_init_wakeup(&client->dev, 1); + + /* + * workaround: set g_pm80x_chip to the first probed chip. if the + * second chip is probed, just point to the companion to each + * other so that pm805 can access those specific register. would + * remove it after HW chip fixes the issue. + */ + if (!g_pm80x_chip) + g_pm80x_chip = chip; + else { + chip->companion = g_pm80x_chip->client; + g_pm80x_chip->companion = chip->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) +{ + 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. + */ + if (g_pm80x_chip->companion) + 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); + +#ifdef CONFIG_PM_SLEEP +static int pm80x_suspend(struct device *dev) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct pm80x_chip *chip = i2c_get_clientdata(client); + + if (chip && chip->wu_flag) + if (device_may_wakeup(chip->dev)) + enable_irq_wake(chip->irq); + + return 0; +} + +static int pm80x_resume(struct device *dev) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct pm80x_chip *chip = i2c_get_clientdata(client); + + if (chip && chip->wu_flag) + if (device_may_wakeup(chip->dev)) + disable_irq_wake(chip->irq); + + return 0; +} +#endif + +SIMPLE_DEV_PM_OPS(pm80x_pm_ops, pm80x_suspend, pm80x_resume); +EXPORT_SYMBOL_GPL(pm80x_pm_ops); + +MODULE_DESCRIPTION("I2C Driver for Marvell 88PM80x"); +MODULE_AUTHOR("Qiao Zhou <zhouqiao@marvell.com>"); +MODULE_LICENSE("GPL"); |