diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2021-09-07 12:38:59 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2021-09-07 12:38:59 -0700 |
commit | 86406a9e733347f877a2bd5269ce7429d3748c6a (patch) | |
tree | 41b71d751d12d9ee61bddd461e0a9e255dad0f21 /drivers/mfd | |
parent | 5e6a5845dd651b00754a62edec2f0a439182024d (diff) | |
parent | cdff1eda69326fb46de10c5454212b3efcf4bb41 (diff) |
Merge tag 'mfd-next-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd
Pull MFD updates from Lee Jones:
"Core Frameworks:
- Add support for registering devices via MFD cells to Simple MFD (I2C)
New Drivers:
- Add support for Renesas Synchronization Management Unit (SMU)
New Device Support:
- Add support for N5010 to Intel M10 BMC
- Add support for Cannon Lake to Intel LPSS ACPI
- Add support for Samsung SSG{1,2} to ST-Ericsson's U8500 family
- Add support for TQMx110EB and TQMxE40x to TQ-Systems PLD TQMx86
New Functionality:
- Add support for GPIO to Intel LPC ICH
- Add support for Reset to Texas Instruments TPS65086
Fix-ups:
- Trivial, sorting, whitespace, renaming, etc; mt6360-core, db8500-prcmu-regs, tqmx86
- Device Tree fiddling; syscon, axp20x, qcom,pm8008, ti,tps65086, brcm,cru
- Use proper APIs for IRQ map resolution; ab8500-core, stmpe, tc3589x, wm8994-irq
- Pass 'supplied-from' property through axp288_fuel_gauge via swnode
- Remove unused file entry; MAINTAINERS
- Make interrupt line optional; tps65086
- Rename db8500-cpuidle driver symbol; db8500-prcmu
- Remove support for unused hardware; tqmx86
- Provide a standard LPC clock frequency for unknown boards; tqmx86
- Remove unused code; ti_am335x_tscadc
- Use of_iomap() instead of ioremap(); syscon
Bug Fixes:
- Clear GPIO IRQ resource flags when no IRQ is set; tqmx86
- Fix incorrect/misleading frequencies; db8500-prcmu
- Mitigate namespace clash with other GPIOBASE users"
* tag 'mfd-next-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (31 commits)
mfd: lpc_sch: Rename GPIOBASE to prevent build error
mfd: syscon: Use of_iomap() instead of ioremap()
dt-bindings: mfd: Add Broadcom CRU
mfd: ti_am335x_tscadc: Delete superfluous error message
mfd: tqmx86: Assume 24MHz LPC clock for unknown boards
mfd: tqmx86: Add support for TQ-Systems DMI IDs
mfd: tqmx86: Add support for TQMx110EB and TQMxE40x
mfd: tqmx86: Fix typo in "platform"
mfd: tqmx86: Remove incorrect TQMx90UC board ID
mfd: tqmx86: Clear GPIO IRQ resource when no IRQ is set
mfd: simple-mfd-i2c: Add support for registering devices via MFD cells
mfd/cpuidle: ux500: Rename driver symbol
mfd: tps65086: Add cell entry for reset driver
mfd: tps65086: Make interrupt line optional
dt-bindings: mfd: Convert tps65086.txt to YAML
MAINTAINERS: Adjust ARM/NOMADIK/Ux500 ARCHITECTURES to file renaming
mfd: db8500-prcmu: Handle missing FW variant
mfd: db8500-prcmu: Rename register header
mfd: axp20x: Add supplied-from property to axp288_fuel_gauge cell
mfd: Don't use irq_create_mapping() to resolve a mapping
...
Diffstat (limited to 'drivers/mfd')
-rw-r--r-- | drivers/mfd/Kconfig | 28 | ||||
-rw-r--r-- | drivers/mfd/Makefile | 5 | ||||
-rw-r--r-- | drivers/mfd/ab8500-core.c | 2 | ||||
-rw-r--r-- | drivers/mfd/axp20x.c | 16 | ||||
-rw-r--r-- | drivers/mfd/db8500-prcmu-regs.h (renamed from drivers/mfd/dbx500-prcmu-regs.h) | 0 | ||||
-rw-r--r-- | drivers/mfd/db8500-prcmu.c | 25 | ||||
-rw-r--r-- | drivers/mfd/intel-lpss-acpi.c | 18 | ||||
-rw-r--r-- | drivers/mfd/intel-m10-bmc.c | 12 | ||||
-rw-r--r-- | drivers/mfd/lpc_ich.c | 1 | ||||
-rw-r--r-- | drivers/mfd/lpc_sch.c | 4 | ||||
-rw-r--r-- | drivers/mfd/mt6360-core.c | 8 | ||||
-rw-r--r-- | drivers/mfd/rsmu.h | 16 | ||||
-rw-r--r-- | drivers/mfd/rsmu_core.c | 88 | ||||
-rw-r--r-- | drivers/mfd/rsmu_i2c.c | 203 | ||||
-rw-r--r-- | drivers/mfd/rsmu_spi.c | 273 | ||||
-rw-r--r-- | drivers/mfd/simple-mfd-i2c.c | 41 | ||||
-rw-r--r-- | drivers/mfd/simple-mfd-i2c.h | 32 | ||||
-rw-r--r-- | drivers/mfd/stmpe.c | 4 | ||||
-rw-r--r-- | drivers/mfd/syscon.c | 2 | ||||
-rw-r--r-- | drivers/mfd/tc3589x.c | 2 | ||||
-rw-r--r-- | drivers/mfd/ti_am335x_tscadc.c | 5 | ||||
-rw-r--r-- | drivers/mfd/tps65086.c | 22 | ||||
-rw-r--r-- | drivers/mfd/tqmx86.c | 48 | ||||
-rw-r--r-- | drivers/mfd/wm8994-irq.c | 2 |
24 files changed, 799 insertions, 58 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 01bb42f0ca0b..ca0edab91aeb 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -2199,5 +2199,33 @@ config MFD_INTEL_M10_BMC additional drivers must be enabled in order to use the functionality of the device. +config MFD_RSMU_I2C + tristate "Renesas Synchronization Management Unit with I2C" + depends on I2C && OF + select MFD_CORE + select REGMAP_I2C + help + Support for the Renesas Synchronization Management Unit, such as + Clockmatrix and 82P33XXX series. This option supports I2C as + the control interface. + + This driver provides common support for accessing the device. + Additional drivers must be enabled in order to use the functionality + of the device. + +config MFD_RSMU_SPI + tristate "Renesas Synchronization Management Unit with SPI" + depends on SPI && OF + select MFD_CORE + select REGMAP_SPI + help + Support for the Renesas Synchronization Management Unit, such as + Clockmatrix and 82P33XXX series. This option supports SPI as + the control interface. + + This driver provides common support for accessing the device. + Additional drivers must be enabled in order to use the functionality + of the device. + endmenu endif diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 570b9ffb34d0..2ba6646e874c 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -273,3 +273,8 @@ obj-$(CONFIG_MFD_INTEL_M10_BMC) += intel-m10-bmc.o obj-$(CONFIG_MFD_ATC260X) += atc260x-core.o obj-$(CONFIG_MFD_ATC260X_I2C) += atc260x-i2c.o + +rsmu-i2c-objs := rsmu_core.o rsmu_i2c.o +rsmu-spi-objs := rsmu_core.o rsmu_spi.o +obj-$(CONFIG_MFD_RSMU_I2C) += rsmu-i2c.o +obj-$(CONFIG_MFD_RSMU_SPI) += rsmu-spi.o diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 30489670ea52..cca0aac26148 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -485,7 +485,7 @@ static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500, if (line == AB8540_INT_GPIO43F || line == AB8540_INT_GPIO44F) line += 1; - handle_nested_irq(irq_create_mapping(ab8500->domain, line)); + handle_nested_irq(irq_find_mapping(ab8500->domain, line)); } return 0; diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c index 4145a38b3890..8161a5dc68e8 100644 --- a/drivers/mfd/axp20x.c +++ b/drivers/mfd/axp20x.c @@ -125,12 +125,13 @@ 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(AXP22X_PWR_OUT_CTRL1, AXP22X_ALDO3_V_OUT), regmap_reg_range(AXP288_BC_GLOBAL, AXP288_BC_GLOBAL), regmap_reg_range(AXP288_BC_DET_STAT, AXP20X_VBUS_IPSOUT_MGMT), regmap_reg_range(AXP20X_CHRG_BAK_CTRL, AXP20X_CHRG_BAK_CTRL), 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(AXP20X_GPIO1_CTRL, 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), }; @@ -699,6 +700,18 @@ static const struct resource axp288_charger_resources[] = { DEFINE_RES_IRQ(AXP288_IRQ_CBTO), }; +static const char * const axp288_fuel_gauge_suppliers[] = { "axp288_charger" }; + +static const struct property_entry axp288_fuel_gauge_properties[] = { + PROPERTY_ENTRY_STRING_ARRAY("supplied-from", axp288_fuel_gauge_suppliers), + { } +}; + +static const struct software_node axp288_fuel_gauge_sw_node = { + .name = "axp288_fuel_gauge", + .properties = axp288_fuel_gauge_properties, +}; + static const struct mfd_cell axp288_cells[] = { { .name = "axp288_adc", @@ -716,6 +729,7 @@ static const struct mfd_cell axp288_cells[] = { .name = "axp288_fuel_gauge", .num_resources = ARRAY_SIZE(axp288_fuel_gauge_resources), .resources = axp288_fuel_gauge_resources, + .swnode = &axp288_fuel_gauge_sw_node, }, { .name = "axp221-pek", .num_resources = ARRAY_SIZE(axp288_power_button_resources), diff --git a/drivers/mfd/dbx500-prcmu-regs.h b/drivers/mfd/db8500-prcmu-regs.h index 75fd1069372c..75fd1069372c 100644 --- a/drivers/mfd/dbx500-prcmu-regs.h +++ b/drivers/mfd/db8500-prcmu-regs.h diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c index 287da20f1231..c1d3e7c116cf 100644 --- a/drivers/mfd/db8500-prcmu.c +++ b/drivers/mfd/db8500-prcmu.c @@ -37,7 +37,7 @@ #include <linux/regulator/db8500-prcmu.h> #include <linux/regulator/machine.h> #include <linux/platform_data/ux500_wdt.h> -#include "dbx500-prcmu-regs.h" +#include "db8500-prcmu-regs.h" /* Index of different voltages to be used when accessing AVSData */ #define PRCM_AVS_BASE 0x2FC @@ -1622,22 +1622,20 @@ static long round_clock_rate(u8 clock, unsigned long rate) } static const unsigned long db8500_armss_freqs[] = { - 200000000, - 400000000, - 800000000, + 199680000, + 399360000, + 798720000, 998400000 }; /* The DB8520 has slightly higher ARMSS max frequency */ static const unsigned long db8520_armss_freqs[] = { - 200000000, - 400000000, - 800000000, + 199680000, + 399360000, + 798720000, 1152000000 }; - - static long round_armss_rate(unsigned long rate) { unsigned long freq = 0; @@ -2567,14 +2565,16 @@ static char *fw_project_name(u32 project) return "U8500 C4"; case PRCMU_FW_PROJECT_U9500_MBL: return "U9500 MBL"; - case PRCMU_FW_PROJECT_U8500_MBL: - return "U8500 MBL"; + case PRCMU_FW_PROJECT_U8500_SSG1: + return "U8500 Samsung 1"; case PRCMU_FW_PROJECT_U8500_MBL2: return "U8500 MBL2"; case PRCMU_FW_PROJECT_U8520: return "U8520 MBL"; case PRCMU_FW_PROJECT_U8420: return "U8420"; + case PRCMU_FW_PROJECT_U8500_SSG2: + return "U8500 Samsung 2"; case PRCMU_FW_PROJECT_U8420_SYSCLK: return "U8420-sysclk"; case PRCMU_FW_PROJECT_U9540: @@ -2951,14 +2951,13 @@ static const struct mfd_cell common_prcmu_devs[] = { .pdata_size = sizeof(db8500_wdt_pdata), .id = -1, }, + MFD_CELL_NAME("db8500-cpuidle"), }; static const struct mfd_cell db8500_prcmu_devs[] = { MFD_CELL_OF("db8500-prcmu-regulators", NULL, &db8500_regulators, sizeof(db8500_regulators), 0, "stericsson,db8500-prcmu-regulator"), - MFD_CELL_OF("cpuidle-dbx500", - NULL, NULL, 0, 0, "stericsson,cpuidle-dbx500"), MFD_CELL_OF("db8500-thermal", NULL, NULL, 0, 0, "stericsson,db8500-thermal"), }; diff --git a/drivers/mfd/intel-lpss-acpi.c b/drivers/mfd/intel-lpss-acpi.c index 1f396039d58f..3f1d976eb67c 100644 --- a/drivers/mfd/intel-lpss-acpi.c +++ b/drivers/mfd/intel-lpss-acpi.c @@ -89,6 +89,11 @@ static const struct intel_lpss_platform_info apl_i2c_info = { .swnode = &apl_i2c_node, }; +static const struct intel_lpss_platform_info cnl_i2c_info = { + .clk_rate = 216000000, + .swnode = &spt_i2c_node, +}; + static const struct acpi_device_id intel_lpss_acpi_ids[] = { /* SPT */ { "INT3440", (kernel_ulong_t)&spt_info }, @@ -102,6 +107,19 @@ static const struct acpi_device_id intel_lpss_acpi_ids[] = { { "INT3448", (kernel_ulong_t)&spt_uart_info }, { "INT3449", (kernel_ulong_t)&spt_uart_info }, { "INT344A", (kernel_ulong_t)&spt_uart_info }, + /* CNL */ + { "INT34B0", (kernel_ulong_t)&spt_info }, + { "INT34B1", (kernel_ulong_t)&spt_info }, + { "INT34B2", (kernel_ulong_t)&cnl_i2c_info }, + { "INT34B3", (kernel_ulong_t)&cnl_i2c_info }, + { "INT34B4", (kernel_ulong_t)&cnl_i2c_info }, + { "INT34B5", (kernel_ulong_t)&cnl_i2c_info }, + { "INT34B6", (kernel_ulong_t)&cnl_i2c_info }, + { "INT34B7", (kernel_ulong_t)&cnl_i2c_info }, + { "INT34B8", (kernel_ulong_t)&spt_uart_info }, + { "INT34B9", (kernel_ulong_t)&spt_uart_info }, + { "INT34BA", (kernel_ulong_t)&spt_uart_info }, + { "INT34BC", (kernel_ulong_t)&spt_info }, /* BXT */ { "80860AAC", (kernel_ulong_t)&bxt_i2c_info }, { "80860ABC", (kernel_ulong_t)&bxt_info }, diff --git a/drivers/mfd/intel-m10-bmc.c b/drivers/mfd/intel-m10-bmc.c index 1a9bfb7f48cd..8db3bcf5fccc 100644 --- a/drivers/mfd/intel-m10-bmc.c +++ b/drivers/mfd/intel-m10-bmc.c @@ -15,7 +15,8 @@ enum m10bmc_type { M10_N3000, - M10_D5005 + M10_D5005, + M10_N5010, }; static struct mfd_cell m10bmc_d5005_subdevs[] = { @@ -28,6 +29,10 @@ static struct mfd_cell m10bmc_pacn3000_subdevs[] = { { .name = "n3000bmc-secure" }, }; +static struct mfd_cell m10bmc_n5010_subdevs[] = { + { .name = "n5010bmc-hwmon" }, +}; + static const struct regmap_range m10bmc_regmap_range[] = { regmap_reg_range(M10BMC_LEGACY_BUILD_VER, M10BMC_LEGACY_BUILD_VER), regmap_reg_range(M10BMC_SYS_BASE, M10BMC_SYS_END), @@ -192,6 +197,10 @@ static int intel_m10_bmc_spi_probe(struct spi_device *spi) cells = m10bmc_d5005_subdevs; n_cell = ARRAY_SIZE(m10bmc_d5005_subdevs); break; + case M10_N5010: + cells = m10bmc_n5010_subdevs; + n_cell = ARRAY_SIZE(m10bmc_n5010_subdevs); + break; default: return -ENODEV; } @@ -207,6 +216,7 @@ static int intel_m10_bmc_spi_probe(struct spi_device *spi) static const struct spi_device_id m10bmc_spi_id[] = { { "m10-n3000", M10_N3000 }, { "m10-d5005", M10_D5005 }, + { "m10-n5010", M10_N5010 }, { } }; MODULE_DEVICE_TABLE(spi, m10bmc_spi_id); diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index 3bbb29a7e7a5..f10e53187f67 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c @@ -489,6 +489,7 @@ static struct lpc_ich_info lpc_chipset_info[] = { [LPC_DH89XXCC] = { .name = "DH89xxCC", .iTCO_version = 2, + .gpio_version = ICH_V5_GPIO, }, [LPC_PPT] = { .name = "Panther Point", diff --git a/drivers/mfd/lpc_sch.c b/drivers/mfd/lpc_sch.c index 428a526cbe86..9ab9adce06fd 100644 --- a/drivers/mfd/lpc_sch.c +++ b/drivers/mfd/lpc_sch.c @@ -22,7 +22,7 @@ #define SMBASE 0x40 #define SMBUS_IO_SIZE 64 -#define GPIOBASE 0x44 +#define GPIO_BASE 0x44 #define GPIO_IO_SIZE 64 #define GPIO_IO_SIZE_CENTERTON 128 @@ -145,7 +145,7 @@ static int lpc_sch_probe(struct pci_dev *dev, const struct pci_device_id *id) if (ret == 0) cells++; - ret = lpc_sch_populate_cell(dev, GPIOBASE, "sch_gpio", + ret = lpc_sch_populate_cell(dev, GPIO_BASE, "sch_gpio", info->io_size_gpio, id->device, &lpc_sch_cells[cells]); if (ret < 0) diff --git a/drivers/mfd/mt6360-core.c b/drivers/mfd/mt6360-core.c index e628953548ce..6eaa6775b888 100644 --- a/drivers/mfd/mt6360-core.c +++ b/drivers/mfd/mt6360-core.c @@ -319,18 +319,18 @@ static const struct resource mt6360_regulator_resources[] = { DEFINE_RES_IRQ_NAMED(MT6360_BUCK2_OC_EVT, "buck2_oc_evt"), DEFINE_RES_IRQ_NAMED(MT6360_BUCK2_OV_EVT, "buck2_ov_evt"), DEFINE_RES_IRQ_NAMED(MT6360_BUCK2_UV_EVT, "buck2_uv_evt"), - DEFINE_RES_IRQ_NAMED(MT6360_LDO6_OC_EVT, "ldo6_oc_evt"), - DEFINE_RES_IRQ_NAMED(MT6360_LDO7_OC_EVT, "ldo7_oc_evt"), - DEFINE_RES_IRQ_NAMED(MT6360_LDO6_PGB_EVT, "ldo6_pgb_evt"), - DEFINE_RES_IRQ_NAMED(MT6360_LDO7_PGB_EVT, "ldo7_pgb_evt"), DEFINE_RES_IRQ_NAMED(MT6360_LDO1_OC_EVT, "ldo1_oc_evt"), DEFINE_RES_IRQ_NAMED(MT6360_LDO2_OC_EVT, "ldo2_oc_evt"), DEFINE_RES_IRQ_NAMED(MT6360_LDO3_OC_EVT, "ldo3_oc_evt"), DEFINE_RES_IRQ_NAMED(MT6360_LDO5_OC_EVT, "ldo5_oc_evt"), + DEFINE_RES_IRQ_NAMED(MT6360_LDO6_OC_EVT, "ldo6_oc_evt"), + DEFINE_RES_IRQ_NAMED(MT6360_LDO7_OC_EVT, "ldo7_oc_evt"), DEFINE_RES_IRQ_NAMED(MT6360_LDO1_PGB_EVT, "ldo1_pgb_evt"), DEFINE_RES_IRQ_NAMED(MT6360_LDO2_PGB_EVT, "ldo2_pgb_evt"), DEFINE_RES_IRQ_NAMED(MT6360_LDO3_PGB_EVT, "ldo3_pgb_evt"), DEFINE_RES_IRQ_NAMED(MT6360_LDO5_PGB_EVT, "ldo5_pgb_evt"), + DEFINE_RES_IRQ_NAMED(MT6360_LDO6_PGB_EVT, "ldo6_pgb_evt"), + DEFINE_RES_IRQ_NAMED(MT6360_LDO7_PGB_EVT, "ldo7_pgb_evt"), }; static const struct mfd_cell mt6360_devs[] = { diff --git a/drivers/mfd/rsmu.h b/drivers/mfd/rsmu.h new file mode 100644 index 000000000000..bb88597d189f --- /dev/null +++ b/drivers/mfd/rsmu.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Renesas Synchronization Management Unit (SMU) devices. + * + * Copyright (C) 2021 Integrated Device Technology, Inc., a Renesas Company. + */ + +#ifndef __RSMU_MFD_H +#define __RSMU_MFD_H + +#include <linux/mfd/rsmu.h> + +int rsmu_core_init(struct rsmu_ddata *rsmu); +void rsmu_core_exit(struct rsmu_ddata *rsmu); + +#endif /* __RSMU_MFD_H */ diff --git a/drivers/mfd/rsmu_core.c b/drivers/mfd/rsmu_core.c new file mode 100644 index 000000000000..29437fd0bd5b --- /dev/null +++ b/drivers/mfd/rsmu_core.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Core driver for Renesas Synchronization Management Unit (SMU) devices. + * + * Copyright (C) 2021 Integrated Device Technology, Inc., a Renesas Company. + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/mfd/core.h> +#include <linux/mfd/rsmu.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/regmap.h> +#include <linux/slab.h> + +#include "rsmu.h" + +enum { + RSMU_PHC = 0, + RSMU_CDEV = 1, + RSMU_N_DEVS = 2, +}; + +static struct mfd_cell rsmu_cm_devs[] = { + [RSMU_PHC] = { + .name = "8a3400x-phc", + }, + [RSMU_CDEV] = { + .name = "8a3400x-cdev", + }, +}; + +static struct mfd_cell rsmu_sabre_devs[] = { + [RSMU_PHC] = { + .name = "82p33x1x-phc", + }, + [RSMU_CDEV] = { + .name = "82p33x1x-cdev", + }, +}; + +static struct mfd_cell rsmu_sl_devs[] = { + [RSMU_PHC] = { + .name = "8v19n85x-phc", + }, + [RSMU_CDEV] = { + .name = "8v19n85x-cdev", + }, +}; + +int rsmu_core_init(struct rsmu_ddata *rsmu) +{ + struct mfd_cell *cells; + int ret; + + switch (rsmu->type) { + case RSMU_CM: + cells = rsmu_cm_devs; + break; + case RSMU_SABRE: + cells = rsmu_sabre_devs; + break; + case RSMU_SL: + cells = rsmu_sl_devs; + break; + default: + dev_err(rsmu->dev, "Unsupported RSMU device type: %d\n", rsmu->type); + return -ENODEV; + } + + mutex_init(&rsmu->lock); + + ret = devm_mfd_add_devices(rsmu->dev, PLATFORM_DEVID_AUTO, cells, + RSMU_N_DEVS, NULL, 0, NULL); + if (ret < 0) + dev_err(rsmu->dev, "Failed to register sub-devices: %d\n", ret); + + return ret; +} + +void rsmu_core_exit(struct rsmu_ddata *rsmu) +{ + mutex_destroy(&rsmu->lock); +} + +MODULE_DESCRIPTION("Renesas SMU core driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/rsmu_i2c.c b/drivers/mfd/rsmu_i2c.c new file mode 100644 index 000000000000..dc001c9791c1 --- /dev/null +++ b/drivers/mfd/rsmu_i2c.c @@ -0,0 +1,203 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * I2C driver for Renesas Synchronization Management Unit (SMU) devices. + * + * Copyright (C) 2021 Integrated Device Technology, Inc., a Renesas Company. + */ + +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/mfd/core.h> +#include <linux/mfd/rsmu.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/regmap.h> +#include <linux/slab.h> + +#include "rsmu.h" + +/* + * 16-bit register address: the lower 8 bits of the register address come + * from the offset addr byte and the upper 8 bits come from the page register. + */ +#define RSMU_CM_PAGE_ADDR 0xFD +#define RSMU_CM_PAGE_WINDOW 256 + +/* + * 15-bit register address: the lower 7 bits of the register address come + * from the offset addr byte and the upper 8 bits come from the page register. + */ +#define RSMU_SABRE_PAGE_ADDR 0x7F +#define RSMU_SABRE_PAGE_WINDOW 128 + +static const struct regmap_range_cfg rsmu_cm_range_cfg[] = { + { + .range_min = 0, + .range_max = 0xD000, + .selector_reg = RSMU_CM_PAGE_ADDR, + .selector_mask = 0xFF, + .selector_shift = 0, + .window_start = 0, + .window_len = RSMU_CM_PAGE_WINDOW, + } +}; + +static const struct regmap_range_cfg rsmu_sabre_range_cfg[] = { + { + .range_min = 0, + .range_max = 0x400, + .selector_reg = RSMU_SABRE_PAGE_ADDR, + .selector_mask = 0xFF, + .selector_shift = 0, + .window_start = 0, + .window_len = RSMU_SABRE_PAGE_WINDOW, + } +}; + +static bool rsmu_cm_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case RSMU_CM_PAGE_ADDR: + return false; + default: + return true; + } +} + +static bool rsmu_sabre_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case RSMU_SABRE_PAGE_ADDR: + return false; + default: + return true; + } +} + +static const struct regmap_config rsmu_cm_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0xD000, + .ranges = rsmu_cm_range_cfg, + .num_ranges = ARRAY_SIZE(rsmu_cm_range_cfg), + .volatile_reg = rsmu_cm_volatile_reg, + .cache_type = REGCACHE_RBTREE, + .can_multi_write = true, +}; + +static const struct regmap_config rsmu_sabre_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x400, + .ranges = rsmu_sabre_range_cfg, + .num_ranges = ARRAY_SIZE(rsmu_sabre_range_cfg), + .volatile_reg = rsmu_sabre_volatile_reg, + .cache_type = REGCACHE_RBTREE, + .can_multi_write = true, +}; + +static const struct regmap_config rsmu_sl_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .max_register = 0x339, + .cache_type = REGCACHE_NONE, + .can_multi_write = true, +}; + +static int rsmu_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + const struct regmap_config *cfg; + struct rsmu_ddata *rsmu; + int ret; + + rsmu = devm_kzalloc(&client->dev, sizeof(*rsmu), GFP_KERNEL); + if (!rsmu) + return -ENOMEM; + + i2c_set_clientdata(client, rsmu); + + rsmu->dev = &client->dev; + rsmu->type = (enum rsmu_type)id->driver_data; + + switch (rsmu->type) { + case RSMU_CM: + cfg = &rsmu_cm_regmap_config; + break; + case RSMU_SABRE: + cfg = &rsmu_sabre_regmap_config; + break; + case RSMU_SL: + cfg = &rsmu_sl_regmap_config; + break; + default: + dev_err(rsmu->dev, "Unsupported RSMU device type: %d\n", rsmu->type); + return -ENODEV; + } + rsmu->regmap = devm_regmap_init_i2c(client, cfg); + if (IS_ERR(rsmu->regmap)) { + ret = PTR_ERR(rsmu->regmap); + dev_err(rsmu->dev, "Failed to allocate register map: %d\n", ret); + return ret; + } + + return rsmu_core_init(rsmu); +} + +static int rsmu_i2c_remove(struct i2c_client *client) +{ + struct rsmu_ddata *rsmu = i2c_get_clientdata(client); + + rsmu_core_exit(rsmu); + + return 0; +} + +static const struct i2c_device_id rsmu_i2c_id[] = { + { "8a34000", RSMU_CM }, + { "8a34001", RSMU_CM }, + { "82p33810", RSMU_SABRE }, + { "82p33811", RSMU_SABRE }, + { "8v19n850", RSMU_SL }, + { "8v19n851", RSMU_SL }, + {} +}; +MODULE_DEVICE_TABLE(i2c, rsmu_i2c_id); + +static const struct of_device_id rsmu_i2c_of_match[] = { + { .compatible = "idt,8a34000", .data = (void *)RSMU_CM }, + { .compatible = "idt,8a34001", .data = (void *)RSMU_CM }, + { .compatible = "idt,82p33810", .data = (void *)RSMU_SABRE }, + { .compatible = "idt,82p33811", .data = (void *)RSMU_SABRE }, + { .compatible = "idt,8v19n850", .data = (void *)RSMU_SL }, + { .compatible = "idt,8v19n851", .data = (void *)RSMU_SL }, + {} +}; +MODULE_DEVICE_TABLE(of, rsmu_i2c_of_match); + +static struct i2c_driver rsmu_i2c_driver = { + .driver = { + .name = "rsmu-i2c", + .of_match_table = of_match_ptr(rsmu_i2c_of_match), + }, + .probe = rsmu_i2c_probe, + .remove = rsmu_i2c_remove, + .id_table = rsmu_i2c_id, +}; + +static int __init rsmu_i2c_init(void) +{ + return i2c_add_driver(&rsmu_i2c_driver); +} +subsys_initcall(rsmu_i2c_init); + +static void __exit rsmu_i2c_exit(void) +{ + i2c_del_driver(&rsmu_i2c_driver); +} +module_exit(rsmu_i2c_exit); + +MODULE_DESCRIPTION("Renesas SMU I2C driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/rsmu_spi.c b/drivers/mfd/rsmu_spi.c new file mode 100644 index 000000000000..fec2b4ec477c --- /dev/null +++ b/drivers/mfd/rsmu_spi.c @@ -0,0 +1,273 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * SPI driver for Renesas Synchronization Management Unit (SMU) devices. + * + * Copyright (C) 2021 Integrated Device Technology, Inc., a Renesas Company. + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/mfd/core.h> +#include <linux/mfd/rsmu.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <linux/spi/spi.h> + +#include "rsmu.h" + +#define RSMU_CM_PAGE_ADDR 0x7C +#define RSMU_SABRE_PAGE_ADDR 0x7F +#define RSMU_HIGHER_ADDR_MASK 0xFF80 +#define RSMU_HIGHER_ADDR_SHIFT 7 +#define RSMU_LOWER_ADDR_MASK 0x7F + +static int rsmu_read_device(struct rsmu_ddata *rsmu, u8 reg, u8 *buf, u16 bytes) +{ + struct spi_device *client = to_spi_device(rsmu->dev); + struct spi_transfer xfer = {0}; + struct spi_message msg; + u8 cmd[256] = {0}; + u8 rsp[256] = {0}; + int ret; + + cmd[0] = reg | 0x80; + xfer.rx_buf = rsp; + xfer.len = bytes + 1; + xfer.tx_buf = cmd; + xfer.bits_per_word = client->bits_per_word; + xfer.speed_hz = client->max_speed_hz; + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + + /* + * 4-wire SPI is a shift register, so for every byte you send, + * you get one back at the same time. Example read from 0xC024, + * which has value of 0x2D + * + * MOSI: + * 7C 00 C0 #Set page register + * A4 00 #MSB is set, so this is read command + * MISO: + * XX 2D #XX is a dummy byte from sending A4 and we + * need to throw it away + */ + ret = spi_sync(client, &msg); + if (ret >= 0) + memcpy(buf, &rsp[1], xfer.len-1); + + return ret; +} + +static int rsmu_write_device(struct rsmu_ddata *rsmu, u8 reg, u8 *buf, u16 bytes) +{ + struct spi_device *client = to_spi_device(rsmu->dev); + struct spi_transfer xfer = {0}; + struct spi_message msg; + u8 cmd[256] = {0}; + + cmd[0] = reg; + memcpy(&cmd[1], buf, bytes); + + xfer.len = bytes + 1; + xfer.tx_buf = cmd; + xfer.bits_per_word = client->bits_per_word; + xfer.speed_hz = client->max_speed_hz; + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + + return spi_sync(client, &msg); +} + +/* + * 1-byte (1B) offset addressing: + * 16-bit register address: the lower 7 bits of the register address come + * from the offset addr byte and the upper 9 bits come from the page register. + */ +static int rsmu_write_page_register(struct rsmu_ddata *rsmu, u16 reg) +{ + u8 page_reg; + u8 buf[2]; + u16 bytes; + u16 page; + int err; + + switch (rsmu->type) { + case RSMU_CM: + page_reg = RSMU_CM_PAGE_ADDR; + page = reg & RSMU_HIGHER_ADDR_MASK; + buf[0] = (u8)(page & 0xff); + buf[1] = (u8)((page >> 8) & 0xff); + bytes = 2; + break; + case RSMU_SABRE: + page_reg = RSMU_SABRE_PAGE_ADDR; + page = reg >> RSMU_HIGHER_ADDR_SHIFT; + buf[0] = (u8)(page & 0xff); + bytes = 1; + break; + default: + dev_err(rsmu->dev, "Unsupported RSMU device type: %d\n", rsmu->type); + return -ENODEV; + } + + /* Simply return if we are on the same page */ + if (rsmu->page == page) + return 0; + + err = rsmu_write_device(rsmu, page_reg, buf, bytes); + if (err) + dev_err(rsmu->dev, "Failed to set page offset 0x%x\n", page); + else + /* Remember the last page */ + rsmu->page = page; + + return err; +} + +static int rsmu_reg_read(void *context, unsigned int reg, unsigned int *val) +{ + struct rsmu_ddata *rsmu = spi_get_drvdata((struct spi_device *)context); + u8 addr = (u8)(reg & RSMU_LOWER_ADDR_MASK); + int err; + + err = rsmu_write_page_register(rsmu, reg); + if (err) + return err; + + err = rsmu_read_device(rsmu, addr, (u8 *)val, 1); + if (err) + dev_err(rsmu->dev, "Failed to read offset address 0x%x\n", addr); + + return err; +} + +static int rsmu_reg_write(void *context, unsigned int reg, unsigned int val) +{ + struct rsmu_ddata *rsmu = spi_get_drvdata((struct spi_device *)context); + u8 addr = (u8)(reg & RSMU_LOWER_ADDR_MASK); + u8 data = (u8)val; + int err; + + err = rsmu_write_page_register(rsmu, reg); + if (err) + return err; + + err = rsmu_write_device(rsmu, addr, &data, 1); + if (err) + dev_err(rsmu->dev, + "Failed to write offset address 0x%x\n", addr); + + return err; +} + +static const struct regmap_config rsmu_cm_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .max_register = 0xD000, + .reg_read = rsmu_reg_read, + .reg_write = rsmu_reg_write, + .cache_type = REGCACHE_NONE, +}; + +static const struct regmap_config rsmu_sabre_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .max_register = 0x400, + .reg_read = rsmu_reg_read, + .reg_write = rsmu_reg_write, + .cache_type = REGCACHE_NONE, +}; + +static int rsmu_spi_probe(struct spi_device *client) +{ + const struct spi_device_id *id = spi_get_device_id(client); + const struct regmap_config *cfg; + struct rsmu_ddata *rsmu; + int ret; + + rsmu = devm_kzalloc(&client->dev, sizeof(*rsmu), GFP_KERNEL); + if (!rsmu) + return -ENOMEM; + + spi_set_drvdata(client, rsmu); + + rsmu->dev = &client->dev; + rsmu->type = (enum rsmu_type)id->driver_data; + + /* Initialize regmap */ + switch (rsmu->type) { + case RSMU_CM: + cfg = &rsmu_cm_regmap_config; + break; + case RSMU_SABRE: + cfg = &rsmu_sabre_regmap_config; + break; + default: + dev_err(rsmu->dev, "Unsupported RSMU device type: %d\n", rsmu->type); + return -ENODEV; + } + + rsmu->regmap = devm_regmap_init(&client->dev, NULL, client, cfg); + if (IS_ERR(rsmu->regmap)) { + ret = PTR_ERR(rsmu->regmap); + dev_err(rsmu->dev, "Failed to allocate register map: %d\n", ret); + return ret; + } + + return rsmu_core_init(rsmu); +} + +static int rsmu_spi_remove(struct spi_device *client) +{ + struct rsmu_ddata *rsmu = spi_get_drvdata(client); + + rsmu_core_exit(rsmu); + + return 0; +} + +static const struct spi_device_id rsmu_spi_id[] = { + { "8a34000", RSMU_CM }, + { "8a34001", RSMU_CM }, + { "82p33810", RSMU_SABRE }, + { "82p33811", RSMU_SABRE }, + {} +}; +MODULE_DEVICE_TABLE(spi, rsmu_spi_id); + +static const struct of_device_id rsmu_spi_of_match[] = { + { .compatible = "idt,8a34000", .data = (void *)RSMU_CM }, + { .compatible = "idt,8a34001", .data = (void *)RSMU_CM }, + { .compatible = "idt,82p33810", .data = (void *)RSMU_SABRE }, + { .compatible = "idt,82p33811", .data = (void *)RSMU_SABRE }, + {} +}; +MODULE_DEVICE_TABLE(of, rsmu_spi_of_match); + +static struct spi_driver rsmu_spi_driver = { + .driver = { + .name = "rsmu-spi", + .of_match_table = of_match_ptr(rsmu_spi_of_match), + }, + .probe = rsmu_spi_probe, + .remove = rsmu_spi_remove, + .id_table = rsmu_spi_id, +}; + +static int __init rsmu_spi_init(void) +{ + return spi_register_driver(&rsmu_spi_driver); +} +subsys_initcall(rsmu_spi_init); + +static void __exit rsmu_spi_exit(void) +{ + spi_unregister_driver(&rsmu_spi_driver); +} +module_exit(rsmu_spi_exit); + +MODULE_DESCRIPTION("Renesas SMU SPI driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/simple-mfd-i2c.c b/drivers/mfd/simple-mfd-i2c.c index 87f684cff9a1..51536691ad9d 100644 --- a/drivers/mfd/simple-mfd-i2c.c +++ b/drivers/mfd/simple-mfd-i2c.c @@ -2,39 +2,64 @@ /* * Simple MFD - I2C * + * Author(s): + * Michael Walle <michael@walle.cc> + * Lee Jones <lee.jones@linaro.org> + * * This driver creates a single register map with the intention for it to be * shared by all sub-devices. Children can use their parent's device structure * (dev.parent) in order to reference it. * * Once the register map has been successfully initialised, any sub-devices - * represented by child nodes in Device Tree will be subsequently registered. + * represented by child nodes in Device Tree or via the MFD cells in this file + * will be subsequently registered. */ #include <linux/i2c.h> #include <linux/kernel.h> +#include <linux/mfd/core.h> #include <linux/module.h> #include <linux/of_platform.h> #include <linux/regmap.h> -static const struct regmap_config simple_regmap_config = { +#include "simple-mfd-i2c.h" + +static const struct regmap_config regmap_config_8r_8v = { .reg_bits = 8, .val_bits = 8, }; static int simple_mfd_i2c_probe(struct i2c_client *i2c) { - const struct regmap_config *config; + const struct simple_mfd_data *simple_mfd_data; + const struct regmap_config *regmap_config; struct regmap *regmap; + int ret; + + simple_mfd_data = device_get_match_data(&i2c->dev); - config = device_get_match_data(&i2c->dev); - if (!config) - config = &simple_regmap_config; + /* If no regmap_config is specified, use the default 8reg and 8val bits */ + if (!simple_mfd_data || !simple_mfd_data->regmap_config) + regmap_config = ®map_config_8r_8v; + else + regmap_config = simple_mfd_data->regmap_config; - regmap = devm_regmap_init_i2c(i2c, config); + regmap = devm_regmap_init_i2c(i2c, regmap_config); if (IS_ERR(regmap)) return PTR_ERR(regmap); - return devm_of_platform_populate(&i2c->dev); + /* If no MFD cells are spedified, use register the DT child nodes instead */ + if (!simple_mfd_data || !simple_mfd_data->mfd_cell) + return devm_of_platform_populate(&i2c->dev); + + ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, + simple_mfd_data->mfd_cell, + simple_mfd_data->mfd_cell_size, + NULL, 0, NULL); + if (ret) + dev_err(&i2c->dev, "Failed to add child devices\n"); + + return ret; } static const struct of_device_id simple_mfd_i2c_of_match[] = { diff --git a/drivers/mfd/simple-mfd-i2c.h b/drivers/mfd/simple-mfd-i2c.h new file mode 100644 index 000000000000..7cb2bdd347d9 --- /dev/null +++ b/drivers/mfd/simple-mfd-i2c.h @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Simple MFD - I2C + * + * Author: Lee Jones <lee.jones@linaro.org> + * + * This driver creates a single register map with the intention for it to be + * shared by all sub-devices. Children can use their parent's device structure + * (dev.parent) in order to reference it. + * + * This driver creates a single register map with the intention for it to be + * shared by all sub-devices. Children can use their parent's device structure + * (dev.parent) in order to reference it. + * + * Once the register map has been successfully initialised, any sub-devices + * represented by child nodes in Device Tree or via the MFD cells in the + * associated C file will be subsequently registered. + */ + +#ifndef __MFD_SIMPLE_MFD_I2C_H +#define __MFD_SIMPLE_MFD_I2C_H + +#include <linux/mfd/core.h> +#include <linux/regmap.h> + +struct simple_mfd_data { + const struct regmap_config *regmap_config; + const struct mfd_cell *mfd_cell; + size_t mfd_cell_size; +}; + +#endif /* __MFD_SIMPLE_MFD_I2C_H */ diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index 1dd39483e7c1..58d09c615e67 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c @@ -1095,7 +1095,7 @@ static irqreturn_t stmpe_irq(int irq, void *data) if (variant->id_val == STMPE801_ID || variant->id_val == STMPE1600_ID) { - int base = irq_create_mapping(stmpe->domain, 0); + int base = irq_find_mapping(stmpe->domain, 0); handle_nested_irq(base); return IRQ_HANDLED; @@ -1123,7 +1123,7 @@ static irqreturn_t stmpe_irq(int irq, void *data) while (status) { int bit = __ffs(status); int line = bank * 8 + bit; - int nestedirq = irq_create_mapping(stmpe->domain, line); + int nestedirq = irq_find_mapping(stmpe->domain, line); handle_nested_irq(nestedirq); status &= ~(1 << bit); diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c index 765c0210cb52..191fdb87c424 100644 --- a/drivers/mfd/syscon.c +++ b/drivers/mfd/syscon.c @@ -60,7 +60,7 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_clk) goto err_map; } - base = ioremap(res.start, resource_size(&res)); + base = of_iomap(np, 0); if (!base) { ret = -ENOMEM; goto err_map; diff --git a/drivers/mfd/tc3589x.c b/drivers/mfd/tc3589x.c index 7614f8fe0e91..13583cdb93b6 100644 --- a/drivers/mfd/tc3589x.c +++ b/drivers/mfd/tc3589x.c @@ -187,7 +187,7 @@ again: while (status) { int bit = __ffs(status); - int virq = irq_create_mapping(tc3589x->domain, bit); + int virq = irq_find_mapping(tc3589x->domain, bit); handle_nested_irq(virq); status &= ~(1 << bit); diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c index 0e6e25308190..55adc379f94b 100644 --- a/drivers/mfd/ti_am335x_tscadc.c +++ b/drivers/mfd/ti_am335x_tscadc.c @@ -175,10 +175,9 @@ static int ti_tscadc_probe(struct platform_device *pdev) tscadc->dev = &pdev->dev; err = platform_get_irq(pdev, 0); - if (err < 0) { - dev_err(&pdev->dev, "no irq ID is specified.\n"); + if (err < 0) goto ret; - } else + else tscadc->irq = err; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/mfd/tps65086.c b/drivers/mfd/tps65086.c index 341466ef20cc..3bd5728844a0 100644 --- a/drivers/mfd/tps65086.c +++ b/drivers/mfd/tps65086.c @@ -24,6 +24,7 @@ static const struct mfd_cell tps65086_cells[] = { { .name = "tps65086-regulator", }, { .name = "tps65086-gpio", }, + { .name = "tps65086-reset", }, }; static const struct regmap_range tps65086_yes_ranges[] = { @@ -100,29 +101,30 @@ static int tps65086_probe(struct i2c_client *client, (char)((version & TPS65086_DEVICEID_OTP_MASK) >> 4) + 'A', (version & TPS65086_DEVICEID_REV_MASK) >> 6); - ret = regmap_add_irq_chip(tps->regmap, tps->irq, IRQF_ONESHOT, 0, - &tps65086_irq_chip, &tps->irq_data); - if (ret) { - dev_err(tps->dev, "Failed to register IRQ chip\n"); - return ret; + if (tps->irq > 0) { + ret = regmap_add_irq_chip(tps->regmap, tps->irq, IRQF_ONESHOT, 0, + &tps65086_irq_chip, &tps->irq_data); + if (ret) { + dev_err(tps->dev, "Failed to register IRQ chip\n"); + return ret; + } } ret = mfd_add_devices(tps->dev, PLATFORM_DEVID_AUTO, tps65086_cells, ARRAY_SIZE(tps65086_cells), NULL, 0, regmap_irq_get_domain(tps->irq_data)); - if (ret) { + if (ret && tps->irq > 0) regmap_del_irq_chip(tps->irq, tps->irq_data); - return ret; - } - return 0; + return ret; } static int tps65086_remove(struct i2c_client *client) { struct tps65086 *tps = i2c_get_clientdata(client); - regmap_del_irq_chip(tps->irq, tps->irq_data); + if (tps->irq > 0) + regmap_del_irq_chip(tps->irq, tps->irq_data); return 0; } diff --git a/drivers/mfd/tqmx86.c b/drivers/mfd/tqmx86.c index ddddf08b6a4c..7ae906ff8e35 100644 --- a/drivers/mfd/tqmx86.c +++ b/drivers/mfd/tqmx86.c @@ -35,7 +35,11 @@ #define TQMX86_REG_BOARD_ID_E39x 7 #define TQMX86_REG_BOARD_ID_70EB 8 #define TQMX86_REG_BOARD_ID_80UC 9 -#define TQMX86_REG_BOARD_ID_90UC 10 +#define TQMX86_REG_BOARD_ID_110EB 11 +#define TQMX86_REG_BOARD_ID_E40M 12 +#define TQMX86_REG_BOARD_ID_E40S 13 +#define TQMX86_REG_BOARD_ID_E40C1 14 +#define TQMX86_REG_BOARD_ID_E40C2 15 #define TQMX86_REG_BOARD_REV 0x21 #define TQMX86_REG_IO_EXT_INT 0x26 #define TQMX86_REG_IO_EXT_INT_NONE 0 @@ -77,7 +81,7 @@ static struct i2c_board_info tqmx86_i2c_devices[] = { }, }; -static struct ocores_i2c_platform_data ocores_platfom_data = { +static struct ocores_i2c_platform_data ocores_platform_data = { .num_devices = ARRAY_SIZE(tqmx86_i2c_devices), .devices = tqmx86_i2c_devices, }; @@ -85,8 +89,8 @@ static struct ocores_i2c_platform_data ocores_platfom_data = { static const struct mfd_cell tqmx86_i2c_soft_dev[] = { { .name = "ocores-i2c", - .platform_data = &ocores_platfom_data, - .pdata_size = sizeof(ocores_platfom_data), + .platform_data = &ocores_platform_data, + .pdata_size = sizeof(ocores_platform_data), .resources = tqmx_i2c_soft_resources, .num_resources = ARRAY_SIZE(tqmx_i2c_soft_resources), }, @@ -128,21 +132,33 @@ static const char *tqmx86_board_id_to_name(u8 board_id) return "TQMx70EB"; case TQMX86_REG_BOARD_ID_80UC: return "TQMx80UC"; - case TQMX86_REG_BOARD_ID_90UC: - return "TQMx90UC"; + case TQMX86_REG_BOARD_ID_110EB: + return "TQMx110EB"; + case TQMX86_REG_BOARD_ID_E40M: + return "TQMxE40M"; + case TQMX86_REG_BOARD_ID_E40S: + return "TQMxE40S"; + case TQMX86_REG_BOARD_ID_E40C1: + return "TQMxE40C1"; + case TQMX86_REG_BOARD_ID_E40C2: + return "TQMxE40C2"; default: return "Unknown"; } } -static int tqmx86_board_id_to_clk_rate(u8 board_id) +static int tqmx86_board_id_to_clk_rate(struct device *dev, u8 board_id) { switch (board_id) { case TQMX86_REG_BOARD_ID_50UC: case TQMX86_REG_BOARD_ID_60EB: case TQMX86_REG_BOARD_ID_70EB: case TQMX86_REG_BOARD_ID_80UC: - case TQMX86_REG_BOARD_ID_90UC: + case TQMX86_REG_BOARD_ID_110EB: + case TQMX86_REG_BOARD_ID_E40M: + case TQMX86_REG_BOARD_ID_E40S: + case TQMX86_REG_BOARD_ID_E40C1: + case TQMX86_REG_BOARD_ID_E40C2: return 24000; case TQMX86_REG_BOARD_ID_E39M: case TQMX86_REG_BOARD_ID_E39C: @@ -152,7 +168,9 @@ static int tqmx86_board_id_to_clk_rate(u8 board_id) case TQMX86_REG_BOARD_ID_E38C: return 33000; default: - return 0; + dev_warn(dev, "unknown board %d, assuming 24MHz LPC clock\n", + board_id); + return 24000; } } @@ -209,9 +227,11 @@ static int tqmx86_probe(struct platform_device *pdev) /* Assumes the IRQ resource is first. */ tqmx_gpio_resources[0].start = gpio_irq; + } else { + tqmx_gpio_resources[0].flags = 0; } - ocores_platfom_data.clock_khz = tqmx86_board_id_to_clk_rate(board_id); + ocores_platform_data.clock_khz = tqmx86_board_id_to_clk_rate(dev, board_id); if (i2c_det == TQMX86_REG_I2C_DETECT_SOFT) { err = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, @@ -253,6 +273,14 @@ static const struct dmi_system_id tqmx86_dmi_table[] __initconst = { }, .callback = tqmx86_create_platform_device, }, + { + .ident = "TQMX86", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TQ-Systems"), + DMI_MATCH(DMI_PRODUCT_NAME, "TQMx"), + }, + .callback = tqmx86_create_platform_device, + }, {} }; MODULE_DEVICE_TABLE(dmi, tqmx86_dmi_table); diff --git a/drivers/mfd/wm8994-irq.c b/drivers/mfd/wm8994-irq.c index 6c3a619e2628..651a028bc519 100644 --- a/drivers/mfd/wm8994-irq.c +++ b/drivers/mfd/wm8994-irq.c @@ -154,7 +154,7 @@ static irqreturn_t wm8994_edge_irq(int irq, void *data) struct wm8994 *wm8994 = data; while (gpio_get_value_cansleep(wm8994->pdata.irq_gpio)) - handle_nested_irq(irq_create_mapping(wm8994->edge_irq, 0)); + handle_nested_irq(irq_find_mapping(wm8994->edge_irq, 0)); return IRQ_HANDLED; } |