diff options
Diffstat (limited to 'drivers/mfd')
-rw-r--r-- | drivers/mfd/Kconfig | 17 | ||||
-rw-r--r-- | drivers/mfd/Makefile | 1 | ||||
-rw-r--r-- | drivers/mfd/ab8500-core.c | 4 | ||||
-rw-r--r-- | drivers/mfd/ab8500-sysctrl.c | 14 | ||||
-rw-r--r-- | drivers/mfd/arizona-irq.c | 86 | ||||
-rw-r--r-- | drivers/mfd/arizona.h | 2 | ||||
-rw-r--r-- | drivers/mfd/axp20x.c | 78 | ||||
-rw-r--r-- | drivers/mfd/cros_ec.c | 53 | ||||
-rw-r--r-- | drivers/mfd/intel-lpss-pci.c | 17 | ||||
-rw-r--r-- | drivers/mfd/kempld-core.c | 40 | ||||
-rw-r--r-- | drivers/mfd/lpc_ich.c | 17 | ||||
-rw-r--r-- | drivers/mfd/max77686.c | 25 | ||||
-rw-r--r-- | drivers/mfd/motorola-cpcap.c | 259 | ||||
-rw-r--r-- | drivers/mfd/mt6397-core.c | 4 | ||||
-rw-r--r-- | drivers/mfd/rk808.c | 4 | ||||
-rw-r--r-- | drivers/mfd/sun6i-prcm.c | 13 | ||||
-rw-r--r-- | drivers/mfd/tps65912-i2c.c | 1 |
17 files changed, 549 insertions, 86 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index d0c14b88b24e..55ecdfb74d31 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -46,6 +46,7 @@ config MFD_SUN4I_GPADC select REGMAP_MMIO select REGMAP_IRQ depends on ARCH_SUNXI || COMPILE_TEST + depends on !TOUCHSCREEN_SUN4I help Select this to get support for Allwinner SoCs (A10, A13 and A31) ADC. This driver will only map the hardware interrupt and registers, you @@ -506,17 +507,22 @@ config MFD_KEMPLD device may provide functions like watchdog, GPIO, UART and I2C bus. The following modules are supported: + * COMe-bBD# * COMe-bBL6 * COMe-bHL6 + * COMe-bSL6 * COMe-bIP# + * COMe-bKL6 * COMe-bPC2 (ETXexpress-PC) * COMe-bSC# (ETXexpress-SC T#) + * COMe-cAL6 * COMe-cBL6 * COMe-cBT6 * COMe-cBW6 * COMe-cCT6 * COMe-cDC2 (microETXexpress-DC) * COMe-cHL6 + * COMe-cKL6 * COMe-cPC2 (microETXexpress-PC) * COMe-cSL6 * COMe-mAL10 @@ -714,6 +720,17 @@ config EZX_PCAP This enables the PCAP ASIC present on EZX Phones. This is needed for MMC, TouchScreen, Sound, USB, etc.. +config MFD_CPCAP + tristate "Support for Motorola CPCAP" + depends on SPI + depends on OF || COMPILE_TEST + select REGMAP_SPI + select REGMAP_IRQ + help + Say yes here if you want to include driver for CPCAP. + It is used on many Motorola phones and tablets as a PMIC. + At least Motorola Droid 4 is known to use CPCAP. + config MFD_VIPERBOARD tristate "Nano River Technologies Viperboard" select MFD_CORE diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 876ca8600c51..31ce07611a6f 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -97,6 +97,7 @@ obj-$(CONFIG_MFD_MC13XXX_I2C) += mc13xxx-i2c.o obj-$(CONFIG_MFD_CORE) += mfd-core.o obj-$(CONFIG_EZX_PCAP) += ezx-pcap.o +obj-$(CONFIG_MFD_CPCAP) += motorola-cpcap.o obj-$(CONFIG_MCP) += mcp-core.o obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 6e00124cef01..8511c068a610 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -656,8 +656,8 @@ static const struct mfd_cell ab8500_devs[] = { .of_compatible = "stericsson,ab8500-regulator", }, { - .name = "abx500-clk", - .of_compatible = "stericsson,abx500-clk", + .name = "ab8500-clk", + .of_compatible = "stericsson,ab8500-clk", }, { .name = "ab8500-gpadc", diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c index 80c0efa66ac1..5b0a0850ef69 100644 --- a/drivers/mfd/ab8500-sysctrl.c +++ b/drivers/mfd/ab8500-sysctrl.c @@ -101,7 +101,7 @@ int ab8500_sysctrl_read(u16 reg, u8 *value) u8 bank; if (sysctrl_dev == NULL) - return -EINVAL; + return -EPROBE_DEFER; bank = (reg >> 8); if (!valid_bank(bank)) @@ -117,11 +117,13 @@ int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value) u8 bank; if (sysctrl_dev == NULL) - return -EINVAL; + return -EPROBE_DEFER; bank = (reg >> 8); - if (!valid_bank(bank)) + if (!valid_bank(bank)) { + pr_err("invalid bank\n"); return -EINVAL; + } return abx500_mask_and_set_register_interruptible(sysctrl_dev, bank, (u8)(reg & 0xFF), mask, value); @@ -148,9 +150,15 @@ static int ab8500_sysctrl_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id ab8500_sysctrl_match[] = { + { .compatible = "stericsson,ab8500-sysctrl", }, + {} +}; + static struct platform_driver ab8500_sysctrl_driver = { .driver = { .name = "ab8500-sysctrl", + .of_match_table = ab8500_sysctrl_match, }, .probe = ab8500_sysctrl_probe, .remove = ab8500_sysctrl_remove, diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c index 2e01975f042d..09cf3699e354 100644 --- a/drivers/mfd/arizona-irq.c +++ b/drivers/mfd/arizona-irq.c @@ -26,6 +26,9 @@ #include "arizona.h" +#define ARIZONA_AOD_IRQ_INDEX 0 +#define ARIZONA_MAIN_IRQ_INDEX 1 + static int arizona_map_irq(struct arizona *arizona, int irq) { int ret; @@ -204,9 +207,10 @@ static const struct irq_domain_ops arizona_domain_ops = { int arizona_irq_init(struct arizona *arizona) { int flags = IRQF_ONESHOT; - int ret, i; + int ret; const struct regmap_irq_chip *aod, *irq; struct irq_data *irq_data; + unsigned int virq; arizona->ctrlif_error = true; @@ -318,24 +322,34 @@ int arizona_irq_init(struct arizona *arizona) } if (aod) { - ret = regmap_add_irq_chip(arizona->regmap, - irq_create_mapping(arizona->virq, 0), - IRQF_ONESHOT, 0, aod, - &arizona->aod_irq_chip); + virq = irq_create_mapping(arizona->virq, ARIZONA_AOD_IRQ_INDEX); + if (!virq) { + dev_err(arizona->dev, "Failed to map AOD IRQs\n"); + ret = -EINVAL; + goto err_domain; + } + + ret = regmap_add_irq_chip(arizona->regmap, virq, IRQF_ONESHOT, + 0, aod, &arizona->aod_irq_chip); if (ret != 0) { dev_err(arizona->dev, "Failed to add AOD IRQs: %d\n", ret); - goto err; + goto err_map_aod; } } - ret = regmap_add_irq_chip(arizona->regmap, - irq_create_mapping(arizona->virq, 1), - IRQF_ONESHOT, 0, irq, - &arizona->irq_chip); + virq = irq_create_mapping(arizona->virq, ARIZONA_MAIN_IRQ_INDEX); + if (!virq) { + dev_err(arizona->dev, "Failed to map main IRQs\n"); + ret = -EINVAL; + goto err_aod; + } + + ret = regmap_add_irq_chip(arizona->regmap, virq, IRQF_ONESHOT, + 0, irq, &arizona->irq_chip); if (ret != 0) { dev_err(arizona->dev, "Failed to add main IRQs: %d\n", ret); - goto err_aod; + goto err_map_main_irq; } /* Used to emulate edge trigger and to work around broken pinmux */ @@ -368,9 +382,8 @@ int arizona_irq_init(struct arizona *arizona) } /* Make sure the boot done IRQ is unmasked for resumes */ - i = arizona_map_irq(arizona, ARIZONA_IRQ_BOOT_DONE); - ret = request_threaded_irq(i, NULL, arizona_boot_done, IRQF_ONESHOT, - "Boot done", arizona); + ret = arizona_request_irq(arizona, ARIZONA_IRQ_BOOT_DONE, "Boot done", + arizona_boot_done, arizona); if (ret != 0) { dev_err(arizona->dev, "Failed to request boot done %d: %d\n", arizona->irq, ret); @@ -379,10 +392,9 @@ int arizona_irq_init(struct arizona *arizona) /* Handle control interface errors in the core */ if (arizona->ctrlif_error) { - i = arizona_map_irq(arizona, ARIZONA_IRQ_CTRLIF_ERR); - ret = request_threaded_irq(i, NULL, arizona_ctrlif_err, - IRQF_ONESHOT, - "Control interface error", arizona); + ret = arizona_request_irq(arizona, ARIZONA_IRQ_CTRLIF_ERR, + "Control interface error", + arizona_ctrlif_err, arizona); if (ret != 0) { dev_err(arizona->dev, "Failed to request CTRLIF_ERR %d: %d\n", @@ -394,29 +406,47 @@ int arizona_irq_init(struct arizona *arizona) return 0; err_ctrlif: - free_irq(arizona_map_irq(arizona, ARIZONA_IRQ_BOOT_DONE), arizona); + arizona_free_irq(arizona, ARIZONA_IRQ_BOOT_DONE, arizona); err_boot_done: free_irq(arizona->irq, arizona); err_main_irq: - regmap_del_irq_chip(irq_find_mapping(arizona->virq, 1), + regmap_del_irq_chip(irq_find_mapping(arizona->virq, + ARIZONA_MAIN_IRQ_INDEX), arizona->irq_chip); +err_map_main_irq: + irq_dispose_mapping(irq_find_mapping(arizona->virq, + ARIZONA_MAIN_IRQ_INDEX)); err_aod: - regmap_del_irq_chip(irq_find_mapping(arizona->virq, 0), + regmap_del_irq_chip(irq_find_mapping(arizona->virq, + ARIZONA_AOD_IRQ_INDEX), arizona->aod_irq_chip); +err_map_aod: + irq_dispose_mapping(irq_find_mapping(arizona->virq, + ARIZONA_AOD_IRQ_INDEX)); +err_domain: + irq_domain_remove(arizona->virq); err: return ret; } int arizona_irq_exit(struct arizona *arizona) { + unsigned int virq; + if (arizona->ctrlif_error) - free_irq(arizona_map_irq(arizona, ARIZONA_IRQ_CTRLIF_ERR), - arizona); - free_irq(arizona_map_irq(arizona, ARIZONA_IRQ_BOOT_DONE), arizona); - regmap_del_irq_chip(irq_find_mapping(arizona->virq, 1), - arizona->irq_chip); - regmap_del_irq_chip(irq_find_mapping(arizona->virq, 0), - arizona->aod_irq_chip); + arizona_free_irq(arizona, ARIZONA_IRQ_CTRLIF_ERR, arizona); + arizona_free_irq(arizona, ARIZONA_IRQ_BOOT_DONE, arizona); + + virq = irq_find_mapping(arizona->virq, ARIZONA_MAIN_IRQ_INDEX); + regmap_del_irq_chip(virq, arizona->irq_chip); + irq_dispose_mapping(virq); + + virq = irq_find_mapping(arizona->virq, ARIZONA_AOD_IRQ_INDEX); + regmap_del_irq_chip(virq, arizona->aod_irq_chip); + irq_dispose_mapping(virq); + + irq_domain_remove(arizona->virq); + free_irq(arizona->irq, arizona); return 0; diff --git a/drivers/mfd/arizona.h b/drivers/mfd/arizona.h index 198e9cea77f9..a0bddc5bd043 100644 --- a/drivers/mfd/arizona.h +++ b/drivers/mfd/arizona.h @@ -17,8 +17,6 @@ #include <linux/regmap.h> #include <linux/pm.h> -struct wm_arizona; - extern const struct regmap_config wm5102_i2c_regmap; extern const struct regmap_config wm5102_spi_regmap; diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c index ed918de84238..25115fe2acdf 100644 --- a/drivers/mfd/axp20x.c +++ b/drivers/mfd/axp20x.c @@ -31,6 +31,8 @@ #define AXP20X_OFF 0x80 +#define AXP806_REG_ADDR_EXT_ADDR_SLAVE_MODE BIT(4) + static const char * const axp20x_model_names[] = { "AXP152", "AXP202", @@ -118,7 +120,14 @@ static const struct regmap_range axp288_writeable_ranges[] = { }; static const struct regmap_range axp288_volatile_ranges[] = { + regmap_reg_range(AXP20X_PWR_INPUT_STATUS, AXP288_POWER_REASON), + regmap_reg_range(AXP288_BC_GLOBAL, AXP288_BC_GLOBAL), + regmap_reg_range(AXP288_BC_DET_STAT, AXP288_BC_DET_STAT), regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IPSOUT_V_HIGH_L), + regmap_reg_range(AXP20X_TIMER_CTRL, AXP20X_TIMER_CTRL), + regmap_reg_range(AXP22X_GPIO_STATE, AXP22X_GPIO_STATE), + regmap_reg_range(AXP288_RT_BATT_V_H, AXP288_RT_BATT_V_L), + regmap_reg_range(AXP20X_FG_RES, AXP288_FG_CC_CAP_REG), }; static const struct regmap_access_table axp288_writeable_table = { @@ -207,14 +216,14 @@ static struct resource axp22x_pek_resources[] = { static struct resource axp288_power_button_resources[] = { { .name = "PEK_DBR", - .start = AXP288_IRQ_POKN, - .end = AXP288_IRQ_POKN, + .start = AXP288_IRQ_POKP, + .end = AXP288_IRQ_POKP, .flags = IORESOURCE_IRQ, }, { .name = "PEK_DBF", - .start = AXP288_IRQ_POKP, - .end = AXP288_IRQ_POKP, + .start = AXP288_IRQ_POKN, + .end = AXP288_IRQ_POKN, .flags = IORESOURCE_IRQ, }, }; @@ -407,6 +416,9 @@ static const struct regmap_irq axp288_regmap_irqs[] = { INIT_REGMAP_IRQ(AXP288, VBUS_FALL, 0, 2), INIT_REGMAP_IRQ(AXP288, VBUS_RISE, 0, 3), INIT_REGMAP_IRQ(AXP288, OV, 0, 4), + INIT_REGMAP_IRQ(AXP288, FALLING_ALT, 0, 5), + INIT_REGMAP_IRQ(AXP288, RISING_ALT, 0, 6), + INIT_REGMAP_IRQ(AXP288, OV_ALT, 0, 7), INIT_REGMAP_IRQ(AXP288, DONE, 1, 2), INIT_REGMAP_IRQ(AXP288, CHARGING, 1, 3), @@ -589,7 +601,22 @@ static struct mfd_cell axp20x_cells[] = { }, }; -static struct mfd_cell axp22x_cells[] = { +static struct mfd_cell axp221_cells[] = { + { + .name = "axp20x-pek", + .num_resources = ARRAY_SIZE(axp22x_pek_resources), + .resources = axp22x_pek_resources, + }, { + .name = "axp20x-regulator", + }, { + .name = "axp20x-usb-power-supply", + .of_compatible = "x-powers,axp221-usb-power-supply", + .num_resources = ARRAY_SIZE(axp22x_usb_power_supply_resources), + .resources = axp22x_usb_power_supply_resources, + }, +}; + +static struct mfd_cell axp223_cells[] = { { .name = "axp20x-pek", .num_resources = ARRAY_SIZE(axp22x_pek_resources), @@ -598,7 +625,7 @@ static struct mfd_cell axp22x_cells[] = { .name = "axp20x-regulator", }, { .name = "axp20x-usb-power-supply", - .of_compatible = "x-powers,axp221-usb-power-supply", + .of_compatible = "x-powers,axp223-usb-power-supply", .num_resources = ARRAY_SIZE(axp22x_usb_power_supply_resources), .resources = axp22x_usb_power_supply_resources, }, @@ -791,9 +818,14 @@ int axp20x_match_device(struct axp20x_dev *axp20x) axp20x->regmap_irq_chip = &axp20x_regmap_irq_chip; break; case AXP221_ID: + axp20x->nr_cells = ARRAY_SIZE(axp221_cells); + axp20x->cells = axp221_cells; + axp20x->regmap_cfg = &axp22x_regmap_config; + axp20x->regmap_irq_chip = &axp22x_regmap_irq_chip; + break; case AXP223_ID: - axp20x->nr_cells = ARRAY_SIZE(axp22x_cells); - axp20x->cells = axp22x_cells; + axp20x->nr_cells = ARRAY_SIZE(axp223_cells); + axp20x->cells = axp223_cells; axp20x->regmap_cfg = &axp22x_regmap_config; axp20x->regmap_irq_chip = &axp22x_regmap_irq_chip; break; @@ -802,6 +834,7 @@ int axp20x_match_device(struct axp20x_dev *axp20x) axp20x->nr_cells = ARRAY_SIZE(axp288_cells); axp20x->regmap_cfg = &axp288_regmap_config; axp20x->regmap_irq_chip = &axp288_regmap_irq_chip; + axp20x->irq_flags = IRQF_TRIGGER_LOW; break; case AXP806_ID: axp20x->nr_cells = ARRAY_SIZE(axp806_cells); @@ -830,10 +863,33 @@ int axp20x_device_probe(struct axp20x_dev *axp20x) { int ret; + /* + * The AXP806 supports either master/standalone or slave mode. + * Slave mode allows sharing the serial bus, even with multiple + * AXP806 which all have the same hardware address. + * + * This is done with extra "serial interface address extension", + * or AXP806_BUS_ADDR_EXT, and "register address extension", or + * AXP806_REG_ADDR_EXT, registers. The former is read-only, with + * 1 bit customizable at the factory, and 1 bit depending on the + * state of an external pin. The latter is writable. The device + * will only respond to operations to its other registers when + * the these device addressing bits (in the upper 4 bits of the + * registers) match. + * + * Since we only support an AXP806 chained to an AXP809 in slave + * mode, and there isn't any existing hardware which uses AXP806 + * in master mode, or has 2 AXP806s in the same system, we can + * just program the register address extension to the slave mode + * address. + */ + if (axp20x->variant == AXP806_ID) + regmap_write(axp20x->regmap, AXP806_REG_ADDR_EXT, + AXP806_REG_ADDR_EXT_ADDR_SLAVE_MODE); + ret = regmap_add_irq_chip(axp20x->regmap, axp20x->irq, - IRQF_ONESHOT | IRQF_SHARED, -1, - axp20x->regmap_irq_chip, - &axp20x->regmap_irqc); + IRQF_ONESHOT | IRQF_SHARED | axp20x->irq_flags, + -1, axp20x->regmap_irq_chip, &axp20x->regmap_irqc); if (ret) { dev_err(axp20x->dev, "failed to add irq chip: %d\n", ret); return ret; diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c index abd83424b498..9b66a98ba4bf 100644 --- a/drivers/mfd/cros_ec.c +++ b/drivers/mfd/cros_ec.c @@ -23,6 +23,7 @@ #include <linux/module.h> #include <linux/mfd/core.h> #include <linux/mfd/cros_ec.h> +#include <linux/suspend.h> #include <asm/unaligned.h> #define CROS_EC_DEV_EC_INDEX 0 @@ -65,6 +66,24 @@ static irqreturn_t ec_irq_thread(int irq, void *data) return IRQ_HANDLED; } +static int cros_ec_sleep_event(struct cros_ec_device *ec_dev, u8 sleep_event) +{ + struct { + struct cros_ec_command msg; + struct ec_params_host_sleep_event req; + } __packed buf; + + memset(&buf, 0, sizeof(buf)); + + buf.req.sleep_event = sleep_event; + + buf.msg.command = EC_CMD_HOST_SLEEP_EVENT; + buf.msg.version = 0; + buf.msg.outsize = sizeof(buf.req); + + return cros_ec_cmd_xfer(ec_dev, &buf.msg); +} + int cros_ec_register(struct cros_ec_device *ec_dev) { struct device *dev = ec_dev->dev; @@ -136,6 +155,15 @@ int cros_ec_register(struct cros_ec_device *ec_dev) } } + /* + * Clear sleep event - this will fail harmlessly on platforms that + * don't implement the sleep event host command. + */ + err = cros_ec_sleep_event(ec_dev, 0); + if (err < 0) + dev_dbg(ec_dev->dev, "Error %d clearing sleep event to ec", + err); + dev_info(dev, "Chrome EC device registered\n"); return 0; @@ -159,12 +187,24 @@ EXPORT_SYMBOL(cros_ec_remove); int cros_ec_suspend(struct cros_ec_device *ec_dev) { struct device *dev = ec_dev->dev; + int ret; + u8 sleep_event; + + sleep_event = (!IS_ENABLED(CONFIG_ACPI) || pm_suspend_via_firmware()) ? + HOST_SLEEP_EVENT_S3_RESUME : + HOST_SLEEP_EVENT_S0IX_RESUME; + + ret = cros_ec_sleep_event(ec_dev, sleep_event); + if (ret < 0) + dev_dbg(ec_dev->dev, "Error %d sending suspend event to ec", + ret); if (device_may_wakeup(dev)) ec_dev->wake_enabled = !enable_irq_wake(ec_dev->irq); disable_irq(ec_dev->irq); ec_dev->was_wake_device = ec_dev->wake_enabled; + ec_dev->suspended = true; return 0; } @@ -179,8 +219,21 @@ static void cros_ec_drain_events(struct cros_ec_device *ec_dev) int cros_ec_resume(struct cros_ec_device *ec_dev) { + int ret; + u8 sleep_event; + + ec_dev->suspended = false; enable_irq(ec_dev->irq); + sleep_event = (!IS_ENABLED(CONFIG_ACPI) || pm_suspend_via_firmware()) ? + HOST_SLEEP_EVENT_S3_RESUME : + HOST_SLEEP_EVENT_S0IX_RESUME; + + ret = cros_ec_sleep_event(ec_dev, sleep_event); + if (ret < 0) + dev_dbg(ec_dev->dev, "Error %d sending resume event to ec", + ret); + /* * In some cases, we need to distinguish between events that occur * during suspend if the EC is not a wake source. For example, diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c index 78dbcf8b0bef..16ffeaeb1385 100644 --- a/drivers/mfd/intel-lpss-pci.c +++ b/drivers/mfd/intel-lpss-pci.c @@ -157,7 +157,22 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x1ac4), (kernel_ulong_t)&bxt_info }, { PCI_VDEVICE(INTEL, 0x1ac6), (kernel_ulong_t)&bxt_info }, { PCI_VDEVICE(INTEL, 0x1aee), (kernel_ulong_t)&bxt_uart_info }, - + /* GLK */ + { PCI_VDEVICE(INTEL, 0x31ac), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x31ae), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x31b0), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x31b2), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x31b4), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x31b6), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x31b8), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x31ba), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x31bc), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0x31be), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0x31c0), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0x31ee), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0x31c2), (kernel_ulong_t)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x31c4), (kernel_ulong_t)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x31c6), (kernel_ulong_t)&bxt_info }, /* APL */ { PCI_VDEVICE(INTEL, 0x5aac), (kernel_ulong_t)&apl_i2c_info }, { PCI_VDEVICE(INTEL, 0x5aae), (kernel_ulong_t)&apl_i2c_info }, diff --git a/drivers/mfd/kempld-core.c b/drivers/mfd/kempld-core.c index da5722d7c540..895f655780a7 100644 --- a/drivers/mfd/kempld-core.c +++ b/drivers/mfd/kempld-core.c @@ -496,6 +496,14 @@ static struct platform_driver kempld_driver = { static struct dmi_system_id kempld_dmi_table[] __initdata = { { + .ident = "BBD6", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), + DMI_MATCH(DMI_BOARD_NAME, "COMe-bBD"), + }, + .driver_data = (void *)&kempld_platform_data_generic, + .callback = kempld_create_platform_device, + }, { .ident = "BBL6", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), @@ -512,6 +520,30 @@ static struct dmi_system_id kempld_dmi_table[] __initdata = { .driver_data = (void *)&kempld_platform_data_generic, .callback = kempld_create_platform_device, }, { + .ident = "BKL6", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), + DMI_MATCH(DMI_BOARD_NAME, "COMe-bKL6"), + }, + .driver_data = (void *)&kempld_platform_data_generic, + .callback = kempld_create_platform_device, + }, { + .ident = "BSL6", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), + DMI_MATCH(DMI_BOARD_NAME, "COMe-bSL6"), + }, + .driver_data = (void *)&kempld_platform_data_generic, + .callback = kempld_create_platform_device, + }, { + .ident = "CAL6", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), + DMI_MATCH(DMI_BOARD_NAME, "COMe-cAL"), + }, + .driver_data = (void *)&kempld_platform_data_generic, + .callback = kempld_create_platform_device, + }, { .ident = "CBL6", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), @@ -600,6 +632,14 @@ static struct dmi_system_id kempld_dmi_table[] __initdata = { .driver_data = (void *)&kempld_platform_data_generic, .callback = kempld_create_platform_device, }, { + .ident = "CKL6", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), + DMI_MATCH(DMI_BOARD_NAME, "COMe-cKL6"), + }, + .driver_data = (void *)&kempld_platform_data_generic, + .callback = kempld_create_platform_device, + }, { .ident = "CNTG", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index be42957a78e1..d98a5d974092 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c @@ -20,10 +20,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * * This driver supports the following I/O Controller hubs: * (See the intel documentation on http://developer.intel.com.) * document number 290655-003, 290677-014: 82801AA (ICH), 82801AB (ICHO) @@ -45,18 +41,6 @@ * document number 322169-001, 322170-003: 5 Series, 3400 Series (PCH) * document number 320066-003, 320257-008: EP80597 (IICH) * document number 324645-001, 324646-001: Cougar Point (CPT) - * document number TBD : Patsburg (PBG) - * document number TBD : DH89xxCC - * document number TBD : Panther Point - * document number TBD : Lynx Point - * document number TBD : Lynx Point-LP - * document number TBD : Wellsburg - * document number TBD : Avoton SoC - * document number TBD : Coleto Creek - * document number TBD : Wildcat Point-LP - * document number TBD : 9 Series - * document number TBD : Lewisburg - * document number TBD : Apollo Lake SoC */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -567,6 +551,7 @@ static struct lpc_ich_info lpc_chipset_info[] = { }, [LPC_APL] = { .name = "Apollo Lake SoC", + .iTCO_version = 5, .spi_type = INTEL_SPI_BXT, }, }; diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c index 7b68ed72e9cb..b0e8e13c0049 100644 --- a/drivers/mfd/max77686.c +++ b/drivers/mfd/max77686.c @@ -34,6 +34,7 @@ #include <linux/mfd/max77686-private.h> #include <linux/err.h> #include <linux/of.h> +#include <linux/of_device.h> static const struct mfd_cell max77686_devs[] = { { .name = "max77686-pmic", }, @@ -171,11 +172,9 @@ static const struct of_device_id max77686_pmic_dt_match[] = { }; MODULE_DEVICE_TABLE(of, max77686_pmic_dt_match); -static int max77686_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int max77686_i2c_probe(struct i2c_client *i2c) { struct max77686_dev *max77686 = NULL; - const struct of_device_id *match; unsigned int data; int ret = 0; const struct regmap_config *config; @@ -188,16 +187,8 @@ static int max77686_i2c_probe(struct i2c_client *i2c, if (!max77686) return -ENOMEM; - if (i2c->dev.of_node) { - match = of_match_node(max77686_pmic_dt_match, i2c->dev.of_node); - if (!match) - return -EINVAL; - - max77686->type = (unsigned long)match->data; - } else - max77686->type = id->driver_data; - i2c_set_clientdata(i2c, max77686); + max77686->type = (unsigned long)of_device_get_match_data(&i2c->dev); max77686->dev = &i2c->dev; max77686->i2c = i2c; @@ -250,13 +241,6 @@ static int max77686_i2c_probe(struct i2c_client *i2c, return 0; } -static const struct i2c_device_id max77686_i2c_id[] = { - { "max77686", TYPE_MAX77686 }, - { "max77802", TYPE_MAX77802 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, max77686_i2c_id); - #ifdef CONFIG_PM_SLEEP static int max77686_suspend(struct device *dev) { @@ -302,8 +286,7 @@ static struct i2c_driver max77686_i2c_driver = { .pm = &max77686_pm, .of_match_table = of_match_ptr(max77686_pmic_dt_match), }, - .probe = max77686_i2c_probe, - .id_table = max77686_i2c_id, + .probe_new = max77686_i2c_probe, }; module_i2c_driver(max77686_i2c_driver); diff --git a/drivers/mfd/motorola-cpcap.c b/drivers/mfd/motorola-cpcap.c new file mode 100644 index 000000000000..6aeada7d7ce5 --- /dev/null +++ b/drivers/mfd/motorola-cpcap.c @@ -0,0 +1,259 @@ +/* + * Motorola CPCAP PMIC core driver + * + * Copyright (C) 2016 Tony Lindgren <tony@atomide.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/device.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/regmap.h> +#include <linux/sysfs.h> + +#include <linux/mfd/motorola-cpcap.h> +#include <linux/spi/spi.h> + +#define CPCAP_NR_IRQ_REG_BANKS 6 +#define CPCAP_NR_IRQ_CHIPS 3 + +struct cpcap_ddata { + struct spi_device *spi; + struct regmap_irq *irqs; + struct regmap_irq_chip_data *irqdata[CPCAP_NR_IRQ_CHIPS]; + const struct regmap_config *regmap_conf; + struct regmap *regmap; +}; + +static int cpcap_check_revision(struct cpcap_ddata *cpcap) +{ + u16 vendor, rev; + int ret; + + ret = cpcap_get_vendor(&cpcap->spi->dev, cpcap->regmap, &vendor); + if (ret) + return ret; + + ret = cpcap_get_revision(&cpcap->spi->dev, cpcap->regmap, &rev); + if (ret) + return ret; + + dev_info(&cpcap->spi->dev, "CPCAP vendor: %s rev: %i.%i (%x)\n", + vendor == CPCAP_VENDOR_ST ? "ST" : "TI", + CPCAP_REVISION_MAJOR(rev), CPCAP_REVISION_MINOR(rev), + rev); + + if (rev < CPCAP_REVISION_2_1) { + dev_info(&cpcap->spi->dev, + "Please add old CPCAP revision support as needed\n"); + return -ENODEV; + } + + return 0; +} + +/* + * First two irq chips are the two private macro interrupt chips, the third + * irq chip is for register banks 1 - 4 and is available for drivers to use. + */ +static struct regmap_irq_chip cpcap_irq_chip[CPCAP_NR_IRQ_CHIPS] = { + { + .name = "cpcap-m2", + .num_regs = 1, + .status_base = CPCAP_REG_MI1, + .ack_base = CPCAP_REG_MI1, + .mask_base = CPCAP_REG_MIM1, + .use_ack = true, + }, + { + .name = "cpcap-m2", + .num_regs = 1, + .status_base = CPCAP_REG_MI2, + .ack_base = CPCAP_REG_MI2, + .mask_base = CPCAP_REG_MIM2, + .use_ack = true, + }, + { + .name = "cpcap1-4", + .num_regs = 4, + .status_base = CPCAP_REG_INT1, + .ack_base = CPCAP_REG_INT1, + .mask_base = CPCAP_REG_INTM1, + .type_base = CPCAP_REG_INTS1, + .use_ack = true, + }, +}; + +static void cpcap_init_one_regmap_irq(struct cpcap_ddata *cpcap, + struct regmap_irq *rirq, + int irq_base, int irq) +{ + unsigned int reg_offset; + unsigned int bit, mask; + + reg_offset = irq - irq_base; + reg_offset /= cpcap->regmap_conf->val_bits; + reg_offset *= cpcap->regmap_conf->reg_stride; + + bit = irq % cpcap->regmap_conf->val_bits; + mask = (1 << bit); + + rirq->reg_offset = reg_offset; + rirq->mask = mask; +} + +static int cpcap_init_irq_chip(struct cpcap_ddata *cpcap, int irq_chip, + int irq_start, int nr_irqs) +{ + struct regmap_irq_chip *chip = &cpcap_irq_chip[irq_chip]; + int i, ret; + + for (i = irq_start; i < irq_start + nr_irqs; i++) { + struct regmap_irq *rirq = &cpcap->irqs[i]; + + cpcap_init_one_regmap_irq(cpcap, rirq, irq_start, i); + } + chip->irqs = &cpcap->irqs[irq_start]; + chip->num_irqs = nr_irqs; + chip->irq_drv_data = cpcap; + + ret = devm_regmap_add_irq_chip(&cpcap->spi->dev, cpcap->regmap, + cpcap->spi->irq, + IRQF_TRIGGER_RISING | + IRQF_SHARED, -1, + chip, &cpcap->irqdata[irq_chip]); + if (ret) { + dev_err(&cpcap->spi->dev, "could not add irq chip %i: %i\n", + irq_chip, ret); + return ret; + } + + return 0; +} + +static int cpcap_init_irq(struct cpcap_ddata *cpcap) +{ + int ret; + + cpcap->irqs = devm_kzalloc(&cpcap->spi->dev, + sizeof(*cpcap->irqs) * + CPCAP_NR_IRQ_REG_BANKS * + cpcap->regmap_conf->val_bits, + GFP_KERNEL); + if (!cpcap->irqs) + return -ENOMEM; + + ret = cpcap_init_irq_chip(cpcap, 0, 0, 16); + if (ret) + return ret; + + ret = cpcap_init_irq_chip(cpcap, 1, 16, 16); + if (ret) + return ret; + + ret = cpcap_init_irq_chip(cpcap, 2, 32, 64); + if (ret) + return ret; + + enable_irq_wake(cpcap->spi->irq); + + return 0; +} + +static const struct of_device_id cpcap_of_match[] = { + { .compatible = "motorola,cpcap", }, + { .compatible = "st,6556002", }, + {}, +}; +MODULE_DEVICE_TABLE(of, cpcap_of_match); + +static const struct regmap_config cpcap_regmap_config = { + .reg_bits = 16, + .reg_stride = 4, + .pad_bits = 0, + .val_bits = 16, + .write_flag_mask = 0x8000, + .max_register = CPCAP_REG_ST_TEST2, + .cache_type = REGCACHE_NONE, + .reg_format_endian = REGMAP_ENDIAN_LITTLE, + .val_format_endian = REGMAP_ENDIAN_LITTLE, +}; + +static int cpcap_probe(struct spi_device *spi) +{ + const struct of_device_id *match; + struct cpcap_ddata *cpcap; + int ret; + + match = of_match_device(of_match_ptr(cpcap_of_match), &spi->dev); + if (!match) + return -ENODEV; + + cpcap = devm_kzalloc(&spi->dev, sizeof(*cpcap), GFP_KERNEL); + if (!cpcap) + return -ENOMEM; + + cpcap->spi = spi; + spi_set_drvdata(spi, cpcap); + + spi->bits_per_word = 16; + spi->mode = SPI_MODE_0 | SPI_CS_HIGH; + + ret = spi_setup(spi); + if (ret) + return ret; + + cpcap->regmap_conf = &cpcap_regmap_config; + cpcap->regmap = devm_regmap_init_spi(spi, &cpcap_regmap_config); + if (IS_ERR(cpcap->regmap)) { + ret = PTR_ERR(cpcap->regmap); + dev_err(&cpcap->spi->dev, "Failed to initialize regmap: %d\n", + ret); + + return ret; + } + + ret = cpcap_check_revision(cpcap); + if (ret) { + dev_err(&cpcap->spi->dev, "Failed to detect CPCAP: %i\n", ret); + return ret; + } + + ret = cpcap_init_irq(cpcap); + if (ret) + return ret; + + return of_platform_populate(spi->dev.of_node, NULL, NULL, + &cpcap->spi->dev); +} + +static int cpcap_remove(struct spi_device *pdev) +{ + struct cpcap_ddata *cpcap = spi_get_drvdata(pdev); + + of_platform_depopulate(&cpcap->spi->dev); + + return 0; +} + +static struct spi_driver cpcap_driver = { + .driver = { + .name = "cpcap-core", + .of_match_table = cpcap_of_match, + }, + .probe = cpcap_probe, + .remove = cpcap_remove, +}; +module_spi_driver(cpcap_driver); + +MODULE_ALIAS("platform:cpcap"); +MODULE_DESCRIPTION("CPCAP driver"); +MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c index e14d8b058f0c..8e601c846d08 100644 --- a/drivers/mfd/mt6397-core.c +++ b/drivers/mfd/mt6397-core.c @@ -48,6 +48,10 @@ static const struct mfd_cell mt6323_devs[] = { .name = "mt6323-regulator", .of_compatible = "mediatek,mt6323-regulator" }, + { + .name = "mt6323-led", + .of_compatible = "mediatek,mt6323-led" + }, }; static const struct mfd_cell mt6397_devs[] = { diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c index 2c9acdba7c2d..fd087cbb0bde 100644 --- a/drivers/mfd/rk808.c +++ b/drivers/mfd/rk808.c @@ -247,7 +247,7 @@ static const struct regmap_irq rk818_irqs[] = { }, }; -static struct regmap_irq_chip rk808_irq_chip = { +static const struct regmap_irq_chip rk808_irq_chip = { .name = "rk808", .irqs = rk808_irqs, .num_irqs = ARRAY_SIZE(rk808_irqs), @@ -259,7 +259,7 @@ static struct regmap_irq_chip rk808_irq_chip = { .init_ack_masked = true, }; -static struct regmap_irq_chip rk818_irq_chip = { +static const struct regmap_irq_chip rk818_irq_chip = { .name = "rk818", .irqs = rk818_irqs, .num_irqs = ARRAY_SIZE(rk818_irqs), diff --git a/drivers/mfd/sun6i-prcm.c b/drivers/mfd/sun6i-prcm.c index 011fcc555945..2b658bed47db 100644 --- a/drivers/mfd/sun6i-prcm.c +++ b/drivers/mfd/sun6i-prcm.c @@ -12,6 +12,9 @@ #include <linux/init.h> #include <linux/of.h> +#define SUN8I_CODEC_ANALOG_BASE 0x1c0 +#define SUN8I_CODEC_ANALOG_SIZE 0x4 + struct prcm_data { int nsubdevs; const struct mfd_cell *subdevs; @@ -57,6 +60,10 @@ static const struct resource sun6i_a31_apb0_rstc_res[] = { }, }; +static const struct resource sun8i_codec_analog_res[] = { + DEFINE_RES_MEM(SUN8I_CODEC_ANALOG_BASE, SUN8I_CODEC_ANALOG_SIZE), +}; + static const struct mfd_cell sun6i_a31_prcm_subdevs[] = { { .name = "sun6i-a31-ar100-clk", @@ -109,6 +116,12 @@ static const struct mfd_cell sun8i_a23_prcm_subdevs[] = { .num_resources = ARRAY_SIZE(sun6i_a31_apb0_rstc_res), .resources = sun6i_a31_apb0_rstc_res, }, + { + .name = "sun8i-codec-analog", + .of_compatible = "allwinner,sun8i-a23-codec-analog", + .num_resources = ARRAY_SIZE(sun8i_codec_analog_res), + .resources = sun8i_codec_analog_res, + }, }; static const struct prcm_data sun6i_a31_prcm_data = { diff --git a/drivers/mfd/tps65912-i2c.c b/drivers/mfd/tps65912-i2c.c index 45871403f995..785d19f6f7c9 100644 --- a/drivers/mfd/tps65912-i2c.c +++ b/drivers/mfd/tps65912-i2c.c @@ -27,6 +27,7 @@ static const struct of_device_id tps65912_i2c_of_match_table[] = { { .compatible = "ti,tps65912", }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, tps65912_i2c_of_match_table); static int tps65912_i2c_probe(struct i2c_client *client, const struct i2c_device_id *ids) |