diff options
Diffstat (limited to 'drivers/mfd')
-rw-r--r-- | drivers/mfd/da9150-core.c | 191 | ||||
-rw-r--r-- | drivers/mfd/intel_quark_i2c_gpio.c | 33 | ||||
-rw-r--r-- | drivers/mfd/mfd-core.c | 52 | ||||
-rw-r--r-- | drivers/mfd/wm5110-tables.c | 6 |
4 files changed, 219 insertions, 63 deletions
diff --git a/drivers/mfd/da9150-core.c b/drivers/mfd/da9150-core.c index 94b9bbd1a69b..195fdcfa1a0d 100644 --- a/drivers/mfd/da9150-core.c +++ b/drivers/mfd/da9150-core.c @@ -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) { @@ -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; @@ -262,54 +355,45 @@ static const struct regmap_irq_chip da9150_regmap_irq_chip = { }; static struct resource da9150_gpadc_resources[] = { - { - .name = "GPADC", - .start = DA9150_IRQ_GPADC, - .end = DA9150_IRQ_GPADC, - .flags = IORESOURCE_IRQ, - }, + DEFINE_RES_IRQ_NAMED(DA9150_IRQ_GPADC, "GPADC"), }; static struct resource da9150_charger_resources[] = { - { - .name = "CHG_STATUS", - .start = DA9150_IRQ_CHG, - .end = DA9150_IRQ_CHG, - .flags = IORESOURCE_IRQ, - }, - { - .name = "CHG_TJUNC", - .start = DA9150_IRQ_TJUNC, - .end = DA9150_IRQ_TJUNC, - .flags = IORESOURCE_IRQ, - }, - { - .name = "CHG_VFAULT", - .start = DA9150_IRQ_VFAULT, - .end = DA9150_IRQ_VFAULT, - .flags = IORESOURCE_IRQ, - }, - { - .name = "CHG_VBUS", - .start = DA9150_IRQ_VBUS, - .end = DA9150_IRQ_VBUS, - .flags = IORESOURCE_IRQ, - }, + DEFINE_RES_IRQ_NAMED(DA9150_IRQ_CHG, "CHG_STATUS"), + DEFINE_RES_IRQ_NAMED(DA9150_IRQ_TJUNC, "CHG_TJUNC"), + DEFINE_RES_IRQ_NAMED(DA9150_IRQ_VFAULT, "CHG_VFAULT"), + DEFINE_RES_IRQ_NAMED(DA9150_IRQ_VBUS, "CHG_VBUS"), +}; + +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, @@ -317,6 +401,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); @@ -335,16 +420,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, @@ -352,11 +462,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) @@ -365,6 +481,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; } diff --git a/drivers/mfd/intel_quark_i2c_gpio.c b/drivers/mfd/intel_quark_i2c_gpio.c index 1ce16037d043..042137465300 100644 --- a/drivers/mfd/intel_quark_i2c_gpio.c +++ b/drivers/mfd/intel_quark_i2c_gpio.c @@ -31,6 +31,10 @@ #define MFD_I2C_BAR 0 #define MFD_GPIO_BAR 1 +/* ACPI _ADR value to match the child node */ +#define MFD_ACPI_MATCH_GPIO 0ULL +#define MFD_ACPI_MATCH_I2C 1ULL + /* The base GPIO number under GPIOLIB framework */ #define INTEL_QUARK_MFD_GPIO_BASE 8 @@ -82,27 +86,37 @@ static struct resource intel_quark_i2c_res[] = { }, }; +static struct mfd_cell_acpi_match intel_quark_acpi_match_i2c = { + .adr = MFD_ACPI_MATCH_I2C, +}; + static struct resource intel_quark_gpio_res[] = { [INTEL_QUARK_IORES_MEM] = { .flags = IORESOURCE_MEM, }, }; +static struct mfd_cell_acpi_match intel_quark_acpi_match_gpio = { + .adr = MFD_ACPI_MATCH_GPIO, +}; + static struct mfd_cell intel_quark_mfd_cells[] = { { - .id = MFD_I2C_BAR, - .name = "i2c_designware", - .num_resources = ARRAY_SIZE(intel_quark_i2c_res), - .resources = intel_quark_i2c_res, - .ignore_resource_conflicts = true, - }, - { .id = MFD_GPIO_BAR, .name = "gpio-dwapb", + .acpi_match = &intel_quark_acpi_match_gpio, .num_resources = ARRAY_SIZE(intel_quark_gpio_res), .resources = intel_quark_gpio_res, .ignore_resource_conflicts = true, }, + { + .id = MFD_I2C_BAR, + .name = "i2c_designware", + .acpi_match = &intel_quark_acpi_match_i2c, + .num_resources = ARRAY_SIZE(intel_quark_i2c_res), + .resources = intel_quark_i2c_res, + .ignore_resource_conflicts = true, + }, }; static const struct pci_device_id intel_quark_mfd_ids[] = { @@ -248,12 +262,11 @@ static int intel_quark_mfd_probe(struct pci_dev *pdev, dev_set_drvdata(&pdev->dev, quark_mfd); - ret = intel_quark_i2c_setup(pdev, &intel_quark_mfd_cells[MFD_I2C_BAR]); + ret = intel_quark_i2c_setup(pdev, &intel_quark_mfd_cells[1]); if (ret) return ret; - ret = intel_quark_gpio_setup(pdev, - &intel_quark_mfd_cells[MFD_GPIO_BAR]); + ret = intel_quark_gpio_setup(pdev, &intel_quark_mfd_cells[0]); if (ret) return ret; diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index c17635d3e504..60b60dc63ddd 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -82,29 +82,49 @@ static int mfd_platform_add_cell(struct platform_device *pdev, static void mfd_acpi_add_device(const struct mfd_cell *cell, struct platform_device *pdev) { - struct acpi_device *parent_adev; + const struct mfd_cell_acpi_match *match = cell->acpi_match; + struct acpi_device *parent, *child; struct acpi_device *adev; - parent_adev = ACPI_COMPANION(pdev->dev.parent); - if (!parent_adev) + parent = ACPI_COMPANION(pdev->dev.parent); + if (!parent) return; /* - * MFD child device gets its ACPI handle either from the ACPI - * device directly under the parent that matches the acpi_pnpid or - * it will use the parent handle if is no acpi_pnpid is given. + * MFD child device gets its ACPI handle either from the ACPI device + * directly under the parent that matches the either _HID or _CID, or + * _ADR or it will use the parent handle if is no ID is given. + * + * Note that use of _ADR is a grey area in the ACPI specification, + * though Intel Galileo Gen2 is using it to distinguish the children + * devices. */ - adev = parent_adev; - if (cell->acpi_pnpid) { - struct acpi_device_id ids[2] = {}; - struct acpi_device *child_adev; - - strlcpy(ids[0].id, cell->acpi_pnpid, sizeof(ids[0].id)); - list_for_each_entry(child_adev, &parent_adev->children, node) - if (acpi_match_device_ids(child_adev, ids)) { - adev = child_adev; - break; + adev = parent; + if (match) { + if (match->pnpid) { + struct acpi_device_id ids[2] = {}; + + strlcpy(ids[0].id, match->pnpid, sizeof(ids[0].id)); + list_for_each_entry(child, &parent->children, node) { + if (acpi_match_device_ids(child, ids)) { + adev = child; + break; + } + } + } else { + unsigned long long adr; + acpi_status status; + + list_for_each_entry(child, &parent->children, node) { + status = acpi_evaluate_integer(child->handle, + "_ADR", NULL, + &adr); + if (ACPI_SUCCESS(status) && match->adr == adr) { + adev = child; + break; + } } + } } ACPI_COMPANION_SET(&pdev->dev, adev); diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c index c4b9374efd76..28f2ae30507a 100644 --- a/drivers/mfd/wm5110-tables.c +++ b/drivers/mfd/wm5110-tables.c @@ -1481,6 +1481,7 @@ static const struct reg_default wm5110_reg_default[] = { { 0x00000C04, 0xA101 }, /* R3076 - GPIO5 CTRL */ { 0x00000C0F, 0x0400 }, /* R3087 - IRQ CTRL 1 */ { 0x00000C10, 0x1000 }, /* R3088 - GPIO Debounce Config */ + { 0x00000C18, 0x0000 }, /* R3096 - GP Switch 1 */ { 0x00000C20, 0x8002 }, /* R3104 - Misc Pad Ctrl 1 */ { 0x00000C21, 0x8001 }, /* R3105 - Misc Pad Ctrl 2 */ { 0x00000C22, 0x0000 }, /* R3106 - Misc Pad Ctrl 3 */ @@ -1811,6 +1812,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg) case ARIZONA_MIC_DETECT_1: case ARIZONA_MIC_DETECT_2: case ARIZONA_MIC_DETECT_3: + case ARIZONA_MIC_DETECT_4: case ARIZONA_MIC_DETECT_LEVEL_1: case ARIZONA_MIC_DETECT_LEVEL_2: case ARIZONA_MIC_DETECT_LEVEL_3: @@ -1910,6 +1912,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg) case ARIZONA_HP1_SHORT_CIRCUIT_CTRL: case ARIZONA_HP2_SHORT_CIRCUIT_CTRL: case ARIZONA_HP3_SHORT_CIRCUIT_CTRL: + case ARIZONA_HP_TEST_CTRL_1: case ARIZONA_AIF1_BCLK_CTRL: case ARIZONA_AIF1_TX_PIN_CTRL: case ARIZONA_AIF1_RX_PIN_CTRL: @@ -2527,6 +2530,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg) case ARIZONA_GPIO5_CTRL: case ARIZONA_IRQ_CTRL_1: case ARIZONA_GPIO_DEBOUNCE_CONFIG: + case ARIZONA_GP_SWITCH_1: case ARIZONA_MISC_PAD_CTRL_1: case ARIZONA_MISC_PAD_CTRL_2: case ARIZONA_MISC_PAD_CTRL_3: @@ -2847,12 +2851,14 @@ static bool wm5110_volatile_register(struct device *dev, unsigned int reg) case ARIZONA_ASYNC_SAMPLE_RATE_1_STATUS: case ARIZONA_ASYNC_SAMPLE_RATE_2_STATUS: case ARIZONA_MIC_DETECT_3: + case ARIZONA_MIC_DETECT_4: case ARIZONA_HP_CTRL_1L: case ARIZONA_HP_CTRL_1R: case ARIZONA_HEADPHONE_DETECT_2: case ARIZONA_INPUT_ENABLES_STATUS: case ARIZONA_OUTPUT_STATUS_1: case ARIZONA_RAW_OUTPUT_STATUS_1: + case ARIZONA_HP_TEST_CTRL_1: case ARIZONA_SLIMBUS_RX_PORT_STATUS: case ARIZONA_SLIMBUS_TX_PORT_STATUS: case ARIZONA_INTERRUPT_STATUS_1: |