aboutsummaryrefslogtreecommitdiff
path: root/drivers/mfd
diff options
context:
space:
mode:
authorGravatar Linus Torvalds <torvalds@linux-foundation.org> 2023-02-23 15:03:05 -0800
committerGravatar Linus Torvalds <torvalds@linux-foundation.org> 2023-02-23 15:03:05 -0800
commitc2c23dc7d5f866a8bec3db638fae7f63789303ac (patch)
tree6317ceec34644b5a176e83ee64553922a964796b /drivers/mfd
parentMerge tag 'efi-next-for-v6.3' of git://git.kernel.org/pub/scm/linux/kernel/gi... (diff)
parentdt-bindings: mfd: qcom,tcsr: Add compatible for IPQ5332 (diff)
downloadlinux-c2c23dc7d5f866a8bec3db638fae7f63789303ac.tar.gz
linux-c2c23dc7d5f866a8bec3db638fae7f63789303ac.tar.bz2
linux-c2c23dc7d5f866a8bec3db638fae7f63789303ac.zip
Merge tag 'mfd-next-6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd
Pull MFD updates from Lee Jones: "Core Framework: - Change MFD support status from Supported to Maintained New Drivers: - Add support for the Intel Platform Management Component Interface (PMCI) Removed Drivers: - HTC PASIC3 LED/DS1WM - Toshiba T7L66XB, TC6387XB and TC6393XB TMIO New Device Support: - Add support for N6000 Flash to Intel M10 BMC PMCI - Add support for Lenovo Yoga Tab 3 to Intel CHTWC PMIC New Functionality: - Provide Reset support to Syscon Fix-ups: - Explicitly provide missing include files - Pass platform type data/info via the SPI/I2C/DT registration strategy - Lots of DT documentation / adaptions - Replace scnprintf() with preferred sysfs_emit() - Remove unused / superfluous code - Fix some trivial whitesspace / spelling / grammatical issues - Replace pm_power_off with new and improved register_sys_off_handler() API Bug Fixes: - Reintroduce RK808-clkout registration - fixing Wi-Fi and Bluetooth - Repair the order of AXPxxx IRQ PEK RISE/FALL definitions - Refuse to build CS5535 on unsupported UML architectures - Fix memory leaks in error return paths - Prevent refcount leaks in error return paths" * tag 'mfd-next-6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (40 commits) dt-bindings: mfd: qcom,tcsr: Add compatible for IPQ5332 dt-bindings: mfd: Add NXP BBNSM mfd: ntxec: Add version number for EC in Tolino Vision dt-bindings: mfd: syscon: Add mt8365-syscfg mfd: Remove toshiba tmio drivers mfd: arizona: Use pm_runtime_resume_and_get() to prevent refcnt leak mfd: syscon: Allow reset control for syscon devices dt-bindings: mfd/syscon: Add resets property dt-bindings: mfd: syscon: Add amd,pensando-elba-syscon compatible dt-bindings: mfd: qcom,tcsr: Add compatible for MSM8226 mfd: simple-mfd-i2c: Fix incoherent comment regarding DT registration mfd: axp20x: Switch to the sys-off handler API mfd: core: Spelling s/compement/complement/ mfd: max8925: Remove the unused function irq_to_max8925() mfd: qcom-pm8xxx: Remove set but unused variable 'rev' dt-bindings: mfd: syscon: Document GXP register compatible mfd: twl4030-power: Drop empty platform remove function mfd: twl: Fix TWL6032 phy vbus detection mfd: pcf50633-adc: Fix potential memleak in pcf50633_adc_async_read() MAINTAINERS: Move MFD from a Supported to Maintaied state ...
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/Kconfig33
-rw-r--r--drivers/mfd/Makefile5
-rw-r--r--drivers/mfd/arizona-core.c2
-rw-r--r--drivers/mfd/axp20x.c27
-rw-r--r--drivers/mfd/intel-m10-bmc-core.c122
-rw-r--r--drivers/mfd/intel-m10-bmc-pmci.c455
-rw-r--r--drivers/mfd/intel-m10-bmc-spi.c168
-rw-r--r--drivers/mfd/intel-m10-bmc.c238
-rw-r--r--drivers/mfd/intel_soc_pmic_chtwc.c8
-rw-r--r--drivers/mfd/kempld-core.c7
-rw-r--r--drivers/mfd/lm3533-core.c2
-rw-r--r--drivers/mfd/max8925-core.c6
-rw-r--r--drivers/mfd/ntxec.c1
-rw-r--r--drivers/mfd/pcf50633-adc.c7
-rw-r--r--drivers/mfd/qcom-pm8xxx.c3
-rw-r--r--drivers/mfd/rk808.c1
-rw-r--r--drivers/mfd/simple-mfd-i2c.c2
-rw-r--r--drivers/mfd/syscon.c27
-rw-r--r--drivers/mfd/twl-core.c9
-rw-r--r--drivers/mfd/twl4030-power.c6
20 files changed, 833 insertions, 296 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 5c24841e5699..fcc141e067b9 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -15,6 +15,7 @@ config MFD_CS5535
tristate "AMD CS5535 and CS5536 southbridge core functions"
select MFD_CORE
depends on PCI && (X86_32 || (X86 && COMPILE_TEST))
+ depends on !UML
help
This is the core driver for CS5535/CS5536 MFD functions. This is
necessary for using the board's GPIO and MFGPT functionality.
@@ -2166,14 +2167,32 @@ config SGI_MFD_IOC3
If you have an SGI Origin, Octane, or a PCI IOC3 card,
then say Y. Otherwise say N.
-config MFD_INTEL_M10_BMC
- tristate "Intel MAX 10 Board Management Controller"
- depends on SPI_MASTER
- select REGMAP_SPI_AVMM
- select MFD_CORE
+config MFD_INTEL_M10_BMC_CORE
+ tristate
+ select MFD_CORE
+ select REGMAP
+ default n
+
+config MFD_INTEL_M10_BMC_SPI
+ tristate "Intel MAX 10 Board Management Controller with SPI"
+ depends on SPI_MASTER
+ select MFD_INTEL_M10_BMC_CORE
+ select REGMAP_SPI_AVMM
+ help
+ Support for the Intel MAX 10 board management controller using the
+ SPI 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_INTEL_M10_BMC_PMCI
+ tristate "Intel MAX 10 Board Management Controller with PMCI"
+ depends on FPGA_DFL
+ select MFD_INTEL_M10_BMC_CORE
+ select REGMAP
help
- Support for the Intel MAX 10 board management controller using the
- SPI interface.
+ Support for the Intel MAX 10 board management controller via PMCI.
This driver provides common support for accessing the device,
additional drivers must be enabled in order to use the functionality
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 09712495f4f4..2f6c89d1e277 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -262,7 +262,10 @@ obj-$(CONFIG_MFD_QCOM_PM8008) += qcom-pm8008.o
obj-$(CONFIG_SGI_MFD_IOC3) += ioc3.o
obj-$(CONFIG_MFD_SIMPLE_MFD_I2C) += simple-mfd-i2c.o
obj-$(CONFIG_MFD_SMPRO) += smpro-core.o
-obj-$(CONFIG_MFD_INTEL_M10_BMC) += intel-m10-bmc.o
+
+obj-$(CONFIG_MFD_INTEL_M10_BMC_CORE) += intel-m10-bmc-core.o
+obj-$(CONFIG_MFD_INTEL_M10_BMC_SPI) += intel-m10-bmc-spi.o
+obj-$(CONFIG_MFD_INTEL_M10_BMC_PMCI) += intel-m10-bmc-pmci.o
obj-$(CONFIG_MFD_ATC260X) += atc260x-core.o
obj-$(CONFIG_MFD_ATC260X_I2C) += atc260x-i2c.o
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c
index bd7ee3260d53..c166fcd331f1 100644
--- a/drivers/mfd/arizona-core.c
+++ b/drivers/mfd/arizona-core.c
@@ -45,7 +45,7 @@ int arizona_clk32k_enable(struct arizona *arizona)
if (arizona->clk32k_ref == 1) {
switch (arizona->pdata.clk32k_src) {
case ARIZONA_32KZ_MCLK1:
- ret = pm_runtime_get_sync(arizona->dev);
+ ret = pm_runtime_resume_and_get(arizona->dev);
if (ret != 0)
goto err_ref;
ret = clk_prepare_enable(arizona->mclk[ARIZONA_MCLK1]);
diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
index 47fd700f284f..01a6bbb6d266 100644
--- a/drivers/mfd/axp20x.c
+++ b/drivers/mfd/axp20x.c
@@ -23,7 +23,7 @@
#include <linux/mfd/core.h>
#include <linux/module.h>
#include <linux/of_device.h>
-#include <linux/pm_runtime.h>
+#include <linux/reboot.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
@@ -825,17 +825,16 @@ static const struct mfd_cell axp813_cells[] = {
},
};
-static struct axp20x_dev *axp20x_pm_power_off;
-static void axp20x_power_off(void)
+static int axp20x_power_off(struct sys_off_data *data)
{
- if (axp20x_pm_power_off->variant == AXP288_ID)
- return;
+ struct axp20x_dev *axp20x = data->cb_data;
- regmap_write(axp20x_pm_power_off->regmap, AXP20X_OFF_CTRL,
- AXP20X_OFF);
+ regmap_write(axp20x->regmap, AXP20X_OFF_CTRL, AXP20X_OFF);
/* Give capacitors etc. time to drain to avoid kernel panic msg. */
mdelay(500);
+
+ return NOTIFY_DONE;
}
int axp20x_match_device(struct axp20x_dev *axp20x)
@@ -1002,10 +1001,11 @@ int axp20x_device_probe(struct axp20x_dev *axp20x)
return ret;
}
- if (!pm_power_off) {
- axp20x_pm_power_off = axp20x;
- pm_power_off = axp20x_power_off;
- }
+ if (axp20x->variant != AXP288_ID)
+ devm_register_sys_off_handler(axp20x->dev,
+ SYS_OFF_MODE_POWER_OFF,
+ SYS_OFF_PRIO_DEFAULT,
+ axp20x_power_off, axp20x);
dev_info(axp20x->dev, "AXP20X driver loaded\n");
@@ -1015,11 +1015,6 @@ EXPORT_SYMBOL(axp20x_device_probe);
void axp20x_device_remove(struct axp20x_dev *axp20x)
{
- if (axp20x == axp20x_pm_power_off) {
- axp20x_pm_power_off = NULL;
- pm_power_off = NULL;
- }
-
mfd_remove_devices(axp20x->dev);
regmap_del_irq_chip(axp20x->irq, axp20x->regmap_irqc);
}
diff --git a/drivers/mfd/intel-m10-bmc-core.c b/drivers/mfd/intel-m10-bmc-core.c
new file mode 100644
index 000000000000..dac9cf7bcb4a
--- /dev/null
+++ b/drivers/mfd/intel-m10-bmc-core.c
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Intel MAX 10 Board Management Controller chip - common code
+ *
+ * Copyright (C) 2018-2020 Intel Corporation. All rights reserved.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/device.h>
+#include <linux/dev_printk.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/intel-m10-bmc.h>
+#include <linux/module.h>
+
+static ssize_t bmc_version_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct intel_m10bmc *ddata = dev_get_drvdata(dev);
+ unsigned int val;
+ int ret;
+
+ ret = m10bmc_sys_read(ddata, ddata->info->csr_map->build_version, &val);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "0x%x\n", val);
+}
+static DEVICE_ATTR_RO(bmc_version);
+
+static ssize_t bmcfw_version_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct intel_m10bmc *ddata = dev_get_drvdata(dev);
+ unsigned int val;
+ int ret;
+
+ ret = m10bmc_sys_read(ddata, ddata->info->csr_map->fw_version, &val);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "0x%x\n", val);
+}
+static DEVICE_ATTR_RO(bmcfw_version);
+
+static ssize_t mac_address_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct intel_m10bmc *ddata = dev_get_drvdata(dev);
+ unsigned int macaddr_low, macaddr_high;
+ int ret;
+
+ ret = m10bmc_sys_read(ddata, ddata->info->csr_map->mac_low, &macaddr_low);
+ if (ret)
+ return ret;
+
+ ret = m10bmc_sys_read(ddata, ddata->info->csr_map->mac_high, &macaddr_high);
+ if (ret)
+ return ret;
+
+ return sysfs_emit(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n",
+ (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE1, macaddr_low),
+ (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE2, macaddr_low),
+ (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE3, macaddr_low),
+ (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE4, macaddr_low),
+ (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE5, macaddr_high),
+ (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE6, macaddr_high));
+}
+static DEVICE_ATTR_RO(mac_address);
+
+static ssize_t mac_count_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct intel_m10bmc *ddata = dev_get_drvdata(dev);
+ unsigned int macaddr_high;
+ int ret;
+
+ ret = m10bmc_sys_read(ddata, ddata->info->csr_map->mac_high, &macaddr_high);
+ if (ret)
+ return ret;
+
+ return sysfs_emit(buf, "%u\n", (u8)FIELD_GET(M10BMC_N3000_MAC_COUNT, macaddr_high));
+}
+static DEVICE_ATTR_RO(mac_count);
+
+static struct attribute *m10bmc_attrs[] = {
+ &dev_attr_bmc_version.attr,
+ &dev_attr_bmcfw_version.attr,
+ &dev_attr_mac_address.attr,
+ &dev_attr_mac_count.attr,
+ NULL,
+};
+
+static const struct attribute_group m10bmc_group = {
+ .attrs = m10bmc_attrs,
+};
+
+const struct attribute_group *m10bmc_dev_groups[] = {
+ &m10bmc_group,
+ NULL,
+};
+EXPORT_SYMBOL_GPL(m10bmc_dev_groups);
+
+int m10bmc_dev_init(struct intel_m10bmc *m10bmc, const struct intel_m10bmc_platform_info *info)
+{
+ int ret;
+
+ m10bmc->info = info;
+ dev_set_drvdata(m10bmc->dev, m10bmc);
+
+ ret = devm_mfd_add_devices(m10bmc->dev, PLATFORM_DEVID_AUTO,
+ info->cells, info->n_cells,
+ NULL, 0, NULL);
+ if (ret)
+ dev_err(m10bmc->dev, "Failed to register sub-devices: %d\n", ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(m10bmc_dev_init);
+
+MODULE_DESCRIPTION("Intel MAX 10 BMC core driver");
+MODULE_AUTHOR("Intel Corporation");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/intel-m10-bmc-pmci.c b/drivers/mfd/intel-m10-bmc-pmci.c
new file mode 100644
index 000000000000..8821f1876dd6
--- /dev/null
+++ b/drivers/mfd/intel-m10-bmc-pmci.c
@@ -0,0 +1,455 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MAX10 BMC Platform Management Component Interface (PMCI) based
+ * interface.
+ *
+ * Copyright (C) 2020-2023 Intel Corporation.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/device.h>
+#include <linux/dfl.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/intel-m10-bmc.h>
+#include <linux/minmax.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+struct m10bmc_pmci_device {
+ void __iomem *base;
+ struct intel_m10bmc m10bmc;
+ struct mutex flash_mutex; /* protects flash_busy and serializes flash read/read */
+ bool flash_busy;
+};
+
+/*
+ * Intel FGPA indirect register access via hardware controller/bridge.
+ */
+#define INDIRECT_CMD_OFF 0
+#define INDIRECT_CMD_CLR 0
+#define INDIRECT_CMD_RD BIT(0)
+#define INDIRECT_CMD_WR BIT(1)
+#define INDIRECT_CMD_ACK BIT(2)
+
+#define INDIRECT_ADDR_OFF 0x4
+#define INDIRECT_RD_OFF 0x8
+#define INDIRECT_WR_OFF 0xc
+
+#define INDIRECT_INT_US 1
+#define INDIRECT_TIMEOUT_US 10000
+
+struct indirect_ctx {
+ void __iomem *base;
+ struct device *dev;
+};
+
+static int indirect_clear_cmd(struct indirect_ctx *ctx)
+{
+ unsigned int cmd;
+ int ret;
+
+ writel(INDIRECT_CMD_CLR, ctx->base + INDIRECT_CMD_OFF);
+
+ ret = readl_poll_timeout(ctx->base + INDIRECT_CMD_OFF, cmd,
+ cmd == INDIRECT_CMD_CLR,
+ INDIRECT_INT_US, INDIRECT_TIMEOUT_US);
+ if (ret)
+ dev_err(ctx->dev, "timed out waiting clear cmd (residual cmd=0x%x)\n", cmd);
+
+ return ret;
+}
+
+static int indirect_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+ struct indirect_ctx *ctx = context;
+ unsigned int cmd, ack, tmpval;
+ int ret, ret2;
+
+ cmd = readl(ctx->base + INDIRECT_CMD_OFF);
+ if (cmd != INDIRECT_CMD_CLR)
+ dev_warn(ctx->dev, "residual cmd 0x%x on read entry\n", cmd);
+
+ writel(reg, ctx->base + INDIRECT_ADDR_OFF);
+ writel(INDIRECT_CMD_RD, ctx->base + INDIRECT_CMD_OFF);
+
+ ret = readl_poll_timeout(ctx->base + INDIRECT_CMD_OFF, ack,
+ (ack & INDIRECT_CMD_ACK) == INDIRECT_CMD_ACK,
+ INDIRECT_INT_US, INDIRECT_TIMEOUT_US);
+ if (ret)
+ dev_err(ctx->dev, "read timed out on reg 0x%x ack 0x%x\n", reg, ack);
+ else
+ tmpval = readl(ctx->base + INDIRECT_RD_OFF);
+
+ ret2 = indirect_clear_cmd(ctx);
+
+ if (ret)
+ return ret;
+ if (ret2)
+ return ret2;
+
+ *val = tmpval;
+ return 0;
+}
+
+static int indirect_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+ struct indirect_ctx *ctx = context;
+ unsigned int cmd, ack;
+ int ret, ret2;
+
+ cmd = readl(ctx->base + INDIRECT_CMD_OFF);
+ if (cmd != INDIRECT_CMD_CLR)
+ dev_warn(ctx->dev, "residual cmd 0x%x on write entry\n", cmd);
+
+ writel(val, ctx->base + INDIRECT_WR_OFF);
+ writel(reg, ctx->base + INDIRECT_ADDR_OFF);
+ writel(INDIRECT_CMD_WR, ctx->base + INDIRECT_CMD_OFF);
+
+ ret = readl_poll_timeout(ctx->base + INDIRECT_CMD_OFF, ack,
+ (ack & INDIRECT_CMD_ACK) == INDIRECT_CMD_ACK,
+ INDIRECT_INT_US, INDIRECT_TIMEOUT_US);
+ if (ret)
+ dev_err(ctx->dev, "write timed out on reg 0x%x ack 0x%x\n", reg, ack);
+
+ ret2 = indirect_clear_cmd(ctx);
+
+ if (ret)
+ return ret;
+ return ret2;
+}
+
+static void pmci_write_fifo(void __iomem *base, const u32 *buf, size_t count)
+{
+ while (count--)
+ writel(*buf++, base);
+}
+
+static void pmci_read_fifo(void __iomem *base, u32 *buf, size_t count)
+{
+ while (count--)
+ *buf++ = readl(base);
+}
+
+static u32 pmci_get_write_space(struct m10bmc_pmci_device *pmci)
+{
+ u32 val;
+ int ret;
+
+ ret = read_poll_timeout(readl, val,
+ FIELD_GET(M10BMC_N6000_FLASH_FIFO_SPACE, val) ==
+ M10BMC_N6000_FIFO_MAX_WORDS,
+ M10BMC_FLASH_INT_US, M10BMC_FLASH_TIMEOUT_US,
+ false, pmci->base + M10BMC_N6000_FLASH_CTRL);
+ if (ret == -ETIMEDOUT)
+ return 0;
+
+ return FIELD_GET(M10BMC_N6000_FLASH_FIFO_SPACE, val) * M10BMC_N6000_FIFO_WORD_SIZE;
+}
+
+static int pmci_flash_bulk_write(struct intel_m10bmc *m10bmc, const u8 *buf, u32 size)
+{
+ struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc);
+ u32 blk_size, offset = 0, write_count;
+
+ while (size) {
+ blk_size = min(pmci_get_write_space(pmci), size);
+ if (blk_size == 0) {
+ dev_err(m10bmc->dev, "get FIFO available size fail\n");
+ return -EIO;
+ }
+
+ if (size < M10BMC_N6000_FIFO_WORD_SIZE)
+ break;
+
+ write_count = blk_size / M10BMC_N6000_FIFO_WORD_SIZE;
+ pmci_write_fifo(pmci->base + M10BMC_N6000_FLASH_FIFO,
+ (u32 *)(buf + offset), write_count);
+
+ size -= blk_size;
+ offset += blk_size;
+ }
+
+ /* Handle remainder (less than M10BMC_N6000_FIFO_WORD_SIZE bytes) */
+ if (size) {
+ u32 tmp = 0;
+
+ memcpy(&tmp, buf + offset, size);
+ pmci_write_fifo(pmci->base + M10BMC_N6000_FLASH_FIFO, &tmp, 1);
+ }
+
+ return 0;
+}
+
+static int pmci_flash_bulk_read(struct intel_m10bmc *m10bmc, u8 *buf, u32 addr, u32 size)
+{
+ struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc);
+ u32 blk_size, offset = 0, val, full_read_count, read_count;
+ int ret;
+
+ while (size) {
+ blk_size = min_t(u32, size, M10BMC_N6000_READ_BLOCK_SIZE);
+ full_read_count = blk_size / M10BMC_N6000_FIFO_WORD_SIZE;
+
+ read_count = full_read_count;
+ if (full_read_count * M10BMC_N6000_FIFO_WORD_SIZE < blk_size)
+ read_count++;
+
+ writel(addr + offset, pmci->base + M10BMC_N6000_FLASH_ADDR);
+ writel(FIELD_PREP(M10BMC_N6000_FLASH_READ_COUNT, read_count) |
+ M10BMC_N6000_FLASH_RD_MODE,
+ pmci->base + M10BMC_N6000_FLASH_CTRL);
+
+ ret = readl_poll_timeout((pmci->base + M10BMC_N6000_FLASH_CTRL), val,
+ !(val & M10BMC_N6000_FLASH_BUSY),
+ M10BMC_FLASH_INT_US, M10BMC_FLASH_TIMEOUT_US);
+ if (ret) {
+ dev_err(m10bmc->dev, "read timed out on reading flash 0x%xn", val);
+ return ret;
+ }
+
+ pmci_read_fifo(pmci->base + M10BMC_N6000_FLASH_FIFO,
+ (u32 *)(buf + offset), full_read_count);
+
+ size -= blk_size;
+ offset += blk_size;
+
+ if (full_read_count < read_count)
+ break;
+
+ writel(0, pmci->base + M10BMC_N6000_FLASH_CTRL);
+ }
+
+ /* Handle remainder (less than M10BMC_N6000_FIFO_WORD_SIZE bytes) */
+ if (size) {
+ u32 tmp;
+
+ pmci_read_fifo(pmci->base + M10BMC_N6000_FLASH_FIFO, &tmp, 1);
+ memcpy(buf + offset, &tmp, size);
+
+ writel(0, pmci->base + M10BMC_N6000_FLASH_CTRL);
+ }
+
+ return 0;
+}
+
+static int m10bmc_pmci_set_flash_host_mux(struct intel_m10bmc *m10bmc, bool request)
+{
+ u32 ctrl;
+ int ret;
+
+ ret = regmap_update_bits(m10bmc->regmap, M10BMC_N6000_FLASH_MUX_CTRL,
+ M10BMC_N6000_FLASH_HOST_REQUEST,
+ FIELD_PREP(M10BMC_N6000_FLASH_HOST_REQUEST, request));
+ if (ret)
+ return ret;
+
+ return regmap_read_poll_timeout(m10bmc->regmap,
+ M10BMC_N6000_FLASH_MUX_CTRL, ctrl,
+ request ?
+ (get_flash_mux(ctrl) == M10BMC_N6000_FLASH_MUX_HOST) :
+ (get_flash_mux(ctrl) != M10BMC_N6000_FLASH_MUX_HOST),
+ M10BMC_FLASH_INT_US, M10BMC_FLASH_TIMEOUT_US);
+}
+
+static int m10bmc_pmci_flash_read(struct intel_m10bmc *m10bmc, u8 *buf, u32 addr, u32 size)
+{
+ struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc);
+ int ret, ret2;
+
+ mutex_lock(&pmci->flash_mutex);
+ if (pmci->flash_busy) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ ret = m10bmc_pmci_set_flash_host_mux(m10bmc, true);
+ if (ret)
+ goto mux_fail;
+
+ ret = pmci_flash_bulk_read(m10bmc, buf, addr, size);
+
+mux_fail:
+ ret2 = m10bmc_pmci_set_flash_host_mux(m10bmc, false);
+
+unlock:
+ mutex_unlock(&pmci->flash_mutex);
+ if (ret)
+ return ret;
+ return ret2;
+}
+
+static int m10bmc_pmci_flash_write(struct intel_m10bmc *m10bmc, const u8 *buf, u32 offset, u32 size)
+{
+ struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc);
+ int ret;
+
+ mutex_lock(&pmci->flash_mutex);
+ WARN_ON_ONCE(!pmci->flash_busy);
+ /* On write, firmware manages flash MUX */
+ ret = pmci_flash_bulk_write(m10bmc, buf + offset, size);
+ mutex_unlock(&pmci->flash_mutex);
+
+ return ret;
+}
+
+static int m10bmc_pmci_flash_lock(struct intel_m10bmc *m10bmc)
+{
+ struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc);
+ int ret = 0;
+
+ mutex_lock(&pmci->flash_mutex);
+ if (pmci->flash_busy) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ pmci->flash_busy = true;
+
+unlock:
+ mutex_unlock(&pmci->flash_mutex);
+ return ret;
+}
+
+static void m10bmc_pmci_flash_unlock(struct intel_m10bmc *m10bmc)
+{
+ struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc);
+
+ mutex_lock(&pmci->flash_mutex);
+ WARN_ON_ONCE(!pmci->flash_busy);
+ pmci->flash_busy = false;
+ mutex_unlock(&pmci->flash_mutex);
+}
+
+static const struct intel_m10bmc_flash_bulk_ops m10bmc_pmci_flash_bulk_ops = {
+ .read = m10bmc_pmci_flash_read,
+ .write = m10bmc_pmci_flash_write,
+ .lock_write = m10bmc_pmci_flash_lock,
+ .unlock_write = m10bmc_pmci_flash_unlock,
+};
+
+static const struct regmap_range m10bmc_pmci_regmap_range[] = {
+ regmap_reg_range(M10BMC_N6000_SYS_BASE, M10BMC_N6000_SYS_END),
+};
+
+static const struct regmap_access_table m10bmc_pmci_access_table = {
+ .yes_ranges = m10bmc_pmci_regmap_range,
+ .n_yes_ranges = ARRAY_SIZE(m10bmc_pmci_regmap_range),
+};
+
+static struct regmap_config m10bmc_pmci_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .wr_table = &m10bmc_pmci_access_table,
+ .rd_table = &m10bmc_pmci_access_table,
+ .reg_read = &indirect_reg_read,
+ .reg_write = &indirect_reg_write,
+ .max_register = M10BMC_N6000_SYS_END,
+};
+
+static struct mfd_cell m10bmc_pmci_n6000_bmc_subdevs[] = {
+ { .name = "n6000bmc-hwmon" },
+ { .name = "n6000bmc-sec-update" },
+};
+
+static const struct m10bmc_csr_map m10bmc_n6000_csr_map = {
+ .base = M10BMC_N6000_SYS_BASE,
+ .build_version = M10BMC_N6000_BUILD_VER,
+ .fw_version = NIOS2_N6000_FW_VERSION,
+ .mac_low = M10BMC_N6000_MAC_LOW,
+ .mac_high = M10BMC_N6000_MAC_HIGH,
+ .doorbell = M10BMC_N6000_DOORBELL,
+ .auth_result = M10BMC_N6000_AUTH_RESULT,
+ .bmc_prog_addr = M10BMC_N6000_BMC_PROG_ADDR,
+ .bmc_reh_addr = M10BMC_N6000_BMC_REH_ADDR,
+ .bmc_magic = M10BMC_N6000_BMC_PROG_MAGIC,
+ .sr_prog_addr = M10BMC_N6000_SR_PROG_ADDR,
+ .sr_reh_addr = M10BMC_N6000_SR_REH_ADDR,
+ .sr_magic = M10BMC_N6000_SR_PROG_MAGIC,
+ .pr_prog_addr = M10BMC_N6000_PR_PROG_ADDR,
+ .pr_reh_addr = M10BMC_N6000_PR_REH_ADDR,
+ .pr_magic = M10BMC_N6000_PR_PROG_MAGIC,
+ .rsu_update_counter = M10BMC_N6000_STAGING_FLASH_COUNT,
+};
+
+static const struct intel_m10bmc_platform_info m10bmc_pmci_n6000 = {
+ .cells = m10bmc_pmci_n6000_bmc_subdevs,
+ .n_cells = ARRAY_SIZE(m10bmc_pmci_n6000_bmc_subdevs),
+ .csr_map = &m10bmc_n6000_csr_map,
+};
+
+static int m10bmc_pmci_probe(struct dfl_device *ddev)
+{
+ struct device *dev = &ddev->dev;
+ struct m10bmc_pmci_device *pmci;
+ struct indirect_ctx *ctx;
+ int ret;
+
+ pmci = devm_kzalloc(dev, sizeof(*pmci), GFP_KERNEL);
+ if (!pmci)
+ return -ENOMEM;
+
+ pmci->m10bmc.flash_bulk_ops = &m10bmc_pmci_flash_bulk_ops;
+ pmci->m10bmc.dev = dev;
+
+ pmci->base = devm_ioremap_resource(dev, &ddev->mmio_res);
+ if (IS_ERR(pmci->base))
+ return PTR_ERR(pmci->base);
+
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ mutex_init(&pmci->flash_mutex);
+
+ ctx->base = pmci->base + M10BMC_N6000_INDIRECT_BASE;
+ ctx->dev = dev;
+ indirect_clear_cmd(ctx);
+ pmci->m10bmc.regmap = devm_regmap_init(dev, NULL, ctx, &m10bmc_pmci_regmap_config);
+
+ if (IS_ERR(pmci->m10bmc.regmap)) {
+ ret = PTR_ERR(pmci->m10bmc.regmap);
+ goto destroy_mutex;
+ }
+
+ ret = m10bmc_dev_init(&pmci->m10bmc, &m10bmc_pmci_n6000);
+ if (ret)
+ goto destroy_mutex;
+ return 0;
+
+destroy_mutex:
+ mutex_destroy(&pmci->flash_mutex);
+ return ret;
+}
+
+static void m10bmc_pmci_remove(struct dfl_device *ddev)
+{
+ struct intel_m10bmc *m10bmc = dev_get_drvdata(&ddev->dev);
+ struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc);
+
+ mutex_destroy(&pmci->flash_mutex);
+}
+
+#define FME_FEATURE_ID_M10BMC_PMCI 0x12
+
+static const struct dfl_device_id m10bmc_pmci_ids[] = {
+ { FME_ID, FME_FEATURE_ID_M10BMC_PMCI },
+ { }
+};
+MODULE_DEVICE_TABLE(dfl, m10bmc_pmci_ids);
+
+static struct dfl_driver m10bmc_pmci_driver = {
+ .drv = {
+ .name = "intel-m10-bmc",
+ .dev_groups = m10bmc_dev_groups,
+ },
+ .id_table = m10bmc_pmci_ids,
+ .probe = m10bmc_pmci_probe,
+ .remove = m10bmc_pmci_remove,
+};
+
+module_dfl_driver(m10bmc_pmci_driver);
+
+MODULE_DESCRIPTION("MAX10 BMC PMCI-based interface");
+MODULE_AUTHOR("Intel Corporation");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/intel-m10-bmc-spi.c b/drivers/mfd/intel-m10-bmc-spi.c
new file mode 100644
index 000000000000..957200e17fed
--- /dev/null
+++ b/drivers/mfd/intel-m10-bmc-spi.c
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Intel MAX 10 Board Management Controller chip
+ *
+ * Copyright (C) 2018-2020 Intel Corporation. All rights reserved.
+ */
+#include <linux/bitfield.h>
+#include <linux/dev_printk.h>
+#include <linux/init.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/intel-m10-bmc.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+
+static const struct regmap_range m10bmc_regmap_range[] = {
+ regmap_reg_range(M10BMC_N3000_LEGACY_BUILD_VER, M10BMC_N3000_LEGACY_BUILD_VER),
+ regmap_reg_range(M10BMC_N3000_SYS_BASE, M10BMC_N3000_SYS_END),
+ regmap_reg_range(M10BMC_N3000_FLASH_BASE, M10BMC_N3000_FLASH_END),
+};
+
+static const struct regmap_access_table m10bmc_access_table = {
+ .yes_ranges = m10bmc_regmap_range,
+ .n_yes_ranges = ARRAY_SIZE(m10bmc_regmap_range),
+};
+
+static struct regmap_config intel_m10bmc_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .wr_table = &m10bmc_access_table,
+ .rd_table = &m10bmc_access_table,
+ .max_register = M10BMC_N3000_MEM_END,
+};
+
+static int check_m10bmc_version(struct intel_m10bmc *ddata)
+{
+ unsigned int v;
+ int ret;
+
+ /*
+ * This check is to filter out the very old legacy BMC versions. In the
+ * old BMC chips, the BMC version info is stored in the old version
+ * register (M10BMC_N3000_LEGACY_BUILD_VER), so its read out value would have
+ * not been M10BMC_N3000_VER_LEGACY_INVALID (0xffffffff). But in new BMC
+ * chips that the driver supports, the value of this register should be
+ * M10BMC_N3000_VER_LEGACY_INVALID.
+ */
+ ret = m10bmc_raw_read(ddata, M10BMC_N3000_LEGACY_BUILD_VER, &v);
+ if (ret)
+ return -ENODEV;
+
+ if (v != M10BMC_N3000_VER_LEGACY_INVALID) {
+ dev_err(ddata->dev, "bad version M10BMC detected\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int intel_m10_bmc_spi_probe(struct spi_device *spi)
+{
+ const struct spi_device_id *id = spi_get_device_id(spi);
+ const struct intel_m10bmc_platform_info *info;
+ struct device *dev = &spi->dev;
+ struct intel_m10bmc *ddata;
+ int ret;
+
+ ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
+ if (!ddata)
+ return -ENOMEM;
+
+ info = (struct intel_m10bmc_platform_info *)id->driver_data;
+ ddata->dev = dev;
+
+ ddata->regmap = devm_regmap_init_spi_avmm(spi, &intel_m10bmc_regmap_config);
+ if (IS_ERR(ddata->regmap)) {
+ ret = PTR_ERR(ddata->regmap);
+ dev_err(dev, "Failed to allocate regmap: %d\n", ret);
+ return ret;
+ }
+
+ spi_set_drvdata(spi, ddata);
+
+ ret = check_m10bmc_version(ddata);
+ if (ret) {
+ dev_err(dev, "Failed to identify m10bmc hardware\n");
+ return ret;
+ }
+
+ return m10bmc_dev_init(ddata, info);
+}
+
+static const struct m10bmc_csr_map m10bmc_n3000_csr_map = {
+ .base = M10BMC_N3000_SYS_BASE,
+ .build_version = M10BMC_N3000_BUILD_VER,
+ .fw_version = NIOS2_N3000_FW_VERSION,
+ .mac_low = M10BMC_N3000_MAC_LOW,
+ .mac_high = M10BMC_N3000_MAC_HIGH,
+ .doorbell = M10BMC_N3000_DOORBELL,
+ .auth_result = M10BMC_N3000_AUTH_RESULT,
+ .bmc_prog_addr = M10BMC_N3000_BMC_PROG_ADDR,
+ .bmc_reh_addr = M10BMC_N3000_BMC_REH_ADDR,
+ .bmc_magic = M10BMC_N3000_BMC_PROG_MAGIC,
+ .sr_prog_addr = M10BMC_N3000_SR_PROG_ADDR,
+ .sr_reh_addr = M10BMC_N3000_SR_REH_ADDR,
+ .sr_magic = M10BMC_N3000_SR_PROG_MAGIC,
+ .pr_prog_addr = M10BMC_N3000_PR_PROG_ADDR,
+ .pr_reh_addr = M10BMC_N3000_PR_REH_ADDR,
+ .pr_magic = M10BMC_N3000_PR_PROG_MAGIC,
+ .rsu_update_counter = M10BMC_N3000_STAGING_FLASH_COUNT,
+};
+
+static struct mfd_cell m10bmc_d5005_subdevs[] = {
+ { .name = "d5005bmc-hwmon" },
+ { .name = "d5005bmc-sec-update" },
+};
+
+static struct mfd_cell m10bmc_pacn3000_subdevs[] = {
+ { .name = "n3000bmc-hwmon" },
+ { .name = "n3000bmc-retimer" },
+ { .name = "n3000bmc-sec-update" },
+};
+
+static struct mfd_cell m10bmc_n5010_subdevs[] = {
+ { .name = "n5010bmc-hwmon" },
+};
+
+static const struct intel_m10bmc_platform_info m10bmc_spi_n3000 = {
+ .cells = m10bmc_pacn3000_subdevs,
+ .n_cells = ARRAY_SIZE(m10bmc_pacn3000_subdevs),
+ .csr_map = &m10bmc_n3000_csr_map,
+};
+
+static const struct intel_m10bmc_platform_info m10bmc_spi_d5005 = {
+ .cells = m10bmc_d5005_subdevs,
+ .n_cells = ARRAY_SIZE(m10bmc_d5005_subdevs),
+ .csr_map = &m10bmc_n3000_csr_map,
+};
+
+static const struct intel_m10bmc_platform_info m10bmc_spi_n5010 = {
+ .cells = m10bmc_n5010_subdevs,
+ .n_cells = ARRAY_SIZE(m10bmc_n5010_subdevs),
+ .csr_map = &m10bmc_n3000_csr_map,
+};
+
+static const struct spi_device_id m10bmc_spi_id[] = {
+ { "m10-n3000", (kernel_ulong_t)&m10bmc_spi_n3000 },
+ { "m10-d5005", (kernel_ulong_t)&m10bmc_spi_d5005 },
+ { "m10-n5010", (kernel_ulong_t)&m10bmc_spi_n5010 },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, m10bmc_spi_id);
+
+static struct spi_driver intel_m10bmc_spi_driver = {
+ .driver = {
+ .name = "intel-m10-bmc",
+ .dev_groups = m10bmc_dev_groups,
+ },
+ .probe = intel_m10_bmc_spi_probe,
+ .id_table = m10bmc_spi_id,
+};
+module_spi_driver(intel_m10bmc_spi_driver);
+
+MODULE_DESCRIPTION("Intel MAX 10 BMC SPI bus interface");
+MODULE_AUTHOR("Intel Corporation");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("spi:intel-m10-bmc");
diff --git a/drivers/mfd/intel-m10-bmc.c b/drivers/mfd/intel-m10-bmc.c
deleted file mode 100644
index 7e3319e5b22f..000000000000
--- a/drivers/mfd/intel-m10-bmc.c
+++ /dev/null
@@ -1,238 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Intel MAX 10 Board Management Controller chip
- *
- * Copyright (C) 2018-2020 Intel Corporation. All rights reserved.
- */
-#include <linux/bitfield.h>
-#include <linux/init.h>
-#include <linux/mfd/core.h>
-#include <linux/mfd/intel-m10-bmc.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/regmap.h>
-#include <linux/spi/spi.h>
-
-enum m10bmc_type {
- M10_N3000,
- M10_D5005,
- M10_N5010,
-};
-
-static struct mfd_cell m10bmc_d5005_subdevs[] = {
- { .name = "d5005bmc-hwmon" },
- { .name = "d5005bmc-sec-update" }
-};
-
-static struct mfd_cell m10bmc_pacn3000_subdevs[] = {
- { .name = "n3000bmc-hwmon" },
- { .name = "n3000bmc-retimer" },
- { .name = "n3000bmc-sec-update" },
-};
-
-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),
- regmap_reg_range(M10BMC_FLASH_BASE, M10BMC_FLASH_END),
-};
-
-static const struct regmap_access_table m10bmc_access_table = {
- .yes_ranges = m10bmc_regmap_range,
- .n_yes_ranges = ARRAY_SIZE(m10bmc_regmap_range),
-};
-
-static struct regmap_config intel_m10bmc_regmap_config = {
- .reg_bits = 32,
- .val_bits = 32,
- .reg_stride = 4,
- .wr_table = &m10bmc_access_table,
- .rd_table = &m10bmc_access_table,
- .max_register = M10BMC_MEM_END,
-};
-
-static ssize_t bmc_version_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct intel_m10bmc *ddata = dev_get_drvdata(dev);
- unsigned int val;
- int ret;
-
- ret = m10bmc_sys_read(ddata, M10BMC_BUILD_VER, &val);
- if (ret)
- return ret;
-
- return sprintf(buf, "0x%x\n", val);
-}
-static DEVICE_ATTR_RO(bmc_version);
-
-static ssize_t bmcfw_version_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct intel_m10bmc *ddata = dev_get_drvdata(dev);
- unsigned int val;
- int ret;
-
- ret = m10bmc_sys_read(ddata, NIOS2_FW_VERSION, &val);
- if (ret)
- return ret;
-
- return sprintf(buf, "0x%x\n", val);
-}
-static DEVICE_ATTR_RO(bmcfw_version);
-
-static ssize_t mac_address_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct intel_m10bmc *max10 = dev_get_drvdata(dev);
- unsigned int macaddr_low, macaddr_high;
- int ret;
-
- ret = m10bmc_sys_read(max10, M10BMC_MAC_LOW, &macaddr_low);
- if (ret)
- return ret;
-
- ret = m10bmc_sys_read(max10, M10BMC_MAC_HIGH, &macaddr_high);
- if (ret)
- return ret;
-
- return sysfs_emit(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n",
- (u8)FIELD_GET(M10BMC_MAC_BYTE1, macaddr_low),
- (u8)FIELD_GET(M10BMC_MAC_BYTE2, macaddr_low),
- (u8)FIELD_GET(M10BMC_MAC_BYTE3, macaddr_low),
- (u8)FIELD_GET(M10BMC_MAC_BYTE4, macaddr_low),
- (u8)FIELD_GET(M10BMC_MAC_BYTE5, macaddr_high),
- (u8)FIELD_GET(M10BMC_MAC_BYTE6, macaddr_high));
-}
-static DEVICE_ATTR_RO(mac_address);
-
-static ssize_t mac_count_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct intel_m10bmc *max10 = dev_get_drvdata(dev);
- unsigned int macaddr_high;
- int ret;
-
- ret = m10bmc_sys_read(max10, M10BMC_MAC_HIGH, &macaddr_high);
- if (ret)
- return ret;
-
- return sysfs_emit(buf, "%u\n",
- (u8)FIELD_GET(M10BMC_MAC_COUNT, macaddr_high));
-}
-static DEVICE_ATTR_RO(mac_count);
-
-static struct attribute *m10bmc_attrs[] = {
- &dev_attr_bmc_version.attr,
- &dev_attr_bmcfw_version.attr,
- &dev_attr_mac_address.attr,
- &dev_attr_mac_count.attr,
- NULL,
-};
-ATTRIBUTE_GROUPS(m10bmc);
-
-static int check_m10bmc_version(struct intel_m10bmc *ddata)
-{
- unsigned int v;
- int ret;
-
- /*
- * This check is to filter out the very old legacy BMC versions. In the
- * old BMC chips, the BMC version info is stored in the old version
- * register (M10BMC_LEGACY_BUILD_VER), so its read out value would have
- * not been M10BMC_VER_LEGACY_INVALID (0xffffffff). But in new BMC
- * chips that the driver supports, the value of this register should be
- * M10BMC_VER_LEGACY_INVALID.
- */
- ret = m10bmc_raw_read(ddata, M10BMC_LEGACY_BUILD_VER, &v);
- if (ret)
- return -ENODEV;
-
- if (v != M10BMC_VER_LEGACY_INVALID) {
- dev_err(ddata->dev, "bad version M10BMC detected\n");
- return -ENODEV;
- }
-
- return 0;
-}
-
-static int intel_m10_bmc_spi_probe(struct spi_device *spi)
-{
- const struct spi_device_id *id = spi_get_device_id(spi);
- struct device *dev = &spi->dev;
- struct mfd_cell *cells;
- struct intel_m10bmc *ddata;
- int ret, n_cell;
-
- ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
- if (!ddata)
- return -ENOMEM;
-
- ddata->dev = dev;
-
- ddata->regmap =
- devm_regmap_init_spi_avmm(spi, &intel_m10bmc_regmap_config);
- if (IS_ERR(ddata->regmap)) {
- ret = PTR_ERR(ddata->regmap);
- dev_err(dev, "Failed to allocate regmap: %d\n", ret);
- return ret;
- }
-
- spi_set_drvdata(spi, ddata);
-
- ret = check_m10bmc_version(ddata);
- if (ret) {
- dev_err(dev, "Failed to identify m10bmc hardware\n");
- return ret;
- }
-
- switch (id->driver_data) {
- case M10_N3000:
- cells = m10bmc_pacn3000_subdevs;
- n_cell = ARRAY_SIZE(m10bmc_pacn3000_subdevs);
- break;
- case M10_D5005:
- 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;
- }
-
- ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, cells, n_cell,
- NULL, 0, NULL);
- if (ret)
- dev_err(dev, "Failed to register sub-devices: %d\n", ret);
-
- return ret;
-}
-
-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);
-
-static struct spi_driver intel_m10bmc_spi_driver = {
- .driver = {
- .name = "intel-m10-bmc",
- .dev_groups = m10bmc_groups,
- },
- .probe = intel_m10_bmc_spi_probe,
- .id_table = m10bmc_spi_id,
-};
-module_spi_driver(intel_m10bmc_spi_driver);
-
-MODULE_DESCRIPTION("Intel MAX 10 BMC Device Driver");
-MODULE_AUTHOR("Intel Corporation");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("spi:intel-m10-bmc");
diff --git a/drivers/mfd/intel_soc_pmic_chtwc.c b/drivers/mfd/intel_soc_pmic_chtwc.c
index 9216f0d34206..d53dae255490 100644
--- a/drivers/mfd/intel_soc_pmic_chtwc.c
+++ b/drivers/mfd/intel_soc_pmic_chtwc.c
@@ -165,6 +165,14 @@ static const struct dmi_system_id cht_wc_model_dmi_ids[] = {
/* Non exact match to match all versions */
DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X9"),
},
+ }, {
+ /* Lenovo Yoga Tab 3 Pro YT3-X90F */
+ .driver_data = (void *)(long)INTEL_CHT_WC_LENOVO_YT3_X90,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "Blade3-10A-001"),
+ },
},
{ }
};
diff --git a/drivers/mfd/kempld-core.c b/drivers/mfd/kempld-core.c
index bb26241c73bd..33c6cfe9fe42 100644
--- a/drivers/mfd/kempld-core.c
+++ b/drivers/mfd/kempld-core.c
@@ -349,7 +349,7 @@ static ssize_t pld_version_show(struct device *dev,
{
struct kempld_device_data *pld = dev_get_drvdata(dev);
- return scnprintf(buf, PAGE_SIZE, "%s\n", pld->info.version);
+ return sysfs_emit(buf, "%s\n", pld->info.version);
}
static ssize_t pld_specification_show(struct device *dev,
@@ -357,8 +357,7 @@ static ssize_t pld_specification_show(struct device *dev,
{
struct kempld_device_data *pld = dev_get_drvdata(dev);
- return scnprintf(buf, PAGE_SIZE, "%d.%d\n", pld->info.spec_major,
- pld->info.spec_minor);
+ return sysfs_emit(buf, "%d.%d\n", pld->info.spec_major, pld->info.spec_minor);
}
static ssize_t pld_type_show(struct device *dev,
@@ -366,7 +365,7 @@ static ssize_t pld_type_show(struct device *dev,
{
struct kempld_device_data *pld = dev_get_drvdata(dev);
- return scnprintf(buf, PAGE_SIZE, "%s\n", kempld_get_type_string(pld));
+ return sysfs_emit(buf, "%s\n", kempld_get_type_string(pld));
}
static DEVICE_ATTR_RO(pld_version);
diff --git a/drivers/mfd/lm3533-core.c b/drivers/mfd/lm3533-core.c
index 74a553329416..946f94f3a3c3 100644
--- a/drivers/mfd/lm3533-core.c
+++ b/drivers/mfd/lm3533-core.c
@@ -286,7 +286,7 @@ static ssize_t show_output(struct device *dev,
val = (val & mask) >> shift;
- return scnprintf(buf, PAGE_SIZE, "%u\n", val);
+ return sysfs_emit(buf, "%u\n", val);
}
static ssize_t store_output(struct device *dev,
diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c
index eb3f061c8ee6..0246bbe80354 100644
--- a/drivers/mfd/max8925-core.c
+++ b/drivers/mfd/max8925-core.c
@@ -469,12 +469,6 @@ static struct max8925_irq_data max8925_irqs[] = {
},
};
-static inline struct max8925_irq_data *irq_to_max8925(struct max8925_chip *chip,
- int irq)
-{
- return &max8925_irqs[irq - chip->irq_base];
-}
-
static irqreturn_t max8925_irq(int irq, void *data)
{
struct max8925_chip *chip = data;
diff --git a/drivers/mfd/ntxec.c b/drivers/mfd/ntxec.c
index e16a7a82a929..b02785b10d48 100644
--- a/drivers/mfd/ntxec.c
+++ b/drivers/mfd/ntxec.c
@@ -175,6 +175,7 @@ static int ntxec_probe(struct i2c_client *client)
/* Bail out if we encounter an unknown firmware version */
switch (version) {
case NTXEC_VERSION_KOBO_AURA:
+ case NTXEC_VERSION_TOLINO_VISION:
subdevs = ntxec_subdev;
n_subdevs = ARRAY_SIZE(ntxec_subdev);
break;
diff --git a/drivers/mfd/pcf50633-adc.c b/drivers/mfd/pcf50633-adc.c
index 5cd653e61512..191b1bc6141c 100644
--- a/drivers/mfd/pcf50633-adc.c
+++ b/drivers/mfd/pcf50633-adc.c
@@ -136,6 +136,7 @@ int pcf50633_adc_async_read(struct pcf50633 *pcf, int mux, int avg,
void *callback_param)
{
struct pcf50633_adc_request *req;
+ int ret;
/* req is freed when the result is ready, in interrupt handler */
req = kmalloc(sizeof(*req), GFP_KERNEL);
@@ -147,7 +148,11 @@ int pcf50633_adc_async_read(struct pcf50633 *pcf, int mux, int avg,
req->callback = callback;
req->callback_param = callback_param;
- return adc_enqueue_request(pcf, req);
+ ret = adc_enqueue_request(pcf, req);
+ if (ret)
+ kfree(req);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(pcf50633_adc_async_read);
diff --git a/drivers/mfd/qcom-pm8xxx.c b/drivers/mfd/qcom-pm8xxx.c
index 601106580e2e..9a948df8c28d 100644
--- a/drivers/mfd/qcom-pm8xxx.c
+++ b/drivers/mfd/qcom-pm8xxx.c
@@ -510,7 +510,6 @@ static int pm8xxx_probe(struct platform_device *pdev)
struct regmap *regmap;
int irq, rc;
unsigned int val;
- u32 rev;
struct pm_irq_chip *chip;
data = of_device_get_match_data(&pdev->dev);
@@ -535,7 +534,6 @@ static int pm8xxx_probe(struct platform_device *pdev)
return rc;
}
pr_info("PMIC revision 1: %02X\n", val);
- rev = val;
/* Read PMIC chip revision 2 */
rc = regmap_read(regmap, REG_HWREV_2, &val);
@@ -545,7 +543,6 @@ static int pm8xxx_probe(struct platform_device *pdev)
return rc;
}
pr_info("PMIC revision 2: %02X\n", val);
- rev |= val << BITS_PER_BYTE;
chip = devm_kzalloc(&pdev->dev,
struct_size(chip, config, data->num_irqs),
diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c
index f44fc3f080a8..0f22ef61e817 100644
--- a/drivers/mfd/rk808.c
+++ b/drivers/mfd/rk808.c
@@ -189,6 +189,7 @@ static const struct mfd_cell rk817s[] = {
};
static const struct mfd_cell rk818s[] = {
+ { .name = "rk808-clkout", .id = PLATFORM_DEVID_NONE, },
{ .name = "rk808-regulator", .id = PLATFORM_DEVID_NONE, },
{
.name = "rk808-rtc",
diff --git a/drivers/mfd/simple-mfd-i2c.c b/drivers/mfd/simple-mfd-i2c.c
index f4c8fc3ee463..e31f13fd6a79 100644
--- a/drivers/mfd/simple-mfd-i2c.c
+++ b/drivers/mfd/simple-mfd-i2c.c
@@ -48,7 +48,7 @@ static int simple_mfd_i2c_probe(struct i2c_client *i2c)
if (IS_ERR(regmap))
return PTR_ERR(regmap);
- /* If no MFD cells are spedified, use register the DT child nodes instead */
+ /* If no MFD cells are specified, register using the DT child nodes instead */
if (!simple_mfd_data || !simple_mfd_data->mfd_cell)
return devm_of_platform_populate(&i2c->dev);
diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c
index bdb2ce7ff03b..57b29c325131 100644
--- a/drivers/mfd/syscon.c
+++ b/drivers/mfd/syscon.c
@@ -20,6 +20,7 @@
#include <linux/platform_data/syscon.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
+#include <linux/reset.h>
#include <linux/mfd/syscon.h>
#include <linux/slab.h>
@@ -31,6 +32,7 @@ static LIST_HEAD(syscon_list);
struct syscon {
struct device_node *np;
struct regmap *regmap;
+ struct reset_control *reset;
struct list_head list;
};
@@ -40,7 +42,7 @@ static const struct regmap_config syscon_regmap_config = {
.reg_stride = 4,
};
-static struct syscon *of_syscon_register(struct device_node *np, bool check_clk)
+static struct syscon *of_syscon_register(struct device_node *np, bool check_res)
{
struct clk *clk;
struct syscon *syscon;
@@ -50,6 +52,7 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_clk)
int ret;
struct regmap_config syscon_config = syscon_regmap_config;
struct resource res;
+ struct reset_control *reset;
syscon = kzalloc(sizeof(*syscon), GFP_KERNEL);
if (!syscon)
@@ -114,7 +117,7 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_clk)
goto err_regmap;
}
- if (check_clk) {
+ if (check_res) {
clk = of_clk_get(np, 0);
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
@@ -124,8 +127,18 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_clk)
} else {
ret = regmap_mmio_attach_clk(regmap, clk);
if (ret)
- goto err_attach;
+ goto err_attach_clk;
}
+
+ reset = of_reset_control_get_optional_exclusive(np, NULL);
+ if (IS_ERR(reset)) {
+ ret = PTR_ERR(reset);
+ goto err_attach_clk;
+ }
+
+ ret = reset_control_deassert(reset);
+ if (ret)
+ goto err_reset;
}
syscon->regmap = regmap;
@@ -137,7 +150,9 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_clk)
return syscon;
-err_attach:
+err_reset:
+ reset_control_put(reset);
+err_attach_clk:
if (!IS_ERR(clk))
clk_put(clk);
err_clk:
@@ -150,7 +165,7 @@ err_map:
}
static struct regmap *device_node_get_regmap(struct device_node *np,
- bool check_clk)
+ bool check_res)
{
struct syscon *entry, *syscon = NULL;
@@ -165,7 +180,7 @@ static struct regmap *device_node_get_regmap(struct device_node *np,
spin_unlock(&syscon_list_slock);
if (!syscon)
- syscon = of_syscon_register(np, check_clk);
+ syscon = of_syscon_register(np, check_res);
if (IS_ERR(syscon))
return ERR_CAST(syscon);
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 62be2326c9b2..e2d9a93be43b 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -110,8 +110,8 @@
#define TWL6030_BASEADD_PWM 0x00BA
#define TWL6030_BASEADD_GASGAUGE 0x00C0
#define TWL6030_BASEADD_PIH 0x00D0
-#define TWL6030_BASEADD_CHARGER 0x00E0
#define TWL6032_BASEADD_CHARGER 0x00DA
+#define TWL6030_BASEADD_CHARGER 0x00E0
#define TWL6030_BASEADD_LED 0x00F4
/* subchip/slave 2 0x4A - DFT */
@@ -353,6 +353,9 @@ static struct twl_mapping twl6030_map[] = {
{ 2, TWL6030_BASEADD_ZERO },
{ 1, TWL6030_BASEADD_GPADC_CTRL },
{ 1, TWL6030_BASEADD_GASGAUGE },
+
+ /* TWL6032 specific charger registers */
+ { 1, TWL6032_BASEADD_CHARGER },
};
static const struct regmap_config twl6030_regmap_config[3] = {
@@ -803,10 +806,6 @@ twl_probe(struct i2c_client *client)
if ((id->driver_data) & TWL6030_CLASS) {
twl_priv->twl_id = TWL6030_CLASS_ID;
twl_priv->twl_map = &twl6030_map[0];
- /* The charger base address is different in twl6032 */
- if ((id->driver_data) & TWL6032_SUBCLASS)
- twl_priv->twl_map[TWL_MODULE_MAIN_CHARGE].base =
- TWL6032_BASEADD_CHARGER;
twl_regmap_config = twl6030_regmap_config;
} else {
twl_priv->twl_id = TWL4030_CLASS_ID;
diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c
index 6b36932263ba..e35b0f788c50 100644
--- a/drivers/mfd/twl4030-power.c
+++ b/drivers/mfd/twl4030-power.c
@@ -953,18 +953,12 @@ relock:
return err;
}
-static int twl4030_power_remove(struct platform_device *pdev)
-{
- return 0;
-}
-
static struct platform_driver twl4030_power_driver = {
.driver = {
.name = "twl4030_power",
.of_match_table = of_match_ptr(twl4030_power_of_match),
},
.probe = twl4030_power_probe,
- .remove = twl4030_power_remove,
};
module_platform_driver(twl4030_power_driver);