Loading drivers/mfd/da9150-core.c +149 −7 Original line number Diff line number Diff line Loading @@ -23,6 +23,77 @@ #include <linux/mfd/da9150/core.h> #include <linux/mfd/da9150/registers.h> /* Raw device access, used for QIF */ static int da9150_i2c_read_device(struct i2c_client *client, u8 addr, int count, u8 *buf) { struct i2c_msg xfer; int ret; /* * Read is split into two transfers as device expects STOP/START rather * than repeated start to carry out this kind of access. */ /* Write address */ xfer.addr = client->addr; xfer.flags = 0; xfer.len = 1; xfer.buf = &addr; ret = i2c_transfer(client->adapter, &xfer, 1); if (ret != 1) { if (ret < 0) return ret; else return -EIO; } /* Read data */ xfer.addr = client->addr; xfer.flags = I2C_M_RD; xfer.len = count; xfer.buf = buf; ret = i2c_transfer(client->adapter, &xfer, 1); if (ret == 1) return 0; else if (ret < 0) return ret; else return -EIO; } static int da9150_i2c_write_device(struct i2c_client *client, u8 addr, int count, const u8 *buf) { struct i2c_msg xfer; u8 *reg_data; int ret; reg_data = kzalloc(1 + count, GFP_KERNEL); if (!reg_data) return -ENOMEM; reg_data[0] = addr; memcpy(®_data[1], buf, count); /* Write address & data */ xfer.addr = client->addr; xfer.flags = 0; xfer.len = 1 + count; xfer.buf = reg_data; ret = i2c_transfer(client->adapter, &xfer, 1); kfree(reg_data); if (ret == 1) return 0; else if (ret < 0) return ret; else return -EIO; } static bool da9150_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { Loading Loading @@ -107,6 +178,28 @@ static const struct regmap_config da9150_regmap_config = { .volatile_reg = da9150_volatile_reg, }; void da9150_read_qif(struct da9150 *da9150, u8 addr, int count, u8 *buf) { int ret; ret = da9150_i2c_read_device(da9150->core_qif, addr, count, buf); if (ret < 0) dev_err(da9150->dev, "Failed to read from QIF 0x%x: %d\n", addr, ret); } EXPORT_SYMBOL_GPL(da9150_read_qif); void da9150_write_qif(struct da9150 *da9150, u8 addr, int count, const u8 *buf) { int ret; ret = da9150_i2c_write_device(da9150->core_qif, addr, count, buf); if (ret < 0) dev_err(da9150->dev, "Failed to write to QIF 0x%x: %d\n", addr, ret); } EXPORT_SYMBOL_GPL(da9150_write_qif); u8 da9150_reg_read(struct da9150 *da9150, u16 reg) { int val, ret; Loading Loading @@ -297,19 +390,35 @@ static struct resource da9150_charger_resources[] = { }, }; static struct resource da9150_fg_resources[] = { DEFINE_RES_IRQ_NAMED(DA9150_IRQ_FG, "FG"), }; enum da9150_dev_idx { DA9150_GPADC_IDX = 0, DA9150_CHARGER_IDX, DA9150_FG_IDX, }; static struct mfd_cell da9150_devs[] = { { [DA9150_GPADC_IDX] = { .name = "da9150-gpadc", .of_compatible = "dlg,da9150-gpadc", .resources = da9150_gpadc_resources, .num_resources = ARRAY_SIZE(da9150_gpadc_resources), }, { [DA9150_CHARGER_IDX] = { .name = "da9150-charger", .of_compatible = "dlg,da9150-charger", .resources = da9150_charger_resources, .num_resources = ARRAY_SIZE(da9150_charger_resources), }, [DA9150_FG_IDX] = { .name = "da9150-fuel-gauge", .of_compatible = "dlg,da9150-fuel-gauge", .resources = da9150_fg_resources, .num_resources = ARRAY_SIZE(da9150_fg_resources), }, }; static int da9150_probe(struct i2c_client *client, Loading @@ -317,6 +426,7 @@ static int da9150_probe(struct i2c_client *client, { struct da9150 *da9150; struct da9150_pdata *pdata = dev_get_platdata(&client->dev); int qif_addr; int ret; da9150 = devm_kzalloc(&client->dev, sizeof(*da9150), GFP_KERNEL); Loading @@ -335,16 +445,41 @@ static int da9150_probe(struct i2c_client *client, return ret; } da9150->irq_base = pdata ? pdata->irq_base : -1; /* Setup secondary I2C interface for QIF access */ qif_addr = da9150_reg_read(da9150, DA9150_CORE2WIRE_CTRL_A); qif_addr = (qif_addr & DA9150_CORE_BASE_ADDR_MASK) >> 1; qif_addr |= DA9150_QIF_I2C_ADDR_LSB; da9150->core_qif = i2c_new_dummy(client->adapter, qif_addr); if (!da9150->core_qif) { dev_err(da9150->dev, "Failed to attach QIF client\n"); return -ENODEV; } i2c_set_clientdata(da9150->core_qif, da9150); if (pdata) { da9150->irq_base = pdata->irq_base; da9150_devs[DA9150_FG_IDX].platform_data = pdata->fg_pdata; da9150_devs[DA9150_FG_IDX].pdata_size = sizeof(struct da9150_fg_pdata); } else { da9150->irq_base = -1; } ret = regmap_add_irq_chip(da9150->regmap, da9150->irq, IRQF_TRIGGER_LOW | IRQF_ONESHOT, da9150->irq_base, &da9150_regmap_irq_chip, &da9150->regmap_irq_data); if (ret) return ret; if (ret) { dev_err(da9150->dev, "Failed to add regmap irq chip: %d\n", ret); goto regmap_irq_fail; } da9150->irq_base = regmap_irq_chip_get_base(da9150->regmap_irq_data); enable_irq_wake(da9150->irq); ret = mfd_add_devices(da9150->dev, -1, da9150_devs, Loading @@ -352,11 +487,17 @@ static int da9150_probe(struct i2c_client *client, da9150->irq_base, NULL); if (ret) { dev_err(da9150->dev, "Failed to add child devices: %d\n", ret); regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data); return ret; goto mfd_fail; } return 0; mfd_fail: regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data); regmap_irq_fail: i2c_unregister_device(da9150->core_qif); return ret; } static int da9150_remove(struct i2c_client *client) Loading @@ -365,6 +506,7 @@ static int da9150_remove(struct i2c_client *client) regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data); mfd_remove_devices(da9150->dev); i2c_unregister_device(da9150->core_qif); return 0; } Loading include/linux/mfd/da9150/core.h +18 −1 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ #define __DA9150_CORE_H #include <linux/device.h> #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/regmap.h> Loading Loading @@ -46,23 +47,39 @@ #define DA9150_IRQ_GPADC 19 #define DA9150_IRQ_WKUP 20 /* I2C sub-device address */ #define DA9150_QIF_I2C_ADDR_LSB 0x5 struct da9150_fg_pdata { u32 update_interval; /* msecs */ u8 warn_soc_lvl; /* % value */ u8 crit_soc_lvl; /* % value */ }; struct da9150_pdata { int irq_base; struct da9150_fg_pdata *fg_pdata; }; struct da9150 { struct device *dev; struct regmap *regmap; struct i2c_client *core_qif; struct regmap_irq_chip_data *regmap_irq_data; int irq; int irq_base; }; /* Device I/O */ /* Device I/O - Query Interface for FG and standard register access */ void da9150_read_qif(struct da9150 *da9150, u8 addr, int count, u8 *buf); void da9150_write_qif(struct da9150 *da9150, u8 addr, int count, const u8 *buf); u8 da9150_reg_read(struct da9150 *da9150, u16 reg); void da9150_reg_write(struct da9150 *da9150, u16 reg, u8 val); void da9150_set_bits(struct da9150 *da9150, u16 reg, u8 mask, u8 val); void da9150_bulk_read(struct da9150 *da9150, u16 reg, int count, u8 *buf); void da9150_bulk_write(struct da9150 *da9150, u16 reg, int count, const u8 *buf); #endif /* __DA9150_CORE_H */ Loading
drivers/mfd/da9150-core.c +149 −7 Original line number Diff line number Diff line Loading @@ -23,6 +23,77 @@ #include <linux/mfd/da9150/core.h> #include <linux/mfd/da9150/registers.h> /* Raw device access, used for QIF */ static int da9150_i2c_read_device(struct i2c_client *client, u8 addr, int count, u8 *buf) { struct i2c_msg xfer; int ret; /* * Read is split into two transfers as device expects STOP/START rather * than repeated start to carry out this kind of access. */ /* Write address */ xfer.addr = client->addr; xfer.flags = 0; xfer.len = 1; xfer.buf = &addr; ret = i2c_transfer(client->adapter, &xfer, 1); if (ret != 1) { if (ret < 0) return ret; else return -EIO; } /* Read data */ xfer.addr = client->addr; xfer.flags = I2C_M_RD; xfer.len = count; xfer.buf = buf; ret = i2c_transfer(client->adapter, &xfer, 1); if (ret == 1) return 0; else if (ret < 0) return ret; else return -EIO; } static int da9150_i2c_write_device(struct i2c_client *client, u8 addr, int count, const u8 *buf) { struct i2c_msg xfer; u8 *reg_data; int ret; reg_data = kzalloc(1 + count, GFP_KERNEL); if (!reg_data) return -ENOMEM; reg_data[0] = addr; memcpy(®_data[1], buf, count); /* Write address & data */ xfer.addr = client->addr; xfer.flags = 0; xfer.len = 1 + count; xfer.buf = reg_data; ret = i2c_transfer(client->adapter, &xfer, 1); kfree(reg_data); if (ret == 1) return 0; else if (ret < 0) return ret; else return -EIO; } static bool da9150_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { Loading Loading @@ -107,6 +178,28 @@ static const struct regmap_config da9150_regmap_config = { .volatile_reg = da9150_volatile_reg, }; void da9150_read_qif(struct da9150 *da9150, u8 addr, int count, u8 *buf) { int ret; ret = da9150_i2c_read_device(da9150->core_qif, addr, count, buf); if (ret < 0) dev_err(da9150->dev, "Failed to read from QIF 0x%x: %d\n", addr, ret); } EXPORT_SYMBOL_GPL(da9150_read_qif); void da9150_write_qif(struct da9150 *da9150, u8 addr, int count, const u8 *buf) { int ret; ret = da9150_i2c_write_device(da9150->core_qif, addr, count, buf); if (ret < 0) dev_err(da9150->dev, "Failed to write to QIF 0x%x: %d\n", addr, ret); } EXPORT_SYMBOL_GPL(da9150_write_qif); u8 da9150_reg_read(struct da9150 *da9150, u16 reg) { int val, ret; Loading Loading @@ -297,19 +390,35 @@ static struct resource da9150_charger_resources[] = { }, }; static struct resource da9150_fg_resources[] = { DEFINE_RES_IRQ_NAMED(DA9150_IRQ_FG, "FG"), }; enum da9150_dev_idx { DA9150_GPADC_IDX = 0, DA9150_CHARGER_IDX, DA9150_FG_IDX, }; static struct mfd_cell da9150_devs[] = { { [DA9150_GPADC_IDX] = { .name = "da9150-gpadc", .of_compatible = "dlg,da9150-gpadc", .resources = da9150_gpadc_resources, .num_resources = ARRAY_SIZE(da9150_gpadc_resources), }, { [DA9150_CHARGER_IDX] = { .name = "da9150-charger", .of_compatible = "dlg,da9150-charger", .resources = da9150_charger_resources, .num_resources = ARRAY_SIZE(da9150_charger_resources), }, [DA9150_FG_IDX] = { .name = "da9150-fuel-gauge", .of_compatible = "dlg,da9150-fuel-gauge", .resources = da9150_fg_resources, .num_resources = ARRAY_SIZE(da9150_fg_resources), }, }; static int da9150_probe(struct i2c_client *client, Loading @@ -317,6 +426,7 @@ static int da9150_probe(struct i2c_client *client, { struct da9150 *da9150; struct da9150_pdata *pdata = dev_get_platdata(&client->dev); int qif_addr; int ret; da9150 = devm_kzalloc(&client->dev, sizeof(*da9150), GFP_KERNEL); Loading @@ -335,16 +445,41 @@ static int da9150_probe(struct i2c_client *client, return ret; } da9150->irq_base = pdata ? pdata->irq_base : -1; /* Setup secondary I2C interface for QIF access */ qif_addr = da9150_reg_read(da9150, DA9150_CORE2WIRE_CTRL_A); qif_addr = (qif_addr & DA9150_CORE_BASE_ADDR_MASK) >> 1; qif_addr |= DA9150_QIF_I2C_ADDR_LSB; da9150->core_qif = i2c_new_dummy(client->adapter, qif_addr); if (!da9150->core_qif) { dev_err(da9150->dev, "Failed to attach QIF client\n"); return -ENODEV; } i2c_set_clientdata(da9150->core_qif, da9150); if (pdata) { da9150->irq_base = pdata->irq_base; da9150_devs[DA9150_FG_IDX].platform_data = pdata->fg_pdata; da9150_devs[DA9150_FG_IDX].pdata_size = sizeof(struct da9150_fg_pdata); } else { da9150->irq_base = -1; } ret = regmap_add_irq_chip(da9150->regmap, da9150->irq, IRQF_TRIGGER_LOW | IRQF_ONESHOT, da9150->irq_base, &da9150_regmap_irq_chip, &da9150->regmap_irq_data); if (ret) return ret; if (ret) { dev_err(da9150->dev, "Failed to add regmap irq chip: %d\n", ret); goto regmap_irq_fail; } da9150->irq_base = regmap_irq_chip_get_base(da9150->regmap_irq_data); enable_irq_wake(da9150->irq); ret = mfd_add_devices(da9150->dev, -1, da9150_devs, Loading @@ -352,11 +487,17 @@ static int da9150_probe(struct i2c_client *client, da9150->irq_base, NULL); if (ret) { dev_err(da9150->dev, "Failed to add child devices: %d\n", ret); regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data); return ret; goto mfd_fail; } return 0; mfd_fail: regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data); regmap_irq_fail: i2c_unregister_device(da9150->core_qif); return ret; } static int da9150_remove(struct i2c_client *client) Loading @@ -365,6 +506,7 @@ static int da9150_remove(struct i2c_client *client) regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data); mfd_remove_devices(da9150->dev); i2c_unregister_device(da9150->core_qif); return 0; } Loading
include/linux/mfd/da9150/core.h +18 −1 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ #define __DA9150_CORE_H #include <linux/device.h> #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/regmap.h> Loading Loading @@ -46,23 +47,39 @@ #define DA9150_IRQ_GPADC 19 #define DA9150_IRQ_WKUP 20 /* I2C sub-device address */ #define DA9150_QIF_I2C_ADDR_LSB 0x5 struct da9150_fg_pdata { u32 update_interval; /* msecs */ u8 warn_soc_lvl; /* % value */ u8 crit_soc_lvl; /* % value */ }; struct da9150_pdata { int irq_base; struct da9150_fg_pdata *fg_pdata; }; struct da9150 { struct device *dev; struct regmap *regmap; struct i2c_client *core_qif; struct regmap_irq_chip_data *regmap_irq_data; int irq; int irq_base; }; /* Device I/O */ /* Device I/O - Query Interface for FG and standard register access */ void da9150_read_qif(struct da9150 *da9150, u8 addr, int count, u8 *buf); void da9150_write_qif(struct da9150 *da9150, u8 addr, int count, const u8 *buf); u8 da9150_reg_read(struct da9150 *da9150, u16 reg); void da9150_reg_write(struct da9150 *da9150, u16 reg, u8 val); void da9150_set_bits(struct da9150 *da9150, u16 reg, u8 mask, u8 val); void da9150_bulk_read(struct da9150 *da9150, u16 reg, int count, u8 *buf); void da9150_bulk_write(struct da9150 *da9150, u16 reg, int count, const u8 *buf); #endif /* __DA9150_CORE_H */