mfd: Support 88pm80x in 80x driver
88PM800 and 88PM805 are two discrete chips used for power management.
Hardware designer can use them together or only one of them according
to requirement.
88pm80x.c provides common i2c driver handling for both 800 and
805, such as i2c_driver init, regmap init, read/write api etc.
88pm800.c handles specifically for 800, such as chip init, irq
init/handle, mfd device register, including rtc, onkey, regulator(
to be add later) etc. besides that, 800 has three i2c device, one
regular i2c client, two other i2c dummy for gpadc and power purpose.
88pm805.c handles specifically for 805, such as chip init, irq
init/handle, mfd device register, including codec, headset/mic detect
etc.
the i2c operation of both 800 and 805 are via regmap, and 88pm80x-i2c
exported a group of r/w bulk r/w and bits set API for facility.
Signed-off-by: Qiao Zhou <zhouqiao@marvell.com>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
2012-07-09 14:37:32 +08:00
|
|
|
/*
|
|
|
|
* 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>
|
|
|
|
|
2012-07-09 14:37:33 +08:00
|
|
|
/*
|
|
|
|
* 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;
|
mfd: Support 88pm80x in 80x driver
88PM800 and 88PM805 are two discrete chips used for power management.
Hardware designer can use them together or only one of them according
to requirement.
88pm80x.c provides common i2c driver handling for both 800 and
805, such as i2c_driver init, regmap init, read/write api etc.
88pm800.c handles specifically for 800, such as chip init, irq
init/handle, mfd device register, including rtc, onkey, regulator(
to be add later) etc. besides that, 800 has three i2c device, one
regular i2c client, two other i2c dummy for gpadc and power purpose.
88pm805.c handles specifically for 805, such as chip init, irq
init/handle, mfd device register, including codec, headset/mic detect
etc.
the i2c operation of both 800 and 805 are via regmap, and 88pm80x-i2c
exported a group of r/w bulk r/w and bits set API for facility.
Signed-off-by: Qiao Zhou <zhouqiao@marvell.com>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
2012-07-09 14:37:32 +08:00
|
|
|
|
|
|
|
const struct regmap_config pm80x_regmap_config = {
|
|
|
|
.reg_bits = 8,
|
|
|
|
.val_bits = 8,
|
|
|
|
};
|
2012-07-09 22:44:21 +08:00
|
|
|
EXPORT_SYMBOL_GPL(pm80x_regmap_config);
|
mfd: Support 88pm80x in 80x driver
88PM800 and 88PM805 are two discrete chips used for power management.
Hardware designer can use them together or only one of them according
to requirement.
88pm80x.c provides common i2c driver handling for both 800 and
805, such as i2c_driver init, regmap init, read/write api etc.
88pm800.c handles specifically for 800, such as chip init, irq
init/handle, mfd device register, including rtc, onkey, regulator(
to be add later) etc. besides that, 800 has three i2c device, one
regular i2c client, two other i2c dummy for gpadc and power purpose.
88pm805.c handles specifically for 805, such as chip init, irq
init/handle, mfd device register, including codec, headset/mic detect
etc.
the i2c operation of both 800 and 805 are via regmap, and 88pm80x-i2c
exported a group of r/w bulk r/w and bits set API for facility.
Signed-off-by: Qiao Zhou <zhouqiao@marvell.com>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
2012-07-09 14:37:32 +08:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2012-07-09 14:37:33 +08:00
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
mfd: Support 88pm80x in 80x driver
88PM800 and 88PM805 are two discrete chips used for power management.
Hardware designer can use them together or only one of them according
to requirement.
88pm80x.c provides common i2c driver handling for both 800 and
805, such as i2c_driver init, regmap init, read/write api etc.
88pm800.c handles specifically for 800, such as chip init, irq
init/handle, mfd device register, including rtc, onkey, regulator(
to be add later) etc. besides that, 800 has three i2c device, one
regular i2c client, two other i2c dummy for gpadc and power purpose.
88pm805.c handles specifically for 805, such as chip init, irq
init/handle, mfd device register, including codec, headset/mic detect
etc.
the i2c operation of both 800 and 805 are via regmap, and 88pm80x-i2c
exported a group of r/w bulk r/w and bits set API for facility.
Signed-off-by: Qiao Zhou <zhouqiao@marvell.com>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
2012-07-09 14:37:32 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
err_chip_id:
|
|
|
|
regmap_exit(map);
|
|
|
|
err_regmap_init:
|
|
|
|
devm_kfree(&client->dev, chip);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(pm80x_init);
|
|
|
|
|
2012-07-11 10:01:10 +08:00
|
|
|
int pm80x_deinit(struct i2c_client *client)
|
mfd: Support 88pm80x in 80x driver
88PM800 and 88PM805 are two discrete chips used for power management.
Hardware designer can use them together or only one of them according
to requirement.
88pm80x.c provides common i2c driver handling for both 800 and
805, such as i2c_driver init, regmap init, read/write api etc.
88pm800.c handles specifically for 800, such as chip init, irq
init/handle, mfd device register, including rtc, onkey, regulator(
to be add later) etc. besides that, 800 has three i2c device, one
regular i2c client, two other i2c dummy for gpadc and power purpose.
88pm805.c handles specifically for 805, such as chip init, irq
init/handle, mfd device register, including codec, headset/mic detect
etc.
the i2c operation of both 800 and 805 are via regmap, and 88pm80x-i2c
exported a group of r/w bulk r/w and bits set API for facility.
Signed-off-by: Qiao Zhou <zhouqiao@marvell.com>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
2012-07-09 14:37:32 +08:00
|
|
|
{
|
|
|
|
struct pm80x_chip *chip = i2c_get_clientdata(client);
|
|
|
|
|
2012-07-09 14:37:33 +08:00
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
|
mfd: Support 88pm80x in 80x driver
88PM800 and 88PM805 are two discrete chips used for power management.
Hardware designer can use them together or only one of them according
to requirement.
88pm80x.c provides common i2c driver handling for both 800 and
805, such as i2c_driver init, regmap init, read/write api etc.
88pm800.c handles specifically for 800, such as chip init, irq
init/handle, mfd device register, including rtc, onkey, regulator(
to be add later) etc. besides that, 800 has three i2c device, one
regular i2c client, two other i2c dummy for gpadc and power purpose.
88pm805.c handles specifically for 805, such as chip init, irq
init/handle, mfd device register, including codec, headset/mic detect
etc.
the i2c operation of both 800 and 805 are via regmap, and 88pm80x-i2c
exported a group of r/w bulk r/w and bits set API for facility.
Signed-off-by: Qiao Zhou <zhouqiao@marvell.com>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
2012-07-09 14:37:32 +08:00
|
|
|
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");
|