* [PATCH 0/2] mfd: bq2415x charger driver
[not found] <"cover.1298918741.git.aliaksei.katovich@nokia.com">
@ 2011-02-28 21:36 ` aliaksei.katovich
2011-02-28 21:36 ` [PATCH 1/2] " aliaksei.katovich
2011-02-28 21:36 ` [PATCH 2/2] mfd: bq2415x compilation enablers aliaksei.katovich
0 siblings, 2 replies; 3+ messages in thread
From: aliaksei.katovich @ 2011-02-28 21:36 UTC (permalink / raw)
To: sameo; +Cc: linux-kernel, Aliaksei Katovich
From: Aliaksei Katovich <aliaksei.katovich@nokia.com>
The bq2415x family of Texas Instruments charger ICs are multifunctional chips
that combine voltage/current regulation with Li-Ion battery charge controller.
Given bq2415x driver implements both regulator and i2c devices within single
module. Despite not being mfd core dependant this driver however is thought
to belong to mfd subsystem rather than regulators or i2c one.
Also I have some concern about hardcoded i2c addresses which may well limit
driver usage to some certain hardware set. Alternatively driver can be extented
to support device tree or another relevant interface to eliminate this possible
limit.
Implementation is based on BQ24153/6/8 datasheet.
The patch set applies cleanly to the MFD repository at
git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6.git
Please review.
Aliaksei Katovich (2):
mfd: bq2415x charger driver
mfd: bq2415x compilation enablers
drivers/mfd/Kconfig | 7 +
drivers/mfd/Makefile | 1 +
drivers/mfd/bq2415x.c | 780 +++++++++++++++++++++++++++++++++++++++++++
include/linux/mfd/bq2415x.h | 88 +++++
4 files changed, 876 insertions(+), 0 deletions(-)
create mode 100644 drivers/mfd/bq2415x.c
create mode 100644 include/linux/mfd/bq2415x.h
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH 1/2] mfd: bq2415x charger driver
2011-02-28 21:36 ` [PATCH 0/2] mfd: bq2415x charger driver aliaksei.katovich
@ 2011-02-28 21:36 ` aliaksei.katovich
2011-02-28 21:36 ` [PATCH 2/2] mfd: bq2415x compilation enablers aliaksei.katovich
1 sibling, 0 replies; 3+ messages in thread
From: aliaksei.katovich @ 2011-02-28 21:36 UTC (permalink / raw)
To: sameo; +Cc: linux-kernel, Aliaksei Katovich
From: Aliaksei Katovich <aliaksei.katovich@nokia.com>
Added driver to support TI bq24153/6 one-cell Li-Ion chargers.
Signed-off-by: Aliaksei Katovich <aliaksei.katovich@nokia.com>
---
drivers/mfd/bq2415x.c | 780 +++++++++++++++++++++++++++++++++++++++++++
include/linux/mfd/bq2415x.h | 88 +++++
2 files changed, 868 insertions(+), 0 deletions(-)
create mode 100644 drivers/mfd/bq2415x.c
create mode 100644 include/linux/mfd/bq2415x.h
diff --git a/drivers/mfd/bq2415x.c b/drivers/mfd/bq2415x.c
new file mode 100644
index 0000000..4d57cb4
--- /dev/null
+++ b/drivers/mfd/bq2415x.c
@@ -0,0 +1,780 @@
+/*
+ * bq2415x.c - TI BQ24153/6 one-cell Li-Ion charger driver
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contact: Aliaksei Katovich <aliaksei.katovich@nokia.com>
+ *
+ * This software is distributed under the terms of the GNU General
+ * Public License ("GPL") as published by the Free Software Foundation,
+ * version 2 of that License.
+ */
+
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/kernel.h>
+#include <linux/regulator/driver.h>
+#include <linux/mfd/bq2415x.h>
+
+#define BQ2415X_RESET_MASK 0x80
+
+#define BQ2415X_IIN_LIMIT_500_MASK 0x40
+#define BQ2415X_IIN_LIMIT_800_MASK 0x80
+#define BQ2415X_IIN_LIMIT_UNLIM_MASK 0xc0
+
+static DEFINE_MUTEX(bq2415x_dev_list_mutex);
+static LIST_HEAD(bq2415x_dev_list);
+
+static struct i2c_client *bq2415x_cli;
+
+struct bq2415x_regulator {
+ struct i2c_client *cli;
+ u8 reg; /* associated register */
+ u8 val_summ; /* value summand */
+ u8 msk_summ; /* bit mask summand */
+ u8 msk_mult; /* bit mask multiplier */
+ u8 min_mask;
+ u8 max_mask; /* read bitmask */
+ struct regulator_init_data init;
+ struct regulator_desc desc;
+};
+
+struct bq2415x_device {
+ struct i2c_client *cli;
+ struct regulator_dev *rdev[BQ2415X_MAX_REG];
+ struct list_head list;
+};
+
+/* i2c operations */
+
+static inline int bq2415x_i2c_read(struct i2c_client *cli, u8 reg)
+{
+ return i2c_smbus_read_byte_data(cli, reg);
+}
+
+static inline int bq2415x_i2c_write(struct i2c_client *cli, u8 reg, u8 val)
+{
+ return i2c_smbus_write_byte_data(cli, reg, val);
+}
+
+static inline int bq2415x_enable_charger(bool flag)
+{
+ int res;
+
+ res = bq2415x_i2c_read(bq2415x_cli, BQ2415X_GEN_CTL);
+ if (unlikely(res < 0))
+ return res;
+
+ if (flag)
+ res &= ~(BQ2415X_CE | BQ2415X_HZ_MODE);
+ else
+ res |= (BQ2415X_CE | BQ2415X_HZ_MODE);
+
+ return bq2415x_i2c_write(bq2415x_cli, BQ2415X_GEN_CTL, res);
+}
+
+static inline int bq2415x_enable_stat(bool flag)
+{
+ int res;
+
+ res = bq2415x_i2c_read(bq2415x_cli, BQ2415X_STS_CTL);
+ if (unlikely(res < 0))
+ return res;
+
+ if (flag)
+ res |= BQ2415X_EN_STAT;
+ else
+ res &= ~BQ2415X_EN_STAT;
+
+ return bq2415x_i2c_write(bq2415x_cli, BQ2415X_STS_CTL, res);
+}
+
+static inline int bq2415x_enable_otg(bool flag)
+{
+ int res;
+
+ res = bq2415x_i2c_read(bq2415x_cli, BQ2415X_BAT_CTL);
+ if (unlikely(res < 0))
+ return res;
+
+ if (flag)
+ res |= BQ2415X_OTG_EN;
+ else
+ res &= ~BQ2415X_OTG_EN;
+
+ return bq2415x_i2c_write(bq2415x_cli, BQ2415X_STS_CTL, res);
+}
+
+static inline int bq2415x_otg_high(bool flag)
+{
+ int res;
+
+ res = bq2415x_i2c_read(bq2415x_cli, BQ2415X_BAT_CTL);
+ if (unlikely(res < 0))
+ return res;
+
+ if (flag)
+ res |= BQ2415X_OTG_PL;
+ else
+ res &= ~BQ2415X_OTG_PL;
+
+ return bq2415x_i2c_write(bq2415x_cli, BQ2415X_STS_CTL, res);
+}
+
+static inline int bq2415x_chg_low(bool flag)
+{
+ int res;
+
+ res = bq2415x_i2c_read(bq2415x_cli, BQ2415X_SPC_CTL);
+ if (unlikely(res < 0))
+ return res;
+
+ if (flag)
+ res |= BQ2415X_LOW_CHG;
+ else
+ res &= ~BQ2415X_LOW_CHG;
+
+ return bq2415x_i2c_write(bq2415x_cli, BQ2415X_SPC_CTL, res);
+}
+
+/**
+ * bq2415x_exec - execute charger specific command
+ *
+ * Returns result of command execution upon success or negative otherwise
+ */
+int bq2415x_exec(enum bq2415x_cmd cmd)
+{
+ int res;
+
+ if (!bq2415x_cli)
+ return -ENODEV;
+
+ switch (cmd) {
+ case BQ2415X_ENABLE_CHARGER:
+ res = bq2415x_enable_charger(true);
+ break;
+ case BQ2415X_DISABLE_CHARGER:
+ res = bq2415x_enable_charger(false);
+ break;
+ case BQ2415X_READ_STATUS:
+ res = bq2415x_i2c_read(bq2415x_cli, BQ2415X_STS_CTL);
+ break;
+ case BQ2415X_RESET_CHARGER:
+ res = bq2415x_i2c_write(bq2415x_cli, BQ2415X_CHG_CTL,
+ BQ2415X_RESET_MASK);
+ break;
+ case BQ2415X_RESET_WATCHDOG:
+ res = bq2415x_i2c_read(bq2415x_cli, BQ2415X_STS_CTL);
+ if (unlikely(res < 0))
+ break;
+
+ res |= BQ2415X_TMR_RST;
+ res = bq2415x_i2c_write(bq2415x_cli, BQ2415X_STS_CTL, res);
+ break;
+ case BQ2415X_ENABLE_STAT:
+ res = bq2415x_enable_stat(true);
+ break;
+ case BQ2415X_DISABLE_STAT:
+ res = bq2415x_enable_stat(false);
+ break;
+ case BQ2415X_ENABLE_OTG:
+ res = bq2415x_enable_otg(true);
+ break;
+ case BQ2415X_DISABLE_OTG:
+ res = bq2415x_enable_otg(false);
+ break;
+ case BQ2415X_OTG_HIGH:
+ res = bq2415x_otg_high(true);
+ break;
+ case BQ2415X_OTG_LOW:
+ res = bq2415x_otg_high(false);
+ break;
+ case BQ2415X_CHG_LOW:
+ res = bq2415x_chg_low(true);
+ break;
+ case BQ2415X_CHG_NORM:
+ res = bq2415x_chg_low(false);
+ break;
+ case BQ2415X_READ_DPM:
+ res = bq2415x_i2c_read(bq2415x_cli, BQ2415X_SPC_CTL);
+ if (res & BQ2415X_DPM_STATUS)
+ res = 1; /* DPM mode is active */
+ else
+ res = 0;
+ break;
+ case BQ2415X_READ_CD:
+ res = bq2415x_i2c_read(bq2415x_cli, BQ2415X_SPC_CTL);
+ if (res & BQ2415X_CD_STATUS)
+ res = 1; /* CD ping at HIGH level */
+ else
+ res = 0;
+ break;
+ default:
+ res = -ENOSYS;
+ }
+
+ return res;
+}
+EXPORT_SYMBOL(bq2415x_exec);
+
+static inline int bq2415x_vmap_index(unsigned val, unsigned div)
+{
+ return (val / div) - 1;
+}
+
+static inline int bq2415x_vmap_calc(unsigned i, unsigned summ, unsigned mult)
+{
+ return (i + summ) * mult;
+}
+
+/* regulator operations */
+
+static int bq2415x_list_voltage(struct regulator_dev *rdev, unsigned i)
+{
+ struct bq2415x_regulator *r = rdev_get_drvdata(rdev);
+
+ if (i >= r->desc.n_voltages)
+ return 0;
+
+ return bq2415x_vmap_calc(i, r->val_summ, r->init.constraints.min_uV);
+}
+
+static int
+bq2415x_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
+{
+ int i, res;
+ struct bq2415x_regulator *r = rdev_get_drvdata(rdev);
+
+ i = bq2415x_vmap_index(max_uV, r->init.constraints.min_uV);
+ if (i >= r->desc.n_voltages)
+ return -EINVAL;
+
+ res = bq2415x_i2c_read(r->cli, r->reg);
+ if (res < 0)
+ return res;
+
+ res |= bq2415x_vmap_calc(i, r->msk_summ, r->msk_mult);
+ return bq2415x_i2c_write(r->cli, r->reg, res);
+}
+
+static int bq2415x_get_voltage(struct regulator_dev *rdev)
+{
+ int i, ret;
+ struct bq2415x_regulator *r = rdev_get_drvdata(rdev);
+
+ ret = bq2415x_i2c_read(r->cli, r->reg);
+ if (ret < 0)
+ return ret;
+
+ i = bq2415x_vmap_index(ret & r->max_mask, r->min_mask);
+ if (i >= r->desc.n_voltages)
+ return -EINVAL;
+
+ return bq2415x_vmap_calc(i, r->val_summ, r->init.constraints.min_uV);
+}
+
+static int
+bq2415x_set_current_limit(struct regulator_dev *rdev, int min_uA, int max_uA)
+{
+ int res;
+ struct bq2415x_regulator *r = rdev_get_drvdata(rdev);
+
+ res = bq2415x_i2c_read(r->cli, r->reg);
+ if (res < 0)
+ return res;
+
+ if (BQ2415X_IIN_LIMIT_100 <= min_uA && max_uA < BQ2415X_IIN_LIMIT_500)
+ res &= ~BQ2415X_IIN_LIMIT_UNLIM_MASK;
+ else if (BQ2415X_IIN_LIMIT_500 <= min_uA &&
+ max_uA < BQ2415X_IIN_LIMIT_800)
+ res |= BQ2415X_IIN_LIMIT_500_MASK;
+ else if (BQ2415X_IIN_LIMIT_800 <= min_uA &&
+ max_uA < BQ2415X_IIN_LIMIT_UNLIM)
+ res |= BQ2415X_IIN_LIMIT_800_MASK;
+ else if (BQ2415X_IIN_LIMIT_UNLIM <= min_uA)
+ res |= BQ2415X_IIN_LIMIT_UNLIM_MASK;
+ else
+ return -EINVAL;
+
+ return bq2415x_i2c_write(r->cli, r->reg, res);
+}
+
+static int bq2415x_get_current_limit(struct regulator_dev *rdev)
+{
+ int ret;
+ struct bq2415x_regulator *r = rdev_get_drvdata(rdev);
+
+ ret = bq2415x_i2c_read(r->cli, r->reg);
+ if (ret < 0)
+ return ret;
+
+ ret &= BQ2415X_IIN_LIMIT_UNLIM_MASK;
+ if (ret == BQ2415X_IIN_LIMIT_UNLIM_MASK)
+ ret = BQ2415X_IIN_LIMIT_UNLIM;
+ else if (ret == BQ2415X_IIN_LIMIT_500_MASK)
+ ret = BQ2415X_IIN_LIMIT_500;
+ else if (ret == BQ2415X_IIN_LIMIT_800_MASK)
+ ret = BQ2415X_IIN_LIMIT_800;
+ else
+ ret = BQ2415X_IIN_LIMIT_100;
+
+ return ret;
+}
+
+static int bq2415x_v_iterm_enable(struct regulator_dev *rdev)
+{
+ int val;
+ struct bq2415x_regulator *r = rdev_get_drvdata(rdev);
+
+ val = bq2415x_i2c_read(r->cli, BQ2415X_GEN_CTL);
+ if (val < 0)
+ return val;
+
+ val |= BQ2415X_TE;
+ return bq2415x_i2c_write(r->cli, BQ2415X_GEN_CTL, val);
+}
+
+static int bq2415x_v_iterm_disable(struct regulator_dev *rdev)
+{
+ int val;
+ struct bq2415x_regulator *r = rdev_get_drvdata(rdev);
+
+ val = bq2415x_i2c_read(r->cli, BQ2415X_GEN_CTL);
+ if (val < 0)
+ return val;
+
+ val &= ~BQ2415X_TE;
+ return bq2415x_i2c_write(r->cli, BQ2415X_GEN_CTL, val);
+}
+
+static int bq2415x_v_iterm_is_enabled(struct regulator_dev *rdev)
+{
+ int val;
+ struct bq2415x_regulator *r = rdev_get_drvdata(rdev);
+
+ val = bq2415x_i2c_read(r->cli, BQ2415X_GEN_CTL);
+ if (val < 0)
+ return val;
+
+ return val & BQ2415X_TE;
+}
+
+/* regulator initialization */
+
+static struct regulator_ops bq2415x_c_basic_ops = {
+ .set_current_limit = bq2415x_set_current_limit,
+ .get_current_limit = bq2415x_get_current_limit,
+};
+
+static struct regulator_ops bq2415x_v_basic_ops = {
+ .list_voltage = bq2415x_list_voltage,
+ .set_voltage = bq2415x_set_voltage,
+ .get_voltage = bq2415x_get_voltage,
+};
+
+static struct regulator_ops bq2415x_v_iterm_ops = {
+ .list_voltage = bq2415x_list_voltage,
+ .set_voltage = bq2415x_set_voltage,
+ .get_voltage = bq2415x_get_voltage,
+ .enable = bq2415x_v_iterm_enable,
+ .disable = bq2415x_v_iterm_disable,
+ .is_enabled = bq2415x_v_iterm_is_enabled,
+};
+
+static struct bq2415x_regulator bq2415x_regulator[] = {
+ [BQ2415X_V_LOWV] = { /* weak battery voltage */
+ .reg = BQ2415X_GEN_CTL,
+ .val_summ = 1,
+ .msk_summ = 1,
+ .msk_mult = 16,
+ .min_mask = 0x10,
+ .max_mask = 0x30,
+ .init.constraints = {
+ .name = "V_LOWV",
+ .min_uV = 100000,
+ .max_uV = 300000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ .always_on = 1,
+ .boot_on = 1,
+ },
+ .desc = {
+ .name = "V_LOWV",
+ .id = BQ2415X_V_LOWV,
+ .n_voltages = 3,
+ .ops = &bq2415x_v_basic_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ },
+ [BQ2415X_V_OREG] = { /* battery regulation */
+ .reg = BQ2415X_BAT_CTL,
+ .val_summ = 1,
+ .msk_summ = 1,
+ .msk_mult = 4,
+ .min_mask = 0x04,
+ .max_mask = 0xfc,
+ .init.constraints = {
+ .name = "V_OREG",
+ .min_uV = 20000,
+ .max_uV = 1260000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ .always_on = 1,
+ .boot_on = 1,
+ },
+ .desc = {
+ .name = "V_OREG",
+ .id = BQ2415X_V_OREG,
+ .n_voltages = 63,
+ .ops = &bq2415x_v_basic_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ },
+ [BQ2415X_V_ICHRG_VAC] = { /* charge current sense (USB) */
+ .reg = BQ2415X_CHG_CTL,
+ .val_summ = 1,
+ .msk_summ = 1,
+ .msk_mult = 8,
+ .min_mask = 0x08,
+ .max_mask = 0x78,
+ .init.constraints = {
+ .name = "V_ICHRG_VAC",
+ .min_uV = 6800,
+ .max_uV = 102000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ .always_on = 1,
+ .boot_on = 1,
+ },
+ .desc = {
+ .name = "V_ICHRG_VAC",
+ .id = BQ2415X_V_ICHRG_VAC,
+ .n_voltages = 15,
+ .ops = &bq2415x_v_basic_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ },
+ [BQ2415X_V_ICHRG_USB] = { /* charge current sense (VAC) */
+ .reg = BQ2415X_CHG_CTL,
+ .val_summ = 1,
+ .msk_summ = 2,
+ .msk_mult = 8,
+ .min_mask = 0x10,
+ .max_mask = 0x40,
+ .init.constraints = {
+ .name = "V_ICHRG_USB",
+ .min_uV = 6800,
+ .max_uV = 47600,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ .always_on = 1,
+ .boot_on = 1,
+ },
+ .desc = {
+ .name = "V_ICHRG_USB",
+ .id = BQ2415X_V_ICHRG_USB,
+ .n_voltages = 7,
+ .ops = &bq2415x_v_basic_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ },
+ [BQ2415X_V_ITERM] = { /* termination current sense */
+ .reg = BQ2415X_CHG_CTL,
+ .val_summ = 1,
+ .msk_summ = 1,
+ .msk_mult = 1,
+ .min_mask = 0x01,
+ .max_mask = 0x07,
+ .init.constraints = {
+ .name = "V_ITERM",
+ .min_uV = 3400,
+ .max_uV = 23800,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS,
+ .always_on = 0,
+ .boot_on = 0,
+ },
+ .desc = {
+ .name = "V_ITERM",
+ .id = BQ2415X_V_ITERM,
+ .n_voltages = 7,
+ .ops = &bq2415x_v_iterm_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ },
+ [BQ2415X_V_SREG] = { /* special charger */
+ .reg = BQ2415X_SPC_CTL,
+ .val_summ = 1,
+ .msk_summ = 1,
+ .msk_mult = 1,
+ .min_mask = 0x01,
+ .max_mask = 0x07,
+ .init.constraints = {
+ .name = "V_SREG",
+ .min_uV = 80000,
+ .max_uV = 560000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ .always_on = 1,
+ .boot_on = 1,
+ },
+ .desc = {
+ .name = "V_SREG",
+ .id = BQ2415X_V_SREG,
+ .n_voltages = 7,
+ .ops = &bq2415x_v_basic_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ },
+ [BQ2415X_V_MCHRG] = { /* maximum charge current */
+ .reg = BQ2415X_SFT_CTL,
+ .val_summ = 1,
+ .msk_summ = 1,
+ .msk_mult = 16,
+ .min_mask = 0x10,
+ .max_mask = 0xf0,
+ .init.constraints = {
+ .name = "V_MCHRG",
+ .min_uV = 6800,
+ .max_uV = 102000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ .always_on = 1,
+ .boot_on = 1,
+ },
+ .desc = {
+ .name = "V_MCHRG",
+ .id = BQ2415X_V_MCHRG,
+ .n_voltages = 15,
+ .ops = &bq2415x_v_basic_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ },
+ [BQ2415X_V_MREG] = { /* maximum battery regulation */
+ .reg = BQ2415X_SFT_CTL,
+ .val_summ = 1,
+ .msk_summ = 1,
+ .msk_mult = 1,
+ .min_mask = 0x01,
+ .max_mask = 0x0f,
+ .init.constraints = {
+ .name = "V_MREG",
+ .min_uV = 20000,
+ .max_uV = 300000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ .always_on = 1,
+ .boot_on = 1,
+ },
+ .desc = {
+ .name = "V_MREG",
+ .id = BQ2415X_V_MREG,
+ .n_voltages = 15,
+ .ops = &bq2415x_v_basic_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ },
+ [BQ2415X_I_INLIMIT] = { /* input current limit */
+ .reg = BQ2415X_GEN_CTL,
+ .init.constraints = {
+ .name = "I_INLIMIT",
+ .min_uA = 100000,
+ .max_uA = 1500000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask = REGULATOR_CHANGE_CURRENT,
+ .always_on = 1,
+ .boot_on = 1,
+ },
+ .desc = {
+ .name = "I_INLIMIT",
+ .id = BQ2415X_I_INLIMIT,
+ .n_voltages = 4,
+ .ops = &bq2415x_c_basic_ops,
+ .type = REGULATOR_CURRENT,
+ .owner = THIS_MODULE,
+ },
+ },
+};
+
+static void __init bq2415x_add_consumers(struct bq2415x_regulator *r,
+ struct regulator_init_data *init)
+{
+ int i, j, n;
+ struct regulator_consumer_supply *cons;
+
+ /* count my consumers */
+ for (i = 0, n = 0; i < init->num_consumer_supplies; i++) {
+ if (strcmp(init->consumer_supplies[i].supply,
+ r->init.constraints.name) == 0)
+ n++;
+ }
+
+ cons = kzalloc(sizeof(*cons) * n, GFP_KERNEL);
+ if (!cons)
+ return;
+
+ /* populate my consumers table */
+ for (i = 0, j = 0; i < init->num_consumer_supplies && j < n; i++) {
+ if (!init->consumer_supplies[i].supply)
+ continue;
+ if (strcmp(init->consumer_supplies[i].supply,
+ r->init.constraints.name) != 0)
+ continue;
+
+ cons[j].supply = init->consumer_supplies[i].supply;
+
+ if (init->consumer_supplies[i].dev)
+ cons[j].dev = init->consumer_supplies[i].dev;
+ if (init->consumer_supplies[i].dev_name)
+ cons[j].dev_name = init->consumer_supplies[i].dev_name;
+
+ j++;
+ }
+
+ r->init.num_consumer_supplies = n;
+ r->init.consumer_supplies = cons;
+}
+
+static int __devinit bq2415x_regulator_init(struct bq2415x_device *bq)
+{
+ int i;
+ struct device *dev = &bq->cli->dev;
+ struct bq2415x_regulator *r;
+ struct regulator_dev *rdev;
+ struct regulator_init_data *init = dev->platform_data;
+
+ for (i = 0; i < ARRAY_SIZE(bq2415x_regulator); i++) {
+ r = &bq2415x_regulator[i];
+ r->cli = bq->cli;
+
+ if (init)
+ bq2415x_add_consumers(r, init);
+
+ rdev = regulator_register(&r->desc, dev, &r->init, r);
+ if (IS_ERR(rdev))
+ return PTR_ERR(rdev);
+
+ bq->rdev[i] = rdev;
+ }
+
+ return 0;
+}
+
+/* driver initialization */
+
+static struct bq2415x_device *bq2415x_getdev(struct i2c_client *cli)
+{
+ struct bq2415x_device *pos, *dev = 0;
+
+ mutex_lock(&bq2415x_dev_list_mutex);
+ list_for_each_entry(pos, &bq2415x_dev_list, list) {
+ if (pos->cli == cli ||
+ (pos->cli->addr == cli->addr &&
+ pos->cli->adapter == cli->adapter)) {
+ dev = pos;
+ break;
+ }
+ }
+ mutex_unlock(&bq2415x_dev_list_mutex);
+ return dev;
+}
+
+static int bq2415x_remove(struct i2c_client *cli)
+{
+ int i;
+ struct bq2415x_device *dev = bq2415x_getdev(cli);
+
+ if (dev) {
+ for (i = 0; i < ARRAY_SIZE(dev->rdev); i++) {
+ if (dev->rdev[i])
+ regulator_unregister(dev->rdev[i]);
+ }
+
+ mutex_lock(&bq2415x_dev_list_mutex);
+ list_del(&dev->list);
+ mutex_unlock(&bq2415x_dev_list_mutex);
+ kfree(dev);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(bq2415x_regulator); i++)
+ kfree(bq2415x_regulator[i].init.consumer_supplies);
+
+ return 0;
+}
+
+static int __devinit
+bq2415x_probe(struct i2c_client *cli, const struct i2c_device_id *id)
+{
+ int rc = 0;
+ struct bq2415x_device *dev;
+
+ bq2415x_cli = cli;
+
+ if (i2c_check_functionality(cli->adapter, I2C_FUNC_I2C) == 0) {
+ dev_dbg(&cli->dev, "i2c is not supported\n");
+ return -EIO;
+ }
+
+ dev = bq2415x_getdev(cli);
+ if (dev)
+ return -EBUSY;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ dev->cli = cli;
+ rc = bq2415x_regulator_init(dev);
+ if (rc < 0) {
+ bq2415x_remove(cli);
+ } else {
+ mutex_lock(&bq2415x_dev_list_mutex);
+ list_add(&dev->list, &bq2415x_dev_list);
+ mutex_unlock(&bq2415x_dev_list_mutex);
+ }
+
+ return rc;
+}
+
+static const struct i2c_device_id bq2415x_id[] = {
+ { "bq24156", 0 }, /* VAC charger */
+ { "bq24153", 0 }, /* USB charger */
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, bq2415x_id);
+
+static struct i2c_driver bq2415x_driver = {
+ .driver = {
+ .name = "bq2415x",
+ .owner = THIS_MODULE,
+ },
+ .id_table = bq2415x_id,
+ .probe = bq2415x_probe,
+ .remove = bq2415x_remove,
+};
+
+static int __init bq2415x_init(void)
+{
+ return i2c_add_driver(&bq2415x_driver);
+}
+module_init(bq2415x_init);
+
+static void __exit bq2415x_exit(void)
+{
+ i2c_del_driver(&bq2415x_driver);
+}
+module_exit(bq2415x_exit);
+
+MODULE_AUTHOR("Aliaksei Katovich <aliaksei.katovich@nokia.com>");
+MODULE_DESCRIPTION("TI BQ24153/6 one-cell Li-Ion charger driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/bq2415x.h b/include/linux/mfd/bq2415x.h
new file mode 100644
index 0000000..fb9ecb5
--- /dev/null
+++ b/include/linux/mfd/bq2415x.h
@@ -0,0 +1,88 @@
+/*
+ * bq2415x.h - header of TI BQ24153/6 one-cell Li-Ion Charger Driver
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contact: Aliaksei Katovich <aliaksei.katovich@nokia.com>
+ *
+ * This software is distributed under the terms of the GNU General
+ * Public License ("GPL") as published by the Free Software Foundation,
+ * version 2 of that License.
+ */
+
+#ifndef __BQ2415X_H_
+#define __BQ2415X_H_
+
+#include <linux/i2c.h>
+#include <linux/regulator/machine.h>
+
+#define BQ24156_ADDR 0x6a
+#define BQ24153_ADDR 0x6b
+
+#define BQ2415X_STS_CTL 0x00 /* status/control (rw) */
+#define BQ2415X_TMR_RST BIT(7)
+#define BQ2415X_EN_STAT BIT(6)
+#define BQ2415X_STAT2 BIT(5)
+#define BQ2415X_STAT1 BIT(4)
+
+#define BQ2415X_GEN_CTL 0x01 /* generic control (rw) */
+#define BQ2415X_TE BIT(3)
+#define BQ2415X_CE BIT(2)
+#define BQ2415X_HZ_MODE BIT(1)
+
+#define BQ2415X_BAT_CTL 0x02 /* control/battery voltage (rw) */
+#define BQ2415X_OTG_PL BIT(1)
+#define BQ2415X_OTG_EN BIT(0)
+
+#define BQ2415X_REV_STS 0x03 /* vender/part/revision (ro) */
+#define BQ2415X_CHG_CTL 0x04 /* battery termination/fast charge
+ * current (rw) */
+#define BQ2415X_SPC_CTL 0x05 /* special charger voltage/enable pin
+ * status (rw) */
+#define BQ2415X_LOW_CHG BIT(5)
+#define BQ2415X_DPM_STATUS BIT(4)
+#define BQ2415X_CD_STATUS BIT(3)
+
+#define BQ2415X_SFT_CTL 0x06 /* safety limit (rw, write-once after
+ * reset!)*/
+
+/* pre-defined input current limits, uA */
+#define BQ2415X_IIN_LIMIT_100 100000
+#define BQ2415X_IIN_LIMIT_500 500000
+#define BQ2415X_IIN_LIMIT_800 800000
+#define BQ2415X_IIN_LIMIT_UNLIM 1500000
+
+enum { /* regulator id */
+ BQ2415X_V_LOWV = 0,
+ BQ2415X_V_OREG,
+ BQ2415X_V_ICHRG_VAC,
+ BQ2415X_V_ICHRG_USB,
+ BQ2415X_V_ITERM,
+ BQ2415X_V_SREG,
+ BQ2415X_V_MCHRG,
+ BQ2415X_V_MREG,
+ BQ2415X_I_INLIMIT,
+ BQ2415X_MAX_REG,
+};
+
+enum bq2415x_cmd {
+ BQ2415X_ENABLE_CHARGER = 1,
+ BQ2415X_DISABLE_CHARGER,
+ BQ2415X_READ_STATUS,
+ BQ2415X_RESET_CHARGER,
+ BQ2415X_RESET_WATCHDOG,
+ BQ2415X_ENABLE_STAT,
+ BQ2415X_DISABLE_STAT,
+ BQ2415X_ENABLE_OTG,
+ BQ2415X_DISABLE_OTG,
+ BQ2415X_OTG_HIGH,
+ BQ2415X_OTG_LOW,
+ BQ2415X_CHG_LOW, /* LOW_CHG bit */
+ BQ2415X_CHG_NORM, /* LOW_CHG bit */
+ BQ2415X_READ_DPM,
+ BQ2415X_READ_CD,
+};
+
+int bq2415x_exec(enum bq2415x_cmd cmd);
+
+#endif /* __BQ2415X_H_ */
--
1.7.0.4
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH 2/2] mfd: bq2415x compilation enablers
2011-02-28 21:36 ` [PATCH 0/2] mfd: bq2415x charger driver aliaksei.katovich
2011-02-28 21:36 ` [PATCH 1/2] " aliaksei.katovich
@ 2011-02-28 21:36 ` aliaksei.katovich
1 sibling, 0 replies; 3+ messages in thread
From: aliaksei.katovich @ 2011-02-28 21:36 UTC (permalink / raw)
To: sameo; +Cc: linux-kernel, Aliaksei Katovich
From: Aliaksei Katovich <aliaksei.katovich@nokia.com>
Enable compilation of bq2415x charger driver
Signed-off-by: Aliaksei Katovich <aliaksei.katovich@nokia.com>
---
drivers/mfd/Kconfig | 7 +++++++
drivers/mfd/Makefile | 1 +
2 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index fd01836..d0ab44a 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -624,6 +624,13 @@ config MFD_WL1273_CORE
driver connects the radio-wl1273 V4L2 module and the wl1273
audio codec.
+config MFD_BQ2415X
+ tristate "TI bq24153/6 one-cell Li-Ion charger IC"
+ depends on I2C && REGULATOR
+ help
+ This driver supports TI bq24153/6 integrated switch-mode chargers
+ attached to i2c.
+
endif # MFD_SUPPORT
menu "Multimedia Capabilities Port drivers"
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index a54e2c7..a0df0db 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -83,3 +83,4 @@ obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o
obj-$(CONFIG_MFD_VX855) += vx855.o
obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o
obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o
+obj-$(CONFIG_MFD_BQ2415X) += bq2415x.o
--
1.7.0.4
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2011-02-28 21:37 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
[not found] <"cover.1298918741.git.aliaksei.katovich@nokia.com">
2011-02-28 21:36 ` [PATCH 0/2] mfd: bq2415x charger driver aliaksei.katovich
2011-02-28 21:36 ` [PATCH 1/2] " aliaksei.katovich
2011-02-28 21:36 ` [PATCH 2/2] mfd: bq2415x compilation enablers aliaksei.katovich
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®