summaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/Kconfig86
-rw-r--r--drivers/mfd/Makefile7
-rw-r--r--drivers/mfd/ab3100-core.c929
-rw-r--r--drivers/mfd/ab3100-otp.c240
-rw-r--r--drivers/mfd/ab8500-core.c37
-rw-r--r--drivers/mfd/arizona-core.c20
-rw-r--r--drivers/mfd/arizona-irq.c2
-rw-r--r--drivers/mfd/arizona-spi.c4
-rw-r--r--drivers/mfd/atc260x-core.c310
-rw-r--r--drivers/mfd/atc260x-i2c.c64
-rw-r--r--drivers/mfd/da9063-i2c.c10
-rw-r--r--drivers/mfd/ene-kb3930.c2
-rw-r--r--drivers/mfd/intel-lpss-acpi.c32
-rw-r--r--drivers/mfd/intel-lpss-pci.c46
-rw-r--r--drivers/mfd/intel-lpss.c2
-rw-r--r--drivers/mfd/intel-lpss.h4
-rw-r--r--drivers/mfd/intel-m10-bmc.c40
-rw-r--r--drivers/mfd/intel_pmt.c112
-rw-r--r--drivers/mfd/intel_quark_i2c_gpio.c118
-rw-r--r--drivers/mfd/lm3533-core.c2
-rw-r--r--drivers/mfd/lpc_sch.c32
-rw-r--r--drivers/mfd/max8997.c4
-rw-r--r--drivers/mfd/mfd-core.c29
-rw-r--r--drivers/mfd/ntxec.c271
-rw-r--r--drivers/mfd/rn5t618.c3
-rw-r--r--drivers/mfd/rohm-bd71828.c486
-rw-r--r--drivers/mfd/rohm-bd718x7.c43
-rw-r--r--drivers/mfd/rohm-bd9576.c189
-rw-r--r--drivers/mfd/sec-core.c14
-rw-r--r--drivers/mfd/stm32-timers.c7
-rw-r--r--drivers/mfd/stmpe.c14
31 files changed, 1567 insertions, 1592 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index b74efa469e90..5c7f2b100191 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -21,7 +21,7 @@ config MFD_CS5535
config MFD_ALTERA_A10SR
bool "Altera Arria10 DevKit System Resource chip"
- depends on ARCH_SOCFPGA && SPI_MASTER=y && OF
+ depends on ARCH_INTEL_SOCFPGA && SPI_MASTER=y && OF
select REGMAP_SPI
select MFD_CORE
help
@@ -32,7 +32,7 @@ config MFD_ALTERA_A10SR
config MFD_ALTERA_SYSMGR
bool "Altera SOCFPGA System Manager"
- depends on (ARCH_SOCFPGA || ARCH_STRATIX10) && OF
+ depends on ARCH_INTEL_SOCFPGA && OF
select MFD_SYSCON
help
Select this to get System Manager support for all Altera branded
@@ -967,6 +967,17 @@ config MFD_VIPERBOARD
You need to select the mfd cell drivers separately.
The drivers do not support all features the board exposes.
+config MFD_NTXEC
+ tristate "Netronix embedded controller (EC)"
+ depends on OF || COMPILE_TEST
+ depends on I2C
+ select REGMAP_I2C
+ select MFD_CORE
+ help
+ Say yes here if you want to support the embedded controller found in
+ certain e-book readers designed by the original design manufacturer
+ Netronix.
+
config MFD_RETU
tristate "Nokia Retu and Tahvo multi-function device"
select MFD_CORE
@@ -1224,7 +1235,8 @@ config MFD_SC27XX_PMIC
config ABX500_CORE
bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions"
- default y if ARCH_U300 || ARCH_U8500 || COMPILE_TEST
+ depends on ARCH_U8500 || COMPILE_TEST
+ default y if ARCH_U8500
help
Say yes here if you have the ABX500 Mixed Signal IC family
chips. This core driver expose register access functions.
@@ -1232,30 +1244,6 @@ config ABX500_CORE
remain unchanged when IC changes. Binding of the functions to
actual register access is done by the IC core driver.
-config AB3100_CORE
- bool "ST-Ericsson AB3100 Mixed Signal Circuit core functions"
- depends on I2C=y && ABX500_CORE
- select MFD_CORE
- default y if ARCH_U300
- help
- Select this to enable the AB3100 Mixed Signal IC core
- functionality. This connects to a AB3100 on the I2C bus
- and expose a number of symbols needed for dependent devices
- to read and write registers and subscribe to events from
- this multi-functional IC. This is needed to use other features
- of the AB3100 such as battery-backed RTC, charging control,
- LEDs, vibrator, system power and temperature, power management
- and ALSA sound.
-
-config AB3100_OTP
- tristate "ST-Ericsson AB3100 OTP functions"
- depends on AB3100_CORE
- default y if AB3100_CORE
- help
- Select this to enable the AB3100 Mixed Signal IC OTP (one-time
- programmable memory) support. This exposes a sysfs file to read
- out OTP values.
-
config AB8500_CORE
bool "ST-Ericsson AB8500 Mixed Signal Power Management chip"
depends on ABX500_CORE && MFD_DB8500_PRCMU
@@ -1975,19 +1963,31 @@ config MFD_ROHM_BD70528
charger.
config MFD_ROHM_BD71828
- tristate "ROHM BD71828 Power Management IC"
+ tristate "ROHM BD71828 and BD71815 Power Management IC"
depends on I2C=y
depends on OF
select REGMAP_I2C
select REGMAP_IRQ
select MFD_CORE
help
- Select this option to get support for the ROHM BD71828 Power
- Management IC. BD71828GW is a single-chip power management IC for
- battery-powered portable devices. The IC integrates 7 buck
- converters, 7 LDOs, and a 1500 mA single-cell linear charger.
- Also included is a Coulomb counter, a real-time clock (RTC), and
- a 32.768 kHz clock gate.
+ Select this option to get support for the ROHM BD71828 and BD71815
+ Power Management ICs. BD71828GW and BD71815AGW are single-chip power
+ management ICs mainly for battery-powered portable devices.
+ The BD71828 integrates 7 buck converters and 7 LDOs. The BD71815
+ has 5 bucks, 7 LDOs, and a boost for driving LEDs. Both ICs provide
+ also a single-cell linear charger, a Coulomb counter, a real-time
+ clock (RTC), GPIOs and a 32.768 kHz clock gate.
+
+config MFD_ROHM_BD957XMUF
+ tristate "ROHM BD9576MUF and BD9573MUF Power Management ICs"
+ depends on I2C=y
+ depends on OF
+ select REGMAP_I2C
+ select MFD_CORE
+ help
+ Select this option to get support for the ROHM BD9576MUF and
+ BD9573MUF Power Management ICs. BD9576 and BD9573 are primarily
+ designed to be used to power R-Car series processors.
config MFD_STM32_LPTIMER
tristate "Support for STM32 Low-Power Timer"
@@ -2055,6 +2055,24 @@ config MFD_WCD934X
This driver provides common support WCD934x audio codec and its
associated Pin Controller, Soundwire Controller and Audio codec.
+config MFD_ATC260X
+ tristate
+ select MFD_CORE
+ select REGMAP
+ select REGMAP_IRQ
+
+config MFD_ATC260X_I2C
+ tristate "Actions Semi ATC260x PMICs with I2C"
+ select MFD_ATC260X
+ select REGMAP_I2C
+ depends on I2C
+ help
+ Support for the Actions Semi ATC260x PMICs controlled via I2C.
+
+ This driver provides common support for accessing the ATC2603C
+ and ATC2609A chip variants, additional drivers must be enabled
+ in order to use the functionality of the device.
+
config MFD_KHADAS_MCU
tristate "Support for Khadas System control Microcontroller"
depends on I2C
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 834f5463af28..4f6d2b8a5f76 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -178,8 +178,6 @@ obj-$(CONFIG_MFD_PCF50633) += pcf50633.o
obj-$(CONFIG_PCF50633_ADC) += pcf50633-adc.o
obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o
obj-$(CONFIG_ABX500_CORE) += abx500-core.o
-obj-$(CONFIG_AB3100_CORE) += ab3100-core.o
-obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o
obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o
obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o
# ab8500-core need to come after db8500-prcmu (which provides the channel)
@@ -218,6 +216,7 @@ obj-$(CONFIG_MFD_INTEL_PMC_BXT) += intel_pmc_bxt.o
obj-$(CONFIG_MFD_INTEL_PMT) += intel_pmt.o
obj-$(CONFIG_MFD_PALMAS) += palmas.o
obj-$(CONFIG_MFD_VIPERBOARD) += viperboard.o
+obj-$(CONFIG_MFD_NTXEC) += ntxec.o
obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o
obj-$(CONFIG_MFD_RK808) += rk808.o
obj-$(CONFIG_MFD_RN5T618) += rn5t618.o
@@ -261,6 +260,7 @@ obj-$(CONFIG_RAVE_SP_CORE) += rave-sp.o
obj-$(CONFIG_MFD_ROHM_BD70528) += rohm-bd70528.o
obj-$(CONFIG_MFD_ROHM_BD71828) += rohm-bd71828.o
obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o
+obj-$(CONFIG_MFD_ROHM_BD957XMUF) += rohm-bd9576.o
obj-$(CONFIG_MFD_STMFX) += stmfx.o
obj-$(CONFIG_MFD_KHADAS_MCU) += khadas-mcu.o
obj-$(CONFIG_MFD_ACER_A500_EC) += acer-ec-a500.o
@@ -268,3 +268,6 @@ obj-$(CONFIG_MFD_ACER_A500_EC) += acer-ec-a500.o
obj-$(CONFIG_SGI_MFD_IOC3) += ioc3.o
obj-$(CONFIG_MFD_SIMPLE_MFD_I2C) += simple-mfd-i2c.o
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
diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c
deleted file mode 100644
index ee71ae04b5e6..000000000000
--- a/drivers/mfd/ab3100-core.c
+++ /dev/null
@@ -1,929 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 2007-2010 ST-Ericsson
- * Low-level core for exclusive access to the AB3100 IC on the I2C bus
- * and some basic chip-configuration.
- * Author: Linus Walleij <linus.walleij@stericsson.com>
- */
-
-#include <linux/i2c.h>
-#include <linux/mutex.h>
-#include <linux/list.h>
-#include <linux/notifier.h>
-#include <linux/slab.h>
-#include <linux/err.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/device.h>
-#include <linux/interrupt.h>
-#include <linux/random.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/uaccess.h>
-#include <linux/mfd/core.h>
-#include <linux/mfd/ab3100.h>
-#include <linux/mfd/abx500.h>
-
-/* These are the only registers inside AB3100 used in this main file */
-
-/* Interrupt event registers */
-#define AB3100_EVENTA1 0x21
-#define AB3100_EVENTA2 0x22
-#define AB3100_EVENTA3 0x23
-
-/* AB3100 DAC converter registers */
-#define AB3100_DIS 0x00
-#define AB3100_D0C 0x01
-#define AB3100_D1C 0x02
-#define AB3100_D2C 0x03
-#define AB3100_D3C 0x04
-
-/* Chip ID register */
-#define AB3100_CID 0x20
-
-/* AB3100 interrupt registers */
-#define AB3100_IMRA1 0x24
-#define AB3100_IMRA2 0x25
-#define AB3100_IMRA3 0x26
-#define AB3100_IMRB1 0x2B
-#define AB3100_IMRB2 0x2C
-#define AB3100_IMRB3 0x2D
-
-/* System Power Monitoring and control registers */
-#define AB3100_MCA 0x2E
-#define AB3100_MCB 0x2F
-
-/* SIM power up */
-#define AB3100_SUP 0x50
-
-/*
- * I2C communication
- *
- * The AB3100 is usually assigned address 0x48 (7-bit)
- * The chip is defined in the platform i2c_board_data section.
- */
-static int ab3100_get_chip_id(struct device *dev)
-{
- struct ab3100 *ab3100 = dev_get_drvdata(dev->parent);
-
- return (int)ab3100->chip_id;
-}
-
-static int ab3100_set_register_interruptible(struct ab3100 *ab3100,
- u8 reg, u8 regval)
-{
- u8 regandval[2] = {reg, regval};
- int err;
-
- err = mutex_lock_interruptible(&ab3100->access_mutex);
- if (err)
- return err;
-
- /*
- * A two-byte write message with the first byte containing the register
- * number and the second byte containing the value to be written
- * effectively sets a register in the AB3100.
- */
- err = i2c_master_send(ab3100->i2c_client, regandval, 2);
- if (err < 0) {
- dev_err(ab3100->dev,
- "write error (write register): %d\n",
- err);
- } else if (err != 2) {
- dev_err(ab3100->dev,
- "write error (write register)\n"
- " %d bytes transferred (expected 2)\n",
- err);
- err = -EIO;
- } else {
- /* All is well */
- err = 0;
- }
- mutex_unlock(&ab3100->access_mutex);
- return err;
-}
-
-static int set_register_interruptible(struct device *dev,
- u8 bank, u8 reg, u8 value)
-{
- struct ab3100 *ab3100 = dev_get_drvdata(dev->parent);
-
- return ab3100_set_register_interruptible(ab3100, reg, value);
-}
-
-/*
- * The test registers exist at an I2C bus address up one
- * from the ordinary base. They are not supposed to be used
- * in production code, but sometimes you have to do that
- * anyway. It's currently only used from this file so declare
- * it static and do not export.
- */
-static int ab3100_set_test_register_interruptible(struct ab3100 *ab3100,
- u8 reg, u8 regval)
-{
- u8 regandval[2] = {reg, regval};
- int err;
-
- err = mutex_lock_interruptible(&ab3100->access_mutex);
- if (err)
- return err;
-
- err = i2c_master_send(ab3100->testreg_client, regandval, 2);
- if (err < 0) {
- dev_err(ab3100->dev,
- "write error (write test register): %d\n",
- err);
- } else if (err != 2) {
- dev_err(ab3100->dev,
- "write error (write test register)\n"
- " %d bytes transferred (expected 2)\n",
- err);
- err = -EIO;
- } else {
- /* All is well */
- err = 0;
- }
- mutex_unlock(&ab3100->access_mutex);
-
- return err;
-}
-
-static int ab3100_get_register_interruptible(struct ab3100 *ab3100,
- u8 reg, u8 *regval)
-{
- int err;
-
- err = mutex_lock_interruptible(&ab3100->access_mutex);
- if (err)
- return err;
-
- /*
- * AB3100 require an I2C "stop" command between each message, else
- * it will not work. The only way of achieveing this with the
- * message transport layer is to send the read and write messages
- * separately.
- */
- err = i2c_master_send(ab3100->i2c_client, &reg, 1);
- if (err < 0) {
- dev_err(ab3100->dev,
- "write error (send register address): %d\n",
- err);
- goto get_reg_out_unlock;
- } else if (err != 1) {
- dev_err(ab3100->dev,
- "write error (send register address)\n"
- " %d bytes transferred (expected 1)\n",
- err);
- err = -EIO;
- goto get_reg_out_unlock;
- } else {
- /* All is well */
- err = 0;
- }
-
- err = i2c_master_recv(ab3100->i2c_client, regval, 1);
- if (err < 0) {
- dev_err(ab3100->dev,
- "write error (read register): %d\n",
- err);
- goto get_reg_out_unlock;
- } else if (err != 1) {
- dev_err(ab3100->dev,
- "write error (read register)\n"
- " %d bytes transferred (expected 1)\n",
- err);
- err = -EIO;
- goto get_reg_out_unlock;
- } else {
- /* All is well */
- err = 0;
- }
-
- get_reg_out_unlock:
- mutex_unlock(&ab3100->access_mutex);
- return err;
-}
-
-static int get_register_interruptible(struct device *dev, u8 bank, u8 reg,
- u8 *value)
-{
- struct ab3100 *ab3100 = dev_get_drvdata(dev->parent);
-
- return ab3100_get_register_interruptible(ab3100, reg, value);
-}
-
-static int ab3100_get_register_page_interruptible(struct ab3100 *ab3100,
- u8 first_reg, u8 *regvals, u8 numregs)
-{
- int err;
-
- if (ab3100->chip_id == 0xa0 ||
- ab3100->chip_id == 0xa1)
- /* These don't support paged reads */
- return -EIO;
-
- err = mutex_lock_interruptible(&ab3100->access_mutex);
- if (err)
- return err;
-
- /*
- * Paged read also require an I2C "stop" command.
- */
- err = i2c_master_send(ab3100->i2c_client, &first_reg, 1);
- if (err < 0) {
- dev_err(ab3100->dev,
- "write error (send first register address): %d\n",
- err);
- goto get_reg_page_out_unlock;
- } else if (err != 1) {
- dev_err(ab3100->dev,
- "write error (send first register address)\n"
- " %d bytes transferred (expected 1)\n",
- err);
- err = -EIO;
- goto get_reg_page_out_unlock;
- }
-
- err = i2c_master_recv(ab3100->i2c_client, regvals, numregs);
- if (err < 0) {
- dev_err(ab3100->dev,
- "write error (read register page): %d\n",
- err);
- goto get_reg_page_out_unlock;
- } else if (err != numregs) {
- dev_err(ab3100->dev,
- "write error (read register page)\n"
- " %d bytes transferred (expected %d)\n",
- err, numregs);
- err = -EIO;
- goto get_reg_page_out_unlock;
- }
-
- /* All is well */
- err = 0;
-
- get_reg_page_out_unlock:
- mutex_unlock(&ab3100->access_mutex);
- return err;
-}
-
-static int get_register_page_interruptible(struct device *dev, u8 bank,
- u8 first_reg, u8 *regvals, u8 numregs)
-{
- struct ab3100 *ab3100 = dev_get_drvdata(dev->parent);
-
- return ab3100_get_register_page_interruptible(ab3100,
- first_reg, regvals, numregs);
-}
-
-static int ab3100_mask_and_set_register_interruptible(struct ab3100 *ab3100,
- u8 reg, u8 andmask, u8 ormask)
-{
- u8 regandval[2] = {reg, 0};
- int err;
-
- err = mutex_lock_interruptible(&ab3100->access_mutex);
- if (err)
- return err;
-
- /* First read out the target register */
- err = i2c_master_send(ab3100->i2c_client, &reg, 1);
- if (err < 0) {
- dev_err(ab3100->dev,
- "write error (maskset send address): %d\n",
- err);
- goto get_maskset_unlock;
- } else if (err != 1) {
- dev_err(ab3100->dev,
- "write error (maskset send address)\n"
- " %d bytes transferred (expected 1)\n",
- err);
- err = -EIO;
- goto get_maskset_unlock;
- }
-
- err = i2c_master_recv(ab3100->i2c_client, &regandval[1], 1);
- if (err < 0) {
- dev_err(ab3100->dev,
- "write error (maskset read register): %d\n",
- err);
- goto get_maskset_unlock;
- } else if (err != 1) {
- dev_err(ab3100->dev,
- "write error (maskset read register)\n"
- " %d bytes transferred (expected 1)\n",
- err);
- err = -EIO;
- goto get_maskset_unlock;
- }
-
- /* Modify the register */
- regandval[1] &= andmask;
- regandval[1] |= ormask;
-
- /* Write the register */
- err = i2c_master_send(ab3100->i2c_client, regandval, 2);
- if (err < 0) {
- dev_err(ab3100->dev,
- "write error (write register): %d\n",
- err);
- goto get_maskset_unlock;
- } else if (err != 2) {
- dev_err(ab3100->dev,
- "write error (write register)\n"
- " %d bytes transferred (expected 2)\n",
- err);
- err = -EIO;
- goto get_maskset_unlock;
- }
-
- /* All is well */
- err = 0;
-
- get_maskset_unlock:
- mutex_unlock(&ab3100->access_mutex);
- return err;
-}
-
-static int mask_and_set_register_interruptible(struct device *dev, u8 bank,
- u8 reg, u8 bitmask, u8 bitvalues)
-{
- struct ab3100 *ab3100 = dev_get_drvdata(dev->parent);
-
- return ab3100_mask_and_set_register_interruptible(ab3100,
- reg, bitmask, (bitmask & bitvalues));
-}
-
-/*
- * Register a simple callback for handling any AB3100 events.
- */
-int ab3100_event_register(struct ab3100 *ab3100,
- struct notifier_block *nb)
-{
- return blocking_notifier_chain_register(&ab3100->event_subscribers,
- nb);
-}
-EXPORT_SYMBOL(ab3100_event_register);
-
-/*
- * Remove a previously registered callback.
- */
-int ab3100_event_unregister(struct ab3100 *ab3100,
- struct notifier_block *nb)
-{
- return blocking_notifier_chain_unregister(&ab3100->event_subscribers,
- nb);
-}
-EXPORT_SYMBOL(ab3100_event_unregister);
-
-
-static int ab3100_event_registers_startup_state_get(struct device *dev,
- u8 *event)
-{
- struct ab3100 *ab3100 = dev_get_drvdata(dev->parent);
-
- if (!ab3100->startup_events_read)
- return -EAGAIN; /* Try again later */
- memcpy(event, ab3100->startup_events, 3);
-
- return 0;
-}
-
-static struct abx500_ops ab3100_ops = {
- .get_chip_id = ab3100_get_chip_id,
- .set_register = set_register_interruptible,
- .get_register = get_register_interruptible,
- .get_register_page = get_register_page_interruptible,
- .set_register_page = NULL,
- .mask_and_set_register = mask_and_set_register_interruptible,
- .event_registers_startup_state_get =
- ab3100_event_registers_startup_state_get,
- .startup_irq_enabled = NULL,
-};
-
-/*
- * This is a threaded interrupt handler so we can make some
- * I2C calls etc.
- */
-static irqreturn_t ab3100_irq_handler(int irq, void *data)
-{
- struct ab3100 *ab3100 = data;
- u8 event_regs[3];
- u32 fatevent;
- int err;
-
- err = ab3100_get_register_page_interruptible(ab3100, AB3100_EVENTA1,
- event_regs, 3);
- if (err)
- goto err_event;
-
- fatevent = (event_regs[0] << 16) |
- (event_regs[1] << 8) |
- event_regs[2];
-
- if (!ab3100->startup_events_read) {
- ab3100->startup_events[0] = event_regs[0];
- ab3100->startup_events[1] = event_regs[1];
- ab3100->startup_events[2] = event_regs[2];
- ab3100->startup_events_read = true;
- }
- /*
- * The notified parties will have to mask out the events
- * they're interested in and react to them. They will be
- * notified on all events, then they use the fatevent value
- * to determine if they're interested.
- */
- blocking_notifier_call_chain(&ab3100->event_subscribers,
- fatevent, NULL);
-
- dev_dbg(ab3100->dev,
- "IRQ Event: 0x%08x\n", fatevent);
-
- return IRQ_HANDLED;
-
- err_event:
- dev_dbg(ab3100->dev,
- "error reading event status\n");
- return IRQ_HANDLED;
-}
-
-#ifdef CONFIG_DEBUG_FS
-/*
- * Some debugfs entries only exposed if we're using debug
- */
-static int ab3100_registers_print(struct seq_file *s, void *p)
-{
- struct ab3100 *ab3100 = s->private;
- u8 value;
- u8 reg;
-
- seq_puts(s, "AB3100 registers:\n");
-
- for (reg = 0; reg < 0xff; reg++) {
- ab3100_get_register_interruptible(ab3100, reg, &value);
- seq_printf(s, "[0x%x]: 0x%x\n", reg, value);
- }
- return 0;
-}
-
-static int ab3100_registers_open(struct inode *inode, struct file *file)
-{
- return single_open(file, ab3100_registers_print, inode->i_private);
-}
-
-static const struct file_operations ab3100_registers_fops = {
- .open = ab3100_registers_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
-
-struct ab3100_get_set_reg_priv {
- struct ab3100 *ab3100;
- bool mode;
-};
-
-static ssize_t ab3100_get_set_reg(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct ab3100_get_set_reg_priv *priv = file->private_data;
- struct ab3100 *ab3100 = priv->ab3100;
- char buf[32];
- ssize_t buf_size;
- int regp;
- u8 user_reg;
- int err;
- int i = 0;
-
- /* Get userspace string and assure termination */
- buf_size = min((ssize_t)count, (ssize_t)(sizeof(buf)-1));
- if (copy_from_user(buf, user_buf, buf_size))
- return -EFAULT;
- buf[buf_size] = 0;
-
- /*
- * The idea is here to parse a string which is either
- * "0xnn" for reading a register, or "0xaa 0xbb" for
- * writing 0xbb to the register 0xaa. First move past
- * whitespace and then begin to parse the register.
- */
- while ((i < buf_size) && (buf[i] == ' '))
- i++;
- regp = i;
-
- /*
- * Advance pointer to end of string then terminate
- * the register string. This is needed to satisfy
- * the kstrtou8() function.
- */
- while ((i < buf_size) && (buf[i] != ' '))
- i++;
- buf[i] = '\0';
-
- err = kstrtou8(&buf[regp], 16, &user_reg);
- if (err)
- return err;
-
- /* Either we read or we write a register here */
- if (!priv->mode) {
- /* Reading */
- u8 regvalue;
-
- ab3100_get_register_interruptible(ab3100, user_reg, &regvalue);
-
- dev_info(ab3100->dev,
- "debug read AB3100 reg[0x%02x]: 0x%02x\n",
- user_reg, regvalue);
- } else {
- int valp;
- u8 user_value;
- u8 regvalue;
-
- /*
- * Writing, we need some value to write to
- * the register so keep parsing the string
- * from userspace.
- */
- i++;
- while ((i < buf_size) && (buf[i] == ' '))
- i++;
- valp = i;
- while ((i < buf_size) && (buf[i] != ' '))
- i++;
- buf[i] = '\0';
-
- err = kstrtou8(&buf[valp], 16, &user_value);
- if (err)
- return err;
-
- ab3100_set_register_interruptible(ab3100, user_reg, user_value);
- ab3100_get_register_interruptible(ab3100, user_reg, &regvalue);
-
- dev_info(ab3100->dev,
- "debug write reg[0x%02x]\n"
- " with 0x%02x, after readback: 0x%02x\n",
- user_reg, user_value, regvalue);
- }
- return buf_size;
-}
-
-static const struct file_operations ab3100_get_set_reg_fops = {
- .open = simple_open,
- .write = ab3100_get_set_reg,
- .llseek = noop_llseek,
-};
-
-static struct ab3100_get_set_reg_priv ab3100_get_priv;
-static struct ab3100_get_set_reg_priv ab3100_set_priv;
-
-static void ab3100_setup_debugfs(struct ab3100 *ab3100)
-{
- struct dentry *ab3100_dir;
-
- ab3100_dir = debugfs_create_dir("ab3100", NULL);
-
- debugfs_create_file("registers", S_IRUGO, ab3100_dir, ab3100,
- &ab3100_registers_fops);
-
- ab3100_get_priv.ab3100 = ab3100;
- ab3100_get_priv.mode = false;
- debugfs_create_file("get_reg", S_IWUSR, ab3100_dir, &ab3100_get_priv,
- &ab3100_get_set_reg_fops);
-
- ab3100_set_priv.ab3100 = ab3100;
- ab3100_set_priv.mode = true;
- debugfs_create_file("set_reg", S_IWUSR, ab3100_dir, &ab3100_set_priv,
- &ab3100_get_set_reg_fops);
-}
-#else
-static inline void ab3100_setup_debugfs(struct ab3100 *ab3100)
-{
-}
-#endif
-
-/*
- * Basic set-up, datastructure creation/destruction and I2C interface.
- * This sets up a default config in the AB3100 chip so that it
- * will work as expected.
- */
-
-struct ab3100_init_setting {
- u8 abreg;
- u8 setting;
-};
-
-static const struct ab3100_init_setting ab3100_init_settings[] = {
- {
- .abreg = AB3100_MCA,
- .setting = 0x01
- }, {
- .abreg = AB3100_MCB,
- .setting = 0x30
- }, {
- .abreg = AB3100_IMRA1,
- .setting = 0x00
- }, {
- .abreg = AB3100_IMRA2,
- .setting = 0xFF
- }, {
- .abreg = AB3100_IMRA3,
- .setting = 0x01
- }, {
- .abreg = AB3100_IMRB1,
- .setting = 0xBF
- }, {
- .abreg = AB3100_IMRB2,
- .setting = 0xFF
- }, {
- .abreg = AB3100_IMRB3,
- .setting = 0xFF
- }, {
- .abreg = AB3100_SUP,
- .setting = 0x00
- }, {
- .abreg = AB3100_DIS,
- .setting = 0xF0
- }, {
- .abreg = AB3100_D0C,
- .setting = 0x00
- }, {
- .abreg = AB3100_D1C,
- .setting = 0x00
- }, {
- .abreg = AB3100_D2C,
- .setting = 0x00
- }, {
- .abreg = AB3100_D3C,
- .setting = 0x00
- },
-};
-
-static int ab3100_setup(struct ab3100 *ab3100)
-{
- int err = 0;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(ab3100_init_settings); i++) {
- err = ab3100_set_register_interruptible(ab3100,
- ab3100_init_settings[i].abreg,
- ab3100_init_settings[i].setting);
- if (err)
- goto exit_no_setup;
- }
-
- /*
- * Special trick to make the AB3100 use the 32kHz clock (RTC)
- * bit 3 in test register 0x02 is a special, undocumented test
- * register bit that only exist in AB3100 P1E
- */
- if (ab3100->chip_id == 0xc4) {
- dev_warn(ab3100->dev,
- "AB3100 P1E variant detected forcing chip to 32KHz\n");
- err = ab3100_set_test_register_interruptible(ab3100,
- 0x02, 0x08);
- }
-
- exit_no_setup:
- return err;
-}
-
-/* The subdevices of the AB3100 */
-static struct mfd_cell ab3100_devs[] = {
- {
- .name = "ab3100-dac",
- .id = -1,
- },
- {
- .name = "ab3100-leds",
- .id = -1,
- },
- {
- .name = "ab3100-power",
- .id = -1,
- },
- {
- .name = "ab3100-regulators",
- .of_compatible = "stericsson,ab3100-regulators",
- .id = -1,
- },
- {
- .name = "ab3100-sim",
- .id = -1,
- },
- {
- .name = "ab3100-uart",
- .id = -1,
- },
- {
- .name = "ab3100-rtc",
- .id = -1,
- },
- {
- .name = "ab3100-charger",
- .id = -1,
- },
- {
- .name = "ab3100-boost",
- .id = -1,
- },
- {
- .name = "ab3100-adc",
- .id = -1,
- },
- {
- .name = "ab3100-fuelgauge",
- .id = -1,
- },
- {
- .name = "ab3100-vibrator",
- .id = -1,
- },
- {
- .name = "ab3100-otp",
- .id = -1,
- },
- {
- .name = "ab3100-codec",
- .id = -1,
- },
-};
-
-struct ab_family_id {
- u8 id;
- char *name;
-};
-
-static const struct ab_family_id ids[] = {
- /* AB3100 */
- {
- .id = 0xc0,
- .name = "P1A"
- }, {
- .id = 0xc1,
- .name = "P1B"
- }, {
- .id = 0xc2,
- .name = "P1C"
- }, {
- .id = 0xc3,
- .name = "P1D"
- }, {
- .id = 0xc4,
- .name = "P1E"
- }, {
- .id = 0xc5,
- .name = "P1F/R1A"
- }, {
- .id = 0xc6,
- .name = "P1G/R1A"
- }, {
- .id = 0xc7,
- .name = "P2A/R2A"
- }, {
- .id = 0xc8,
- .name = "P2B/R2B"
- },
- /* AB3000 variants, not supported */
- {
- .id = 0xa0
- }, {
- .id = 0xa1
- }, {
- .id = 0xa2
- }, {
- .id = 0xa3
- }, {
- .id = 0xa4
- }, {
- .id = 0xa5
- }, {
- .id = 0xa6
- }, {
- .id = 0xa7
- },
- /* Terminator */
- {
- .id = 0x00,
- },
-};
-
-static int ab3100_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- struct ab3100 *ab3100;
- struct ab3100_platform_data *ab3100_plf_data =
- dev_get_platdata(&client->dev);
- int err;
- int i;
-
- ab3100 = devm_kzalloc(&client->dev, sizeof(struct ab3100), GFP_KERNEL);
- if (!ab3100)
- return -ENOMEM;
-
- /* Initialize data structure */
- mutex_init(&ab3100->access_mutex);
- BLOCKING_INIT_NOTIFIER_HEAD(&ab3100->event_subscribers);
-
- ab3100->i2c_client = client;
- ab3100->dev = &ab3100->i2c_client->dev;
-
- i2c_set_clientdata(client, ab3100);
-
- /* Read chip ID register */
- err = ab3100_get_register_interruptible(ab3100, AB3100_CID,
- &ab3100->chip_id);
- if (err) {
- dev_err(&client->dev,
- "failed to communicate with AB3100 chip\n");
- goto exit_no_detect;
- }
-
- for (i = 0; ids[i].id != 0x0; i++) {
- if (ids[i].id == ab3100->chip_id) {
- if (ids[i].name)
- break;
-
- dev_err(&client->dev, "AB3000 is not supported\n");
- goto exit_no_detect;
- }
- }
-
- snprintf(&ab3100->chip_name[0],
- sizeof(ab3100->chip_name) - 1, "AB3100 %s", ids[i].name);
-
- if (ids[i].id == 0x0) {
- dev_err(&client->dev, "unknown analog baseband chip id: 0x%x\n",
- ab3100->chip_id);
- dev_err(&client->dev,
- "accepting it anyway. Please update the driver.\n");
- goto exit_no_detect;
- }
-
- dev_info(&client->dev, "Detected chip: %s\n",
- &ab3100->chip_name[0]);
-
- /* Attach a second dummy i2c_client to the test register address */
- ab3100->testreg_client = i2c_new_dummy_device(client->adapter,
- client->addr + 1);
- if (IS_ERR(ab3100->testreg_client)) {
- err = PTR_ERR(ab3100->testreg_client);
- goto exit_no_testreg_client;
- }
-
- err = ab3100_setup(ab3100);
- if (err)
- goto exit_no_setup;
-
- err = devm_request_threaded_irq(&client->dev,
- client->irq, NULL, ab3100_irq_handler,
- IRQF_ONESHOT, "ab3100-core", ab3100);
- if (err)
- goto exit_no_irq;
-
- err = abx500_register_ops(&client->dev, &ab3100_ops);
- if (err)
- goto exit_no_ops;
-
- /* Set up and register the platform devices. */
- for (i = 0; i < ARRAY_SIZE(ab3100_devs); i++) {
- ab3100_devs[i].platform_data = ab3100_plf_data;
- ab3100_devs[i].pdata_size = sizeof(struct ab3100_platform_data);
- }
-
- err = mfd_add_devices(&client->dev, 0, ab3100_devs,
- ARRAY_SIZE(ab3100_devs), NULL, 0, NULL);
-
- ab3100_setup_debugfs(ab3100);
-
- return 0;
-
- exit_no_ops:
- exit_no_irq:
- exit_no_setup:
- i2c_unregister_device(ab3100->testreg_client);
- exit_no_testreg_client:
- exit_no_detect:
- return err;
-}
-
-static const struct i2c_device_id ab3100_id[] = {
- { "ab3100", 0 },
- { }
-};
-
-static struct i2c_driver ab3100_driver = {
- .driver = {
- .name = "ab3100",
- .suppress_bind_attrs = true,
- },
- .id_table = ab3100_id,
- .probe = ab3100_probe,
-};
-
-static int __init ab3100_i2c_init(void)
-{
- return i2c_add_driver(&ab3100_driver);
-}
-subsys_initcall(ab3100_i2c_init);
diff --git a/drivers/mfd/ab3100-otp.c b/drivers/mfd/ab3100-otp.c
deleted file mode 100644
index c393102e3a39..000000000000
--- a/drivers/mfd/ab3100-otp.c
+++ /dev/null
@@ -1,240 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * drivers/mfd/ab3100_otp.c
- *
- * Copyright (C) 2007-2009 ST-Ericsson AB
- * Driver to read out OTP from the AB3100 Mixed-signal circuit
- * Author: Linus Walleij <linus.walleij@stericsson.com>
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/mfd/abx500.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-
-/* The OTP registers */
-#define AB3100_OTP0 0xb0
-#define AB3100_OTP1 0xb1
-#define AB3100_OTP2 0xb2
-#define AB3100_OTP3 0xb3
-#define AB3100_OTP4 0xb4
-#define AB3100_OTP5 0xb5
-#define AB3100_OTP6 0xb6
-#define AB3100_OTP7 0xb7
-#define AB3100_OTPP 0xbf
-
-/**
- * struct ab3100_otp
- * @dev: containing device
- * @locked: whether the OTP is locked, after locking, no more bits
- * can be changed but before locking it is still possible
- * to change bits from 1->0.
- * @freq: clocking frequency for the OTP, this frequency is either
- * 32768Hz or 1MHz/30
- * @paf: product activation flag, indicates whether this is a real
- * product (paf true) or a lab board etc (paf false)
- * @imeich: if this is set it is possible to override the
- * IMEI number found in the tac, fac and svn fields with
- * (secured) software
- * @cid: customer ID
- * @tac: type allocation code of the IMEI
- * @fac: final assembly code of the IMEI
- * @svn: software version number of the IMEI
- * @debugfs: a debugfs file used when dumping to file
- */
-struct ab3100_otp {
- struct device *dev;
- bool locked;
- u32 freq;
- bool paf;
- bool imeich;
- u16 cid:14;
- u32 tac:20;
- u8 fac;
- u32 svn:20;
- struct dentry *debugfs;
-};
-
-static int __init ab3100_otp_read(struct ab3100_otp *otp)
-{
- u8 otpval[8];
- u8 otpp;
- int err;
-
- err = abx500_get_register_interruptible(otp->dev, 0,
- AB3100_OTPP, &otpp);
- if (err) {
- dev_err(otp->dev, "unable to read OTPP register\n");
- return err;
- }
-
- err = abx500_get_register_page_interruptible(otp->dev, 0,
- AB3100_OTP0, otpval, 8);
- if (err) {
- dev_err(otp->dev, "unable to read OTP register page\n");
- return err;
- }
-
- /* Cache OTP properties, they never change by nature */
- otp->locked = (otpp & 0x80);
- otp->freq = (otpp & 0x40) ? 32768 : 34100;
- otp->paf = (otpval[1] & 0x80);
- otp->imeich = (otpval[1] & 0x40);
- otp->cid = ((otpval[1] << 8) | otpval[0]) & 0x3fff;
- otp->tac = ((otpval[4] & 0x0f) << 16) | (otpval[3] << 8) | otpval[2];
- otp->fac = ((otpval[5] & 0x0f) << 4) | (otpval[4] >> 4);
- otp->svn = (otpval[7] << 12) | (otpval[6] << 4) | (otpval[5] >> 4);
- return 0;
-}
-
-/*
- * This is a simple debugfs human-readable file that dumps out
- * the contents of the OTP.
- */
-#ifdef CONFIG_DEBUG_FS
-static int ab3100_show_otp(struct seq_file *s, void *v)
-{
- struct ab3100_otp *otp = s->private;
-
- seq_printf(s, "OTP is %s\n", otp->locked ? "LOCKED" : "UNLOCKED");
- seq_printf(s, "OTP clock switch startup is %uHz\n", otp->freq);
- seq_printf(s, "PAF is %s\n", otp->paf ? "SET" : "NOT SET");
- seq_printf(s, "IMEI is %s\n", otp->imeich ?
- "CHANGEABLE" : "NOT CHANGEABLE");
- seq_printf(s, "CID: 0x%04x (decimal: %d)\n", otp->cid, otp->cid);
- seq_printf(s, "IMEI: %u-%u-%u\n", otp->tac, otp->fac, otp->svn);
- return 0;
-}
-
-static int ab3100_otp_open(struct inode *inode, struct file *file)
-{
- return single_open(file, ab3100_show_otp, inode->i_private);
-}
-
-static const struct file_operations ab3100_otp_operations = {
- .open = ab3100_otp_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static void __init ab3100_otp_init_debugfs(struct device *dev,
- struct ab3100_otp *otp)
-{
- otp->debugfs = debugfs_create_file("ab3100_otp", S_IFREG | S_IRUGO,
- NULL, otp, &ab3100_otp_operations);
-}
-
-static void __exit ab3100_otp_exit_debugfs(struct ab3100_otp *otp)
-{
- debugfs_remove(otp->debugfs);
-}
-#else
-/* Compile this out if debugfs not selected */
-static inline void __init ab3100_otp_init_debugfs(struct device *dev,
- struct ab3100_otp *otp)
-{
-}
-
-static inline void __exit ab3100_otp_exit_debugfs(struct ab3100_otp *otp)
-{
-}
-#endif
-
-#define SHOW_AB3100_ATTR(name) \
-static ssize_t ab3100_otp_##name##_show(struct device *dev, \
- struct device_attribute *attr, \
- char *buf) \
-{\
- struct ab3100_otp *otp = dev_get_drvdata(dev); \
- return sprintf(buf, "%u\n", otp->name); \
-}
-
-SHOW_AB3100_ATTR(locked)
-SHOW_AB3100_ATTR(freq)
-SHOW_AB3100_ATTR(paf)
-SHOW_AB3100_ATTR(imeich)
-SHOW_AB3100_ATTR(cid)
-SHOW_AB3100_ATTR(fac)
-SHOW_AB3100_ATTR(tac)
-SHOW_AB3100_ATTR(svn)
-
-static struct device_attribute ab3100_otp_attrs[] = {
- __ATTR(locked, S_IRUGO, ab3100_otp_locked_show, NULL),
- __ATTR(freq, S_IRUGO, ab3100_otp_freq_show, NULL),
- __ATTR(paf, S_IRUGO, ab3100_otp_paf_show, NULL),
- __ATTR(imeich, S_IRUGO, ab3100_otp_imeich_show, NULL),
- __ATTR(cid, S_IRUGO, ab3100_otp_cid_show, NULL),
- __ATTR(fac, S_IRUGO, ab3100_otp_fac_show, NULL),
- __ATTR(tac, S_IRUGO, ab3100_otp_tac_show, NULL),
- __ATTR(svn, S_IRUGO, ab3100_otp_svn_show, NULL),
-};
-
-static int __init ab3100_otp_probe(struct platform_device *pdev)
-{
- struct ab3100_otp *otp;
- int err = 0;
- int i;
-
- otp = devm_kzalloc(&pdev->dev, sizeof(struct ab3100_otp), GFP_KERNEL);
- if (!otp)
- return -ENOMEM;
-
- otp->dev = &pdev->dev;
-
- /* Replace platform data coming in with a local struct */
- platform_set_drvdata(pdev, otp);
-
- err = ab3100_otp_read(otp);
- if (err)
- return err;
-
- dev_info(&pdev->dev, "AB3100 OTP readout registered\n");
-
- /* sysfs entries */
- for (i = 0; i < ARRAY_SIZE(ab3100_otp_attrs); i++) {
- err = device_create_file(&pdev->dev,
- &ab3100_otp_attrs[i]);
- if (err)
- goto err;
- }
-
- /* debugfs entries */
- ab3100_otp_init_debugfs(&pdev->dev, otp);
-
- return 0;
-
-err:
- while (--i >= 0)
- device_remove_file(&pdev->dev, &ab3100_otp_attrs[i]);
- return err;
-}
-
-static int __exit ab3100_otp_remove(struct platform_device *pdev)
-{
- struct ab3100_otp *otp = platform_get_drvdata(pdev);
- int i;
-
- for (i = 0; i < ARRAY_SIZE(ab3100_otp_attrs); i++)
- device_remove_file(&pdev->dev,
- &ab3100_otp_attrs[i]);
- ab3100_otp_exit_debugfs(otp);
- return 0;
-}
-
-static struct platform_driver ab3100_otp_driver = {
- .driver = {
- .name = "ab3100-otp",
- },
- .remove = __exit_p(ab3100_otp_remove),
-};
-
-module_platform_driver_probe(ab3100_otp_driver, ab3100_otp_probe);
-
-MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
-MODULE_DESCRIPTION("AB3100 OTP Readout Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index a9037911162b..c2ba498ad302 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -19,7 +19,6 @@
#include <linux/mfd/core.h>
#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500/ab8500.h>
-#include <linux/mfd/abx500/ab8500-bm.h>
#include <linux/mfd/dbx500-prcmu.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -121,12 +120,6 @@
static DEFINE_SPINLOCK(on_stat_lock);
static u8 turn_on_stat_mask = 0xFF;
static u8 turn_on_stat_set;
-static bool no_bm; /* No battery management */
-/*
- * not really modular, but the easiest way to keep compat with existing
- * bootargs behaviour is to continue using module_param here.
- */
-module_param(no_bm, bool, S_IRUGO);
#define AB9540_MODEM_CTRL2_REG 0x23
#define AB9540_MODEM_CTRL2_SWDBBRSTN_BIT BIT(2)
@@ -609,14 +602,14 @@ int ab8500_suspend(struct ab8500 *ab8500)
}
static const struct mfd_cell ab8500_bm_devs[] = {
- MFD_CELL_OF("ab8500-charger", NULL, &ab8500_bm_data,
- sizeof(ab8500_bm_data), 0, "stericsson,ab8500-charger"),
- MFD_CELL_OF("ab8500-btemp", NULL, &ab8500_bm_data,
- sizeof(ab8500_bm_data), 0, "stericsson,ab8500-btemp"),
- MFD_CELL_OF("ab8500-fg", NULL, &ab8500_bm_data,
- sizeof(ab8500_bm_data), 0, "stericsson,ab8500-fg"),
- MFD_CELL_OF("ab8500-chargalg", NULL, &ab8500_bm_data,
- sizeof(ab8500_bm_data), 0, "stericsson,ab8500-chargalg"),
+ MFD_CELL_OF("ab8500-charger", NULL, NULL, 0, 0,
+ "stericsson,ab8500-charger"),
+ MFD_CELL_OF("ab8500-btemp", NULL, NULL, 0, 0,
+ "stericsson,ab8500-btemp"),
+ MFD_CELL_OF("ab8500-fg", NULL, NULL, 0, 0,
+ "stericsson,ab8500-fg"),
+ MFD_CELL_OF("ab8500-chargalg", NULL, NULL, 0, 0,
+ "stericsson,ab8500-chargalg"),
};
static const struct mfd_cell ab8500_devs[] = {
@@ -1255,14 +1248,12 @@ static int ab8500_probe(struct platform_device *pdev)
if (ret)
return ret;
- if (!no_bm) {
- /* Add battery management devices */
- ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs,
- ARRAY_SIZE(ab8500_bm_devs), NULL,
- 0, ab8500->domain);
- if (ret)
- dev_err(ab8500->dev, "error adding bm devices\n");
- }
+ /* Add battery management devices */
+ ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs,
+ ARRAY_SIZE(ab8500_bm_devs), NULL,
+ 0, ab8500->domain);
+ if (ret)
+ dev_err(ab8500->dev, "error adding bm devices\n");
if (((is_ab8505(ab8500) || is_ab9540(ab8500)) &&
ab8500->chip_id >= AB8500_CUT2P0) || is_ab8540(ab8500))
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c
index 75f1bc671d59..ce6fe6de34f8 100644
--- a/drivers/mfd/arizona-core.c
+++ b/drivers/mfd/arizona-core.c
@@ -881,11 +881,6 @@ static const char * const wm5102_supplies[] = {
static const struct mfd_cell wm5102_devs[] = {
{ .name = "arizona-micsupp" },
{ .name = "arizona-gpio" },
- {
- .name = "arizona-extcon",
- .parent_supplies = wm5102_supplies,
- .num_parent_supplies = 1, /* We only need MICVDD */
- },
{ .name = "arizona-haptics" },
{ .name = "arizona-pwm" },
{
@@ -898,11 +893,6 @@ static const struct mfd_cell wm5102_devs[] = {
static const struct mfd_cell wm5110_devs[] = {
{ .name = "arizona-micsupp" },
{ .name = "arizona-gpio" },
- {
- .name = "arizona-extcon",
- .parent_supplies = wm5102_supplies,
- .num_parent_supplies = 1, /* We only need MICVDD */
- },
{ .name = "arizona-haptics" },
{ .name = "arizona-pwm" },
{
@@ -939,11 +929,6 @@ static const char * const wm8997_supplies[] = {
static const struct mfd_cell wm8997_devs[] = {
{ .name = "arizona-micsupp" },
{ .name = "arizona-gpio" },
- {
- .name = "arizona-extcon",
- .parent_supplies = wm8997_supplies,
- .num_parent_supplies = 1, /* We only need MICVDD */
- },
{ .name = "arizona-haptics" },
{ .name = "arizona-pwm" },
{
@@ -956,11 +941,6 @@ static const struct mfd_cell wm8997_devs[] = {
static const struct mfd_cell wm8998_devs[] = {
{ .name = "arizona-micsupp" },
{ .name = "arizona-gpio" },
- {
- .name = "arizona-extcon",
- .parent_supplies = wm5102_supplies,
- .num_parent_supplies = 1, /* We only need MICVDD */
- },
{ .name = "arizona-haptics" },
{ .name = "arizona-pwm" },
{
diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c
index 077d9ab112b7..d919ae9691e2 100644
--- a/drivers/mfd/arizona-irq.c
+++ b/drivers/mfd/arizona-irq.c
@@ -100,7 +100,7 @@ static irqreturn_t arizona_irq_thread(int irq, void *data)
unsigned int val;
int ret;
- ret = pm_runtime_get_sync(arizona->dev);
+ ret = pm_runtime_resume_and_get(arizona->dev);
if (ret < 0) {
dev_err(arizona->dev, "Failed to resume device: %d\n", ret);
return IRQ_NONE;
diff --git a/drivers/mfd/arizona-spi.c b/drivers/mfd/arizona-spi.c
index 24a2c75d691a..aa1d6f94ae53 100644
--- a/drivers/mfd/arizona-spi.c
+++ b/drivers/mfd/arizona-spi.c
@@ -25,8 +25,8 @@
#include "arizona.h"
#ifdef CONFIG_ACPI
-const struct acpi_gpio_params reset_gpios = { 1, 0, false };
-const struct acpi_gpio_params ldoena_gpios = { 2, 0, false };
+static const struct acpi_gpio_params reset_gpios = { 1, 0, false };
+static const struct acpi_gpio_params ldoena_gpios = { 2, 0, false };
static const struct acpi_gpio_mapping arizona_acpi_gpios[] = {
{ "reset-gpios", &reset_gpios, 1, },
diff --git a/drivers/mfd/atc260x-core.c b/drivers/mfd/atc260x-core.c
new file mode 100644
index 000000000000..7148ff5b05b1
--- /dev/null
+++ b/drivers/mfd/atc260x-core.c
@@ -0,0 +1,310 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Core support for ATC260x PMICs
+ *
+ * Copyright (C) 2019 Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+ * Copyright (C) 2020 Cristian Ciocaltea <cristian.ciocaltea@gmail.com>
+ */
+
+#include <linux/interrupt.h>
+#include <linux/mfd/atc260x/core.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+
+#define ATC260X_CHIP_REV_MAX 31
+
+struct atc260x_init_regs {
+ unsigned int cmu_devrst;
+ unsigned int cmu_devrst_ints;
+ unsigned int ints_msk;
+ unsigned int pad_en;
+ unsigned int pad_en_extirq;
+};
+
+static void regmap_lock_mutex(void *__mutex)
+{
+ struct mutex *mutex = __mutex;
+
+ /*
+ * Using regmap within an atomic context (e.g. accessing a PMIC when
+ * powering system down) is normally allowed only if the regmap type
+ * is MMIO and the regcache type is either REGCACHE_NONE or
+ * REGCACHE_FLAT. For slow buses like I2C and SPI, the regmap is
+ * internally protected by a mutex which is acquired non-atomically.
+ *
+ * Let's improve this by using a customized locking scheme inspired
+ * from I2C atomic transfer. See i2c_in_atomic_xfer_mode() for a
+ * starting point.
+ */
+ if (system_state > SYSTEM_RUNNING && irqs_disabled())
+ mutex_trylock(mutex);
+ else
+ mutex_lock(mutex);
+}
+
+static void regmap_unlock_mutex(void *__mutex)
+{
+ struct mutex *mutex = __mutex;
+
+ mutex_unlock(mutex);
+}
+
+static const struct regmap_config atc2603c_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 16,
+ .max_register = ATC2603C_SADDR,
+ .cache_type = REGCACHE_NONE,
+};
+
+static const struct regmap_config atc2609a_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 16,
+ .max_register = ATC2609A_SADDR,
+ .cache_type = REGCACHE_NONE,
+};
+
+static const struct regmap_irq atc2603c_regmap_irqs[] = {
+ REGMAP_IRQ_REG(ATC2603C_IRQ_AUDIO, 0, ATC2603C_INTS_MSK_AUDIO),
+ REGMAP_IRQ_REG(ATC2603C_IRQ_OV, 0, ATC2603C_INTS_MSK_OV),
+ REGMAP_IRQ_REG(ATC2603C_IRQ_OC, 0, ATC2603C_INTS_MSK_OC),
+ REGMAP_IRQ_REG(ATC2603C_IRQ_OT, 0, ATC2603C_INTS_MSK_OT),
+ REGMAP_IRQ_REG(ATC2603C_IRQ_UV, 0, ATC2603C_INTS_MSK_UV),
+ REGMAP_IRQ_REG(ATC2603C_IRQ_ALARM, 0, ATC2603C_INTS_MSK_ALARM),
+ REGMAP_IRQ_REG(ATC2603C_IRQ_ONOFF, 0, ATC2603C_INTS_MSK_ONOFF),
+ REGMAP_IRQ_REG(ATC2603C_IRQ_SGPIO, 0, ATC2603C_INTS_MSK_SGPIO),
+ REGMAP_IRQ_REG(ATC2603C_IRQ_IR, 0, ATC2603C_INTS_MSK_IR),
+ REGMAP_IRQ_REG(ATC2603C_IRQ_REMCON, 0, ATC2603C_INTS_MSK_REMCON),
+ REGMAP_IRQ_REG(ATC2603C_IRQ_POWER_IN, 0, ATC2603C_INTS_MSK_POWERIN),
+};
+
+static const struct regmap_irq atc2609a_regmap_irqs[] = {
+ REGMAP_IRQ_REG(ATC2609A_IRQ_AUDIO, 0, ATC2609A_INTS_MSK_AUDIO),
+ REGMAP_IRQ_REG(ATC2609A_IRQ_OV, 0, ATC2609A_INTS_MSK_OV),
+ REGMAP_IRQ_REG(ATC2609A_IRQ_OC, 0, ATC2609A_INTS_MSK_OC),
+ REGMAP_IRQ_REG(ATC2609A_IRQ_OT, 0, ATC2609A_INTS_MSK_OT),
+ REGMAP_IRQ_REG(ATC2609A_IRQ_UV, 0, ATC2609A_INTS_MSK_UV),
+ REGMAP_IRQ_REG(ATC2609A_IRQ_ALARM, 0, ATC2609A_INTS_MSK_ALARM),
+ REGMAP_IRQ_REG(ATC2609A_IRQ_ONOFF, 0, ATC2609A_INTS_MSK_ONOFF),
+ REGMAP_IRQ_REG(ATC2609A_IRQ_WKUP, 0, ATC2609A_INTS_MSK_WKUP),
+ REGMAP_IRQ_REG(ATC2609A_IRQ_IR, 0, ATC2609A_INTS_MSK_IR),
+ REGMAP_IRQ_REG(ATC2609A_IRQ_REMCON, 0, ATC2609A_INTS_MSK_REMCON),
+ REGMAP_IRQ_REG(ATC2609A_IRQ_POWER_IN, 0, ATC2609A_INTS_MSK_POWERIN),
+};
+
+static const struct regmap_irq_chip atc2603c_regmap_irq_chip = {
+ .name = "atc2603c",
+ .irqs = atc2603c_regmap_irqs,
+ .num_irqs = ARRAY_SIZE(atc2603c_regmap_irqs),
+ .num_regs = 1,
+ .status_base = ATC2603C_INTS_PD,
+ .mask_base = ATC2603C_INTS_MSK,
+ .mask_invert = true,
+};
+
+static const struct regmap_irq_chip atc2609a_regmap_irq_chip = {
+ .name = "atc2609a",
+ .irqs = atc2609a_regmap_irqs,
+ .num_irqs = ARRAY_SIZE(atc2609a_regmap_irqs),
+ .num_regs = 1,
+ .status_base = ATC2609A_INTS_PD,
+ .mask_base = ATC2609A_INTS_MSK,
+ .mask_invert = true,
+};
+
+static const struct resource atc2603c_onkey_resources[] = {
+ DEFINE_RES_IRQ(ATC2603C_IRQ_ONOFF),
+};
+
+static const struct resource atc2609a_onkey_resources[] = {
+ DEFINE_RES_IRQ(ATC2609A_IRQ_ONOFF),
+};
+
+static const struct mfd_cell atc2603c_mfd_cells[] = {
+ { .name = "atc260x-regulator" },
+ { .name = "atc260x-pwrc" },
+ {
+ .name = "atc260x-onkey",
+ .num_resources = ARRAY_SIZE(atc2603c_onkey_resources),
+ .resources = atc2603c_onkey_resources,
+ },
+};
+
+static const struct mfd_cell atc2609a_mfd_cells[] = {
+ { .name = "atc260x-regulator" },
+ { .name = "atc260x-pwrc" },
+ {
+ .name = "atc260x-onkey",
+ .num_resources = ARRAY_SIZE(atc2609a_onkey_resources),
+ .resources = atc2609a_onkey_resources,
+ },
+};
+
+static const struct atc260x_init_regs atc2603c_init_regs = {
+ .cmu_devrst = ATC2603C_CMU_DEVRST,
+ .cmu_devrst_ints = ATC2603C_CMU_DEVRST_INTS,
+ .ints_msk = ATC2603C_INTS_MSK,
+ .pad_en = ATC2603C_PAD_EN,
+ .pad_en_extirq = ATC2603C_PAD_EN_EXTIRQ,
+};
+
+static const struct atc260x_init_regs atc2609a_init_regs = {
+ .cmu_devrst = ATC2609A_CMU_DEVRST,
+ .cmu_devrst_ints = ATC2609A_CMU_DEVRST_INTS,
+ .ints_msk = ATC2609A_INTS_MSK,
+ .pad_en = ATC2609A_PAD_EN,
+ .pad_en_extirq = ATC2609A_PAD_EN_EXTIRQ,
+};
+
+static void atc260x_cmu_reset(struct atc260x *atc260x)
+{
+ const struct atc260x_init_regs *regs = atc260x->init_regs;
+
+ /* Assert reset */
+ regmap_update_bits(atc260x->regmap, regs->cmu_devrst,
+ regs->cmu_devrst_ints, ~regs->cmu_devrst_ints);
+
+ /* De-assert reset */
+ regmap_update_bits(atc260x->regmap, regs->cmu_devrst,
+ regs->cmu_devrst_ints, regs->cmu_devrst_ints);
+}
+
+static void atc260x_dev_init(struct atc260x *atc260x)
+{
+ const struct atc260x_init_regs *regs = atc260x->init_regs;
+
+ /* Initialize interrupt block */
+ atc260x_cmu_reset(atc260x);
+
+ /* Disable all interrupt sources */
+ regmap_write(atc260x->regmap, regs->ints_msk, 0);
+
+ /* Enable EXTIRQ pad */
+ regmap_update_bits(atc260x->regmap, regs->pad_en,
+ regs->pad_en_extirq, regs->pad_en_extirq);
+}
+
+/**
+ * atc260x_match_device(): Setup ATC260x variant related fields
+ *
+ * @atc260x: ATC260x device to setup (.dev field must be set)
+ * @regmap_cfg: regmap config associated with this ATC260x device
+ *
+ * This lets the ATC260x core configure the MFD cells and register maps
+ * for later use.
+ */
+int atc260x_match_device(struct atc260x *atc260x, struct regmap_config *regmap_cfg)
+{
+ struct device *dev = atc260x->dev;
+ const void *of_data;
+
+ of_data = of_device_get_match_data(dev);
+ if (!of_data)
+ return -ENODEV;
+
+ atc260x->ic_type = (unsigned long)of_data;
+
+ switch (atc260x->ic_type) {
+ case ATC2603C:
+ *regmap_cfg = atc2603c_regmap_config;
+ atc260x->regmap_irq_chip = &atc2603c_regmap_irq_chip;
+ atc260x->cells = atc2603c_mfd_cells;
+ atc260x->nr_cells = ARRAY_SIZE(atc2603c_mfd_cells);
+ atc260x->type_name = "atc2603c";
+ atc260x->rev_reg = ATC2603C_CHIP_VER;
+ atc260x->init_regs = &atc2603c_init_regs;
+ break;
+ case ATC2609A:
+ *regmap_cfg = atc2609a_regmap_config;
+ atc260x->regmap_irq_chip = &atc2609a_regmap_irq_chip;
+ atc260x->cells = atc2609a_mfd_cells;
+ atc260x->nr_cells = ARRAY_SIZE(atc2609a_mfd_cells);
+ atc260x->type_name = "atc2609a";
+ atc260x->rev_reg = ATC2609A_CHIP_VER;
+ atc260x->init_regs = &atc2609a_init_regs;
+ break;
+ default:
+ dev_err(dev, "Unsupported ATC260x device type: %u\n",
+ atc260x->ic_type);
+ return -EINVAL;
+ }
+
+ atc260x->regmap_mutex = devm_kzalloc(dev, sizeof(*atc260x->regmap_mutex),
+ GFP_KERNEL);
+ if (!atc260x->regmap_mutex)
+ return -ENOMEM;
+
+ mutex_init(atc260x->regmap_mutex);
+
+ regmap_cfg->lock = regmap_lock_mutex,
+ regmap_cfg->unlock = regmap_unlock_mutex,
+ regmap_cfg->lock_arg = atc260x->regmap_mutex;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(atc260x_match_device);
+
+/**
+ * atc260x_device_probe(): Probe a configured ATC260x device
+ *
+ * @atc260x: ATC260x device to probe (must be configured)
+ *
+ * This function lets the ATC260x core register the ATC260x MFD devices
+ * and IRQCHIP. The ATC260x device passed in must be fully configured
+ * with atc260x_match_device, its IRQ set, and regmap created.
+ */
+int atc260x_device_probe(struct atc260x *atc260x)
+{
+ struct device *dev = atc260x->dev;
+ unsigned int chip_rev;
+ int ret;
+
+ if (!atc260x->irq) {
+ dev_err(dev, "No interrupt support\n");
+ return -EINVAL;
+ }
+
+ /* Initialize the hardware */
+ atc260x_dev_init(atc260x);
+
+ ret = regmap_read(atc260x->regmap, atc260x->rev_reg, &chip_rev);
+ if (ret) {
+ dev_err(dev, "Failed to get chip revision\n");
+ return ret;
+ }
+
+ if (chip_rev > ATC260X_CHIP_REV_MAX) {
+ dev_err(dev, "Unknown chip revision: %u\n", chip_rev);
+ return -EINVAL;
+ }
+
+ atc260x->ic_ver = __ffs(chip_rev + 1U);
+
+ dev_info(dev, "Detected chip type %s rev.%c\n",
+ atc260x->type_name, 'A' + atc260x->ic_ver);
+
+ ret = devm_regmap_add_irq_chip(dev, atc260x->regmap, atc260x->irq, IRQF_ONESHOT,
+ -1, atc260x->regmap_irq_chip, &atc260x->irq_data);
+ if (ret) {
+ dev_err(dev, "Failed to add IRQ chip: %d\n", ret);
+ return ret;
+ }
+
+ ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
+ atc260x->cells, atc260x->nr_cells, NULL, 0,
+ regmap_irq_get_domain(atc260x->irq_data));
+ if (ret) {
+ dev_err(dev, "Failed to add child devices: %d\n", ret);
+ regmap_del_irq_chip(atc260x->irq, atc260x->irq_data);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(atc260x_device_probe);
+
+MODULE_DESCRIPTION("ATC260x PMICs Core support");
+MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>");
+MODULE_AUTHOR("Cristian Ciocaltea <cristian.ciocaltea@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/atc260x-i2c.c b/drivers/mfd/atc260x-i2c.c
new file mode 100644
index 000000000000..5855efd09efc
--- /dev/null
+++ b/drivers/mfd/atc260x-i2c.c
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * I2C bus interface for ATC260x PMICs
+ *
+ * Copyright (C) 2019 Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+ * Copyright (C) 2020 Cristian Ciocaltea <cristian.ciocaltea@gmail.com>
+ */
+
+#include <linux/i2c.h>
+#include <linux/mfd/atc260x/core.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+
+static int atc260x_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct atc260x *atc260x;
+ struct regmap_config regmap_cfg;
+ int ret;
+
+ atc260x = devm_kzalloc(&client->dev, sizeof(*atc260x), GFP_KERNEL);
+ if (!atc260x)
+ return -ENOMEM;
+
+ atc260x->dev = &client->dev;
+ atc260x->irq = client->irq;
+
+ ret = atc260x_match_device(atc260x, &regmap_cfg);
+ if (ret)
+ return ret;
+
+ i2c_set_clientdata(client, atc260x);
+
+ atc260x->regmap = devm_regmap_init_i2c(client, &regmap_cfg);
+ if (IS_ERR(atc260x->regmap)) {
+ ret = PTR_ERR(atc260x->regmap);
+ dev_err(&client->dev, "failed to init regmap: %d\n", ret);
+ return ret;
+ }
+
+ return atc260x_device_probe(atc260x);
+}
+
+static const struct of_device_id atc260x_i2c_of_match[] = {
+ { .compatible = "actions,atc2603c", .data = (void *)ATC2603C },
+ { .compatible = "actions,atc2609a", .data = (void *)ATC2609A },
+ { }
+};
+MODULE_DEVICE_TABLE(of, atc260x_i2c_of_match);
+
+static struct i2c_driver atc260x_i2c_driver = {
+ .driver = {
+ .name = "atc260x",
+ .of_match_table = of_match_ptr(atc260x_i2c_of_match),
+ },
+ .probe = atc260x_i2c_probe,
+};
+module_i2c_driver(atc260x_i2c_driver);
+
+MODULE_DESCRIPTION("ATC260x PMICs I2C bus interface");
+MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>");
+MODULE_AUTHOR("Cristian Ciocaltea <cristian.ciocaltea@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/da9063-i2c.c b/drivers/mfd/da9063-i2c.c
index 3781d0bb7786..783a14af18e2 100644
--- a/drivers/mfd/da9063-i2c.c
+++ b/drivers/mfd/da9063-i2c.c
@@ -442,6 +442,16 @@ static int da9063_i2c_probe(struct i2c_client *i2c,
return ret;
}
+ /* If SMBus is not available and only I2C is possible, enter I2C mode */
+ if (i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) {
+ ret = regmap_clear_bits(da9063->regmap, DA9063_REG_CONFIG_J,
+ DA9063_TWOWIRE_TO);
+ if (ret < 0) {
+ dev_err(da9063->dev, "Failed to set Two-Wire Bus Mode.\n");
+ return -EIO;
+ }
+ }
+
return da9063_device_init(da9063, i2c->irq);
}
diff --git a/drivers/mfd/ene-kb3930.c b/drivers/mfd/ene-kb3930.c
index 83243e668e3f..1b73318d1f1f 100644
--- a/drivers/mfd/ene-kb3930.c
+++ b/drivers/mfd/ene-kb3930.c
@@ -33,7 +33,7 @@ struct kb3930 {
struct gpio_descs *off_gpios;
};
-struct kb3930 *kb3930_power_off;
+static struct kb3930 *kb3930_power_off;
#define EC_GPIO_WAVE 0
#define EC_GPIO_OFF_MODE 1
diff --git a/drivers/mfd/intel-lpss-acpi.c b/drivers/mfd/intel-lpss-acpi.c
index c8fe334b5fe8..1f396039d58f 100644
--- a/drivers/mfd/intel-lpss-acpi.c
+++ b/drivers/mfd/intel-lpss-acpi.c
@@ -22,55 +22,71 @@ static const struct intel_lpss_platform_info spt_info = {
.clk_rate = 120000000,
};
-static struct property_entry spt_i2c_properties[] = {
+static const struct property_entry spt_i2c_properties[] = {
PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 230),
{ },
};
+static const struct software_node spt_i2c_node = {
+ .properties = spt_i2c_properties,
+};
+
static const struct intel_lpss_platform_info spt_i2c_info = {
.clk_rate = 120000000,
- .properties = spt_i2c_properties,
+ .swnode = &spt_i2c_node,
};
-static struct property_entry uart_properties[] = {
+static const struct property_entry uart_properties[] = {
PROPERTY_ENTRY_U32("reg-io-width", 4),
PROPERTY_ENTRY_U32("reg-shift", 2),
PROPERTY_ENTRY_BOOL("snps,uart-16550-compatible"),
{ },
};
+static const struct software_node uart_node = {
+ .properties = uart_properties,
+};
+
static const struct intel_lpss_platform_info spt_uart_info = {
.clk_rate = 120000000,
.clk_con_id = "baudclk",
- .properties = uart_properties,
+ .swnode = &uart_node,
};
static const struct intel_lpss_platform_info bxt_info = {
.clk_rate = 100000000,
};
-static struct property_entry bxt_i2c_properties[] = {
+static const struct property_entry bxt_i2c_properties[] = {
PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 42),
PROPERTY_ENTRY_U32("i2c-sda-falling-time-ns", 171),
PROPERTY_ENTRY_U32("i2c-scl-falling-time-ns", 208),
{ },
};
+static const struct software_node bxt_i2c_node = {
+ .properties = bxt_i2c_properties,
+};
+
static const struct intel_lpss_platform_info bxt_i2c_info = {
.clk_rate = 133000000,
- .properties = bxt_i2c_properties,
+ .swnode = &bxt_i2c_node,
};
-static struct property_entry apl_i2c_properties[] = {
+static const struct property_entry apl_i2c_properties[] = {
PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 207),
PROPERTY_ENTRY_U32("i2c-sda-falling-time-ns", 171),
PROPERTY_ENTRY_U32("i2c-scl-falling-time-ns", 208),
{ },
};
+static const struct software_node apl_i2c_node = {
+ .properties = apl_i2c_properties,
+};
+
static const struct intel_lpss_platform_info apl_i2c_info = {
.clk_rate = 133000000,
- .properties = apl_i2c_properties,
+ .swnode = &apl_i2c_node,
};
static const struct acpi_device_id intel_lpss_acpi_ids[] = {
diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c
index 1522c8afc540..79c53617489c 100644
--- a/drivers/mfd/intel-lpss-pci.c
+++ b/drivers/mfd/intel-lpss-pci.c
@@ -65,27 +65,35 @@ static const struct intel_lpss_platform_info spt_info = {
.clk_rate = 120000000,
};
-static struct property_entry spt_i2c_properties[] = {
+static const struct property_entry spt_i2c_properties[] = {
PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 230),
{ },
};
+static const struct software_node spt_i2c_node = {
+ .properties = spt_i2c_properties,
+};
+
static const struct intel_lpss_platform_info spt_i2c_info = {
.clk_rate = 120000000,
- .properties = spt_i2c_properties,
+ .swnode = &spt_i2c_node,
};
-static struct property_entry uart_properties[] = {
+static const struct property_entry uart_properties[] = {
PROPERTY_ENTRY_U32("reg-io-width", 4),
PROPERTY_ENTRY_U32("reg-shift", 2),
PROPERTY_ENTRY_BOOL("snps,uart-16550-compatible"),
{ },
};
+static const struct software_node uart_node = {
+ .properties = uart_properties,
+};
+
static const struct intel_lpss_platform_info spt_uart_info = {
.clk_rate = 120000000,
.clk_con_id = "baudclk",
- .properties = uart_properties,
+ .swnode = &uart_node,
};
static const struct intel_lpss_platform_info bxt_info = {
@@ -95,53 +103,65 @@ static const struct intel_lpss_platform_info bxt_info = {
static const struct intel_lpss_platform_info bxt_uart_info = {
.clk_rate = 100000000,
.clk_con_id = "baudclk",
- .properties = uart_properties,
+ .swnode = &uart_node,
};
-static struct property_entry bxt_i2c_properties[] = {
+static const struct property_entry bxt_i2c_properties[] = {
PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 42),
PROPERTY_ENTRY_U32("i2c-sda-falling-time-ns", 171),
PROPERTY_ENTRY_U32("i2c-scl-falling-time-ns", 208),
{ },
};
+static const struct software_node bxt_i2c_node = {
+ .properties = bxt_i2c_properties,
+};
+
static const struct intel_lpss_platform_info bxt_i2c_info = {
.clk_rate = 133000000,
- .properties = bxt_i2c_properties,
+ .swnode = &bxt_i2c_node,
};
-static struct property_entry apl_i2c_properties[] = {
+static const struct property_entry apl_i2c_properties[] = {
PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 207),
PROPERTY_ENTRY_U32("i2c-sda-falling-time-ns", 171),
PROPERTY_ENTRY_U32("i2c-scl-falling-time-ns", 208),
{ },
};
+static const struct software_node apl_i2c_node = {
+ .properties = apl_i2c_properties,
+};
+
static const struct intel_lpss_platform_info apl_i2c_info = {
.clk_rate = 133000000,
- .properties = apl_i2c_properties,
+ .swnode = &apl_i2c_node,
};
-static struct property_entry glk_i2c_properties[] = {
+static const struct property_entry glk_i2c_properties[] = {
PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 313),
PROPERTY_ENTRY_U32("i2c-sda-falling-time-ns", 171),
PROPERTY_ENTRY_U32("i2c-scl-falling-time-ns", 290),
{ },
};
+static const struct software_node glk_i2c_node = {
+ .properties = glk_i2c_properties,
+};
+
static const struct intel_lpss_platform_info glk_i2c_info = {
.clk_rate = 133000000,
- .properties = glk_i2c_properties,
+ .swnode = &glk_i2c_node,
};
static const struct intel_lpss_platform_info cnl_i2c_info = {
.clk_rate = 216000000,
- .properties = spt_i2c_properties,
+ .swnode = &spt_i2c_node,
};
static const struct intel_lpss_platform_info ehl_i2c_info = {
.clk_rate = 100000000,
- .properties = bxt_i2c_properties,
+ .swnode = &bxt_i2c_node,
};
static const struct pci_device_id intel_lpss_pci_ids[] = {
diff --git a/drivers/mfd/intel-lpss.c b/drivers/mfd/intel-lpss.c
index b0f0781a6b9c..a9bf10bee796 100644
--- a/drivers/mfd/intel-lpss.c
+++ b/drivers/mfd/intel-lpss.c
@@ -399,7 +399,7 @@ int intel_lpss_probe(struct device *dev,
if (ret)
return ret;
- lpss->cell->properties = info->properties;
+ lpss->cell->swnode = info->swnode;
intel_lpss_init_dev(lpss);
diff --git a/drivers/mfd/intel-lpss.h b/drivers/mfd/intel-lpss.h
index 4ae58a86bb42..22dbc4aed793 100644
--- a/drivers/mfd/intel-lpss.h
+++ b/drivers/mfd/intel-lpss.h
@@ -15,14 +15,14 @@
struct device;
struct resource;
-struct property_entry;
+struct software_node;
struct intel_lpss_platform_info {
struct resource *mem;
int irq;
unsigned long clk_rate;
const char *clk_con_id;
- struct property_entry *properties;
+ const struct software_node *swnode;
};
int intel_lpss_probe(struct device *dev,
diff --git a/drivers/mfd/intel-m10-bmc.c b/drivers/mfd/intel-m10-bmc.c
index 06c977519479..1a9bfb7f48cd 100644
--- a/drivers/mfd/intel-m10-bmc.c
+++ b/drivers/mfd/intel-m10-bmc.c
@@ -15,6 +15,11 @@
enum m10bmc_type {
M10_N3000,
+ M10_D5005
+};
+
+static struct mfd_cell m10bmc_d5005_subdevs[] = {
+ { .name = "d5005bmc-hwmon" },
};
static struct mfd_cell m10bmc_pacn3000_subdevs[] = {
@@ -23,10 +28,23 @@ static struct mfd_cell m10bmc_pacn3000_subdevs[] = {
{ .name = "n3000bmc-secure" },
};
+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,
};
@@ -116,17 +134,14 @@ static int check_m10bmc_version(struct intel_m10bmc *ddata)
int ret;
/*
- * This check is to filter out the very old legacy BMC versions,
- * M10BMC_LEGACY_SYS_BASE is the offset to this old block of mmio
- * registers. In the old BMC chips, the BMC version info is stored
- * in this old version register (M10BMC_LEGACY_SYS_BASE +
- * M10BMC_BUILD_VER), so its read out value would have not been
- * LEGACY_INVALID (0xffffffff). But in new BMC chips that the
- * driver supports, the value of this register should be
- * LEGACY_INVALID.
+ * 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_SYS_BASE + M10BMC_BUILD_VER, &v);
+ ret = m10bmc_raw_read(ddata, M10BMC_LEGACY_BUILD_VER, &v);
if (ret)
return -ENODEV;
@@ -173,6 +188,10 @@ static int intel_m10_bmc_spi_probe(struct spi_device *spi)
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;
default:
return -ENODEV;
}
@@ -187,6 +206,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 },
{ }
};
MODULE_DEVICE_TABLE(spi, m10bmc_spi_id);
diff --git a/drivers/mfd/intel_pmt.c b/drivers/mfd/intel_pmt.c
index 744b230cdcca..dd7eb614c28e 100644
--- a/drivers/mfd/intel_pmt.c
+++ b/drivers/mfd/intel_pmt.c
@@ -49,10 +49,14 @@ enum pmt_quirks {
/* Use shift instead of mask to read discovery table offset */
PMT_QUIRK_TABLE_SHIFT = BIT(2),
+
+ /* DVSEC not present (provided in driver data) */
+ PMT_QUIRK_NO_DVSEC = BIT(3),
};
struct pmt_platform_info {
unsigned long quirks;
+ struct intel_dvsec_header **capabilities;
};
static const struct pmt_platform_info tgl_info = {
@@ -60,6 +64,26 @@ static const struct pmt_platform_info tgl_info = {
PMT_QUIRK_TABLE_SHIFT,
};
+/* DG1 Platform with DVSEC quirk*/
+static struct intel_dvsec_header dg1_telemetry = {
+ .length = 0x10,
+ .id = 2,
+ .num_entries = 1,
+ .entry_size = 3,
+ .tbir = 0,
+ .offset = 0x466000,
+};
+
+static struct intel_dvsec_header *dg1_capabilities[] = {
+ &dg1_telemetry,
+ NULL
+};
+
+static const struct pmt_platform_info dg1_info = {
+ .quirks = PMT_QUIRK_NO_DVSEC,
+ .capabilities = dg1_capabilities,
+};
+
static int pmt_add_dev(struct pci_dev *pdev, struct intel_dvsec_header *header,
unsigned long quirks)
{
@@ -79,19 +103,18 @@ static int pmt_add_dev(struct pci_dev *pdev, struct intel_dvsec_header *header,
case DVSEC_INTEL_ID_WATCHER:
if (quirks & PMT_QUIRK_NO_WATCHER) {
dev_info(dev, "Watcher not supported\n");
- return 0;
+ return -EINVAL;
}
name = "pmt_watcher";
break;
case DVSEC_INTEL_ID_CRASHLOG:
if (quirks & PMT_QUIRK_NO_CRASHLOG) {
dev_info(dev, "Crashlog not supported\n");
- return 0;
+ return -EINVAL;
}
name = "pmt_crashlog";
break;
default:
- dev_err(dev, "Unrecognized PMT capability: %d\n", id);
return -EINVAL;
}
@@ -148,41 +171,54 @@ static int pmt_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (info)
quirks = info->quirks;
- do {
- struct intel_dvsec_header header;
- u32 table;
- u16 vid;
-
- pos = pci_find_next_ext_capability(pdev, pos, PCI_EXT_CAP_ID_DVSEC);
- if (!pos)
- break;
-
- pci_read_config_word(pdev, pos + PCI_DVSEC_HEADER1, &vid);
- if (vid != PCI_VENDOR_ID_INTEL)
- continue;
-
- pci_read_config_word(pdev, pos + PCI_DVSEC_HEADER2,
- &header.id);
- pci_read_config_byte(pdev, pos + INTEL_DVSEC_ENTRIES,
- &header.num_entries);
- pci_read_config_byte(pdev, pos + INTEL_DVSEC_SIZE,
- &header.entry_size);
- pci_read_config_dword(pdev, pos + INTEL_DVSEC_TABLE,
- &table);
-
- header.tbir = INTEL_DVSEC_TABLE_BAR(table);
- header.offset = INTEL_DVSEC_TABLE_OFFSET(table);
-
- ret = pmt_add_dev(pdev, &header, quirks);
- if (ret) {
- dev_warn(&pdev->dev,
- "Failed to add device for DVSEC id %d\n",
- header.id);
- continue;
- }
+ if (info && (info->quirks & PMT_QUIRK_NO_DVSEC)) {
+ struct intel_dvsec_header **header;
+
+ header = info->capabilities;
+ while (*header) {
+ ret = pmt_add_dev(pdev, *header, quirks);
+ if (ret)
+ dev_warn(&pdev->dev,
+ "Failed to add device for DVSEC id %d\n",
+ (*header)->id);
+ else
+ found_devices = true;
- found_devices = true;
- } while (true);
+ ++header;
+ }
+ } else {
+ do {
+ struct intel_dvsec_header header;
+ u32 table;
+ u16 vid;
+
+ pos = pci_find_next_ext_capability(pdev, pos, PCI_EXT_CAP_ID_DVSEC);
+ if (!pos)
+ break;
+
+ pci_read_config_word(pdev, pos + PCI_DVSEC_HEADER1, &vid);
+ if (vid != PCI_VENDOR_ID_INTEL)
+ continue;
+
+ pci_read_config_word(pdev, pos + PCI_DVSEC_HEADER2,
+ &header.id);
+ pci_read_config_byte(pdev, pos + INTEL_DVSEC_ENTRIES,
+ &header.num_entries);
+ pci_read_config_byte(pdev, pos + INTEL_DVSEC_SIZE,
+ &header.entry_size);
+ pci_read_config_dword(pdev, pos + INTEL_DVSEC_TABLE,
+ &table);
+
+ header.tbir = INTEL_DVSEC_TABLE_BAR(table);
+ header.offset = INTEL_DVSEC_TABLE_OFFSET(table);
+
+ ret = pmt_add_dev(pdev, &header, quirks);
+ if (ret)
+ continue;
+
+ found_devices = true;
+ } while (true);
+ }
if (!found_devices)
return -ENODEV;
@@ -200,10 +236,12 @@ static void pmt_pci_remove(struct pci_dev *pdev)
}
#define PCI_DEVICE_ID_INTEL_PMT_ADL 0x467d
+#define PCI_DEVICE_ID_INTEL_PMT_DG1 0x490e
#define PCI_DEVICE_ID_INTEL_PMT_OOBMSM 0x09a7
#define PCI_DEVICE_ID_INTEL_PMT_TGL 0x9a0d
static const struct pci_device_id pmt_pci_ids[] = {
{ PCI_DEVICE_DATA(INTEL, PMT_ADL, &tgl_info) },
+ { PCI_DEVICE_DATA(INTEL, PMT_DG1, &dg1_info) },
{ PCI_DEVICE_DATA(INTEL, PMT_OOBMSM, NULL) },
{ PCI_DEVICE_DATA(INTEL, PMT_TGL, &tgl_info) },
{ }
diff --git a/drivers/mfd/intel_quark_i2c_gpio.c b/drivers/mfd/intel_quark_i2c_gpio.c
index fe8ca945f367..01935ae4e9e1 100644
--- a/drivers/mfd/intel_quark_i2c_gpio.c
+++ b/drivers/mfd/intel_quark_i2c_gpio.c
@@ -16,8 +16,9 @@
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/dmi.h>
+#include <linux/i2c.h>
#include <linux/platform_data/gpio-dwapb.h>
-#include <linux/platform_data/i2c-designware.h>
+#include <linux/property.h>
/* PCI BAR for register base address */
#define MFD_I2C_BAR 0
@@ -45,34 +46,54 @@
#define INTEL_QUARK_I2C_CLK_HZ 33000000
struct intel_quark_mfd {
- struct device *dev;
struct clk *i2c_clk;
struct clk_lookup *i2c_clk_lookup;
};
+static const struct property_entry intel_quark_i2c_controller_standard_properties[] = {
+ PROPERTY_ENTRY_U32("clock-frequency", I2C_MAX_STANDARD_MODE_FREQ),
+ { }
+};
+
+static const struct software_node intel_quark_i2c_controller_standard_node = {
+ .name = "intel-quark-i2c-controller",
+ .properties = intel_quark_i2c_controller_standard_properties,
+};
+
+static const struct property_entry intel_quark_i2c_controller_fast_properties[] = {
+ PROPERTY_ENTRY_U32("clock-frequency", I2C_MAX_FAST_MODE_FREQ),
+ { }
+};
+
+static const struct software_node intel_quark_i2c_controller_fast_node = {
+ .name = "intel-quark-i2c-controller",
+ .properties = intel_quark_i2c_controller_fast_properties,
+};
+
static const struct dmi_system_id dmi_platform_info[] = {
{
.matches = {
DMI_EXACT_MATCH(DMI_BOARD_NAME, "Galileo"),
},
- .driver_data = (void *)100000,
+ .driver_data = (void *)&intel_quark_i2c_controller_standard_node,
},
{
.matches = {
DMI_EXACT_MATCH(DMI_BOARD_NAME, "GalileoGen2"),
},
- .driver_data = (void *)400000,
+ .driver_data = (void *)&intel_quark_i2c_controller_fast_node,
},
{
.matches = {
DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"),
},
- .driver_data = (void *)400000,
+ .driver_data = (void *)&intel_quark_i2c_controller_fast_node,
},
{}
};
-static const struct resource intel_quark_i2c_res[] = {
+/* This is used as a place holder and will be modified at run-time */
+static struct resource intel_quark_i2c_res[] = {
[INTEL_QUARK_IORES_MEM] = {
.flags = IORESOURCE_MEM,
},
@@ -85,7 +106,8 @@ static struct mfd_cell_acpi_match intel_quark_acpi_match_i2c = {
.adr = MFD_ACPI_MATCH_I2C,
};
-static const struct resource intel_quark_gpio_res[] = {
+/* This is used as a place holder and will be modified at run-time */
+static struct resource intel_quark_gpio_res[] = {
[INTEL_QUARK_IORES_MEM] = {
.flags = IORESOURCE_MEM,
},
@@ -96,15 +118,7 @@ static struct mfd_cell_acpi_match intel_quark_acpi_match_gpio = {
};
static struct mfd_cell intel_quark_mfd_cells[] = {
- {
- .id = MFD_GPIO_BAR,
- .name = "gpio-dwapb",
- .acpi_match = &intel_quark_acpi_match_gpio,
- .num_resources = ARRAY_SIZE(intel_quark_gpio_res),
- .resources = intel_quark_gpio_res,
- .ignore_resource_conflicts = true,
- },
- {
+ [MFD_I2C_BAR] = {
.id = MFD_I2C_BAR,
.name = "i2c_designware",
.acpi_match = &intel_quark_acpi_match_i2c,
@@ -112,6 +126,14 @@ static struct mfd_cell intel_quark_mfd_cells[] = {
.resources = intel_quark_i2c_res,
.ignore_resource_conflicts = true,
},
+ [MFD_GPIO_BAR] = {
+ .id = MFD_GPIO_BAR,
+ .name = "gpio-dwapb",
+ .acpi_match = &intel_quark_acpi_match_gpio,
+ .num_resources = ARRAY_SIZE(intel_quark_gpio_res),
+ .resources = intel_quark_gpio_res,
+ .ignore_resource_conflicts = true,
+ },
};
static const struct pci_device_id intel_quark_mfd_ids[] = {
@@ -155,48 +177,37 @@ static void intel_quark_unregister_i2c_clk(struct device *dev)
clk_unregister(quark_mfd->i2c_clk);
}
-static int intel_quark_i2c_setup(struct pci_dev *pdev, struct mfd_cell *cell)
+static int intel_quark_i2c_setup(struct pci_dev *pdev)
{
+ struct mfd_cell *cell = &intel_quark_mfd_cells[MFD_I2C_BAR];
+ struct resource *res = intel_quark_i2c_res;
const struct dmi_system_id *dmi_id;
- struct dw_i2c_platform_data *pdata;
- struct resource *res = (struct resource *)cell->resources;
- struct device *dev = &pdev->dev;
- res[INTEL_QUARK_IORES_MEM].start =
- pci_resource_start(pdev, MFD_I2C_BAR);
- res[INTEL_QUARK_IORES_MEM].end =
- pci_resource_end(pdev, MFD_I2C_BAR);
+ res[INTEL_QUARK_IORES_MEM].start = pci_resource_start(pdev, MFD_I2C_BAR);
+ res[INTEL_QUARK_IORES_MEM].end = pci_resource_end(pdev, MFD_I2C_BAR);
- res[INTEL_QUARK_IORES_IRQ].start = pdev->irq;
- res[INTEL_QUARK_IORES_IRQ].end = pdev->irq;
-
- pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata)
- return -ENOMEM;
+ res[INTEL_QUARK_IORES_IRQ].start = pci_irq_vector(pdev, 0);
+ res[INTEL_QUARK_IORES_IRQ].end = pci_irq_vector(pdev, 0);
/* Normal mode by default */
- pdata->i2c_scl_freq = 100000;
+ cell->swnode = &intel_quark_i2c_controller_standard_node;
dmi_id = dmi_first_match(dmi_platform_info);
if (dmi_id)
- pdata->i2c_scl_freq = (uintptr_t)dmi_id->driver_data;
-
- cell->platform_data = pdata;
- cell->pdata_size = sizeof(*pdata);
+ cell->swnode = (struct software_node *)dmi_id->driver_data;
return 0;
}
-static int intel_quark_gpio_setup(struct pci_dev *pdev, struct mfd_cell *cell)
+static int intel_quark_gpio_setup(struct pci_dev *pdev)
{
+ struct mfd_cell *cell = &intel_quark_mfd_cells[MFD_GPIO_BAR];
+ struct resource *res = intel_quark_gpio_res;
struct dwapb_platform_data *pdata;
- struct resource *res = (struct resource *)cell->resources;
struct device *dev = &pdev->dev;
- res[INTEL_QUARK_IORES_MEM].start =
- pci_resource_start(pdev, MFD_GPIO_BAR);
- res[INTEL_QUARK_IORES_MEM].end =
- pci_resource_end(pdev, MFD_GPIO_BAR);
+ res[INTEL_QUARK_IORES_MEM].start = pci_resource_start(pdev, MFD_GPIO_BAR);
+ res[INTEL_QUARK_IORES_MEM].end = pci_resource_end(pdev, MFD_GPIO_BAR);
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
@@ -215,7 +226,7 @@ static int intel_quark_gpio_setup(struct pci_dev *pdev, struct mfd_cell *cell)
pdata->properties->idx = 0;
pdata->properties->ngpio = INTEL_QUARK_MFD_NGPIO;
pdata->properties->gpio_base = INTEL_QUARK_MFD_GPIO_BASE;
- pdata->properties->irq[0] = pdev->irq;
+ pdata->properties->irq[0] = pci_irq_vector(pdev, 0);
pdata->properties->irq_shared = true;
cell->platform_data = pdata;
@@ -238,29 +249,37 @@ static int intel_quark_mfd_probe(struct pci_dev *pdev,
if (!quark_mfd)
return -ENOMEM;
- quark_mfd->dev = &pdev->dev;
dev_set_drvdata(&pdev->dev, quark_mfd);
ret = intel_quark_register_i2c_clk(&pdev->dev);
if (ret)
return ret;
- ret = intel_quark_i2c_setup(pdev, &intel_quark_mfd_cells[1]);
- if (ret)
+ pci_set_master(pdev);
+
+ /* This driver only requires 1 IRQ vector */
+ ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
+ if (ret < 0)
goto err_unregister_i2c_clk;
- ret = intel_quark_gpio_setup(pdev, &intel_quark_mfd_cells[0]);
+ ret = intel_quark_i2c_setup(pdev);
if (ret)
- goto err_unregister_i2c_clk;
+ goto err_free_irq_vectors;
+
+ ret = intel_quark_gpio_setup(pdev);
+ if (ret)
+ goto err_free_irq_vectors;
ret = mfd_add_devices(&pdev->dev, 0, intel_quark_mfd_cells,
ARRAY_SIZE(intel_quark_mfd_cells), NULL, 0,
NULL);
if (ret)
- goto err_unregister_i2c_clk;
+ goto err_free_irq_vectors;
return 0;
+err_free_irq_vectors:
+ pci_free_irq_vectors(pdev);
err_unregister_i2c_clk:
intel_quark_unregister_i2c_clk(&pdev->dev);
return ret;
@@ -268,8 +287,9 @@ err_unregister_i2c_clk:
static void intel_quark_mfd_remove(struct pci_dev *pdev)
{
- intel_quark_unregister_i2c_clk(&pdev->dev);
mfd_remove_devices(&pdev->dev);
+ pci_free_irq_vectors(pdev);
+ intel_quark_unregister_i2c_clk(&pdev->dev);
}
static struct pci_driver intel_quark_mfd_driver = {
diff --git a/drivers/mfd/lm3533-core.c b/drivers/mfd/lm3533-core.c
index 22fdffd564f7..5690768f3e63 100644
--- a/drivers/mfd/lm3533-core.c
+++ b/drivers/mfd/lm3533-core.c
@@ -358,7 +358,7 @@ static struct attribute *lm3533_attributes[] = {
static umode_t lm3533_attr_is_visible(struct kobject *kobj,
struct attribute *attr, int n)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
struct lm3533 *lm3533 = dev_get_drvdata(dev);
struct device_attribute *dattr = to_dev_attr(attr);
struct lm3533_device_attribute *lattr = to_lm3533_dev_attr(dattr);
diff --git a/drivers/mfd/lpc_sch.c b/drivers/mfd/lpc_sch.c
index f27eb8dabc1c..428a526cbe86 100644
--- a/drivers/mfd/lpc_sch.c
+++ b/drivers/mfd/lpc_sch.c
@@ -26,9 +26,6 @@
#define GPIO_IO_SIZE 64
#define GPIO_IO_SIZE_CENTERTON 128
-/* Intel Quark X1000 GPIO IRQ Number */
-#define GPIO_IRQ_QUARK_X1000 9
-
#define WDTBASE 0x84
#define WDT_IO_SIZE 64
@@ -43,30 +40,25 @@ struct lpc_sch_info {
unsigned int io_size_smbus;
unsigned int io_size_gpio;
unsigned int io_size_wdt;
- int irq_gpio;
};
static struct lpc_sch_info sch_chipset_info[] = {
[LPC_SCH] = {
.io_size_smbus = SMBUS_IO_SIZE,
.io_size_gpio = GPIO_IO_SIZE,
- .irq_gpio = -1,
},
[LPC_ITC] = {
.io_size_smbus = SMBUS_IO_SIZE,
.io_size_gpio = GPIO_IO_SIZE,
.io_size_wdt = WDT_IO_SIZE,
- .irq_gpio = -1,
},
[LPC_CENTERTON] = {
.io_size_smbus = SMBUS_IO_SIZE,
.io_size_gpio = GPIO_IO_SIZE_CENTERTON,
.io_size_wdt = WDT_IO_SIZE,
- .irq_gpio = -1,
},
[LPC_QUARK_X1000] = {
.io_size_gpio = GPIO_IO_SIZE,
- .irq_gpio = GPIO_IRQ_QUARK_X1000,
.io_size_wdt = WDT_IO_SIZE,
},
};
@@ -113,13 +105,13 @@ static int lpc_sch_get_io(struct pci_dev *pdev, int where, const char *name,
}
static int lpc_sch_populate_cell(struct pci_dev *pdev, int where,
- const char *name, int size, int irq,
- int id, struct mfd_cell *cell)
+ const char *name, int size, int id,
+ struct mfd_cell *cell)
{
struct resource *res;
int ret;
- res = devm_kcalloc(&pdev->dev, 2, sizeof(*res), GFP_KERNEL);
+ res = devm_kzalloc(&pdev->dev, sizeof(*res), GFP_KERNEL);
if (!res)
return -ENOMEM;
@@ -135,18 +127,6 @@ static int lpc_sch_populate_cell(struct pci_dev *pdev, int where,
cell->ignore_resource_conflicts = true;
cell->id = id;
- /* Check if we need to add an IRQ resource */
- if (irq < 0)
- return 0;
-
- res++;
-
- res->start = irq;
- res->end = irq;
- res->flags = IORESOURCE_IRQ;
-
- cell->num_resources++;
-
return 0;
}
@@ -158,7 +138,7 @@ static int lpc_sch_probe(struct pci_dev *dev, const struct pci_device_id *id)
int ret;
ret = lpc_sch_populate_cell(dev, SMBASE, "isch_smbus",
- info->io_size_smbus, -1,
+ info->io_size_smbus,
id->device, &lpc_sch_cells[cells]);
if (ret < 0)
return ret;
@@ -166,7 +146,7 @@ static int lpc_sch_probe(struct pci_dev *dev, const struct pci_device_id *id)
cells++;
ret = lpc_sch_populate_cell(dev, GPIOBASE, "sch_gpio",
- info->io_size_gpio, info->irq_gpio,
+ info->io_size_gpio,
id->device, &lpc_sch_cells[cells]);
if (ret < 0)
return ret;
@@ -174,7 +154,7 @@ static int lpc_sch_probe(struct pci_dev *dev, const struct pci_device_id *id)
cells++;
ret = lpc_sch_populate_cell(dev, WDTBASE, "ie6xx_wdt",
- info->io_size_wdt, -1,
+ info->io_size_wdt,
id->device, &lpc_sch_cells[cells]);
if (ret < 0)
return ret;
diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c
index 55d3a6f97783..68d8f2b95287 100644
--- a/drivers/mfd/max8997.c
+++ b/drivers/mfd/max8997.c
@@ -29,9 +29,9 @@
static const struct mfd_cell max8997_devs[] = {
{ .name = "max8997-pmic", },
{ .name = "max8997-rtc", },
- { .name = "max8997-battery", .of_compatible = "maxim,max8997-battery", },
+ { .name = "max8997-battery", },
{ .name = "max8997-haptic", },
- { .name = "max8997-muic", .of_compatible = "maxim,max8997-muic", },
+ { .name = "max8997-muic", },
{ .name = "max8997-led", .id = 1 },
{ .name = "max8997-led", .id = 2 },
};
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
index fc00aaccb5f7..6f02b8022c6d 100644
--- a/drivers/mfd/mfd-core.c
+++ b/drivers/mfd/mfd-core.c
@@ -65,7 +65,7 @@ static void mfd_acpi_add_device(const struct mfd_cell *cell,
{
const struct mfd_cell_acpi_match *match = cell->acpi_match;
struct acpi_device *parent, *child;
- struct acpi_device *adev;
+ struct acpi_device *adev = NULL;
parent = ACPI_COMPANION(pdev->dev.parent);
if (!parent)
@@ -77,10 +77,9 @@ static void mfd_acpi_add_device(const struct mfd_cell *cell,
* _ADR or it will use the parent handle if is no ID is given.
*
* Note that use of _ADR is a grey area in the ACPI specification,
- * though Intel Galileo Gen2 is using it to distinguish the children
- * devices.
+ * though at least Intel Galileo Gen 2 is using it to distinguish
+ * the children devices.
*/
- adev = parent;
if (match) {
if (match->pnpid) {
struct acpi_device_id ids[2] = {};
@@ -93,22 +92,11 @@ static void mfd_acpi_add_device(const struct mfd_cell *cell,
}
}
} else {
- unsigned long long adr;
- acpi_status status;
-
- list_for_each_entry(child, &parent->children, node) {
- status = acpi_evaluate_integer(child->handle,
- "_ADR", NULL,
- &adr);
- if (ACPI_SUCCESS(status) && match->adr == adr) {
- adev = child;
- break;
- }
- }
+ adev = acpi_find_child_device(parent, match->adr, false);
}
}
- ACPI_COMPANION_SET(&pdev->dev, adev);
+ ACPI_COMPANION_SET(&pdev->dev, adev ?: parent);
}
#else
static inline void mfd_acpi_add_device(const struct mfd_cell *cell,
@@ -238,8 +226,8 @@ static int mfd_add_device(struct device *parent, int id,
goto fail_of_entry;
}
- if (cell->properties) {
- ret = platform_device_add_properties(pdev, cell->properties);
+ if (cell->swnode) {
+ ret = device_add_software_node(&pdev->dev, cell->swnode);
if (ret)
goto fail_of_entry;
}
@@ -304,6 +292,7 @@ fail_of_entry:
list_del(&of_entry->list);
kfree(of_entry);
}
+ device_remove_software_node(&pdev->dev);
fail_alias:
regulator_bulk_unregister_supply_alias(&pdev->dev,
cell->parent_supplies,
@@ -372,6 +361,8 @@ static int mfd_remove_devices_fn(struct device *dev, void *data)
regulator_bulk_unregister_supply_alias(dev, cell->parent_supplies,
cell->num_parent_supplies);
+ device_remove_software_node(&pdev->dev);
+
platform_device_unregister(pdev);
return 0;
}
diff --git a/drivers/mfd/ntxec.c b/drivers/mfd/ntxec.c
new file mode 100644
index 000000000000..b711e73eedcb
--- /dev/null
+++ b/drivers/mfd/ntxec.c
@@ -0,0 +1,271 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * The Netronix embedded controller is a microcontroller found in some
+ * e-book readers designed by the original design manufacturer Netronix, Inc.
+ * It contains RTC, battery monitoring, system power management, and PWM
+ * functionality.
+ *
+ * This driver implements register access, version detection, and system
+ * power-off/reset.
+ *
+ * Copyright 2020 Jonathan Neuschäfer <j.neuschaefer@gmx.net>
+ */
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/ntxec.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/reboot.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+#include <asm/unaligned.h>
+
+#define NTXEC_REG_VERSION 0x00
+#define NTXEC_REG_POWEROFF 0x50
+#define NTXEC_REG_POWERKEEP 0x70
+#define NTXEC_REG_RESET 0x90
+
+#define NTXEC_POWEROFF_VALUE 0x0100
+#define NTXEC_POWERKEEP_VALUE 0x0800
+#define NTXEC_RESET_VALUE 0xff00
+
+static struct i2c_client *poweroff_restart_client;
+
+static void ntxec_poweroff(void)
+{
+ int res;
+ u8 buf[3] = { NTXEC_REG_POWEROFF };
+ struct i2c_msg msgs[] = {
+ {
+ .addr = poweroff_restart_client->addr,
+ .flags = 0,
+ .len = sizeof(buf),
+ .buf = buf,
+ },
+ };
+
+ put_unaligned_be16(NTXEC_POWEROFF_VALUE, buf + 1);
+
+ res = i2c_transfer(poweroff_restart_client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (res < 0)
+ dev_warn(&poweroff_restart_client->dev,
+ "Failed to power off (err = %d)\n", res);
+
+ /*
+ * The time from the register write until the host CPU is powered off
+ * has been observed to be about 2.5 to 3 seconds. Sleep long enough to
+ * safely avoid returning from the poweroff handler.
+ */
+ msleep(5000);
+}
+
+static int ntxec_restart(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ int res;
+ u8 buf[3] = { NTXEC_REG_RESET };
+ /*
+ * NOTE: The lower half of the reset value is not sent, because sending
+ * it causes an I2C error. (The reset handler in the downstream driver
+ * does send the full two-byte value, but doesn't check the result).
+ */
+ struct i2c_msg msgs[] = {
+ {
+ .addr = poweroff_restart_client->addr,
+ .flags = 0,
+ .len = sizeof(buf) - 1,
+ .buf = buf,
+ },
+ };
+
+ put_unaligned_be16(NTXEC_RESET_VALUE, buf + 1);
+
+ res = i2c_transfer(poweroff_restart_client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (res < 0)
+ dev_warn(&poweroff_restart_client->dev,
+ "Failed to restart (err = %d)\n", res);
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block ntxec_restart_handler = {
+ .notifier_call = ntxec_restart,
+ .priority = 128,
+};
+
+static int regmap_ignore_write(void *context,
+ unsigned int reg, unsigned int val)
+
+{
+ struct regmap *regmap = context;
+
+ regmap_write(regmap, reg, val);
+
+ return 0;
+}
+
+static int regmap_wrap_read(void *context, unsigned int reg,
+ unsigned int *val)
+{
+ struct regmap *regmap = context;
+
+ return regmap_read(regmap, reg, val);
+}
+
+/*
+ * Some firmware versions do not ack written data, add a wrapper. It
+ * is used to stack another regmap on top.
+ */
+static const struct regmap_config regmap_config_noack = {
+ .name = "ntxec_noack",
+ .reg_bits = 8,
+ .val_bits = 16,
+ .cache_type = REGCACHE_NONE,
+ .reg_write = regmap_ignore_write,
+ .reg_read = regmap_wrap_read
+};
+
+static const struct regmap_config regmap_config = {
+ .name = "ntxec",
+ .reg_bits = 8,
+ .val_bits = 16,
+ .cache_type = REGCACHE_NONE,
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+};
+
+static const struct mfd_cell ntxec_subdev[] = {
+ { .name = "ntxec-rtc" },
+ { .name = "ntxec-pwm" },
+};
+
+static const struct mfd_cell ntxec_subdev_pwm[] = {
+ { .name = "ntxec-pwm" },
+};
+
+static int ntxec_probe(struct i2c_client *client)
+{
+ struct ntxec *ec;
+ unsigned int version;
+ int res;
+ const struct mfd_cell *subdevs;
+ size_t n_subdevs;
+
+ ec = devm_kmalloc(&client->dev, sizeof(*ec), GFP_KERNEL);
+ if (!ec)
+ return -ENOMEM;
+
+ ec->dev = &client->dev;
+
+ ec->regmap = devm_regmap_init_i2c(client, &regmap_config);
+ if (IS_ERR(ec->regmap)) {
+ dev_err(ec->dev, "Failed to set up regmap for device\n");
+ return PTR_ERR(ec->regmap);
+ }
+
+ /* Determine the firmware version */
+ res = regmap_read(ec->regmap, NTXEC_REG_VERSION, &version);
+ if (res < 0) {
+ dev_err(ec->dev, "Failed to read firmware version number\n");
+ return res;
+ }
+
+ /* Bail out if we encounter an unknown firmware version */
+ switch (version) {
+ case NTXEC_VERSION_KOBO_AURA:
+ subdevs = ntxec_subdev;
+ n_subdevs = ARRAY_SIZE(ntxec_subdev);
+ break;
+ case NTXEC_VERSION_TOLINO_SHINE2:
+ subdevs = ntxec_subdev_pwm;
+ n_subdevs = ARRAY_SIZE(ntxec_subdev_pwm);
+ /* Another regmap stacked on top of the other */
+ ec->regmap = devm_regmap_init(ec->dev, NULL,
+ ec->regmap,
+ &regmap_config_noack);
+ if (IS_ERR(ec->regmap))
+ return PTR_ERR(ec->regmap);
+ break;
+ default:
+ dev_err(ec->dev,
+ "Netronix embedded controller version %04x is not supported.\n",
+ version);
+ return -ENODEV;
+ }
+
+ dev_info(ec->dev,
+ "Netronix embedded controller version %04x detected.\n", version);
+
+ if (of_device_is_system_power_controller(ec->dev->of_node)) {
+ /*
+ * Set the 'powerkeep' bit. This is necessary on some boards
+ * in order to keep the system running.
+ */
+ res = regmap_write(ec->regmap, NTXEC_REG_POWERKEEP,
+ NTXEC_POWERKEEP_VALUE);
+ if (res < 0)
+ return res;
+
+ if (poweroff_restart_client)
+ /*
+ * Another instance of the driver already took
+ * poweroff/restart duties.
+ */
+ dev_err(ec->dev, "poweroff_restart_client already assigned\n");
+ else
+ poweroff_restart_client = client;
+
+ if (pm_power_off)
+ /* Another driver already registered a poweroff handler. */
+ dev_err(ec->dev, "pm_power_off already assigned\n");
+ else
+ pm_power_off = ntxec_poweroff;
+
+ res = register_restart_handler(&ntxec_restart_handler);
+ if (res)
+ dev_err(ec->dev,
+ "Failed to register restart handler: %d\n", res);
+ }
+
+ i2c_set_clientdata(client, ec);
+
+ res = devm_mfd_add_devices(ec->dev, PLATFORM_DEVID_NONE,
+ subdevs, n_subdevs, NULL, 0, NULL);
+ if (res)
+ dev_err(ec->dev, "Failed to add subdevices: %d\n", res);
+
+ return res;
+}
+
+static int ntxec_remove(struct i2c_client *client)
+{
+ if (client == poweroff_restart_client) {
+ poweroff_restart_client = NULL;
+ pm_power_off = NULL;
+ unregister_restart_handler(&ntxec_restart_handler);
+ }
+
+ return 0;
+}
+
+static const struct of_device_id of_ntxec_match_table[] = {
+ { .compatible = "netronix,ntxec", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, of_ntxec_match_table);
+
+static struct i2c_driver ntxec_driver = {
+ .driver = {
+ .name = "ntxec",
+ .of_match_table = of_ntxec_match_table,
+ },
+ .probe_new = ntxec_probe,
+ .remove = ntxec_remove,
+};
+module_i2c_driver(ntxec_driver);
+
+MODULE_AUTHOR("Jonathan Neuschäfer <j.neuschaefer@gmx.net>");
+MODULE_DESCRIPTION("Core driver for Netronix EC");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/rn5t618.c b/drivers/mfd/rn5t618.c
index dc452df1f1bf..6ed04e6dbc78 100644
--- a/drivers/mfd/rn5t618.c
+++ b/drivers/mfd/rn5t618.c
@@ -45,8 +45,11 @@ static bool rn5t618_volatile_reg(struct device *dev, unsigned int reg)
case RN5T618_INTMON:
case RN5T618_RTC_CTRL1 ... RN5T618_RTC_CTRL2:
case RN5T618_RTC_SECONDS ... RN5T618_RTC_YEAR:
+ case RN5T618_CHGCTL1:
+ case RN5T618_REGISET1 ... RN5T618_REGISET2:
case RN5T618_CHGSTATE:
case RN5T618_CHGCTRL_IRR ... RN5T618_CHGERR_MONI:
+ case RN5T618_GCHGDET:
case RN5T618_CONTROL ... RN5T618_CC_AVEREG0:
return true;
default:
diff --git a/drivers/mfd/rohm-bd71828.c b/drivers/mfd/rohm-bd71828.c
index 210261d026f2..714d9fcbf07b 100644
--- a/drivers/mfd/rohm-bd71828.c
+++ b/drivers/mfd/rohm-bd71828.c
@@ -2,7 +2,7 @@
//
// Copyright (C) 2019 ROHM Semiconductors
//
-// ROHM BD71828 PMIC driver
+// ROHM BD71828/BD71815 PMIC driver
#include <linux/gpio_keys.h>
#include <linux/i2c.h>
@@ -11,7 +11,9 @@
#include <linux/ioport.h>
#include <linux/irq.h>
#include <linux/mfd/core.h>
+#include <linux/mfd/rohm-bd71815.h>
#include <linux/mfd/rohm-bd71828.h>
+#include <linux/mfd/rohm-generic.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
@@ -29,12 +31,84 @@ static struct gpio_keys_platform_data bd71828_powerkey_data = {
.name = "bd71828-pwrkey",
};
-static const struct resource rtc_irqs[] = {
+static const struct resource bd71815_rtc_irqs[] = {
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_RTC0, "bd71815-rtc-alm-0"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_RTC1, "bd71815-rtc-alm-1"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_RTC2, "bd71815-rtc-alm-2"),
+};
+
+static const struct resource bd71828_rtc_irqs[] = {
DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC0, "bd71828-rtc-alm-0"),
DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC1, "bd71828-rtc-alm-1"),
DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC2, "bd71828-rtc-alm-2"),
};
+static struct resource bd71815_power_irqs[] = {
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_RMV, "bd71815-dcin-rmv"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_CLPS_OUT, "bd71815-clps-out"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_CLPS_IN, "bd71815-clps-in"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_OVP_RES, "bd71815-dcin-ovp-res"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_OVP_DET, "bd71815-dcin-ovp-det"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_MON_RES, "bd71815-dcin-mon-res"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_MON_DET, "bd71815-dcin-mon-det"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_UV_RES, "bd71815-vsys-uv-res"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_UV_DET, "bd71815-vsys-uv-det"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_LOW_RES, "bd71815-vsys-low-res"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_LOW_DET, "bd71815-vsys-low-det"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_MON_RES, "bd71815-vsys-mon-res"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_MON_RES, "bd71815-vsys-mon-det"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_WDG_TEMP, "bd71815-chg-wdg-temp"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_WDG_TIME, "bd71815-chg-wdg"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_RECHARGE_RES, "bd71815-rechg-res"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_RECHARGE_DET, "bd71815-rechg-det"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_RANGED_TEMP_TRANSITION, "bd71815-ranged-temp-transit"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_STATE_TRANSITION, "bd71815-chg-state-change"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_TEMP_NORMAL, "bd71815-bat-temp-normal"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_TEMP_ERANGE, "bd71815-bat-temp-erange"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_REMOVED, "bd71815-bat-rmv"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_DETECTED, "bd71815-bat-det"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_THERM_REMOVED, "bd71815-therm-rmv"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_THERM_DETECTED, "bd71815-therm-det"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_DEAD, "bd71815-bat-dead"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_SHORTC_RES, "bd71815-bat-short-res"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_SHORTC_DET, "bd71815-bat-short-det"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_LOW_VOLT_RES, "bd71815-bat-low-res"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_LOW_VOLT_DET, "bd71815-bat-low-det"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_VOLT_RES, "bd71815-bat-over-res"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_VOLT_DET, "bd71815-bat-over-det"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_MON_RES, "bd71815-bat-mon-res"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_MON_DET, "bd71815-bat-mon-det"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_CC_MON1, "bd71815-bat-cc-mon1"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_CC_MON2, "bd71815-bat-cc-mon2"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_CC_MON3, "bd71815-bat-cc-mon3"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_1_RES, "bd71815-bat-oc1-res"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_1_DET, "bd71815-bat-oc1-det"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_2_RES, "bd71815-bat-oc2-res"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_2_DET, "bd71815-bat-oc2-det"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_3_RES, "bd71815-bat-oc3-res"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_3_DET, "bd71815-bat-oc3-det"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_LOW_RES, "bd71815-bat-low-res"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_LOW_DET, "bd71815-bat-low-det"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_HI_RES, "bd71815-bat-hi-res"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_HI_DET, "bd71815-bat-hi-det"),
+};
+
+static struct mfd_cell bd71815_mfd_cells[] = {
+ { .name = "bd71815-pmic", },
+ { .name = "bd71815-clk", },
+ { .name = "bd71815-gpo", },
+ {
+ .name = "bd71815-power",
+ .num_resources = ARRAY_SIZE(bd71815_power_irqs),
+ .resources = &bd71815_power_irqs[0],
+ },
+ {
+ .name = "bd71815-rtc",
+ .num_resources = ARRAY_SIZE(bd71815_rtc_irqs),
+ .resources = &bd71815_rtc_irqs[0],
+ },
+};
+
static struct mfd_cell bd71828_mfd_cells[] = {
{ .name = "bd71828-pmic", },
{ .name = "bd71828-gpio", },
@@ -47,8 +121,8 @@ static struct mfd_cell bd71828_mfd_cells[] = {
{ .name = "bd71827-power", },
{
.name = "bd71828-rtc",
- .resources = rtc_irqs,
- .num_resources = ARRAY_SIZE(rtc_irqs),
+ .resources = bd71828_rtc_irqs,
+ .num_resources = ARRAY_SIZE(bd71828_rtc_irqs),
}, {
.name = "gpio-keys",
.platform_data = &bd71828_powerkey_data,
@@ -56,7 +130,35 @@ static struct mfd_cell bd71828_mfd_cells[] = {
},
};
-static const struct regmap_range volatile_ranges[] = {
+static const struct regmap_range bd71815_volatile_ranges[] = {
+ {
+ .range_min = BD71815_REG_SEC,
+ .range_max = BD71815_REG_YEAR,
+ }, {
+ .range_min = BD71815_REG_CONF,
+ .range_max = BD71815_REG_BAT_TEMP,
+ }, {
+ .range_min = BD71815_REG_VM_IBAT_U,
+ .range_max = BD71815_REG_CC_CTRL,
+ }, {
+ .range_min = BD71815_REG_CC_STAT,
+ .range_max = BD71815_REG_CC_CURCD_L,
+ }, {
+ .range_min = BD71815_REG_VM_BTMP_MON,
+ .range_max = BD71815_REG_VM_BTMP_MON,
+ }, {
+ .range_min = BD71815_REG_INT_STAT,
+ .range_max = BD71815_REG_INT_UPDATE,
+ }, {
+ .range_min = BD71815_REG_VM_VSYS_U,
+ .range_max = BD71815_REG_REX_CTRL_1,
+ }, {
+ .range_min = BD71815_REG_FULL_CCNTD_3,
+ .range_max = BD71815_REG_CCNTD_CHG_2,
+ },
+};
+
+static const struct regmap_range bd71828_volatile_ranges[] = {
{
.range_min = BD71828_REG_PS_CTRL_1,
.range_max = BD71828_REG_PS_CTRL_1,
@@ -80,15 +182,28 @@ static const struct regmap_range volatile_ranges[] = {
},
};
-static const struct regmap_access_table volatile_regs = {
- .yes_ranges = &volatile_ranges[0],
- .n_yes_ranges = ARRAY_SIZE(volatile_ranges),
+static const struct regmap_access_table bd71815_volatile_regs = {
+ .yes_ranges = &bd71815_volatile_ranges[0],
+ .n_yes_ranges = ARRAY_SIZE(bd71815_volatile_ranges),
+};
+
+static const struct regmap_access_table bd71828_volatile_regs = {
+ .yes_ranges = &bd71828_volatile_ranges[0],
+ .n_yes_ranges = ARRAY_SIZE(bd71828_volatile_ranges),
+};
+
+static const struct regmap_config bd71815_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .volatile_table = &bd71815_volatile_regs,
+ .max_register = BD71815_MAX_REGISTER - 1,
+ .cache_type = REGCACHE_RBTREE,
};
-static struct regmap_config bd71828_regmap = {
+static const struct regmap_config bd71828_regmap = {
.reg_bits = 8,
.val_bits = 8,
- .volatile_table = &volatile_regs,
+ .volatile_table = &bd71828_volatile_regs,
.max_register = BD71828_MAX_REGISTER,
.cache_type = REGCACHE_RBTREE,
};
@@ -96,7 +211,7 @@ static struct regmap_config bd71828_regmap = {
/*
* Mapping of main IRQ register bits to sub-IRQ register offsets so that we can
* access corect sub-IRQ registers based on bits that are set in main IRQ
- * register.
+ * register. BD71815 and BD71828 have same sub-register-block offests.
*/
static unsigned int bit0_offsets[] = {11}; /* RTC IRQ */
@@ -108,7 +223,7 @@ static unsigned int bit5_offsets[] = {3}; /* VSYS IRQ */
static unsigned int bit6_offsets[] = {1, 2}; /* DCIN IRQ */
static unsigned int bit7_offsets[] = {0}; /* BUCK IRQ */
-static struct regmap_irq_sub_irq_map bd71828_sub_irq_offsets[] = {
+static struct regmap_irq_sub_irq_map bd718xx_sub_irq_offsets[] = {
REGMAP_IRQ_MAIN_REG_OFFSET(bit0_offsets),
REGMAP_IRQ_MAIN_REG_OFFSET(bit1_offsets),
REGMAP_IRQ_MAIN_REG_OFFSET(bit2_offsets),
@@ -119,6 +234,88 @@ static struct regmap_irq_sub_irq_map bd71828_sub_irq_offsets[] = {
REGMAP_IRQ_MAIN_REG_OFFSET(bit7_offsets),
};
+static const struct regmap_irq bd71815_irqs[] = {
+ REGMAP_IRQ_REG(BD71815_INT_BUCK1_OCP, 0, BD71815_INT_BUCK1_OCP_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_BUCK2_OCP, 0, BD71815_INT_BUCK2_OCP_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_BUCK3_OCP, 0, BD71815_INT_BUCK3_OCP_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_BUCK4_OCP, 0, BD71815_INT_BUCK4_OCP_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_BUCK5_OCP, 0, BD71815_INT_BUCK5_OCP_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_LED_OVP, 0, BD71815_INT_LED_OVP_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_LED_OCP, 0, BD71815_INT_LED_OCP_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_LED_SCP, 0, BD71815_INT_LED_SCP_MASK),
+ /* DCIN1 interrupts */
+ REGMAP_IRQ_REG(BD71815_INT_DCIN_RMV, 1, BD71815_INT_DCIN_RMV_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_CLPS_OUT, 1, BD71815_INT_CLPS_OUT_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_CLPS_IN, 1, BD71815_INT_CLPS_IN_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_DCIN_OVP_RES, 1, BD71815_INT_DCIN_OVP_RES_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_DCIN_OVP_DET, 1, BD71815_INT_DCIN_OVP_DET_MASK),
+ /* DCIN2 interrupts */
+ REGMAP_IRQ_REG(BD71815_INT_DCIN_MON_RES, 2, BD71815_INT_DCIN_MON_RES_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_DCIN_MON_DET, 2, BD71815_INT_DCIN_MON_DET_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_WDOG, 2, BD71815_INT_WDOG_MASK),
+ /* Vsys */
+ REGMAP_IRQ_REG(BD71815_INT_VSYS_UV_RES, 3, BD71815_INT_VSYS_UV_RES_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_VSYS_UV_DET, 3, BD71815_INT_VSYS_UV_DET_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_VSYS_LOW_RES, 3, BD71815_INT_VSYS_LOW_RES_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_VSYS_LOW_DET, 3, BD71815_INT_VSYS_LOW_DET_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_VSYS_MON_RES, 3, BD71815_INT_VSYS_MON_RES_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_VSYS_MON_DET, 3, BD71815_INT_VSYS_MON_DET_MASK),
+ /* Charger */
+ REGMAP_IRQ_REG(BD71815_INT_CHG_WDG_TEMP, 4, BD71815_INT_CHG_WDG_TEMP_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_CHG_WDG_TIME, 4, BD71815_INT_CHG_WDG_TIME_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_CHG_RECHARGE_RES, 4, BD71815_INT_CHG_RECHARGE_RES_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_CHG_RECHARGE_DET, 4, BD71815_INT_CHG_RECHARGE_DET_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_CHG_RANGED_TEMP_TRANSITION, 4,
+ BD71815_INT_CHG_RANGED_TEMP_TRANSITION_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_CHG_STATE_TRANSITION, 4, BD71815_INT_CHG_STATE_TRANSITION_MASK),
+ /* Battery */
+ REGMAP_IRQ_REG(BD71815_INT_BAT_TEMP_NORMAL, 5, BD71815_INT_BAT_TEMP_NORMAL_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_BAT_TEMP_ERANGE, 5, BD71815_INT_BAT_TEMP_ERANGE_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_BAT_REMOVED, 5, BD71815_INT_BAT_REMOVED_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_BAT_DETECTED, 5, BD71815_INT_BAT_DETECTED_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_THERM_REMOVED, 5, BD71815_INT_THERM_REMOVED_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_THERM_DETECTED, 5, BD71815_INT_THERM_DETECTED_MASK),
+ /* Battery Mon 1 */
+ REGMAP_IRQ_REG(BD71815_INT_BAT_DEAD, 6, BD71815_INT_BAT_DEAD_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_BAT_SHORTC_RES, 6, BD71815_INT_BAT_SHORTC_RES_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_BAT_SHORTC_DET, 6, BD71815_INT_BAT_SHORTC_DET_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_BAT_LOW_VOLT_RES, 6, BD71815_INT_BAT_LOW_VOLT_RES_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_BAT_LOW_VOLT_DET, 6, BD71815_INT_BAT_LOW_VOLT_DET_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_VOLT_RES, 6, BD71815_INT_BAT_OVER_VOLT_RES_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_VOLT_DET, 6, BD71815_INT_BAT_OVER_VOLT_DET_MASK),
+ /* Battery Mon 2 */
+ REGMAP_IRQ_REG(BD71815_INT_BAT_MON_RES, 7, BD71815_INT_BAT_MON_RES_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_BAT_MON_DET, 7, BD71815_INT_BAT_MON_DET_MASK),
+ /* Battery Mon 3 (Coulomb counter) */
+ REGMAP_IRQ_REG(BD71815_INT_BAT_CC_MON1, 8, BD71815_INT_BAT_CC_MON1_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_BAT_CC_MON2, 8, BD71815_INT_BAT_CC_MON2_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_BAT_CC_MON3, 8, BD71815_INT_BAT_CC_MON3_MASK),
+ /* Battery Mon 4 */
+ REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_1_RES, 9, BD71815_INT_BAT_OVER_CURR_1_RES_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_1_DET, 9, BD71815_INT_BAT_OVER_CURR_1_DET_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_2_RES, 9, BD71815_INT_BAT_OVER_CURR_2_RES_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_2_DET, 9, BD71815_INT_BAT_OVER_CURR_2_DET_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_3_RES, 9, BD71815_INT_BAT_OVER_CURR_3_RES_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_3_DET, 9, BD71815_INT_BAT_OVER_CURR_3_DET_MASK),
+ /* Temperature */
+ REGMAP_IRQ_REG(BD71815_INT_TEMP_BAT_LOW_RES, 10, BD71815_INT_TEMP_BAT_LOW_RES_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_TEMP_BAT_LOW_DET, 10, BD71815_INT_TEMP_BAT_LOW_DET_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_TEMP_BAT_HI_RES, 10, BD71815_INT_TEMP_BAT_HI_RES_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_TEMP_BAT_HI_DET, 10, BD71815_INT_TEMP_BAT_HI_DET_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_TEMP_CHIP_OVER_125_RES, 10,
+ BD71815_INT_TEMP_CHIP_OVER_125_RES_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_TEMP_CHIP_OVER_125_DET, 10,
+ BD71815_INT_TEMP_CHIP_OVER_125_DET_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_TEMP_CHIP_OVER_VF_RES, 10,
+ BD71815_INT_TEMP_CHIP_OVER_VF_RES_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_TEMP_CHIP_OVER_VF_DET, 10,
+ BD71815_INT_TEMP_CHIP_OVER_VF_DET_MASK),
+ /* RTC Alarm */
+ REGMAP_IRQ_REG(BD71815_INT_RTC0, 11, BD71815_INT_RTC0_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_RTC1, 11, BD71815_INT_RTC1_MASK),
+ REGMAP_IRQ_REG(BD71815_INT_RTC2, 11, BD71815_INT_RTC2_MASK),
+};
+
static struct regmap_irq bd71828_irqs[] = {
REGMAP_IRQ_REG(BD71828_INT_BUCK1_OCP, 0, BD71828_INT_BUCK1_OCP_MASK),
REGMAP_IRQ_REG(BD71828_INT_BUCK2_OCP, 0, BD71828_INT_BUCK2_OCP_MASK),
@@ -134,10 +331,8 @@ static struct regmap_irq bd71828_irqs[] = {
REGMAP_IRQ_REG(BD71828_INT_CLPS_OUT, 1, BD71828_INT_CLPS_OUT_MASK),
REGMAP_IRQ_REG(BD71828_INT_CLPS_IN, 1, BD71828_INT_CLPS_IN_MASK),
/* DCIN2 interrupts */
- REGMAP_IRQ_REG(BD71828_INT_DCIN_MON_RES, 2,
- BD71828_INT_DCIN_MON_RES_MASK),
- REGMAP_IRQ_REG(BD71828_INT_DCIN_MON_DET, 2,
- BD71828_INT_DCIN_MON_DET_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_DCIN_MON_RES, 2, BD71828_INT_DCIN_MON_RES_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_DCIN_MON_DET, 2, BD71828_INT_DCIN_MON_DET_MASK),
REGMAP_IRQ_REG(BD71828_INT_LONGPUSH, 2, BD71828_INT_LONGPUSH_MASK),
REGMAP_IRQ_REG(BD71828_INT_MIDPUSH, 2, BD71828_INT_MIDPUSH_MASK),
REGMAP_IRQ_REG(BD71828_INT_SHORTPUSH, 2, BD71828_INT_SHORTPUSH_MASK),
@@ -145,102 +340,59 @@ static struct regmap_irq bd71828_irqs[] = {
REGMAP_IRQ_REG(BD71828_INT_WDOG, 2, BD71828_INT_WDOG_MASK),
REGMAP_IRQ_REG(BD71828_INT_SWRESET, 2, BD71828_INT_SWRESET_MASK),
/* Vsys */
- REGMAP_IRQ_REG(BD71828_INT_VSYS_UV_RES, 3,
- BD71828_INT_VSYS_UV_RES_MASK),
- REGMAP_IRQ_REG(BD71828_INT_VSYS_UV_DET, 3,
- BD71828_INT_VSYS_UV_DET_MASK),
- REGMAP_IRQ_REG(BD71828_INT_VSYS_LOW_RES, 3,
- BD71828_INT_VSYS_LOW_RES_MASK),
- REGMAP_IRQ_REG(BD71828_INT_VSYS_LOW_DET, 3,
- BD71828_INT_VSYS_LOW_DET_MASK),
- REGMAP_IRQ_REG(BD71828_INT_VSYS_HALL_IN, 3,
- BD71828_INT_VSYS_HALL_IN_MASK),
- REGMAP_IRQ_REG(BD71828_INT_VSYS_HALL_TOGGLE, 3,
- BD71828_INT_VSYS_HALL_TOGGLE_MASK),
- REGMAP_IRQ_REG(BD71828_INT_VSYS_MON_RES, 3,
- BD71828_INT_VSYS_MON_RES_MASK),
- REGMAP_IRQ_REG(BD71828_INT_VSYS_MON_DET, 3,
- BD71828_INT_VSYS_MON_DET_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_VSYS_UV_RES, 3, BD71828_INT_VSYS_UV_RES_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_VSYS_UV_DET, 3, BD71828_INT_VSYS_UV_DET_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_VSYS_LOW_RES, 3, BD71828_INT_VSYS_LOW_RES_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_VSYS_LOW_DET, 3, BD71828_INT_VSYS_LOW_DET_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_VSYS_HALL_IN, 3, BD71828_INT_VSYS_HALL_IN_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_VSYS_HALL_TOGGLE, 3, BD71828_INT_VSYS_HALL_TOGGLE_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_VSYS_MON_RES, 3, BD71828_INT_VSYS_MON_RES_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_VSYS_MON_DET, 3, BD71828_INT_VSYS_MON_DET_MASK),
/* Charger */
- REGMAP_IRQ_REG(BD71828_INT_CHG_DCIN_ILIM, 4,
- BD71828_INT_CHG_DCIN_ILIM_MASK),
- REGMAP_IRQ_REG(BD71828_INT_CHG_TOPOFF_TO_DONE, 4,
- BD71828_INT_CHG_TOPOFF_TO_DONE_MASK),
- REGMAP_IRQ_REG(BD71828_INT_CHG_WDG_TEMP, 4,
- BD71828_INT_CHG_WDG_TEMP_MASK),
- REGMAP_IRQ_REG(BD71828_INT_CHG_WDG_TIME, 4,
- BD71828_INT_CHG_WDG_TIME_MASK),
- REGMAP_IRQ_REG(BD71828_INT_CHG_RECHARGE_RES, 4,
- BD71828_INT_CHG_RECHARGE_RES_MASK),
- REGMAP_IRQ_REG(BD71828_INT_CHG_RECHARGE_DET, 4,
- BD71828_INT_CHG_RECHARGE_DET_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_CHG_DCIN_ILIM, 4, BD71828_INT_CHG_DCIN_ILIM_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_CHG_TOPOFF_TO_DONE, 4, BD71828_INT_CHG_TOPOFF_TO_DONE_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_CHG_WDG_TEMP, 4, BD71828_INT_CHG_WDG_TEMP_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_CHG_WDG_TIME, 4, BD71828_INT_CHG_WDG_TIME_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_CHG_RECHARGE_RES, 4, BD71828_INT_CHG_RECHARGE_RES_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_CHG_RECHARGE_DET, 4, BD71828_INT_CHG_RECHARGE_DET_MASK),
REGMAP_IRQ_REG(BD71828_INT_CHG_RANGED_TEMP_TRANSITION, 4,
BD71828_INT_CHG_RANGED_TEMP_TRANSITION_MASK),
- REGMAP_IRQ_REG(BD71828_INT_CHG_STATE_TRANSITION, 4,
- BD71828_INT_CHG_STATE_TRANSITION_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_CHG_STATE_TRANSITION, 4, BD71828_INT_CHG_STATE_TRANSITION_MASK),
/* Battery */
- REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_NORMAL, 5,
- BD71828_INT_BAT_TEMP_NORMAL_MASK),
- REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_ERANGE, 5,
- BD71828_INT_BAT_TEMP_ERANGE_MASK),
- REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_WARN, 5,
- BD71828_INT_BAT_TEMP_WARN_MASK),
- REGMAP_IRQ_REG(BD71828_INT_BAT_REMOVED, 5,
- BD71828_INT_BAT_REMOVED_MASK),
- REGMAP_IRQ_REG(BD71828_INT_BAT_DETECTED, 5,
- BD71828_INT_BAT_DETECTED_MASK),
- REGMAP_IRQ_REG(BD71828_INT_THERM_REMOVED, 5,
- BD71828_INT_THERM_REMOVED_MASK),
- REGMAP_IRQ_REG(BD71828_INT_THERM_DETECTED, 5,
- BD71828_INT_THERM_DETECTED_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_NORMAL, 5, BD71828_INT_BAT_TEMP_NORMAL_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_ERANGE, 5, BD71828_INT_BAT_TEMP_ERANGE_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_WARN, 5, BD71828_INT_BAT_TEMP_WARN_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_BAT_REMOVED, 5, BD71828_INT_BAT_REMOVED_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_BAT_DETECTED, 5, BD71828_INT_BAT_DETECTED_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_THERM_REMOVED, 5, BD71828_INT_THERM_REMOVED_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_THERM_DETECTED, 5, BD71828_INT_THERM_DETECTED_MASK),
/* Battery Mon 1 */
REGMAP_IRQ_REG(BD71828_INT_BAT_DEAD, 6, BD71828_INT_BAT_DEAD_MASK),
- REGMAP_IRQ_REG(BD71828_INT_BAT_SHORTC_RES, 6,
- BD71828_INT_BAT_SHORTC_RES_MASK),
- REGMAP_IRQ_REG(BD71828_INT_BAT_SHORTC_DET, 6,
- BD71828_INT_BAT_SHORTC_DET_MASK),
- REGMAP_IRQ_REG(BD71828_INT_BAT_LOW_VOLT_RES, 6,
- BD71828_INT_BAT_LOW_VOLT_RES_MASK),
- REGMAP_IRQ_REG(BD71828_INT_BAT_LOW_VOLT_DET, 6,
- BD71828_INT_BAT_LOW_VOLT_DET_MASK),
- REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_VOLT_RES, 6,
- BD71828_INT_BAT_OVER_VOLT_RES_MASK),
- REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_VOLT_DET, 6,
- BD71828_INT_BAT_OVER_VOLT_DET_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_BAT_SHORTC_RES, 6, BD71828_INT_BAT_SHORTC_RES_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_BAT_SHORTC_DET, 6, BD71828_INT_BAT_SHORTC_DET_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_BAT_LOW_VOLT_RES, 6, BD71828_INT_BAT_LOW_VOLT_RES_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_BAT_LOW_VOLT_DET, 6, BD71828_INT_BAT_LOW_VOLT_DET_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_VOLT_RES, 6, BD71828_INT_BAT_OVER_VOLT_RES_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_VOLT_DET, 6, BD71828_INT_BAT_OVER_VOLT_DET_MASK),
/* Battery Mon 2 */
- REGMAP_IRQ_REG(BD71828_INT_BAT_MON_RES, 7,
- BD71828_INT_BAT_MON_RES_MASK),
- REGMAP_IRQ_REG(BD71828_INT_BAT_MON_DET, 7,
- BD71828_INT_BAT_MON_DET_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_BAT_MON_RES, 7, BD71828_INT_BAT_MON_RES_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_BAT_MON_DET, 7, BD71828_INT_BAT_MON_DET_MASK),
/* Battery Mon 3 (Coulomb counter) */
- REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON1, 8,
- BD71828_INT_BAT_CC_MON1_MASK),
- REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON2, 8,
- BD71828_INT_BAT_CC_MON2_MASK),
- REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON3, 8,
- BD71828_INT_BAT_CC_MON3_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON1, 8, BD71828_INT_BAT_CC_MON1_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON2, 8, BD71828_INT_BAT_CC_MON2_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON3, 8, BD71828_INT_BAT_CC_MON3_MASK),
/* Battery Mon 4 */
- REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_1_RES, 9,
- BD71828_INT_BAT_OVER_CURR_1_RES_MASK),
- REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_1_DET, 9,
- BD71828_INT_BAT_OVER_CURR_1_DET_MASK),
- REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_2_RES, 9,
- BD71828_INT_BAT_OVER_CURR_2_RES_MASK),
- REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_2_DET, 9,
- BD71828_INT_BAT_OVER_CURR_2_DET_MASK),
- REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_3_RES, 9,
- BD71828_INT_BAT_OVER_CURR_3_RES_MASK),
- REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_3_DET, 9,
- BD71828_INT_BAT_OVER_CURR_3_DET_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_1_RES, 9, BD71828_INT_BAT_OVER_CURR_1_RES_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_1_DET, 9, BD71828_INT_BAT_OVER_CURR_1_DET_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_2_RES, 9, BD71828_INT_BAT_OVER_CURR_2_RES_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_2_DET, 9, BD71828_INT_BAT_OVER_CURR_2_DET_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_3_RES, 9, BD71828_INT_BAT_OVER_CURR_3_RES_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_3_DET, 9, BD71828_INT_BAT_OVER_CURR_3_DET_MASK),
/* Temperature */
- REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_LOW_RES, 10,
- BD71828_INT_TEMP_BAT_LOW_RES_MASK),
- REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_LOW_DET, 10,
- BD71828_INT_TEMP_BAT_LOW_DET_MASK),
- REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_HI_RES, 10,
- BD71828_INT_TEMP_BAT_HI_RES_MASK),
- REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_HI_DET, 10,
- BD71828_INT_TEMP_BAT_HI_DET_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_LOW_RES, 10, BD71828_INT_TEMP_BAT_LOW_RES_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_LOW_DET, 10, BD71828_INT_TEMP_BAT_LOW_DET_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_HI_RES, 10, BD71828_INT_TEMP_BAT_HI_RES_MASK),
+ REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_HI_DET, 10, BD71828_INT_TEMP_BAT_HI_DET_MASK),
REGMAP_IRQ_REG(BD71828_INT_TEMP_CHIP_OVER_125_RES, 10,
BD71828_INT_TEMP_CHIP_OVER_125_RES_MASK),
REGMAP_IRQ_REG(BD71828_INT_TEMP_CHIP_OVER_125_DET, 10,
@@ -267,57 +419,133 @@ static struct regmap_irq_chip bd71828_irq_chip = {
.init_ack_masked = true,
.num_regs = 12,
.num_main_regs = 1,
- .sub_reg_offsets = &bd71828_sub_irq_offsets[0],
+ .sub_reg_offsets = &bd718xx_sub_irq_offsets[0],
+ .num_main_status_bits = 8,
+ .irq_reg_stride = 1,
+};
+
+static struct regmap_irq_chip bd71815_irq_chip = {
+ .name = "bd71815_irq",
+ .main_status = BD71815_REG_INT_STAT,
+ .irqs = &bd71815_irqs[0],
+ .num_irqs = ARRAY_SIZE(bd71815_irqs),
+ .status_base = BD71815_REG_INT_STAT_01,
+ .mask_base = BD71815_REG_INT_EN_01,
+ .ack_base = BD71815_REG_INT_STAT_01,
+ .mask_invert = true,
+ .init_ack_masked = true,
+ .num_regs = 12,
+ .num_main_regs = 1,
+ .sub_reg_offsets = &bd718xx_sub_irq_offsets[0],
.num_main_status_bits = 8,
.irq_reg_stride = 1,
};
+static int set_clk_mode(struct device *dev, struct regmap *regmap,
+ int clkmode_reg)
+{
+ int ret;
+ unsigned int open_drain;
+
+ ret = of_property_read_u32(dev->of_node, "rohm,clkout-open-drain", &open_drain);
+ if (ret) {
+ if (ret == -EINVAL)
+ return 0;
+ return ret;
+ }
+ if (open_drain > 1) {
+ dev_err(dev, "bad clk32kout mode configuration");
+ return -EINVAL;
+ }
+
+ if (open_drain)
+ return regmap_update_bits(regmap, clkmode_reg, OUT32K_MODE,
+ OUT32K_MODE_OPEN_DRAIN);
+
+ return regmap_update_bits(regmap, clkmode_reg, OUT32K_MODE,
+ OUT32K_MODE_CMOS);
+}
+
static int bd71828_i2c_probe(struct i2c_client *i2c)
{
- struct rohm_regmap_dev *chip;
struct regmap_irq_chip_data *irq_data;
int ret;
+ struct regmap *regmap;
+ const struct regmap_config *regmap_config;
+ struct regmap_irq_chip *irqchip;
+ unsigned int chip_type;
+ struct mfd_cell *mfd;
+ int cells;
+ int button_irq;
+ int clkmode_reg;
if (!i2c->irq) {
dev_err(&i2c->dev, "No IRQ configured\n");
return -EINVAL;
}
- chip = devm_kzalloc(&i2c->dev, sizeof(*chip), GFP_KERNEL);
- if (!chip)
- return -ENOMEM;
-
- dev_set_drvdata(&i2c->dev, chip);
+ chip_type = (unsigned int)(uintptr_t)
+ of_device_get_match_data(&i2c->dev);
+ switch (chip_type) {
+ case ROHM_CHIP_TYPE_BD71828:
+ mfd = bd71828_mfd_cells;
+ cells = ARRAY_SIZE(bd71828_mfd_cells);
+ regmap_config = &bd71828_regmap;
+ irqchip = &bd71828_irq_chip;
+ clkmode_reg = BD71828_REG_OUT32K;
+ button_irq = BD71828_INT_SHORTPUSH;
+ break;
+ case ROHM_CHIP_TYPE_BD71815:
+ mfd = bd71815_mfd_cells;
+ cells = ARRAY_SIZE(bd71815_mfd_cells);
+ regmap_config = &bd71815_regmap;
+ irqchip = &bd71815_irq_chip;
+ clkmode_reg = BD71815_REG_OUT32K;
+ /*
+ * If BD71817 support is needed we should be able to handle it
+ * with proper DT configs + BD71815 drivers + power-button.
+ * BD71815 data-sheet does not list the power-button IRQ so we
+ * don't use it.
+ */
+ button_irq = 0;
+ break;
+ default:
+ dev_err(&i2c->dev, "Unknown device type");
+ return -EINVAL;
+ }
- chip->regmap = devm_regmap_init_i2c(i2c, &bd71828_regmap);
- if (IS_ERR(chip->regmap)) {
+ regmap = devm_regmap_init_i2c(i2c, regmap_config);
+ if (IS_ERR(regmap)) {
dev_err(&i2c->dev, "Failed to initialize Regmap\n");
- return PTR_ERR(chip->regmap);
+ return PTR_ERR(regmap);
}
- ret = devm_regmap_add_irq_chip(&i2c->dev, chip->regmap,
- i2c->irq, IRQF_ONESHOT, 0,
- &bd71828_irq_chip, &irq_data);
+ ret = devm_regmap_add_irq_chip(&i2c->dev, regmap, i2c->irq,
+ IRQF_ONESHOT, 0, irqchip, &irq_data);
if (ret) {
dev_err(&i2c->dev, "Failed to add IRQ chip\n");
return ret;
}
dev_dbg(&i2c->dev, "Registered %d IRQs for chip\n",
- bd71828_irq_chip.num_irqs);
+ irqchip->num_irqs);
- ret = regmap_irq_get_virq(irq_data, BD71828_INT_SHORTPUSH);
- if (ret < 0) {
- dev_err(&i2c->dev, "Failed to get the power-key IRQ\n");
- return ret;
+ if (button_irq) {
+ ret = regmap_irq_get_virq(irq_data, button_irq);
+ if (ret < 0) {
+ dev_err(&i2c->dev, "Failed to get the power-key IRQ\n");
+ return ret;
+ }
+
+ button.irq = ret;
}
- button.irq = ret;
+ ret = set_clk_mode(&i2c->dev, regmap, clkmode_reg);
+ if (ret)
+ return ret;
- ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO,
- bd71828_mfd_cells,
- ARRAY_SIZE(bd71828_mfd_cells), NULL, 0,
- regmap_irq_get_domain(irq_data));
+ ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, mfd, cells,
+ NULL, 0, regmap_irq_get_domain(irq_data));
if (ret)
dev_err(&i2c->dev, "Failed to create subdevices\n");
@@ -325,7 +553,13 @@ static int bd71828_i2c_probe(struct i2c_client *i2c)
}
static const struct of_device_id bd71828_of_match[] = {
- { .compatible = "rohm,bd71828", },
+ {
+ .compatible = "rohm,bd71828",
+ .data = (void *)ROHM_CHIP_TYPE_BD71828,
+ }, {
+ .compatible = "rohm,bd71815",
+ .data = (void *)ROHM_CHIP_TYPE_BD71815,
+ },
{ },
};
MODULE_DEVICE_TABLE(of, bd71828_of_match);
diff --git a/drivers/mfd/rohm-bd718x7.c b/drivers/mfd/rohm-bd718x7.c
index c32c1b6c98fa..bfd81f78beae 100644
--- a/drivers/mfd/rohm-bd718x7.c
+++ b/drivers/mfd/rohm-bd718x7.c
@@ -91,9 +91,9 @@ static const struct regmap_config bd718xx_regmap_config = {
.cache_type = REGCACHE_RBTREE,
};
-static int bd718xx_init_press_duration(struct bd718xx *bd718xx)
+static int bd718xx_init_press_duration(struct regmap *regmap,
+ struct device *dev)
{
- struct device* dev = bd718xx->chip.dev;
u32 short_press_ms, long_press_ms;
u32 short_press_value, long_press_value;
int ret;
@@ -102,8 +102,7 @@ static int bd718xx_init_press_duration(struct bd718xx *bd718xx)
&short_press_ms);
if (!ret) {
short_press_value = min(15u, (short_press_ms + 250) / 500);
- ret = regmap_update_bits(bd718xx->chip.regmap,
- BD718XX_REG_PWRONCONFIG0,
+ ret = regmap_update_bits(regmap, BD718XX_REG_PWRONCONFIG0,
BD718XX_PWRBTN_PRESS_DURATION_MASK,
short_press_value);
if (ret) {
@@ -116,8 +115,7 @@ static int bd718xx_init_press_duration(struct bd718xx *bd718xx)
&long_press_ms);
if (!ret) {
long_press_value = min(15u, (long_press_ms + 500) / 1000);
- ret = regmap_update_bits(bd718xx->chip.regmap,
- BD718XX_REG_PWRONCONFIG1,
+ ret = regmap_update_bits(regmap, BD718XX_REG_PWRONCONFIG1,
BD718XX_PWRBTN_PRESS_DURATION_MASK,
long_press_value);
if (ret) {
@@ -132,7 +130,8 @@ static int bd718xx_init_press_duration(struct bd718xx *bd718xx)
static int bd718xx_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
- struct bd718xx *bd718xx;
+ struct regmap *regmap;
+ struct regmap_irq_chip_data *irq_data;
int ret;
unsigned int chip_type;
struct mfd_cell *mfd;
@@ -142,13 +141,6 @@ static int bd718xx_i2c_probe(struct i2c_client *i2c,
dev_err(&i2c->dev, "No IRQ configured\n");
return -EINVAL;
}
-
- bd718xx = devm_kzalloc(&i2c->dev, sizeof(struct bd718xx), GFP_KERNEL);
-
- if (!bd718xx)
- return -ENOMEM;
-
- bd718xx->chip_irq = i2c->irq;
chip_type = (unsigned int)(uintptr_t)
of_device_get_match_data(&i2c->dev);
switch (chip_type) {
@@ -164,29 +156,26 @@ static int bd718xx_i2c_probe(struct i2c_client *i2c,
dev_err(&i2c->dev, "Unknown device type");
return -EINVAL;
}
- bd718xx->chip.dev = &i2c->dev;
- dev_set_drvdata(&i2c->dev, bd718xx);
- bd718xx->chip.regmap = devm_regmap_init_i2c(i2c,
- &bd718xx_regmap_config);
- if (IS_ERR(bd718xx->chip.regmap)) {
+ regmap = devm_regmap_init_i2c(i2c, &bd718xx_regmap_config);
+ if (IS_ERR(regmap)) {
dev_err(&i2c->dev, "regmap initialization failed\n");
- return PTR_ERR(bd718xx->chip.regmap);
+ return PTR_ERR(regmap);
}
- ret = devm_regmap_add_irq_chip(&i2c->dev, bd718xx->chip.regmap,
- bd718xx->chip_irq, IRQF_ONESHOT, 0,
- &bd718xx_irq_chip, &bd718xx->irq_data);
+ ret = devm_regmap_add_irq_chip(&i2c->dev, regmap, i2c->irq,
+ IRQF_ONESHOT, 0, &bd718xx_irq_chip,
+ &irq_data);
if (ret) {
dev_err(&i2c->dev, "Failed to add irq_chip\n");
return ret;
}
- ret = bd718xx_init_press_duration(bd718xx);
+ ret = bd718xx_init_press_duration(regmap, &i2c->dev);
if (ret)
return ret;
- ret = regmap_irq_get_virq(bd718xx->irq_data, BD718XX_INT_PWRBTN_S);
+ ret = regmap_irq_get_virq(irq_data, BD718XX_INT_PWRBTN_S);
if (ret < 0) {
dev_err(&i2c->dev, "Failed to get the IRQ\n");
@@ -195,9 +184,9 @@ static int bd718xx_i2c_probe(struct i2c_client *i2c,
button.irq = ret;
- ret = devm_mfd_add_devices(bd718xx->chip.dev, PLATFORM_DEVID_AUTO,
+ ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO,
mfd, cells, NULL, 0,
- regmap_irq_get_domain(bd718xx->irq_data));
+ regmap_irq_get_domain(irq_data));
if (ret)
dev_err(&i2c->dev, "Failed to create subdevices\n");
diff --git a/drivers/mfd/rohm-bd9576.c b/drivers/mfd/rohm-bd9576.c
new file mode 100644
index 000000000000..6661a27d69a8
--- /dev/null
+++ b/drivers/mfd/rohm-bd9576.c
@@ -0,0 +1,189 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2021 ROHM Semiconductors
+ *
+ * ROHM BD9576MUF and BD9573MUF PMIC driver
+ */
+
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/irq.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/rohm-bd957x.h>
+#include <linux/mfd/rohm-generic.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+enum {
+ BD957X_REGULATOR_CELL,
+ BD957X_WDT_CELL,
+};
+
+/*
+ * Due to the BD9576MUF nasty IRQ behaiour we don't always populate IRQs.
+ * These will be added to regulator resources only if IRQ information for the
+ * PMIC is populated in device-tree.
+ */
+static const struct resource bd9576_regulator_irqs[] = {
+ DEFINE_RES_IRQ_NAMED(BD9576_INT_THERM, "bd9576-temp"),
+ DEFINE_RES_IRQ_NAMED(BD9576_INT_OVD, "bd9576-ovd"),
+ DEFINE_RES_IRQ_NAMED(BD9576_INT_UVD, "bd9576-uvd"),
+};
+
+static struct mfd_cell bd9573_mfd_cells[] = {
+ [BD957X_REGULATOR_CELL] = { .name = "bd9573-regulator", },
+ [BD957X_WDT_CELL] = { .name = "bd9576-wdt", },
+};
+
+static struct mfd_cell bd9576_mfd_cells[] = {
+ [BD957X_REGULATOR_CELL] = { .name = "bd9576-regulator", },
+ [BD957X_WDT_CELL] = { .name = "bd9576-wdt", },
+};
+
+static const struct regmap_range volatile_ranges[] = {
+ regmap_reg_range(BD957X_REG_SMRB_ASSERT, BD957X_REG_SMRB_ASSERT),
+ regmap_reg_range(BD957X_REG_PMIC_INTERNAL_STAT,
+ BD957X_REG_PMIC_INTERNAL_STAT),
+ regmap_reg_range(BD957X_REG_INT_THERM_STAT, BD957X_REG_INT_THERM_STAT),
+ regmap_reg_range(BD957X_REG_INT_OVP_STAT, BD957X_REG_INT_SYS_STAT),
+ regmap_reg_range(BD957X_REG_INT_MAIN_STAT, BD957X_REG_INT_MAIN_STAT),
+};
+
+static const struct regmap_access_table volatile_regs = {
+ .yes_ranges = &volatile_ranges[0],
+ .n_yes_ranges = ARRAY_SIZE(volatile_ranges),
+};
+
+static struct regmap_config bd957x_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .volatile_table = &volatile_regs,
+ .max_register = BD957X_MAX_REGISTER,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static struct regmap_irq bd9576_irqs[] = {
+ REGMAP_IRQ_REG(BD9576_INT_THERM, 0, BD957X_MASK_INT_MAIN_THERM),
+ REGMAP_IRQ_REG(BD9576_INT_OVP, 0, BD957X_MASK_INT_MAIN_OVP),
+ REGMAP_IRQ_REG(BD9576_INT_SCP, 0, BD957X_MASK_INT_MAIN_SCP),
+ REGMAP_IRQ_REG(BD9576_INT_OCP, 0, BD957X_MASK_INT_MAIN_OCP),
+ REGMAP_IRQ_REG(BD9576_INT_OVD, 0, BD957X_MASK_INT_MAIN_OVD),
+ REGMAP_IRQ_REG(BD9576_INT_UVD, 0, BD957X_MASK_INT_MAIN_UVD),
+ REGMAP_IRQ_REG(BD9576_INT_UVP, 0, BD957X_MASK_INT_MAIN_UVP),
+ REGMAP_IRQ_REG(BD9576_INT_SYS, 0, BD957X_MASK_INT_MAIN_SYS),
+};
+
+static struct regmap_irq_chip bd9576_irq_chip = {
+ .name = "bd9576_irq",
+ .irqs = &bd9576_irqs[0],
+ .num_irqs = ARRAY_SIZE(bd9576_irqs),
+ .status_base = BD957X_REG_INT_MAIN_STAT,
+ .mask_base = BD957X_REG_INT_MAIN_MASK,
+ .ack_base = BD957X_REG_INT_MAIN_STAT,
+ .init_ack_masked = true,
+ .num_regs = 1,
+ .irq_reg_stride = 1,
+};
+
+static int bd957x_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ int ret;
+ struct regmap *regmap;
+ struct mfd_cell *cells;
+ int num_cells;
+ unsigned long chip_type;
+ struct irq_domain *domain;
+ bool usable_irqs;
+
+ chip_type = (unsigned long)of_device_get_match_data(&i2c->dev);
+
+ switch (chip_type) {
+ case ROHM_CHIP_TYPE_BD9576:
+ cells = bd9576_mfd_cells;
+ num_cells = ARRAY_SIZE(bd9576_mfd_cells);
+ usable_irqs = !!i2c->irq;
+ break;
+ case ROHM_CHIP_TYPE_BD9573:
+ cells = bd9573_mfd_cells;
+ num_cells = ARRAY_SIZE(bd9573_mfd_cells);
+ /*
+ * BD9573 only supports fatal IRQs which we can not handle
+ * because SoC is going to lose the power.
+ */
+ usable_irqs = false;
+ break;
+ default:
+ dev_err(&i2c->dev, "Unknown device type");
+ return -EINVAL;
+ }
+
+ regmap = devm_regmap_init_i2c(i2c, &bd957x_regmap);
+ if (IS_ERR(regmap)) {
+ dev_err(&i2c->dev, "Failed to initialize Regmap\n");
+ return PTR_ERR(regmap);
+ }
+
+ /*
+ * BD9576 behaves badly. It kepts IRQ line asserted for the whole
+ * duration of detected HW condition (like over temperature). So we
+ * don't require IRQ to be populated.
+ * If IRQ information is not given, then we mask all IRQs and do not
+ * provide IRQ resources to regulator driver - which then just omits
+ * the notifiers.
+ */
+ if (usable_irqs) {
+ struct regmap_irq_chip_data *irq_data;
+ struct mfd_cell *regulators;
+
+ regulators = &bd9576_mfd_cells[BD957X_REGULATOR_CELL];
+ regulators->resources = bd9576_regulator_irqs;
+ regulators->num_resources = ARRAY_SIZE(bd9576_regulator_irqs);
+
+ ret = devm_regmap_add_irq_chip(&i2c->dev, regmap, i2c->irq,
+ IRQF_ONESHOT, 0,
+ &bd9576_irq_chip, &irq_data);
+ if (ret) {
+ dev_err(&i2c->dev, "Failed to add IRQ chip\n");
+ return ret;
+ }
+ domain = regmap_irq_get_domain(irq_data);
+ } else {
+ ret = regmap_update_bits(regmap, BD957X_REG_INT_MAIN_MASK,
+ BD957X_MASK_INT_ALL,
+ BD957X_MASK_INT_ALL);
+ if (ret)
+ return ret;
+ domain = NULL;
+ }
+
+ ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, cells,
+ num_cells, NULL, 0, domain);
+ if (ret)
+ dev_err(&i2c->dev, "Failed to create subdevices\n");
+
+ return ret;
+}
+
+static const struct of_device_id bd957x_of_match[] = {
+ { .compatible = "rohm,bd9576", .data = (void *)ROHM_CHIP_TYPE_BD9576, },
+ { .compatible = "rohm,bd9573", .data = (void *)ROHM_CHIP_TYPE_BD9573, },
+ { },
+};
+MODULE_DEVICE_TABLE(of, bd957x_of_match);
+
+static struct i2c_driver bd957x_drv = {
+ .driver = {
+ .name = "rohm-bd957x",
+ .of_match_table = bd957x_of_match,
+ },
+ .probe = &bd957x_i2c_probe,
+};
+module_i2c_driver(bd957x_drv);
+
+MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
+MODULE_DESCRIPTION("ROHM BD9576MUF and BD9573MUF Power Management IC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c
index 95473ff9bb4b..8d55992da19e 100644
--- a/drivers/mfd/sec-core.c
+++ b/drivers/mfd/sec-core.c
@@ -549,19 +549,7 @@ static struct i2c_driver sec_pmic_driver = {
.shutdown = sec_pmic_shutdown,
.id_table = sec_pmic_id,
};
-
-static int __init sec_pmic_init(void)
-{
- return i2c_add_driver(&sec_pmic_driver);
-}
-
-subsys_initcall(sec_pmic_init);
-
-static void __exit sec_pmic_exit(void)
-{
- i2c_del_driver(&sec_pmic_driver);
-}
-module_exit(sec_pmic_exit);
+module_i2c_driver(sec_pmic_driver);
MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
MODULE_DESCRIPTION("Core support for the S5M MFD");
diff --git a/drivers/mfd/stm32-timers.c b/drivers/mfd/stm32-timers.c
index add603359124..44ed2fce0319 100644
--- a/drivers/mfd/stm32-timers.c
+++ b/drivers/mfd/stm32-timers.c
@@ -158,13 +158,18 @@ static const struct regmap_config stm32_timers_regmap_cfg = {
static void stm32_timers_get_arr_size(struct stm32_timers *ddata)
{
+ u32 arr;
+
+ /* Backup ARR to restore it after getting the maximum value */
+ regmap_read(ddata->regmap, TIM_ARR, &arr);
+
/*
* Only the available bits will be written so when readback
* we get the maximum value of auto reload register
*/
regmap_write(ddata->regmap, TIM_ARR, ~0L);
regmap_read(ddata->regmap, TIM_ARR, &ddata->max_arr);
- regmap_write(ddata->regmap, TIM_ARR, 0x0);
+ regmap_write(ddata->regmap, TIM_ARR, arr);
}
static int stm32_timers_dma_probe(struct device *dev,
diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c
index 90f3292230c9..1dd39483e7c1 100644
--- a/drivers/mfd/stmpe.c
+++ b/drivers/mfd/stmpe.c
@@ -312,7 +312,7 @@ EXPORT_SYMBOL_GPL(stmpe_set_altfunc);
* GPIO (all variants)
*/
-static const struct resource stmpe_gpio_resources[] = {
+static struct resource stmpe_gpio_resources[] = {
/* Start and end filled dynamically */
{
.flags = IORESOURCE_IRQ,
@@ -336,7 +336,8 @@ static const struct mfd_cell stmpe_gpio_cell_noirq = {
* Keypad (1601, 2401, 2403)
*/
-static const struct resource stmpe_keypad_resources[] = {
+static struct resource stmpe_keypad_resources[] = {
+ /* Start and end filled dynamically */
{
.name = "KEYPAD",
.flags = IORESOURCE_IRQ,
@@ -357,7 +358,8 @@ static const struct mfd_cell stmpe_keypad_cell = {
/*
* PWM (1601, 2401, 2403)
*/
-static const struct resource stmpe_pwm_resources[] = {
+static struct resource stmpe_pwm_resources[] = {
+ /* Start and end filled dynamically */
{
.name = "PWM0",
.flags = IORESOURCE_IRQ,
@@ -445,7 +447,8 @@ static struct stmpe_variant_info stmpe801_noirq = {
* Touchscreen (STMPE811 or STMPE610)
*/
-static const struct resource stmpe_ts_resources[] = {
+static struct resource stmpe_ts_resources[] = {
+ /* Start and end filled dynamically */
{
.name = "TOUCH_DET",
.flags = IORESOURCE_IRQ,
@@ -467,7 +470,8 @@ static const struct mfd_cell stmpe_ts_cell = {
* ADC (STMPE811)
*/
-static const struct resource stmpe_adc_resources[] = {
+static struct resource stmpe_adc_resources[] = {
+ /* Start and end filled dynamically */
{
.name = "STMPE_TEMP_SENS",
.flags = IORESOURCE_IRQ,