summaryrefslogtreecommitdiffstats
path: root/drivers/mfd/88pm800.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-07-10 11:10:27 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2013-07-10 11:10:27 -0700
commit3aa78e0cb5c9b8b4ed2a617bb1e1542bfb508379 (patch)
treea446e1f8a81f63933423ef11ea7d31cc918b30f6 /drivers/mfd/88pm800.c
parentdc5ef1f56968c67e81ad1c81ab7dce678f480285 (diff)
parent25f311fa58c18c19ae1348336265ccb8368638f0 (diff)
downloadlinux-3aa78e0cb5c9b8b4ed2a617bb1e1542bfb508379.tar.bz2
Merge tag 'mfd-3.11-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-next
Pull MFD update from Samuel Ortiz: "For the 3.11 merge we only have one new MFD driver for the Kontron PLD. But we also have: - Support for the TPS659038 PMIC from the palmas driver. - Intel's Coleto Creek and Avoton SoCs support from the lpc_ich driver. - RTL8411B support from the rtsx driver. - More DT support for the Arizona, max8998, twl4030-power and the ti_am335x_tsadc drivers. - The SSBI driver move under MFD. - A conversion to the devm_* API for most of the MFD drivers. - The twl4030-power got split from twl-core into its own module. - A major ti_am335x_adc cleanup, leading to a proper DT support. - Our regular arizona and wm* updates and cleanups from the Wolfson folks. - A better error handling and initialization, and a regulator subdevice addition for the 88pm80x driver. - A bulk platform_set_drvdata() call removal that's no longer need since commit 0998d0631001 ("device-core: Ensure drvdata = NULL when no driver is bound") * tag 'mfd-3.11-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-next: (102 commits) mfd: sec: Provide max_register to regmap mfd: wm8994: Remove duplicate check for active JACKDET MAINTAINERS: Add include directory to MFD file patterns mfd: sec: Remove fields not used since regmap conversion watchdog: Kontron PLD watchdog timer driver mfd: max8998: Add support for Device Tree regulator: max8998: Use arrays for specifying voltages in platform data mfd: max8998: Add irq domain support regulator: palmas: Add TPS659038 support mfd: Kontron PLD mfd driver mfd: palmas: Add TPS659038 PMIC support mfd: palmas: Add SMPS10_BOOST feature mfd: palmas: Check if irq is valid mfd: lpc_ich: iTCO_wdt patch for Intel Coleto Creek DeviceIDs mfd: twl-core: Change TWL6025 references to TWL6032 mfd: davinci_voicecodec: Fix build breakage mfd: vexpress: Make the driver optional for arm and arm64 mfd: htc-egpio: Use devm_ioremap_nocache() instead of ioremap_nocache() mfd: davinci_voicecodec: Convert to use devm_* APIs mfd: twl4030-power: Fix relocking on error ...
Diffstat (limited to 'drivers/mfd/88pm800.c')
-rw-r--r--drivers/mfd/88pm800.c238
1 files changed, 139 insertions, 99 deletions
diff --git a/drivers/mfd/88pm800.c b/drivers/mfd/88pm800.c
index 582bda543520..6c954835d61e 100644
--- a/drivers/mfd/88pm800.c
+++ b/drivers/mfd/88pm800.c
@@ -22,13 +22,12 @@
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/mfd/core.h>
#include <linux/mfd/88pm80x.h>
#include <linux/slab.h>
-#define PM800_CHIP_ID (0x00)
-
/* Interrupt Registers */
#define PM800_INT_STATUS1 (0x05)
#define PM800_ONKEY_INT_STS1 (1 << 0)
@@ -113,20 +112,11 @@ enum {
PM800_MAX_IRQ,
};
-enum {
- /* Procida */
- PM800_CHIP_A0 = 0x60,
- PM800_CHIP_A1 = 0x61,
- PM800_CHIP_B0 = 0x62,
- PM800_CHIP_C0 = 0x63,
- PM800_CHIP_END = PM800_CHIP_C0,
-
- /* Make sure to update this to the last stepping */
- PM8XXX_CHIP_END = PM800_CHIP_END
-};
+/* PM800: generation identification number */
+#define PM800_CHIP_GEN_ID_NUM 0x3
static const struct i2c_device_id pm80x_id_table[] = {
- {"88PM800", CHIP_PM800},
+ {"88PM800", 0},
{} /* NULL terminated */
};
MODULE_DEVICE_TABLE(i2c, pm80x_id_table);
@@ -167,6 +157,13 @@ static struct mfd_cell onkey_devs[] = {
},
};
+static struct mfd_cell regulator_devs[] = {
+ {
+ .name = "88pm80x-regulator",
+ .id = -1,
+ },
+};
+
static const struct regmap_irq pm800_irqs[] = {
/* INT0 */
[PM800_IRQ_ONKEY] = {
@@ -315,10 +312,59 @@ out:
return ret;
}
+static int device_onkey_init(struct pm80x_chip *chip,
+ struct pm80x_platform_data *pdata)
+{
+ int ret;
+
+ ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0],
+ ARRAY_SIZE(onkey_devs), &onkey_resources[0], 0,
+ NULL);
+ if (ret) {
+ dev_err(chip->dev, "Failed to add onkey subdev\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int device_rtc_init(struct pm80x_chip *chip,
+ struct pm80x_platform_data *pdata)
+{
+ int ret;
+
+ rtc_devs[0].platform_data = pdata->rtc;
+ rtc_devs[0].pdata_size =
+ pdata->rtc ? sizeof(struct pm80x_rtc_pdata) : 0;
+ ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0],
+ ARRAY_SIZE(rtc_devs), NULL, 0, NULL);
+ if (ret) {
+ dev_err(chip->dev, "Failed to add rtc subdev\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int device_regulator_init(struct pm80x_chip *chip,
+ struct pm80x_platform_data *pdata)
+{
+ int ret;
+
+ ret = mfd_add_devices(chip->dev, 0, &regulator_devs[0],
+ ARRAY_SIZE(regulator_devs), NULL, 0, NULL);
+ if (ret) {
+ dev_err(chip->dev, "Failed to add regulator subdev\n");
+ return ret;
+ }
+
+ return 0;
+}
+
static int device_irq_init_800(struct pm80x_chip *chip)
{
struct regmap *map = chip->regmap;
- unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
+ unsigned long flags = IRQF_ONESHOT;
int data, mask, ret = -EINVAL;
if (!map || !chip->irq) {
@@ -362,6 +408,7 @@ static struct regmap_irq_chip pm800_irq_chip = {
.status_base = PM800_INT_STATUS1,
.mask_base = PM800_INT_ENA_1,
.ack_base = PM800_INT_STATUS1,
+ .mask_invert = 1,
};
static int pm800_pages_init(struct pm80x_chip *chip)
@@ -369,77 +416,72 @@ static int pm800_pages_init(struct pm80x_chip *chip)
struct pm80x_subchip *subchip;
struct i2c_client *client = chip->client;
+ int ret = 0;
+
subchip = chip->subchip;
- /* PM800 block power: i2c addr 0x31 */
- if (subchip->power_page_addr) {
- subchip->power_page =
- i2c_new_dummy(client->adapter, subchip->power_page_addr);
- subchip->regmap_power =
- devm_regmap_init_i2c(subchip->power_page,
- &pm80x_regmap_config);
- i2c_set_clientdata(subchip->power_page, chip);
- } else
- dev_info(chip->dev,
- "PM800 block power 0x31: No power_page_addr\n");
-
- /* PM800 block GPADC: i2c addr 0x32 */
- if (subchip->gpadc_page_addr) {
- subchip->gpadc_page = i2c_new_dummy(client->adapter,
- subchip->gpadc_page_addr);
- subchip->regmap_gpadc =
- devm_regmap_init_i2c(subchip->gpadc_page,
- &pm80x_regmap_config);
- i2c_set_clientdata(subchip->gpadc_page, chip);
- } else
- dev_info(chip->dev,
- "PM800 block GPADC 0x32: No gpadc_page_addr\n");
+ if (!subchip || !subchip->power_page_addr || !subchip->gpadc_page_addr)
+ return -ENODEV;
+
+ /* PM800 block power page */
+ subchip->power_page = i2c_new_dummy(client->adapter,
+ subchip->power_page_addr);
+ if (subchip->power_page == NULL) {
+ ret = -ENODEV;
+ goto out;
+ }
- return 0;
+ subchip->regmap_power = devm_regmap_init_i2c(subchip->power_page,
+ &pm80x_regmap_config);
+ if (IS_ERR(subchip->regmap_power)) {
+ ret = PTR_ERR(subchip->regmap_power);
+ dev_err(chip->dev,
+ "Failed to allocate regmap_power: %d\n", ret);
+ goto out;
+ }
+
+ i2c_set_clientdata(subchip->power_page, chip);
+
+ /* PM800 block GPADC */
+ subchip->gpadc_page = i2c_new_dummy(client->adapter,
+ subchip->gpadc_page_addr);
+ if (subchip->gpadc_page == NULL) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ subchip->regmap_gpadc = devm_regmap_init_i2c(subchip->gpadc_page,
+ &pm80x_regmap_config);
+ if (IS_ERR(subchip->regmap_gpadc)) {
+ ret = PTR_ERR(subchip->regmap_gpadc);
+ dev_err(chip->dev,
+ "Failed to allocate regmap_gpadc: %d\n", ret);
+ goto out;
+ }
+ i2c_set_clientdata(subchip->gpadc_page, chip);
+
+out:
+ return ret;
}
static void pm800_pages_exit(struct pm80x_chip *chip)
{
struct pm80x_subchip *subchip;
- regmap_exit(chip->regmap);
- i2c_unregister_device(chip->client);
-
subchip = chip->subchip;
- if (subchip->power_page) {
- regmap_exit(subchip->regmap_power);
+
+ if (subchip && subchip->power_page)
i2c_unregister_device(subchip->power_page);
- }
- if (subchip->gpadc_page) {
- regmap_exit(subchip->regmap_gpadc);
+
+ if (subchip && subchip->gpadc_page)
i2c_unregister_device(subchip->gpadc_page);
- }
}
static int device_800_init(struct pm80x_chip *chip,
struct pm80x_platform_data *pdata)
{
- int ret, pmic_id;
+ int ret;
unsigned int val;
- ret = regmap_read(chip->regmap, PM800_CHIP_ID, &val);
- if (ret < 0) {
- dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret);
- goto out;
- }
-
- pmic_id = val & PM80X_VERSION_MASK;
-
- if ((pmic_id >= PM800_CHIP_A0) && (pmic_id <= PM800_CHIP_END)) {
- chip->version = val;
- dev_info(chip->dev,
- "88PM80x:Marvell 88PM800 (ID:0x%x) detected\n", val);
- } else {
- dev_err(chip->dev,
- "Failed to detect Marvell 88PM800:ChipID[0x%x]\n", val);
- ret = -EINVAL;
- goto out;
- }
-
/*
* alarm wake up bit will be clear in device_irq_init(),
* read before that
@@ -468,27 +510,22 @@ static int device_800_init(struct pm80x_chip *chip,
goto out;
}
- ret =
- mfd_add_devices(chip->dev, 0, &onkey_devs[0],
- ARRAY_SIZE(onkey_devs), &onkey_resources[0], 0,
- NULL);
- if (ret < 0) {
+ ret = device_onkey_init(chip, pdata);
+ if (ret) {
dev_err(chip->dev, "Failed to add onkey subdev\n");
goto out_dev;
- } else
- dev_info(chip->dev, "[%s]:Added mfd onkey_devs\n", __func__);
-
- if (pdata && pdata->rtc) {
- rtc_devs[0].platform_data = pdata->rtc;
- rtc_devs[0].pdata_size = sizeof(struct pm80x_rtc_pdata);
- ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0],
- ARRAY_SIZE(rtc_devs), NULL, 0, NULL);
- if (ret < 0) {
- dev_err(chip->dev, "Failed to add rtc subdev\n");
- goto out_dev;
- } else
- dev_info(chip->dev,
- "[%s]:Added mfd rtc_devs\n", __func__);
+ }
+
+ ret = device_rtc_init(chip, pdata);
+ if (ret) {
+ dev_err(chip->dev, "Failed to add rtc subdev\n");
+ goto out;
+ }
+
+ ret = device_regulator_init(chip, pdata);
+ if (ret) {
+ dev_err(chip->dev, "Failed to add regulators subdev\n");
+ goto out;
}
return 0;
@@ -507,7 +544,7 @@ static int pm800_probe(struct i2c_client *client,
struct pm80x_platform_data *pdata = client->dev.platform_data;
struct pm80x_subchip *subchip;
- ret = pm80x_init(client, id);
+ ret = pm80x_init(client);
if (ret) {
dev_err(&client->dev, "pm800_init fail\n");
goto out_init;
@@ -524,28 +561,31 @@ static int pm800_probe(struct i2c_client *client,
goto err_subchip_alloc;
}
- subchip->power_page_addr = pdata->power_page_addr;
- subchip->gpadc_page_addr = pdata->gpadc_page_addr;
+ /* pm800 has 2 addtional pages to support power and gpadc. */
+ subchip->power_page_addr = client->addr + 1;
+ subchip->gpadc_page_addr = client->addr + 2;
chip->subchip = subchip;
- ret = device_800_init(chip, pdata);
- if (ret) {
- dev_err(chip->dev, "%s id 0x%x failed!\n", __func__, chip->id);
- goto err_subchip_alloc;
- }
-
ret = pm800_pages_init(chip);
if (ret) {
dev_err(&client->dev, "pm800_pages_init failed!\n");
goto err_page_init;
}
+ ret = device_800_init(chip, pdata);
+ if (ret) {
+ dev_err(chip->dev, "Failed to initialize 88pm800 devices\n");
+ goto err_device_init;
+ }
+
if (pdata->plat_config)
pdata->plat_config(chip, pdata);
+ return 0;
+
+err_device_init:
+ pm800_pages_exit(chip);
err_page_init:
- mfd_remove_devices(chip->dev);
- device_irq_exit_800(chip);
err_subchip_alloc:
pm80x_deinit();
out_init:
@@ -567,7 +607,7 @@ static int pm800_remove(struct i2c_client *client)
static struct i2c_driver pm800_driver = {
.driver = {
- .name = "88PM80X",
+ .name = "88PM800",
.owner = THIS_MODULE,
.pm = &pm80x_pm_ops,
},