summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-10-26 08:38:17 -1000
committerLinus Torvalds <torvalds@linux-foundation.org>2026-10-26 08:38:17 -1000
commitd857e1f3faf998f2614dcdb52a90a27bc83bd71d (patch)
treecb8bcdc792c62a8542e7d48ecc8198e4d69f0922 /drivers
parentfb2c3f44a7e14627b9dca8e6b568e6cdc234b40b (diff)
parentc8132247fe4df52e9982d74c986bb199d792b85b (diff)
Merge tag 'mfd-next-7.4' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd
Pull MFD updates from Lee Jones: "New Support & Features: - Cirrus Logic CS42L43: Add support for the CS42L44 variant - Khadas MCU: Add support for the VIM4 MCU variant along with per-variant fan duty-cycle levels and optional fan supply regulator support - Maxim MAX77705: Add support for the PASS2 hardware revision - MediaTek MT6397: Add AUXADC sub-device support for MT6397 - Motorola CPCAP: Support per-board sub-device compositions and add the Tegra20 Mot composition - ROHM BD73800: Add support for the BD73800 PMIC core, regulator, RTC, clock gate, and GPIO sub-devices - TI LM3533: Add VIN regulator supply support, configure initial backlight mapping mode from Device Tree, and implement the `backlight_scale` property - X-Powers AC200: Add support for the AC200 I2C mixed-signal companion IC Improvements & Fixes: - Cirrus Logic CS42L43: Synchronize SoundWire enumeration work in `remove()` before devres cleanup begins - Dialog DA903x: Manage IRQ work cancellation and sub-device removal via devres to prevent use-after-free during teardown - Dialog DA9150: Balance `enable_irq_wake()` with `disable_irq_wake()` during probe failure and driver removal - Intel LPSS: Add DMI quirks for Dell Latitude 5285 and 7275 to ignore ACPI resource conflicts on the I2C4 controller - Intel Quark I2C/GPIO: Manage the fixed-rate clock and its clkdev lookup with devres to fix a resource leak on unbind - Maxim MAX77705: Select `REGMAP_I2C` and `REGMAP_IRQ` in Kconfig to fix build errors - Qualcomm WCD934x: Initialize the parent DMA mask to suppress "DMA mask not set" warnings on child devices - Qualcomm WCD934x: Pass the valid device pointer to `dev_err_probe()` on IRQ lookup failure to avoid a NULL pointer dereference - Rockchip RK8xx: Register the poweroff handler in the atomic `SYS_OFF_MODE_POWER_OFF` phase so polling I2C transfers complete during shutdown - ST-Ericsson AB8500: Use `devm_mfd_add_devices()` to prevent leaking child devices on probe failure - TI BQ257xx: Mark self-modifying BQ25792 configuration registers as volatile - TI LM3533: Set `coherent_dma_mask` to zero to suppress "DMA mask not set" warnings - TI TPS65217: Check for errors during IRQ initialization and masking, and manage IRQ domain and wake teardown with devres - TI TWL: Unregister the auxiliary platform device via a devres action on probe failure and driver unbind Cleanups & Refactoring - Core: Convert drivers from deprecated `SIMPLE_DEV_PM_OPS()` to `DEFINE_SIMPLE_DEV_PM_OPS()` and `pm_sleep_ptr()` - Core: Fix spelling mistakes in comments across various MFD drivers and headers - Maintainers: Add ROHM BD73800 PMIC files under the ROHM PMIC entry - Maintainers: Specify the `for-mfd-next` branch for the MFD and Syscon git trees - Dialog DA9062: Use `DEFINE_RES_IRQ_NAMED()` for IRQ resource definitions - Intel LPSS: Simplify DebugFS handling by dropping redundant error checks and intermediate dentry variables, using octal permissions, and switching to `debugfs_remove()` - Khadas MCU: Convert MFD cell arrays to `const` and use `MFD_CELL_NAME()` - ST-Ericsson AB8500: Fix a spelling typo in a comment - TI LM3533: Convert from platform data to Device Tree bindings and pass only regmap and light sensor presence to child devices - TI LM3533: Remove driver-specific regmap wrappers, redundant pdata helpers, and unnecessary `extern` qualifiers, and use `dev_groups` for sysfs attributes - Wolfson WM831x: Fix a spelling typo in a comment Device Tree Binding Updates - HiSilicon Hi6421 SPMI: Fix the compatible string to match `hisilicon,hi6421-spmi` - MediaTek MT6357: Allow an `adc` child node - MediaTek MT6360: Allow two-cell interrupt specifiers with trigger flags - MediaTek MT6397: Document the `#sound-dai-cells` property - MediaTek MT6397: Document the battery-backed NVMEM layout under the RTC child node - MediaTek MT6397: Document the MT6323 PMIC EFUSE child node - Motorola CPCAP: Convert MFD and power button bindings to DT schema and document the Mapphone and Mot compositions - Qualcomm SPMI PMIC: Document the PM4125 audio codec compatible - Qualcomm SPMI PMIC: Document the PMAU0102 PMIC compatible - Qualcomm TCSR: Document the MSM8952 TCSR compatible - Rockchip RK805: Fold the pin controller binding into the RK805 PMIC DT schema - ROHM BD73800: Document the BD73800 PMIC and its regulators - ROHM PMIC: Factor out common pin properties into `rohm,pmic-pins.yaml` and reference them across BD71815, BD71828, and BD72720 bindings - ST-Ericsson AB8500: Document AB8500 and AB8505 buck converter regulators - ST-Ericsson AB8500: Document codec audio graph ports, sound DAI cells, and analog microphone wiring properties - ST-Ericsson DB8500 PRCMU: Deprecate the `db8500-prcmu-regulators` child node and make it optional - Syscon: Document the Ambarella CV75 secure scratchpad compatible - TI BQ25703A: Add the BQ25798 compatible with fallback to BQ25792 - TI Keystone: Convert Device State Control bindings to DT schema - TI LM3533: Document the LM3533 LED controller, backlight, and indicator LED bindings - TI LP3943: Convert MFD and PWM bindings to DT schema - TI TPS61050: Convert bindings to DT schema - TI TPS65086: Make the `regulators` child node optional - TI TPS65910: Document `wakeup-source` and GPIO hog child nodes - TI TWL6040: Convert bindings to DT schema and align property names with the driver - X-Powers AC200: Document the AC200 mixed-signal companion IC" * tag 'mfd-next-7.4' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (74 commits) dt-bindings: mfd: db8500-prcmu: Deprecate EPOD regulators dt-bindings: mfd: syscon: Add Ambarella CV75 secure scratchpad dt-bindings: mfd: rockchip,rk805: Convert pinctrl to DT schema mfd: intel-lpss: Add Dell Latitude 7275 to the resource conflict quirk mfd: intel-lpss: Add resource conflict quirk for Dell Latitude 5285 mfd: tps65217: Use devres for IRQ domain and wake teardown mfd: tps65217: Check return value when masking interrupt sources mfd: tps65217: Fix NULL pointer dereference on IRQ init failure dt-bindings: mfd: qcom,spmi-pmic: Add compatibles for pm4125-codec mfd: bq257xx: Mark self-modifying BQ25792 registers volatile dt-bindings: mfd: mediatek: mt6397: describe the RTC's nvmem layout mfd: mt6397-core: Add mt6397 AUXADC support mfd: max77705: Mark PASS2 revision as supported mfd: ab8500: Fix child device leaks on probe failure dt-bindings: mfd: Add MT6397 sound DAI cells dt-bindings: mfd: mediatek: mt6397: Add mt6323 PMIC EFUSE dt-bindings: mfd: hisilicon: Fix Hi6421 SPMI compatible dt-bindings: mfd: ti,bq25703a: Expand to include BQ25798 dt-bindings: mfd: Allow MT6360 interrupt flags dt-bindings: mfd: mediatek: Allow MT6357 ADC ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/iio/light/lm3533-als.c179
-rw-r--r--drivers/leds/leds-lm3533.c121
-rw-r--r--drivers/mfd/88pm800.c4
-rw-r--r--drivers/mfd/Kconfig16
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/ab8500-core.c46
-rw-r--r--drivers/mfd/ac200.c222
-rw-r--r--drivers/mfd/bq257xx.c10
-rw-r--r--drivers/mfd/cs42l43-i2c.c10
-rw-r--r--drivers/mfd/cs42l43-sdw.c9
-rw-r--r--drivers/mfd/cs42l43.c30
-rw-r--r--drivers/mfd/cs42l43.h1
-rw-r--r--drivers/mfd/da903x.c34
-rw-r--r--drivers/mfd/da9062-core.c24
-rw-r--r--drivers/mfd/da9150-core.c8
-rw-r--r--drivers/mfd/intel-lpss-acpi.c38
-rw-r--r--drivers/mfd/intel-lpss.c24
-rw-r--r--drivers/mfd/intel_quark_i2c_gpio.c52
-rw-r--r--drivers/mfd/iqs62x.c8
-rw-r--r--drivers/mfd/kempld-core.c2
-rw-r--r--drivers/mfd/khadas-mcu.c104
-rw-r--r--drivers/mfd/lm3533-core.c378
-rw-r--r--drivers/mfd/lm3533-ctrlbank.c33
-rw-r--r--drivers/mfd/max77705.c2
-rw-r--r--drivers/mfd/max77843.c8
-rw-r--r--drivers/mfd/max8998.c2
-rw-r--r--drivers/mfd/motorola-cpcap.c143
-rw-r--r--drivers/mfd/mt6360-core.c8
-rw-r--r--drivers/mfd/mt6397-core.c3
-rw-r--r--drivers/mfd/rave-sp.c6
-rw-r--r--drivers/mfd/rk8xx-core.c2
-rw-r--r--drivers/mfd/rk8xx-i2c.c4
-rw-r--r--drivers/mfd/rn5t618.c8
-rw-r--r--drivers/mfd/si476x-i2c.c2
-rw-r--r--drivers/mfd/ti_am335x_tscadc.c8
-rw-r--r--drivers/mfd/tps65217.c69
-rw-r--r--drivers/mfd/tps6586x.c8
-rw-r--r--drivers/mfd/twl-core.c31
-rw-r--r--drivers/mfd/wcd934x.c8
-rw-r--r--drivers/mfd/wm831x-auxadc.c2
-rw-r--r--drivers/thermal/khadas_mcu_fan.c108
-rw-r--r--drivers/video/backlight/lm3533_bl.c188
42 files changed, 1168 insertions, 796 deletions
diff --git a/drivers/iio/light/lm3533-als.c b/drivers/iio/light/lm3533-als.c
index 5db9591a85b9..218cb93b4cf9 100644
--- a/drivers/iio/light/lm3533-als.c
+++ b/drivers/iio/light/lm3533-als.c
@@ -18,14 +18,17 @@
#include <linux/mutex.h>
#include <linux/mfd/core.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
+#include <linux/units.h>
#include <linux/mfd/lm3533.h>
-#define LM3533_ALS_RESISTOR_MIN 1
-#define LM3533_ALS_RESISTOR_MAX 127
+#define LM3533_ALS_RESISTOR_MIN_OHMS 1575
+#define LM3533_ALS_RESISTOR_MAX_OHMS 200000
#define LM3533_ALS_CHANNEL_CURRENT_MAX 2
#define LM3533_ALS_THRESH_MAX 3
#define LM3533_ALS_ZONE_MAX 4
@@ -49,7 +52,7 @@
struct lm3533_als {
- struct lm3533 *lm3533;
+ struct regmap *regmap;
struct platform_device *pdev;
unsigned long flags;
@@ -57,6 +60,9 @@ struct lm3533_als {
atomic_t zone;
struct mutex thresh_mutex;
+
+ u32 r_select;
+ bool pwm_mode;
};
@@ -65,7 +71,7 @@ static int lm3533_als_get_adc(struct iio_dev *indio_dev, bool average,
{
struct lm3533_als *als = iio_priv(indio_dev);
u8 reg;
- u8 val;
+ u32 val;
int ret;
if (average)
@@ -73,7 +79,7 @@ static int lm3533_als_get_adc(struct iio_dev *indio_dev, bool average,
else
reg = LM3533_REG_ALS_READ_ADC_RAW;
- ret = lm3533_read(als->lm3533, reg, &val);
+ ret = regmap_read(als->regmap, reg, &val);
if (ret) {
dev_err(&indio_dev->dev, "failed to read adc\n");
return ret;
@@ -87,10 +93,10 @@ static int lm3533_als_get_adc(struct iio_dev *indio_dev, bool average,
static int _lm3533_als_get_zone(struct iio_dev *indio_dev, u8 *zone)
{
struct lm3533_als *als = iio_priv(indio_dev);
- u8 val;
+ u32 val;
int ret;
- ret = lm3533_read(als->lm3533, LM3533_REG_ALS_ZONE_INFO, &val);
+ ret = regmap_read(als->regmap, LM3533_REG_ALS_ZONE_INFO, &val);
if (ret) {
dev_err(&indio_dev->dev, "failed to read zone\n");
return ret;
@@ -128,7 +134,7 @@ static inline u8 lm3533_als_get_target_reg(unsigned channel, unsigned zone)
}
static int lm3533_als_get_target(struct iio_dev *indio_dev, unsigned channel,
- unsigned zone, u8 *val)
+ unsigned zone, u32 *val)
{
struct lm3533_als *als = iio_priv(indio_dev);
u8 reg;
@@ -141,7 +147,7 @@ static int lm3533_als_get_target(struct iio_dev *indio_dev, unsigned channel,
return -EINVAL;
reg = lm3533_als_get_target_reg(channel, zone);
- ret = lm3533_read(als->lm3533, reg, val);
+ ret = regmap_read(als->regmap, reg, val);
if (ret)
dev_err(&indio_dev->dev, "failed to get target current\n");
@@ -162,7 +168,7 @@ static int lm3533_als_set_target(struct iio_dev *indio_dev, unsigned channel,
return -EINVAL;
reg = lm3533_als_get_target_reg(channel, zone);
- ret = lm3533_write(als->lm3533, reg, val);
+ ret = regmap_write(als->regmap, reg, val);
if (ret)
dev_err(&indio_dev->dev, "failed to set target current\n");
@@ -172,8 +178,8 @@ static int lm3533_als_set_target(struct iio_dev *indio_dev, unsigned channel,
static int lm3533_als_get_current(struct iio_dev *indio_dev, unsigned channel,
int *val)
{
+ u32 target;
u8 zone;
- u8 target;
int ret;
ret = lm3533_als_get_zone(indio_dev, &zone);
@@ -272,16 +278,10 @@ out:
static int lm3533_als_set_int_mode(struct iio_dev *indio_dev, int enable)
{
struct lm3533_als *als = iio_priv(indio_dev);
- u8 mask = LM3533_ALS_INT_ENABLE_MASK;
- u8 val;
int ret;
- if (enable)
- val = mask;
- else
- val = 0;
-
- ret = lm3533_update(als->lm3533, LM3533_REG_ALS_ZONE_INFO, val, mask);
+ ret = regmap_assign_bits(als->regmap, LM3533_REG_ALS_ZONE_INFO,
+ LM3533_ALS_INT_ENABLE_MASK, enable);
if (ret) {
dev_err(&indio_dev->dev, "failed to set int mode %d\n",
enable);
@@ -294,17 +294,16 @@ static int lm3533_als_set_int_mode(struct iio_dev *indio_dev, int enable)
static int lm3533_als_get_int_mode(struct iio_dev *indio_dev, int *enable)
{
struct lm3533_als *als = iio_priv(indio_dev);
- u8 mask = LM3533_ALS_INT_ENABLE_MASK;
- u8 val;
int ret;
- ret = lm3533_read(als->lm3533, LM3533_REG_ALS_ZONE_INFO, &val);
- if (ret) {
+ ret = regmap_test_bits(als->regmap, LM3533_REG_ALS_ZONE_INFO,
+ LM3533_ALS_INT_ENABLE_MASK);
+ if (ret < 0) {
dev_err(&indio_dev->dev, "failed to get int mode\n");
return ret;
}
- *enable = !!(val & mask);
+ *enable = ret;
return 0;
}
@@ -317,7 +316,7 @@ static inline u8 lm3533_als_get_threshold_reg(unsigned nr, bool raising)
}
static int lm3533_als_get_threshold(struct iio_dev *indio_dev, unsigned nr,
- bool raising, u8 *val)
+ bool raising, u32 *val)
{
struct lm3533_als *als = iio_priv(indio_dev);
u8 reg;
@@ -327,7 +326,7 @@ static int lm3533_als_get_threshold(struct iio_dev *indio_dev, unsigned nr,
return -EINVAL;
reg = lm3533_als_get_threshold_reg(nr, raising);
- ret = lm3533_read(als->lm3533, reg, val);
+ ret = regmap_read(als->regmap, reg, val);
if (ret)
dev_err(&indio_dev->dev, "failed to get threshold\n");
@@ -338,8 +337,8 @@ static int lm3533_als_set_threshold(struct iio_dev *indio_dev, unsigned nr,
bool raising, u8 val)
{
struct lm3533_als *als = iio_priv(indio_dev);
- u8 val2;
u8 reg, reg2;
+ u32 val2;
int ret;
if (nr > LM3533_ALS_THRESH_MAX)
@@ -349,7 +348,7 @@ static int lm3533_als_set_threshold(struct iio_dev *indio_dev, unsigned nr,
reg2 = lm3533_als_get_threshold_reg(nr, !raising);
mutex_lock(&als->thresh_mutex);
- ret = lm3533_read(als->lm3533, reg2, &val2);
+ ret = regmap_read(als->regmap, reg2, &val2);
if (ret) {
dev_err(&indio_dev->dev, "failed to get threshold\n");
goto out;
@@ -364,7 +363,7 @@ static int lm3533_als_set_threshold(struct iio_dev *indio_dev, unsigned nr,
goto out;
}
- ret = lm3533_write(als->lm3533, reg, val);
+ ret = regmap_write(als->regmap, reg, val);
if (ret) {
dev_err(&indio_dev->dev, "failed to set threshold\n");
goto out;
@@ -376,11 +375,11 @@ out:
}
static int lm3533_als_get_hysteresis(struct iio_dev *indio_dev, unsigned nr,
- u8 *val)
+ u32 *val)
{
struct lm3533_als *als = iio_priv(indio_dev);
- u8 falling;
- u8 raising;
+ u32 falling;
+ u32 raising;
int ret;
if (nr > LM3533_ALS_THRESH_MAX)
@@ -410,7 +409,7 @@ static ssize_t show_thresh_either_en(struct device *dev,
int enable;
int ret;
- if (als->irq) {
+ if (als->irq > 0) {
ret = lm3533_als_get_int_mode(indio_dev, &enable);
if (ret)
return ret;
@@ -432,7 +431,7 @@ static ssize_t store_thresh_either_en(struct device *dev,
u8 zone;
int ret;
- if (!als->irq)
+ if (als->irq <= 0)
return -EBUSY;
ret = kstrtoul(buf, 0, &enable);
@@ -505,7 +504,7 @@ static ssize_t show_als_attr(struct device *dev,
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct lm3533_als_attribute *als_attr = to_lm3533_als_attr(attr);
- u8 val;
+ u32 val;
int ret;
switch (als_attr->type) {
@@ -717,71 +716,51 @@ static const struct attribute_group lm3533_als_attribute_group = {
.attrs = lm3533_als_attributes
};
-static int lm3533_als_set_input_mode(struct lm3533_als *als, bool pwm_mode)
+static int lm3533_als_setup(struct lm3533_als *als)
{
- u8 mask = LM3533_ALS_INPUT_MODE_MASK;
- u8 val;
+ struct device *dev = &als->pdev->dev;
int ret;
- if (pwm_mode)
- val = mask; /* pwm input */
- else
- val = 0; /* analog input */
-
- ret = lm3533_update(als->lm3533, LM3533_REG_ALS_CONF, val, mask);
- if (ret) {
- dev_err(&als->pdev->dev, "failed to set input mode %d\n",
- pwm_mode);
- return ret;
- }
+ als->pwm_mode = device_property_read_bool(dev, "ti,pwm-mode");
- return 0;
-}
-
-static int lm3533_als_set_resistor(struct lm3533_als *als, u8 val)
-{
- int ret;
+ ret = regmap_assign_bits(als->regmap, LM3533_REG_ALS_CONF,
+ LM3533_ALS_INPUT_MODE_MASK, als->pwm_mode);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to set input mode %d\n",
+ als->pwm_mode);
- if (val < LM3533_ALS_RESISTOR_MIN || val > LM3533_ALS_RESISTOR_MAX) {
- dev_err(&als->pdev->dev, "invalid resistor value\n");
- return -EINVAL;
- }
+ /* ALS input is always high impedance in PWM-mode. */
+ if (als->pwm_mode)
+ return 0;
- ret = lm3533_write(als->lm3533, LM3533_REG_ALS_RESISTOR_SELECT, val);
- if (ret) {
- dev_err(&als->pdev->dev, "failed to set resistor\n");
- return ret;
- }
+ ret = device_property_read_u32(dev, "ti,resistor-ohms",
+ &als->r_select);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to ger resistor value\n");
- return 0;
-}
+ if (als->r_select < LM3533_ALS_RESISTOR_MIN_OHMS ||
+ als->r_select > LM3533_ALS_RESISTOR_MAX_OHMS)
+ return dev_err_probe(dev, -EINVAL,
+ "invalid resistor value\n");
-static int lm3533_als_setup(struct lm3533_als *als,
- const struct lm3533_als_platform_data *pdata)
-{
- int ret;
+ als->r_select = DIV_ROUND_UP(2 * MICRO, 10 * als->r_select);
- ret = lm3533_als_set_input_mode(als, pdata->pwm_mode);
+ ret = regmap_write(als->regmap, LM3533_REG_ALS_RESISTOR_SELECT,
+ als->r_select);
if (ret)
- return ret;
-
- /* ALS input is always high impedance in PWM-mode. */
- if (!pdata->pwm_mode) {
- ret = lm3533_als_set_resistor(als, pdata->r_select);
- if (ret)
- return ret;
- }
+ return dev_err_probe(dev, ret, "failed to set resistor\n");
return 0;
}
static int lm3533_als_setup_irq(struct lm3533_als *als, void *dev)
{
- u8 mask = LM3533_ALS_INT_ENABLE_MASK;
int ret;
/* Make sure interrupts are disabled. */
- ret = lm3533_update(als->lm3533, LM3533_REG_ALS_ZONE_INFO, 0, mask);
+ ret = regmap_clear_bits(als->regmap, LM3533_REG_ALS_ZONE_INFO,
+ LM3533_ALS_INT_ENABLE_MASK);
if (ret) {
dev_err(&als->pdev->dev, "failed to disable interrupts\n");
return ret;
@@ -801,10 +780,10 @@ static int lm3533_als_setup_irq(struct lm3533_als *als, void *dev)
static int lm3533_als_enable(struct lm3533_als *als)
{
- u8 mask = LM3533_ALS_ENABLE_MASK;
int ret;
- ret = lm3533_update(als->lm3533, LM3533_REG_ALS_CONF, mask, mask);
+ ret = regmap_set_bits(als->regmap, LM3533_REG_ALS_CONF,
+ LM3533_ALS_ENABLE_MASK);
if (ret)
dev_err(&als->pdev->dev, "failed to enable ALS\n");
@@ -813,10 +792,10 @@ static int lm3533_als_enable(struct lm3533_als *als)
static int lm3533_als_disable(struct lm3533_als *als)
{
- u8 mask = LM3533_ALS_ENABLE_MASK;
int ret;
- ret = lm3533_update(als->lm3533, LM3533_REG_ALS_CONF, 0, mask);
+ ret = regmap_clear_bits(als->regmap, LM3533_REG_ALS_CONF,
+ LM3533_ALS_ENABLE_MASK);
if (ret)
dev_err(&als->pdev->dev, "failed to disable ALS\n");
@@ -831,7 +810,6 @@ static const struct iio_info lm3533_als_info = {
static int lm3533_als_probe(struct platform_device *pdev)
{
- const struct lm3533_als_platform_data *pdata;
struct lm3533 *lm3533;
struct lm3533_als *als;
struct iio_dev *indio_dev;
@@ -841,12 +819,6 @@ static int lm3533_als_probe(struct platform_device *pdev)
if (!lm3533)
return -EINVAL;
- pdata = dev_get_platdata(&pdev->dev);
- if (!pdata) {
- dev_err(&pdev->dev, "no platform data\n");
- return -EINVAL;
- }
-
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*als));
if (!indio_dev)
return -ENOMEM;
@@ -855,25 +827,27 @@ static int lm3533_als_probe(struct platform_device *pdev)
indio_dev->channels = lm3533_als_channels;
indio_dev->num_channels = ARRAY_SIZE(lm3533_als_channels);
indio_dev->name = dev_name(&pdev->dev);
- iio_device_set_parent(indio_dev, pdev->dev.parent);
indio_dev->modes = INDIO_DIRECT_MODE;
als = iio_priv(indio_dev);
- als->lm3533 = lm3533;
+ als->regmap = lm3533->regmap;
als->pdev = pdev;
- als->irq = lm3533->irq;
+ als->irq = platform_get_irq_optional(pdev, 0);
+ if (als->irq == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
atomic_set(&als->zone, 0);
mutex_init(&als->thresh_mutex);
platform_set_drvdata(pdev, indio_dev);
- if (als->irq) {
+ if (als->irq > 0) {
ret = lm3533_als_setup_irq(als, indio_dev);
if (ret)
return ret;
}
- ret = lm3533_als_setup(als, pdata);
+ ret = lm3533_als_setup(als);
if (ret)
goto err_free_irq;
@@ -892,7 +866,7 @@ static int lm3533_als_probe(struct platform_device *pdev)
err_disable:
lm3533_als_disable(als);
err_free_irq:
- if (als->irq)
+ if (als->irq > 0)
free_irq(als->irq, indio_dev);
return ret;
@@ -906,13 +880,20 @@ static void lm3533_als_remove(struct platform_device *pdev)
lm3533_als_set_int_mode(indio_dev, false);
iio_device_unregister(indio_dev);
lm3533_als_disable(als);
- if (als->irq)
+ if (als->irq > 0)
free_irq(als->irq, indio_dev);
}
+static const struct of_device_id lm3533_als_match_table[] = {
+ { .compatible = "ti,lm3533-als" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, lm3533_als_match_table);
+
static struct platform_driver lm3533_als_driver = {
.driver = {
.name = "lm3533-als",
+ .of_match_table = lm3533_als_match_table,
},
.probe = lm3533_als_probe,
.remove = lm3533_als_remove,
diff --git a/drivers/leds/leds-lm3533.c b/drivers/leds/leds-lm3533.c
index 45795f2a1042..7259097bd6a7 100644
--- a/drivers/leds/leds-lm3533.c
+++ b/drivers/leds/leds-lm3533.c
@@ -12,6 +12,8 @@
#include <linux/mfd/core.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/mfd/lm3533.h>
@@ -41,13 +43,18 @@
struct lm3533_led {
- struct lm3533 *lm3533;
+ struct regmap *regmap;
struct lm3533_ctrlbank cb;
struct led_classdev cdev;
int id;
struct mutex mutex;
unsigned long flags;
+
+ u32 max_current;
+ u32 pwm;
+
+ bool have_als;
};
@@ -80,7 +87,6 @@ static inline u8 lm3533_led_get_pattern_reg(struct lm3533_led *led,
static int lm3533_led_pattern_enable(struct lm3533_led *led, int enable)
{
u8 mask;
- u8 val;
int pattern;
int state;
int ret = 0;
@@ -96,12 +102,8 @@ static int lm3533_led_pattern_enable(struct lm3533_led *led, int enable)
pattern = lm3533_led_get_pattern(led);
mask = 1 << (2 * pattern);
- if (enable)
- val = mask;
- else
- val = 0;
-
- ret = lm3533_update(led->lm3533, LM3533_REG_PATTERN_ENABLE, val, mask);
+ ret = regmap_assign_bits(led->regmap,
+ LM3533_REG_PATTERN_ENABLE, mask, enable);
if (ret) {
dev_err(led->cdev.dev, "failed to enable pattern %d (%d)\n",
pattern, enable);
@@ -131,7 +133,7 @@ static int lm3533_led_set(struct led_classdev *cdev,
static enum led_brightness lm3533_led_get(struct led_classdev *cdev)
{
struct lm3533_led *led = to_lm3533_led(cdev);
- u8 val;
+ u32 val;
int ret;
ret = lm3533_ctrlbank_get_brightness(&led->cb, &val);
@@ -259,7 +261,7 @@ static u8 lm3533_led_delay_set(struct lm3533_led *led, u8 base,
dev_dbg(led->cdev.dev, "%s - %lu: %u (0x%02x)\n", __func__,
*delay, t, val);
reg = lm3533_led_get_pattern_reg(led, base);
- ret = lm3533_write(led->lm3533, reg, val);
+ ret = regmap_write(led->regmap, reg, val);
if (ret)
dev_err(led->cdev.dev, "failed to set delay (%02x)\n", reg);
@@ -337,10 +339,10 @@ static ssize_t show_risefalltime(struct device *dev,
struct lm3533_led *led = to_lm3533_led(led_cdev);
ssize_t ret;
u8 reg;
- u8 val;
+ u32 val;
reg = lm3533_led_get_pattern_reg(led, base);
- ret = lm3533_read(led->lm3533, reg, &val);
+ ret = regmap_read(led->regmap, reg, &val);
if (ret)
return ret;
@@ -375,7 +377,7 @@ static ssize_t store_risefalltime(struct device *dev,
return -EINVAL;
reg = lm3533_led_get_pattern_reg(led, base);
- ret = lm3533_write(led->lm3533, reg, val);
+ ret = regmap_write(led->regmap, reg, val);
if (ret)
return ret;
@@ -405,11 +407,11 @@ static ssize_t show_als_channel(struct device *dev,
struct lm3533_led *led = to_lm3533_led(led_cdev);
unsigned channel;
u8 reg;
- u8 val;
+ u32 val;
int ret;
reg = lm3533_led_get_lv_reg(led, LM3533_REG_CTRLBANK_BCONF_BASE);
- ret = lm3533_read(led->lm3533, reg, &val);
+ ret = regmap_read(led->regmap, reg, &val);
if (ret)
return ret;
@@ -441,7 +443,7 @@ static ssize_t store_als_channel(struct device *dev,
mask = LM3533_REG_CTRLBANK_BCONF_ALS_CHANNEL_MASK;
val = channel - 1;
- ret = lm3533_update(led->lm3533, reg, val, mask);
+ ret = regmap_update_bits(led->regmap, reg, mask, val);
if (ret)
return ret;
@@ -455,11 +457,11 @@ static ssize_t show_als_en(struct device *dev,
struct lm3533_led *led = to_lm3533_led(led_cdev);
bool enable;
u8 reg;
- u8 val;
+ u32 val;
int ret;
reg = lm3533_led_get_lv_reg(led, LM3533_REG_CTRLBANK_BCONF_BASE);
- ret = lm3533_read(led->lm3533, reg, &val);
+ ret = regmap_read(led->regmap, reg, &val);
if (ret)
return ret;
@@ -476,22 +478,15 @@ static ssize_t store_als_en(struct device *dev,
struct lm3533_led *led = to_lm3533_led(led_cdev);
unsigned enable;
u8 reg;
- u8 mask;
- u8 val;
int ret;
if (kstrtouint(buf, 0, &enable))
return -EINVAL;
reg = lm3533_led_get_lv_reg(led, LM3533_REG_CTRLBANK_BCONF_BASE);
- mask = LM3533_REG_CTRLBANK_BCONF_ALS_EN_MASK;
- if (enable)
- val = mask;
- else
- val = 0;
-
- ret = lm3533_update(led->lm3533, reg, val, mask);
+ ret = regmap_assign_bits(led->regmap, reg,
+ LM3533_REG_CTRLBANK_BCONF_ALS_EN_MASK, enable);
if (ret)
return ret;
@@ -504,12 +499,12 @@ static ssize_t show_linear(struct device *dev,
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct lm3533_led *led = to_lm3533_led(led_cdev);
u8 reg;
- u8 val;
+ u32 val;
int linear;
int ret;
reg = lm3533_led_get_lv_reg(led, LM3533_REG_CTRLBANK_BCONF_BASE);
- ret = lm3533_read(led->lm3533, reg, &val);
+ ret = regmap_read(led->regmap, reg, &val);
if (ret)
return ret;
@@ -529,22 +524,15 @@ static ssize_t store_linear(struct device *dev,
struct lm3533_led *led = to_lm3533_led(led_cdev);
unsigned long linear;
u8 reg;
- u8 mask;
- u8 val;
int ret;
if (kstrtoul(buf, 0, &linear))
return -EINVAL;
reg = lm3533_led_get_lv_reg(led, LM3533_REG_CTRLBANK_BCONF_BASE);
- mask = LM3533_REG_CTRLBANK_BCONF_MAPPING_MASK;
-
- if (linear)
- val = mask;
- else
- val = 0;
- ret = lm3533_update(led->lm3533, reg, val, mask);
+ ret = regmap_assign_bits(led->regmap, reg,
+ LM3533_REG_CTRLBANK_BCONF_MAPPING_MASK, linear);
if (ret)
return ret;
@@ -557,7 +545,7 @@ static ssize_t show_pwm(struct device *dev,
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct lm3533_led *led = to_lm3533_led(led_cdev);
- u8 val;
+ u32 val;
int ret;
ret = lm3533_ctrlbank_get_pwm(&led->cb, &val);
@@ -573,10 +561,10 @@ static ssize_t store_pwm(struct device *dev,
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct lm3533_led *led = to_lm3533_led(led_cdev);
- u8 val;
+ u32 val;
int ret;
- if (kstrtou8(buf, 0, &val))
+ if (kstrtou32(buf, 0, &val))
return -EINVAL;
ret = lm3533_ctrlbank_set_pwm(&led->cb, val);
@@ -615,7 +603,7 @@ static umode_t lm3533_led_attr_is_visible(struct kobject *kobj,
if (attr == &dev_attr_als_channel.attr ||
attr == &dev_attr_als_en.attr) {
- if (!led->lm3533->have_als)
+ if (!led->have_als)
mode = 0;
}
@@ -632,22 +620,20 @@ static const struct attribute_group *lm3533_led_attribute_groups[] = {
NULL
};
-static int lm3533_led_setup(struct lm3533_led *led,
- struct lm3533_led_platform_data *pdata)
+static int lm3533_led_setup(struct lm3533_led *led)
{
int ret;
- ret = lm3533_ctrlbank_set_max_current(&led->cb, pdata->max_current);
+ ret = lm3533_ctrlbank_set_max_current(&led->cb, led->max_current);
if (ret)
return ret;
- return lm3533_ctrlbank_set_pwm(&led->cb, pdata->pwm);
+ return lm3533_ctrlbank_set_pwm(&led->cb, led->pwm);
}
static int lm3533_led_probe(struct platform_device *pdev)
{
struct lm3533 *lm3533;
- struct lm3533_led_platform_data *pdata;
struct lm3533_led *led;
int ret;
@@ -657,12 +643,6 @@ static int lm3533_led_probe(struct platform_device *pdev)
if (!lm3533)
return -EINVAL;
- pdata = dev_get_platdata(&pdev->dev);
- if (!pdata) {
- dev_err(&pdev->dev, "no platform data\n");
- return -EINVAL;
- }
-
if (pdev->id < 0 || pdev->id >= LM3533_LVCTRLBANK_COUNT) {
dev_err(&pdev->dev, "illegal LED id %d\n", pdev->id);
return -EINVAL;
@@ -672,9 +652,9 @@ static int lm3533_led_probe(struct platform_device *pdev)
if (!led)
return -ENOMEM;
- led->lm3533 = lm3533;
- led->cdev.name = pdata->name;
- led->cdev.default_trigger = pdata->default_trigger;
+ led->regmap = lm3533->regmap;
+ led->have_als = lm3533->have_als;
+
led->cdev.brightness_set_blocking = lm3533_led_set;
led->cdev.brightness_get = lm3533_led_get;
led->cdev.blink_set = lm3533_led_blink_set;
@@ -682,19 +662,28 @@ static int lm3533_led_probe(struct platform_device *pdev)
led->cdev.groups = lm3533_led_attribute_groups;
led->id = pdev->id;
+ led->cdev.name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s-%d",
+ pdev->name, led->id);
+ if (!led->cdev.name)
+ return -ENOMEM;
+
+ led->cdev.default_trigger = "none";
+ device_property_read_string(&pdev->dev, "linux,default-trigger",
+ &led->cdev.default_trigger);
+
mutex_init(&led->mutex);
/* The class framework makes a callback to get brightness during
* registration so use parent device (for error reporting) until
* registered.
*/
- led->cb.lm3533 = lm3533;
+ led->cb.regmap = lm3533->regmap;
led->cb.id = lm3533_led_get_ctrlbank_id(led);
led->cb.dev = lm3533->dev;
platform_set_drvdata(pdev, led);
- ret = led_classdev_register(pdev->dev.parent, &led->cdev);
+ ret = led_classdev_register(&pdev->dev, &led->cdev);
if (ret) {
dev_err(&pdev->dev, "failed to register LED %d\n", pdev->id);
return ret;
@@ -702,7 +691,14 @@ static int lm3533_led_probe(struct platform_device *pdev)
led->cb.dev = led->cdev.dev;
- ret = lm3533_led_setup(led, pdata);
+ device_property_read_u32(&pdev->dev, "led-max-microamp",
+ &led->max_current);
+ led->max_current = clamp(led->max_current, LM3533_MAX_CURRENT_MIN,
+ LM3533_MAX_CURRENT_MAX);
+
+ device_property_read_u32(&pdev->dev, "ti,pwm-config-mask", &led->pwm);
+
+ ret = lm3533_led_setup(led);
if (ret)
goto err_deregister;
@@ -739,9 +735,16 @@ static void lm3533_led_shutdown(struct platform_device *pdev)
lm3533_led_set(&led->cdev, LED_OFF); /* disable blink */
}
+static const struct of_device_id lm3533_led_match_table[] = {
+ { .compatible = "ti,lm3533-leds" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, lm3533_led_match_table);
+
static struct platform_driver lm3533_led_driver = {
.driver = {
.name = "lm3533-leds",
+ .of_match_table = lm3533_led_match_table,
},
.probe = lm3533_led_probe,
.remove = lm3533_led_remove,
diff --git a/drivers/mfd/88pm800.c b/drivers/mfd/88pm800.c
index e9941da58b18..7f3e312b8f73 100644
--- a/drivers/mfd/88pm800.c
+++ b/drivers/mfd/88pm800.c
@@ -275,10 +275,10 @@ static int device_gpadc_init(struct pm80x_chip *chip,
goto out;
/*
- * the defult of PM800 is GPADC operates at 100Ks/s rate
+ * the default of PM800 is GPADC operates at 100Ks/s rate
* and Number of GPADC slots with active current bias prior
* to GPADC sampling = 1 slot for all GPADCs set for
- * Temprature mesurmants
+ * Temperature measurements
*/
mask = (PM800_GPADC_GP_BIAS_EN0 | PM800_GPADC_GP_BIAS_EN1 |
PM800_GPADC_GP_BIAS_EN2 | PM800_GPADC_GP_BIAS_EN3);
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 439dbf5ee110..87ed55c155f0 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -205,6 +205,20 @@ config MFD_AC100
This driver include only the core APIs. You have to select individual
components like codecs or RTC under the corresponding menus.
+config MFD_AC200
+ tristate "X-Powers AC200"
+ depends on COMMON_CLK
+ depends on I2C
+ depends on OF
+ select MFD_CORE
+ select REGMAP_I2C
+ help
+ Support for the X-Powers AC200 mixed-signal companion IC. The AC200
+ contains audio, video, RTC and Fast Ethernet PHY functions and is
+ co-packaged with some Allwinner H6 and H616 SoCs. This driver provides
+ the shared register access and instantiates the individual function
+ devices.
+
config MFD_AXP20X
tristate
select MFD_CORE
@@ -1006,6 +1020,8 @@ config MFD_MAX77705
depends on I2C
select MFD_CORE
select MFD_SIMPLE_MFD_I2C
+ select REGMAP_I2C
+ select REGMAP_IRQ
help
Say yes here to add support for Maxim Integrated MAX77705 PMIC.
This is a Power Management IC with Charger, safe LDOs, Flash, Haptic
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 72d3944b0ad8..f8101d2a9ce9 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -150,6 +150,7 @@ obj-$(CONFIG_MFD_DA9052_SPI) += da9052-spi.o
obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.o
obj-$(CONFIG_MFD_AC100) += ac100.o
+obj-$(CONFIG_MFD_AC200) += ac200.o
obj-$(CONFIG_MFD_AXP20X) += axp20x.o
obj-$(CONFIG_MFD_AXP20X_I2C) += axp20x-i2c.o
obj-$(CONFIG_MFD_AXP20X_RSB) += axp20x-rsb.o
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index 86fa99022cb3..d5602b2f4a0e 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -125,7 +125,7 @@ static u8 turn_on_stat_set;
/*
* Map interrupt numbers to the LATCH and MASK register offsets, Interrupt
- * numbers are indexed into this array with (num / 8). The interupts are
+ * numbers are indexed into this array with (num / 8). The interrupts are
* defined in linux/mfd/ab8500.h
*
* This is one off from the register names, i.e. AB8500_IT_MASK1_REG is at
@@ -1194,39 +1194,41 @@ static int ab8500_probe(struct platform_device *pdev)
return ret;
if (is_ab9540(ab8500))
- ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs,
- ARRAY_SIZE(ab9540_devs), NULL,
- 0, ab8500->domain);
+ ret = devm_mfd_add_devices(ab8500->dev, 0, ab9540_devs,
+ ARRAY_SIZE(ab9540_devs), NULL,
+ 0, ab8500->domain);
else if (is_ab8540(ab8500)) {
- ret = mfd_add_devices(ab8500->dev, 0, ab8540_devs,
- ARRAY_SIZE(ab8540_devs), NULL,
- 0, ab8500->domain);
+ ret = devm_mfd_add_devices(ab8500->dev, 0, ab8540_devs,
+ ARRAY_SIZE(ab8540_devs), NULL,
+ 0, ab8500->domain);
if (ret)
return ret;
if (is_ab8540_1p2_or_earlier(ab8500))
- ret = mfd_add_devices(ab8500->dev, 0, ab8540_cut1_devs,
- ARRAY_SIZE(ab8540_cut1_devs), NULL,
- 0, ab8500->domain);
+ ret = devm_mfd_add_devices(ab8500->dev, 0,
+ ab8540_cut1_devs,
+ ARRAY_SIZE(ab8540_cut1_devs),
+ NULL, 0, ab8500->domain);
else /* ab8540 >= cut2 */
- ret = mfd_add_devices(ab8500->dev, 0, ab8540_cut2_devs,
- ARRAY_SIZE(ab8540_cut2_devs), NULL,
- 0, ab8500->domain);
+ ret = devm_mfd_add_devices(ab8500->dev, 0,
+ ab8540_cut2_devs,
+ ARRAY_SIZE(ab8540_cut2_devs),
+ NULL, 0, ab8500->domain);
} else if (is_ab8505(ab8500))
- ret = mfd_add_devices(ab8500->dev, 0, ab8505_devs,
- ARRAY_SIZE(ab8505_devs), NULL,
- 0, ab8500->domain);
+ ret = devm_mfd_add_devices(ab8500->dev, 0, ab8505_devs,
+ ARRAY_SIZE(ab8505_devs), NULL,
+ 0, ab8500->domain);
else
- ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs,
- ARRAY_SIZE(ab8500_devs), NULL,
- 0, ab8500->domain);
+ ret = devm_mfd_add_devices(ab8500->dev, 0, ab8500_devs,
+ ARRAY_SIZE(ab8500_devs), NULL,
+ 0, ab8500->domain);
if (ret)
return ret;
/* Add battery management devices */
- ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs,
- ARRAY_SIZE(ab8500_bm_devs), NULL,
- 0, ab8500->domain);
+ ret = devm_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");
diff --git a/drivers/mfd/ac200.c b/drivers/mfd/ac200.c
new file mode 100644
index 000000000000..3c6543a1688c
--- /dev/null
+++ b/drivers/mfd/ac200.c
@@ -0,0 +1,222 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * X-Powers AC200 Core driver
+ *
+ * Copyright (C) 2019 Jernej Skrabec <jernej.skrabec@gmail.com>
+ * Copyright (C) 2026 James Hilliard <james.hilliard1@gmail.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+
+#define AC200_SYS_CONTROL_REG 0x0002
+#define AC200_SYS_CONTROL_CHIP_RESET_DEASSERT BIT(0)
+#define AC200_SYS_IRQ_ENABLE_REG 0x0004
+#define AC200_SYS_IRQ_INTB_ENABLE BIT(15)
+#define AC200_SYS_IRQ_INTB_ACTIVE_HIGH BIT(14)
+#define AC200_SYS_IRQ_RTC BIT(12)
+#define AC200_SYS_IRQ_EPHY BIT(8)
+#define AC200_SYS_IRQ_TVE BIT(4)
+
+/* Interface register accessible from every register page. */
+#define AC200_TWI_REG_ADDR_H 0x00fe
+#define AC200_MAX_REG 0xa1f2
+
+static const struct regmap_range_cfg ac200_range_cfg[] = {
+ {
+ .range_max = AC200_MAX_REG,
+ .selector_reg = AC200_TWI_REG_ADDR_H,
+ .selector_mask = 0xff,
+ .window_len = 256,
+ },
+};
+
+/*
+ * Each AC200 sub-block can reset independently, invalidating its register
+ * contents without regmap's knowledge. Cache only the common page selector;
+ * this avoids a selector read-modify-write for every access on the same page
+ * without ever returning stale functional-register values.
+ */
+static bool ac200_volatile_reg(struct device *dev, unsigned int reg)
+{
+ return reg != AC200_TWI_REG_ADDR_H;
+}
+
+static const struct regmap_config ac200_regmap_config = {
+ .name = "ac200",
+ .reg_bits = 8,
+ .reg_stride = 2,
+ .val_bits = 16,
+ .ranges = ac200_range_cfg,
+ .num_ranges = ARRAY_SIZE(ac200_range_cfg),
+ .max_register = AC200_MAX_REG,
+ .volatile_reg = ac200_volatile_reg,
+ .cache_type = REGCACHE_MAPLE,
+};
+
+static const char * const ac200_codec_supplies[] = {
+ "ac-ldoin",
+};
+
+static const char * const ac200_tve_supplies[] = {
+ "tv-vcc",
+};
+
+static const struct resource ac200_tve_resources[] = {
+ DEFINE_RES_IRQ_NAMED(0, "intb"),
+};
+
+#define AC200_CELL(_name, _supplies, _resources) \
+ { \
+ .name = (_name), \
+ .parent_supplies = (_supplies), \
+ .num_parent_supplies = ARRAY_SIZE(_supplies), \
+ .resources = (_resources), \
+ .num_resources = MFD_RES_SIZE(_resources), \
+ }
+
+static const struct mfd_cell ac200_cells[] = {
+ AC200_CELL("ac200-codec", ac200_codec_supplies, NULL),
+ AC200_CELL("ac200-tve", ac200_tve_supplies, ac200_tve_resources),
+};
+
+static const struct mfd_cell ac200_noirq_cells[] = {
+ AC200_CELL("ac200-codec", ac200_codec_supplies, NULL),
+ AC200_CELL("ac200-tve", ac200_tve_supplies, NULL),
+};
+
+static void ac200_disable_intb(void *data)
+{
+ struct regmap *regmap = data;
+ int ret;
+
+ ret = regmap_clear_bits(regmap, AC200_SYS_IRQ_ENABLE_REG, AC200_SYS_IRQ_INTB_ENABLE);
+ if (ret)
+ dev_err(regmap_get_device(regmap), "failed to disable INTB: %d\n", ret);
+}
+
+static int ac200_init_irq(struct device *dev, struct regmap *regmap, int irq)
+{
+ unsigned int trigger;
+ u16 value = 0;
+ int ret;
+
+ trigger = irq_get_trigger_type(irq);
+ switch (trigger) {
+ case IRQ_TYPE_LEVEL_HIGH:
+ value |= AC200_SYS_IRQ_INTB_ACTIVE_HIGH;
+ break;
+ case IRQ_TYPE_NONE:
+ case IRQ_TYPE_LEVEL_LOW:
+ break;
+ default:
+ return dev_err_probe(dev, -EINVAL,
+ "INTB is level triggered, not type %u\n", trigger);
+ }
+
+ /* Mask every source before enabling the shared output. */
+ ret = regmap_update_bits(regmap, AC200_SYS_IRQ_ENABLE_REG,
+ AC200_SYS_IRQ_INTB_ENABLE | AC200_SYS_IRQ_INTB_ACTIVE_HIGH |
+ AC200_SYS_IRQ_RTC | AC200_SYS_IRQ_EPHY | AC200_SYS_IRQ_TVE, value);
+ if (ret)
+ return ret;
+
+ /* Children are removed before INTB is disabled and the regmap released. */
+ ret = devm_add_action_or_reset(dev, ac200_disable_intb, regmap);
+ if (ret)
+ return ret;
+
+ if (trigger == IRQ_TYPE_NONE) {
+ ret = irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to set INTB trigger\n");
+ }
+
+ /*
+ * Function drivers request INTB with IRQF_SHARED | IRQF_ONESHOT before
+ * enabling their own source. They check and clear their own status and
+ * mask their source before freeing the IRQ. No IRQ domain is needed.
+ */
+ return regmap_set_bits(regmap, AC200_SYS_IRQ_ENABLE_REG, AC200_SYS_IRQ_INTB_ENABLE);
+}
+
+static int ac200_probe(struct i2c_client *client)
+{
+ const struct mfd_cell *cells = ac200_noirq_cells;
+ unsigned int num_cells = ARRAY_SIZE(ac200_noirq_cells);
+ struct device *dev = &client->dev;
+ struct regmap *regmap;
+ struct clk *clk;
+ int ret;
+
+ clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(clk))
+ return dev_err_probe(dev, PTR_ERR(clk), "failed to enable input clock\n");
+
+ ret = devm_clk_rate_exclusive_get(dev, clk);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to lock clock rate\n");
+
+ /*
+ * No minimum delay is documented. Retain the vendor resume path's 40 ms
+ * wait after enabling the input clock and before register access.
+ */
+ msleep(40);
+
+ regmap = devm_regmap_init_i2c(client, &ac200_regmap_config);
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap), "failed to initialize regmap\n");
+
+ ret = regmap_set_bits(regmap, AC200_SYS_CONTROL_REG, AC200_SYS_CONTROL_CHIP_RESET_DEASSERT);
+ if (ret)
+ return ret;
+
+ if (client->irq > 0) {
+ ret = ac200_init_irq(dev, regmap, client->irq);
+ if (ret)
+ return ret;
+ cells = ac200_cells;
+ num_cells = ARRAY_SIZE(ac200_cells);
+ }
+
+ /* Function drivers read their firmware properties from the parent. */
+ ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, cells, num_cells,
+ NULL, client->irq, NULL);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to add function devices\n");
+
+ return 0;
+}
+
+static const struct of_device_id ac200_of_match[] = {
+ { .compatible = "x-powers,ac200" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ac200_of_match);
+
+static const struct i2c_device_id ac200_i2c_ids[] = {
+ { .name = "ac200" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ac200_i2c_ids);
+
+static struct i2c_driver ac200_driver = {
+ .driver = {
+ .name = "ac200",
+ .of_match_table = ac200_of_match,
+ },
+ .probe = ac200_probe,
+ .id_table = ac200_i2c_ids,
+};
+module_i2c_driver(ac200_driver);
+
+MODULE_AUTHOR("Jernej Skrabec <jernej.skrabec@gmail.com>");
+MODULE_AUTHOR("James Hilliard <james.hilliard1@gmail.com>");
+MODULE_DESCRIPTION("X-Powers AC200 Core driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/bq257xx.c b/drivers/mfd/bq257xx.c
index 054342c60b73..01f5fc97f538 100644
--- a/drivers/mfd/bq257xx.c
+++ b/drivers/mfd/bq257xx.c
@@ -52,8 +52,18 @@ static const struct regmap_access_table bq25792_writeable_regs = {
};
static const struct regmap_range bq25792_volatile_reg_ranges[] = {
+ regmap_reg_range(BQ25792_REG05_INPUT_VOLTAGE_LIMIT,
+ BQ25792_REG06_INPUT_CURRENT_LIMIT + 1),
+ regmap_reg_range(BQ25792_REG0F_CHARGER_CONTROL_0,
+ BQ25792_REG0F_CHARGER_CONTROL_0),
+ regmap_reg_range(BQ25792_REG11_CHARGER_CONTROL_2,
+ BQ25792_REG11_CHARGER_CONTROL_2),
+ regmap_reg_range(BQ25792_REG13_CHARGER_CONTROL_4,
+ BQ25792_REG13_CHARGER_CONTROL_4),
regmap_reg_range(BQ25792_REG19_ICO_CURRENT_LIMIT,
BQ25792_REG27_FAULT_FLAG_1),
+ regmap_reg_range(BQ25792_REG2E_ADC_CONTROL,
+ BQ25792_REG2E_ADC_CONTROL),
regmap_reg_range(BQ25792_REG31_IBUS_ADC,
BQ25792_REG47_DPDM_DRIVER),
};
diff --git a/drivers/mfd/cs42l43-i2c.c b/drivers/mfd/cs42l43-i2c.c
index cbe05c3ea910..2f1862199618 100644
--- a/drivers/mfd/cs42l43-i2c.c
+++ b/drivers/mfd/cs42l43-i2c.c
@@ -54,10 +54,18 @@ static int cs42l43_i2c_probe(struct i2c_client *i2c)
return cs42l43_dev_probe(cs42l43);
}
+static void cs42l43_i2c_remove(struct i2c_client *i2c)
+{
+ struct cs42l43 *cs42l43 = dev_get_drvdata(&i2c->dev);
+
+ cs42l43_dev_remove(cs42l43);
+}
+
#if IS_ENABLED(CONFIG_OF)
static const struct of_device_id cs42l43_of_match[] = {
{ .compatible = "cirrus,cs42l43", .data = (void *)CS42L43_DEVID_VAL },
{ .compatible = "cirrus,cs42l43b", .data = (void *)CS42L43B_DEVID_VAL },
+ { .compatible = "cirrus,cs42l44", .data = (void *)CS42L43B_DEVID_VAL },
{}
};
MODULE_DEVICE_TABLE(of, cs42l43_of_match);
@@ -67,6 +75,7 @@ MODULE_DEVICE_TABLE(of, cs42l43_of_match);
static const struct acpi_device_id cs42l43_acpi_match[] = {
{ "CSC4243", CS42L43_DEVID_VAL },
{ "CSC2A3B", CS42L43B_DEVID_VAL },
+ { "CSC4244", CS42L43B_DEVID_VAL },
{}
};
MODULE_DEVICE_TABLE(acpi, cs42l43_acpi_match);
@@ -81,6 +90,7 @@ static struct i2c_driver cs42l43_i2c_driver = {
},
.probe = cs42l43_i2c_probe,
+ .remove = cs42l43_i2c_remove,
};
module_i2c_driver(cs42l43_i2c_driver);
diff --git a/drivers/mfd/cs42l43-sdw.c b/drivers/mfd/cs42l43-sdw.c
index 0a6999453f32..22e4c1fe9298 100644
--- a/drivers/mfd/cs42l43-sdw.c
+++ b/drivers/mfd/cs42l43-sdw.c
@@ -180,9 +180,17 @@ static int cs42l43_sdw_probe(struct sdw_slave *sdw, const struct sdw_device_id *
return cs42l43_dev_probe(cs42l43);
}
+static void cs42l43_sdw_remove(struct sdw_slave *sdw)
+{
+ struct cs42l43 *cs42l43 = dev_get_drvdata(&sdw->dev);
+
+ cs42l43_dev_remove(cs42l43);
+}
+
static const struct sdw_device_id cs42l43_sdw_id[] = {
SDW_SLAVE_ENTRY(0x01FA, 0x4243, (void *)CS42L43_DEVID_VAL),
SDW_SLAVE_ENTRY(0x01FA, 0x2A3B, (void *)CS42L43B_DEVID_VAL),
+ SDW_SLAVE_ENTRY(0x01FA, 0x4244, (void *)CS42L43B_DEVID_VAL),
{ }
};
MODULE_DEVICE_TABLE(sdw, cs42l43_sdw_id);
@@ -194,6 +202,7 @@ static struct sdw_driver cs42l43_sdw_driver = {
},
.probe = cs42l43_sdw_probe,
+ .remove = cs42l43_sdw_remove,
.id_table = cs42l43_sdw_id,
.ops = &cs42l43_sdw_ops,
};
diff --git a/drivers/mfd/cs42l43.c b/drivers/mfd/cs42l43.c
index 4212ebcca60b..a83b62064dae 100644
--- a/drivers/mfd/cs42l43.c
+++ b/drivers/mfd/cs42l43.c
@@ -959,6 +959,7 @@ static void cs42l43_boot_work(struct work_struct *work)
{
struct cs42l43 *cs42l43 = container_of(work, struct cs42l43, boot_work);
unsigned int devid, revid, otp;
+ bool valid_id;
int ret;
ret = cs42l43_wait_for_attach(cs42l43);
@@ -973,19 +974,24 @@ static void cs42l43_boot_work(struct work_struct *work)
switch (devid) {
case CS42L43_DEVID_VAL:
+ valid_id = (cs42l43->variant_id == CS42L43_DEVID_VAL);
+ break;
case CS42L43B_DEVID_VAL:
- if (devid != cs42l43->variant_id) {
- dev_err(cs42l43->dev,
- "Device ID (0x%06x) does not match variant ID (0x%06lx)\n",
- devid, cs42l43->variant_id);
- goto err;
- }
+ case CS42L44_DEVID_VAL:
+ valid_id = (cs42l43->variant_id == CS42L43B_DEVID_VAL);
break;
default:
dev_err(cs42l43->dev, "Unrecognised devid: 0x%06x\n", devid);
goto err;
}
+ if (!valid_id) {
+ dev_err(cs42l43->dev,
+ "Device ID (0x%06x) does not match variant ID (0x%06lx)\n",
+ devid, cs42l43->variant_id);
+ goto err;
+ }
+
ret = regmap_read(cs42l43->regmap, CS42L43_REVID, &revid);
if (ret) {
dev_err(cs42l43->dev, "Failed to read rev: %d\n", ret);
@@ -1099,15 +1105,19 @@ static int cs42l43_power_down(struct cs42l43 *cs42l43)
return 0;
}
-static void cs42l43_dev_remove(void *data)
+static void cs42l43_dev_power_down(void *data)
{
struct cs42l43 *cs42l43 = data;
- cancel_work_sync(&cs42l43->boot_work);
-
cs42l43_power_down(cs42l43);
}
+void cs42l43_dev_remove(struct cs42l43 *cs42l43)
+{
+ flush_work(&cs42l43->boot_work);
+}
+EXPORT_SYMBOL_NS_GPL(cs42l43_dev_remove, "MFD_CS42L43");
+
int cs42l43_dev_probe(struct cs42l43 *cs42l43)
{
int i, ret;
@@ -1153,7 +1163,7 @@ int cs42l43_dev_probe(struct cs42l43 *cs42l43)
if (ret)
return ret;
- ret = devm_add_action_or_reset(cs42l43->dev, cs42l43_dev_remove, cs42l43);
+ ret = devm_add_action_or_reset(cs42l43->dev, cs42l43_dev_power_down, cs42l43);
if (ret)
return ret;
diff --git a/drivers/mfd/cs42l43.h b/drivers/mfd/cs42l43.h
index a0068f6572e2..862bc6fb68cb 100644
--- a/drivers/mfd/cs42l43.h
+++ b/drivers/mfd/cs42l43.h
@@ -25,5 +25,6 @@ bool cs42l43_precious_register(struct device *dev, unsigned int reg);
bool cs42l43_volatile_register(struct device *dev, unsigned int reg);
int cs42l43_dev_probe(struct cs42l43 *cs42l43);
+void cs42l43_dev_remove(struct cs42l43 *cs42l43);
#endif /* CS42L43_CORE_INT_H */
diff --git a/drivers/mfd/da903x.c b/drivers/mfd/da903x.c
index e86b39de3303..e4ad48e1f139 100644
--- a/drivers/mfd/da903x.c
+++ b/drivers/mfd/da903x.c
@@ -421,6 +421,14 @@ static irqreturn_t da903x_irq_handler(int irq, void *data)
return IRQ_HANDLED;
}
+static void da903x_cancel_irq_work(void *data)
+{
+ struct da903x_chip *chip = data;
+
+ disable_irq(chip->client->irq);
+ cancel_work_sync(&chip->irq_work);
+}
+
static const struct da903x_chip_ops da903x_ops[] = {
[0] = {
.init_chip = da9030_init_chip,
@@ -456,6 +464,13 @@ static int da903x_remove_subdevs(struct da903x_chip *chip)
return device_for_each_child(chip->dev, NULL, __remove_subdev);
}
+static void da903x_remove_subdevs_action(void *data)
+{
+ struct da903x_chip *chip = data;
+
+ da903x_remove_subdevs(chip);
+}
+
static int da903x_add_subdevs(struct da903x_chip *chip,
struct da903x_platform_data *pdata)
{
@@ -484,7 +499,6 @@ static int da903x_add_subdevs(struct da903x_chip *chip,
return 0;
failed:
- da903x_remove_subdevs(chip);
return ret;
}
@@ -520,6 +534,11 @@ static int da903x_probe(struct i2c_client *client)
chip->ops->mask_events(chip, chip->events_mask);
chip->ops->read_events(chip, &tmp);
+ ret = devm_add_action_or_reset(&client->dev,
+ da903x_remove_subdevs_action, chip);
+ if (ret)
+ return ret;
+
ret = devm_request_irq(&client->dev, client->irq, da903x_irq_handler,
IRQF_TRIGGER_FALLING,
"da903x", chip);
@@ -529,14 +548,12 @@ static int da903x_probe(struct i2c_client *client)
return ret;
}
- return da903x_add_subdevs(chip, pdata);
-}
-
-static void da903x_remove(struct i2c_client *client)
-{
- struct da903x_chip *chip = i2c_get_clientdata(client);
+ ret = devm_add_action_or_reset(&client->dev, da903x_cancel_irq_work,
+ chip);
+ if (ret)
+ return ret;
- da903x_remove_subdevs(chip);
+ return da903x_add_subdevs(chip, pdata);
}
static struct i2c_driver da903x_driver = {
@@ -544,7 +561,6 @@ static struct i2c_driver da903x_driver = {
.name = "da903x",
},
.probe = da903x_probe,
- .remove = da903x_remove,
.id_table = da903x_id_table,
};
diff --git a/drivers/mfd/da9062-core.c b/drivers/mfd/da9062-core.c
index 637c5f47a4b0..ad198183aff7 100644
--- a/drivers/mfd/da9062-core.c
+++ b/drivers/mfd/da9062-core.c
@@ -203,36 +203,36 @@ static const struct mfd_cell da9061_devs_noirq[] = {
};
static const struct resource da9062_core_resources[] = {
- DEFINE_RES_NAMED(DA9062_IRQ_VDD_WARN, 1, "VDD_WARN", IORESOURCE_IRQ),
+ DEFINE_RES_IRQ_NAMED(DA9062_IRQ_VDD_WARN, "VDD_WARN"),
};
static const struct resource da9062_regulators_resources[] = {
- DEFINE_RES_NAMED(DA9062_IRQ_LDO_LIM, 1, "LDO_LIM", IORESOURCE_IRQ),
+ DEFINE_RES_IRQ_NAMED(DA9062_IRQ_LDO_LIM, "LDO_LIM"),
};
static const struct resource da9062_thermal_resources[] = {
- DEFINE_RES_NAMED(DA9062_IRQ_TEMP, 1, "THERMAL", IORESOURCE_IRQ),
+ DEFINE_RES_IRQ_NAMED(DA9062_IRQ_TEMP, "THERMAL"),
};
static const struct resource da9062_wdt_resources[] = {
- DEFINE_RES_NAMED(DA9062_IRQ_WDG_WARN, 1, "WD_WARN", IORESOURCE_IRQ),
+ DEFINE_RES_IRQ_NAMED(DA9062_IRQ_WDG_WARN, "WD_WARN"),
};
static const struct resource da9062_rtc_resources[] = {
- DEFINE_RES_NAMED(DA9062_IRQ_ALARM, 1, "ALARM", IORESOURCE_IRQ),
- DEFINE_RES_NAMED(DA9062_IRQ_TICK, 1, "TICK", IORESOURCE_IRQ),
+ DEFINE_RES_IRQ_NAMED(DA9062_IRQ_ALARM, "ALARM"),
+ DEFINE_RES_IRQ_NAMED(DA9062_IRQ_TICK, "TICK"),
};
static const struct resource da9062_onkey_resources[] = {
- DEFINE_RES_NAMED(DA9062_IRQ_ONKEY, 1, "ONKEY", IORESOURCE_IRQ),
+ DEFINE_RES_IRQ_NAMED(DA9062_IRQ_ONKEY, "ONKEY"),
};
static const struct resource da9062_gpio_resources[] = {
- DEFINE_RES_NAMED(DA9062_IRQ_GPI0, 1, "GPI0", IORESOURCE_IRQ),
- DEFINE_RES_NAMED(DA9062_IRQ_GPI1, 1, "GPI1", IORESOURCE_IRQ),
- DEFINE_RES_NAMED(DA9062_IRQ_GPI2, 1, "GPI2", IORESOURCE_IRQ),
- DEFINE_RES_NAMED(DA9062_IRQ_GPI3, 1, "GPI3", IORESOURCE_IRQ),
- DEFINE_RES_NAMED(DA9062_IRQ_GPI4, 1, "GPI4", IORESOURCE_IRQ),
+ DEFINE_RES_IRQ_NAMED(DA9062_IRQ_GPI0, "GPI0"),
+ DEFINE_RES_IRQ_NAMED(DA9062_IRQ_GPI1, "GPI1"),
+ DEFINE_RES_IRQ_NAMED(DA9062_IRQ_GPI2, "GPI2"),
+ DEFINE_RES_IRQ_NAMED(DA9062_IRQ_GPI3, "GPI3"),
+ DEFINE_RES_IRQ_NAMED(DA9062_IRQ_GPI4, "GPI4"),
};
static const struct mfd_cell da9062_devs_irq[] = {
diff --git a/drivers/mfd/da9150-core.c b/drivers/mfd/da9150-core.c
index 5c59cc869fb3..19325d72a27e 100644
--- a/drivers/mfd/da9150-core.c
+++ b/drivers/mfd/da9150-core.c
@@ -450,7 +450,7 @@ static int da9150_probe(struct i2c_client *client)
da9150->irq_base = regmap_irq_chip_get_base(da9150->regmap_irq_data);
- enable_irq_wake(da9150->irq);
+ da9150->irq_wake_enabled = !enable_irq_wake(da9150->irq);
ret = mfd_add_devices(da9150->dev, -1, da9150_devs,
ARRAY_SIZE(da9150_devs), NULL,
@@ -463,6 +463,8 @@ static int da9150_probe(struct i2c_client *client)
return 0;
mfd_fail:
+ if (da9150->irq_wake_enabled)
+ disable_irq_wake(da9150->irq);
regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data);
regmap_irq_fail:
i2c_unregister_device(da9150->core_qif);
@@ -474,8 +476,10 @@ static void da9150_remove(struct i2c_client *client)
{
struct da9150 *da9150 = i2c_get_clientdata(client);
- regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data);
mfd_remove_devices(da9150->dev);
+ if (da9150->irq_wake_enabled)
+ disable_irq_wake(da9150->irq);
+ regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data);
i2c_unregister_device(da9150->core_qif);
}
diff --git a/drivers/mfd/intel-lpss-acpi.c b/drivers/mfd/intel-lpss-acpi.c
index d4b24a717848..720adb0ee21f 100644
--- a/drivers/mfd/intel-lpss-acpi.c
+++ b/drivers/mfd/intel-lpss-acpi.c
@@ -8,7 +8,9 @@
* Mika Westerberg <mika.westerberg@linux.intel.com>
*/
+#include <linux/acpi.h>
#include <linux/device.h>
+#include <linux/dmi.h>
#include <linux/gfp_types.h>
#include <linux/ioport.h>
#include <linux/module.h>
@@ -171,6 +173,33 @@ static const struct acpi_device_id intel_lpss_acpi_ids[] = {
};
MODULE_DEVICE_TABLE(acpi, intel_lpss_acpi_ids);
+/*
+ * Devices that need a quirk applied only on the machines matched by
+ * intel_lpss_quirk_dmi[] below. The quirk to apply is carried in the
+ * matching entry's driver_data.
+ */
+static const struct acpi_device_id intel_lpss_acpi_quirk_ids[] = {
+ /* Dell Latitude 5285: ACPI GEXP device conflicts with I2C4 (INT3446) */
+ { .id = "INT3446", .driver_data = QUIRK_IGNORE_RESOURCE_CONFLICTS },
+ { }
+};
+
+static const struct dmi_system_id intel_lpss_quirk_dmi[] = {
+ {
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Latitude 5285"),
+ },
+ },
+ {
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Latitude 7275"),
+ },
+ },
+ { }
+};
+
static int intel_lpss_acpi_probe(struct platform_device *pdev)
{
const struct intel_lpss_platform_info *data;
@@ -185,6 +214,15 @@ static int intel_lpss_acpi_probe(struct platform_device *pdev)
if (!info)
return -ENOMEM;
+ /* Apply per-device quirks that are only needed on certain machines */
+ if (dmi_check_system(intel_lpss_quirk_dmi)) {
+ const struct acpi_device_id *id;
+
+ id = acpi_match_device(intel_lpss_acpi_quirk_ids, &pdev->dev);
+ if (id)
+ info->quirks |= id->driver_data;
+ }
+
/* No need to check mem and irq here as intel_lpss_probe() does it for us */
info->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
info->irq = platform_get_irq(pdev, 0);
diff --git a/drivers/mfd/intel-lpss.c b/drivers/mfd/intel-lpss.c
index 63d6694f7145..29f30ef0da99 100644
--- a/drivers/mfd/intel-lpss.c
+++ b/drivers/mfd/intel-lpss.c
@@ -142,28 +142,21 @@ static void intel_lpss_cache_ltr(struct intel_lpss *lpss)
lpss->idle_ltr = readl(lpss->priv + LPSS_PRIV_IDLELTR);
}
-static int intel_lpss_debugfs_add(struct intel_lpss *lpss)
+static void intel_lpss_debugfs_add(struct intel_lpss *lpss)
{
- struct dentry *dir;
-
- dir = debugfs_create_dir(dev_name(lpss->dev), intel_lpss_debugfs);
- if (IS_ERR(dir))
- return PTR_ERR(dir);
+ lpss->debugfs = debugfs_create_dir(dev_name(lpss->dev), intel_lpss_debugfs);
/* Cache the values into lpss structure */
intel_lpss_cache_ltr(lpss);
- debugfs_create_x32("capabilities", S_IRUGO, dir, &lpss->caps);
- debugfs_create_x32("active_ltr", S_IRUGO, dir, &lpss->active_ltr);
- debugfs_create_x32("idle_ltr", S_IRUGO, dir, &lpss->idle_ltr);
-
- lpss->debugfs = dir;
- return 0;
+ debugfs_create_x32("capabilities", 0444, lpss->debugfs, &lpss->caps);
+ debugfs_create_x32("active_ltr", 0444, lpss->debugfs, &lpss->active_ltr);
+ debugfs_create_x32("idle_ltr", 0444, lpss->debugfs, &lpss->idle_ltr);
}
static void intel_lpss_debugfs_remove(struct intel_lpss *lpss)
{
- debugfs_remove_recursive(lpss->debugfs);
+ debugfs_remove(lpss->debugfs);
}
static void intel_lpss_ltr_set(struct device *dev, s32 val)
@@ -432,10 +425,7 @@ int intel_lpss_probe(struct device *dev,
goto err_clk_register;
intel_lpss_ltr_expose(lpss);
-
- ret = intel_lpss_debugfs_add(lpss);
- if (ret)
- dev_warn(dev, "Failed to create debugfs entries\n");
+ intel_lpss_debugfs_add(lpss);
if (intel_lpss_has_idma(lpss)) {
ret = mfd_add_devices(dev, lpss->devid, &intel_lpss_idma64_cell,
diff --git a/drivers/mfd/intel_quark_i2c_gpio.c b/drivers/mfd/intel_quark_i2c_gpio.c
index 9b9c76bd067b..443a1a0cf777 100644
--- a/drivers/mfd/intel_quark_i2c_gpio.c
+++ b/drivers/mfd/intel_quark_i2c_gpio.c
@@ -35,11 +35,6 @@
/* The Quark I2C controller source clock */
#define INTEL_QUARK_I2C_CLK_HZ 33000000
-struct intel_quark_mfd {
- 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),
{ }
@@ -160,37 +155,12 @@ MODULE_DEVICE_TABLE(pci, intel_quark_mfd_ids);
static int intel_quark_register_i2c_clk(struct device *dev)
{
- struct intel_quark_mfd *quark_mfd = dev_get_drvdata(dev);
- struct clk *i2c_clk;
-
- i2c_clk = clk_register_fixed_rate(dev,
- INTEL_QUARK_I2C_CONTROLLER_CLK, NULL,
- 0, INTEL_QUARK_I2C_CLK_HZ);
- if (IS_ERR(i2c_clk))
- return PTR_ERR(i2c_clk);
-
- quark_mfd->i2c_clk = i2c_clk;
- quark_mfd->i2c_clk_lookup = clkdev_create(i2c_clk, NULL,
- INTEL_QUARK_I2C_CONTROLLER_CLK);
-
- if (!quark_mfd->i2c_clk_lookup) {
- clk_unregister(quark_mfd->i2c_clk);
- dev_err(dev, "Fixed clk register failed\n");
- return -ENOMEM;
- }
-
- return 0;
-}
-
-static void intel_quark_unregister_i2c_clk(struct device *dev)
-{
- struct intel_quark_mfd *quark_mfd = dev_get_drvdata(dev);
-
- if (!quark_mfd->i2c_clk_lookup)
- return;
+ struct clk_hw *hw;
- clkdev_drop(quark_mfd->i2c_clk_lookup);
- clk_unregister(quark_mfd->i2c_clk);
+ hw = devm_clk_hw_register_fixed_rate(dev, INTEL_QUARK_I2C_CONTROLLER_CLK,
+ NULL, 0, INTEL_QUARK_I2C_CLK_HZ);
+ return devm_clk_hw_register_clkdev(dev, hw, NULL,
+ INTEL_QUARK_I2C_CONTROLLER_CLK);
}
static int intel_quark_i2c_setup(struct pci_dev *pdev)
@@ -238,19 +208,12 @@ static int intel_quark_gpio_setup(struct pci_dev *pdev)
static int intel_quark_mfd_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
- struct intel_quark_mfd *quark_mfd;
int ret;
ret = pcim_enable_device(pdev);
if (ret)
return ret;
- quark_mfd = devm_kzalloc(&pdev->dev, sizeof(*quark_mfd), GFP_KERNEL);
- if (!quark_mfd)
- return -ENOMEM;
-
- dev_set_drvdata(&pdev->dev, quark_mfd);
-
ret = intel_quark_register_i2c_clk(&pdev->dev);
if (ret)
return ret;
@@ -260,7 +223,7 @@ static int intel_quark_mfd_probe(struct pci_dev *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;
+ return ret;
ret = intel_quark_i2c_setup(pdev);
if (ret)
@@ -282,8 +245,6 @@ err_unregister_gpio_node_group:
software_node_unregister_node_group(intel_quark_gpio_node_group);
err_free_irq_vectors:
pci_free_irq_vectors(pdev);
-err_unregister_i2c_clk:
- intel_quark_unregister_i2c_clk(&pdev->dev);
return ret;
}
@@ -292,7 +253,6 @@ static void intel_quark_mfd_remove(struct pci_dev *pdev)
mfd_remove_devices(&pdev->dev);
software_node_unregister_node_group(intel_quark_gpio_node_group);
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/iqs62x.c b/drivers/mfd/iqs62x.c
index 412ae7777f72..ef747a7b3845 100644
--- a/drivers/mfd/iqs62x.c
+++ b/drivers/mfd/iqs62x.c
@@ -1015,7 +1015,7 @@ static void iqs62x_remove(struct i2c_client *client)
wait_for_completion(&iqs62x->fw_done);
}
-static int __maybe_unused iqs62x_suspend(struct device *dev)
+static int iqs62x_suspend(struct device *dev)
{
struct iqs62x_core *iqs62x = dev_get_drvdata(dev);
int ret;
@@ -1036,7 +1036,7 @@ static int __maybe_unused iqs62x_suspend(struct device *dev)
IQS62X_PWR_SETTINGS_PWR_MODE_HALT);
}
-static int __maybe_unused iqs62x_resume(struct device *dev)
+static int iqs62x_resume(struct device *dev)
{
struct iqs62x_core *iqs62x = dev_get_drvdata(dev);
int ret;
@@ -1051,7 +1051,7 @@ static int __maybe_unused iqs62x_resume(struct device *dev)
IQS62X_PWR_SETTINGS_DIS_AUTO, 0);
}
-static SIMPLE_DEV_PM_OPS(iqs62x_pm, iqs62x_suspend, iqs62x_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(iqs62x_pm, iqs62x_suspend, iqs62x_resume);
static const struct of_device_id iqs62x_of_match[] = {
{ .compatible = "azoteq,iqs620a" },
@@ -1067,7 +1067,7 @@ static struct i2c_driver iqs62x_i2c_driver = {
.driver = {
.name = "iqs62x",
.of_match_table = iqs62x_of_match,
- .pm = &iqs62x_pm,
+ .pm = pm_sleep_ptr(&iqs62x_pm),
},
.probe = iqs62x_probe,
.remove = iqs62x_remove,
diff --git a/drivers/mfd/kempld-core.c b/drivers/mfd/kempld-core.c
index b64729918dfd..47062f876e5d 100644
--- a/drivers/mfd/kempld-core.c
+++ b/drivers/mfd/kempld-core.c
@@ -37,7 +37,7 @@ static void kempld_get_hardware_mutex(struct kempld_device_data *pld)
static void kempld_release_hardware_mutex(struct kempld_device_data *pld)
{
- /* The harware mutex is released when 1 is written to the mutex bit. */
+ /* The hardware mutex is released when 1 is written to the mutex bit. */
iowrite8(KEMPLD_MUTEX_KEY, pld->io_index);
}
diff --git a/drivers/mfd/khadas-mcu.c b/drivers/mfd/khadas-mcu.c
index ba981a788692..4b37e74e2b04 100644
--- a/drivers/mfd/khadas-mcu.c
+++ b/drivers/mfd/khadas-mcu.c
@@ -75,47 +75,116 @@ static const struct regmap_config khadas_mcu_regmap_config = {
.cache_type = REGCACHE_MAPLE,
};
-static struct mfd_cell khadas_mcu_fan_cells[] = {
+static const struct mfd_cell khadas_mcu_fan_cells[] = {
/* VIM1/2 Rev13+ and VIM3 only */
- { .name = "khadas-mcu-fan-ctrl", },
+ MFD_CELL_NAME("khadas-mcu-fan-ctrl"),
};
-static struct mfd_cell khadas_mcu_cells[] = {
- { .name = "khadas-mcu-user-mem", },
+static const struct mfd_cell khadas_mcu_cells[] = {
+ MFD_CELL_NAME("khadas-mcu-user-mem"),
+};
+
+static bool khadas_mcu_vim4_reg_volatile(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case KHADAS_MCU_PWR_OFF_CMD_REG:
+ case KHADAS_MCU_VIM4_REST_CONF_REG:
+ case KHADAS_MCU_WOL_INIT_START_REG:
+ case KHADAS_MCU_VIM4_LED_ON_RAM_REG:
+ case KHADAS_MCU_VIM4_FAN_CTRL_REG:
+ case KHADAS_MCU_VIM4_WDT_EN_REG:
+ case KHADAS_MCU_VIM4_SYS_RST_REG:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool khadas_mcu_vim4_reg_writeable(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case KHADAS_MCU_VERSION_0_REG:
+ case KHADAS_MCU_VERSION_1_REG:
+ case KHADAS_MCU_SHUTDOWN_NORMAL_STATUS_REG:
+ return false;
+ default:
+ return true;
+ }
+}
+
+static const struct regmap_config khadas_mcu_vim4_regmap_config = {
+ .reg_bits = 8,
+ .reg_stride = 1,
+ .val_bits = 8,
+ .max_register = KHADAS_MCU_VIM4_SYS_RST_REG,
+ .volatile_reg = khadas_mcu_vim4_reg_volatile,
+ .writeable_reg = khadas_mcu_vim4_reg_writeable,
+ .cache_type = REGCACHE_MAPLE,
+};
+
+static const struct mfd_cell khadas_mcu_vim4_fan_cells[] = {
+ MFD_CELL_NAME("khadas-mcu-vim4-fan"),
};
static int khadas_mcu_probe(struct i2c_client *client)
{
+ const struct mfd_cell *cells, *fan_cells;
+ const struct regmap_config *regmap_cfg;
struct device *dev = &client->dev;
+ int ncells, nfan_cells, ret;
struct khadas_mcu *ddata;
- int ret;
+ const void *mcu_variant;
ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
if (!ddata)
return -ENOMEM;
+ mcu_variant = i2c_get_match_data(client);
+ if (!mcu_variant)
+ return -ENODEV;
+
+ switch ((uintptr_t)mcu_variant) {
+ case KHADAS_MCU_GENERIC:
+ regmap_cfg = &khadas_mcu_regmap_config;
+ cells = khadas_mcu_cells;
+ ncells = ARRAY_SIZE(khadas_mcu_cells);
+ fan_cells = khadas_mcu_fan_cells;
+ nfan_cells = ARRAY_SIZE(khadas_mcu_fan_cells);
+ break;
+ case KHADAS_MCU_VIM4:
+ regmap_cfg = &khadas_mcu_vim4_regmap_config;
+ cells = NULL;
+ ncells = 0;
+ fan_cells = khadas_mcu_vim4_fan_cells;
+ nfan_cells = ARRAY_SIZE(khadas_mcu_vim4_fan_cells);
+ break;
+ default:
+ return -ENODEV;
+ }
+
i2c_set_clientdata(client, ddata);
ddata->dev = dev;
- ddata->regmap = devm_regmap_init_i2c(client, &khadas_mcu_regmap_config);
+ ddata->regmap = devm_regmap_init_i2c(client, regmap_cfg);
if (IS_ERR(ddata->regmap)) {
ret = PTR_ERR(ddata->regmap);
- dev_err(dev, "Failed to allocate register map: %d\n", ret);
- return ret;
+ return dev_err_probe(dev, ret, "Failed to allocate register map\n");
}
- ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
- khadas_mcu_cells,
- ARRAY_SIZE(khadas_mcu_cells),
- NULL, 0, NULL);
- if (ret)
- return ret;
+ if (cells && ncells) {
+ ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
+ cells,
+ ncells,
+ NULL, 0, NULL);
+ if (ret)
+ return ret;
+ }
if (of_property_present(dev->of_node, "#cooling-cells"))
return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
- khadas_mcu_fan_cells,
- ARRAY_SIZE(khadas_mcu_fan_cells),
+ fan_cells,
+ nfan_cells,
NULL, 0, NULL);
return 0;
@@ -123,7 +192,8 @@ static int khadas_mcu_probe(struct i2c_client *client)
#ifdef CONFIG_OF
static const struct of_device_id khadas_mcu_of_match[] = {
- { .compatible = "khadas,mcu", },
+ { .compatible = "khadas,mcu", .data = (void *)KHADAS_MCU_GENERIC },
+ { .compatible = "khadas,vim4-mcu", .data = (void *)KHADAS_MCU_VIM4 },
{},
};
MODULE_DEVICE_TABLE(of, khadas_mcu_of_match);
diff --git a/drivers/mfd/lm3533-core.c b/drivers/mfd/lm3533-core.c
index 0a2409d00b2e..9233da7ce099 100644
--- a/drivers/mfd/lm3533-core.c
+++ b/drivers/mfd/lm3533-core.c
@@ -7,6 +7,7 @@
* Author: Johan Hovold <jhovold@gmail.com>
*/
+#include <linux/bitfield.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -14,19 +15,24 @@
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/mfd/core.h>
+#include <linux/property.h>
#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
+#include <linux/units.h>
#include <linux/mfd/lm3533.h>
#define LM3533_BOOST_OVP_MASK 0x06
-#define LM3533_BOOST_OVP_SHIFT 1
+#define LM3533_BOOST_OVP_MIN (16 * MICRO)
+#define LM3533_BOOST_OVP_MAX (40 * MICRO)
#define LM3533_BOOST_FREQ_MASK 0x01
-#define LM3533_BOOST_FREQ_SHIFT 0
+#define LM3533_BOOST_FREQ_MIN (500 * HZ_PER_KHZ)
+#define LM3533_BOOST_FREQ_MAX (1000 * HZ_PER_KHZ)
#define LM3533_BL_ID_MASK 1
#define LM3533_LED_ID_MASK 3
@@ -35,6 +41,7 @@
#define LM3533_HVLED_ID_MAX 2
#define LM3533_LVLED_ID_MAX 5
+#define LM3533_CELLS_MAX 7
#define LM3533_REG_OUTPUT_CONF1 0x10
#define LM3533_REG_OUTPUT_CONF2 0x11
@@ -42,125 +49,6 @@
#define LM3533_REG_MAX 0xb2
-
-static struct mfd_cell lm3533_als_devs[] = {
- {
- .name = "lm3533-als",
- .id = -1,
- },
-};
-
-static struct mfd_cell lm3533_bl_devs[] = {
- {
- .name = "lm3533-backlight",
- .id = 0,
- },
- {
- .name = "lm3533-backlight",
- .id = 1,
- },
-};
-
-static struct mfd_cell lm3533_led_devs[] = {
- {
- .name = "lm3533-leds",
- .id = 0,
- },
- {
- .name = "lm3533-leds",
- .id = 1,
- },
- {
- .name = "lm3533-leds",
- .id = 2,
- },
- {
- .name = "lm3533-leds",
- .id = 3,
- },
-};
-
-int lm3533_read(struct lm3533 *lm3533, u8 reg, u8 *val)
-{
- int tmp;
- int ret;
-
- ret = regmap_read(lm3533->regmap, reg, &tmp);
- if (ret < 0) {
- dev_err(lm3533->dev, "failed to read register %02x: %d\n",
- reg, ret);
- return ret;
- }
-
- *val = tmp;
-
- dev_dbg(lm3533->dev, "read [%02x]: %02x\n", reg, *val);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(lm3533_read);
-
-int lm3533_write(struct lm3533 *lm3533, u8 reg, u8 val)
-{
- int ret;
-
- dev_dbg(lm3533->dev, "write [%02x]: %02x\n", reg, val);
-
- ret = regmap_write(lm3533->regmap, reg, val);
- if (ret < 0) {
- dev_err(lm3533->dev, "failed to write register %02x: %d\n",
- reg, ret);
- }
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(lm3533_write);
-
-int lm3533_update(struct lm3533 *lm3533, u8 reg, u8 val, u8 mask)
-{
- int ret;
-
- dev_dbg(lm3533->dev, "update [%02x]: %02x/%02x\n", reg, val, mask);
-
- ret = regmap_update_bits(lm3533->regmap, reg, mask, val);
- if (ret < 0) {
- dev_err(lm3533->dev, "failed to update register %02x: %d\n",
- reg, ret);
- }
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(lm3533_update);
-
-static int lm3533_set_boost_freq(struct lm3533 *lm3533,
- enum lm3533_boost_freq freq)
-{
- int ret;
-
- ret = lm3533_update(lm3533, LM3533_REG_BOOST_PWM,
- freq << LM3533_BOOST_FREQ_SHIFT,
- LM3533_BOOST_FREQ_MASK);
- if (ret)
- dev_err(lm3533->dev, "failed to set boost frequency\n");
-
- return ret;
-}
-
-
-static int lm3533_set_boost_ovp(struct lm3533 *lm3533,
- enum lm3533_boost_ovp ovp)
-{
- int ret;
-
- ret = lm3533_update(lm3533, LM3533_REG_BOOST_PWM,
- ovp << LM3533_BOOST_OVP_SHIFT,
- LM3533_BOOST_OVP_MASK);
- if (ret)
- dev_err(lm3533->dev, "failed to set boost ovp\n");
-
- return ret;
-}
-
/*
* HVLED output config -- output hvled controlled by backlight bl
*/
@@ -181,7 +69,8 @@ static int lm3533_set_hvled_config(struct lm3533 *lm3533, u8 hvled, u8 bl)
mask = LM3533_BL_ID_MASK << shift;
val = bl << shift;
- ret = lm3533_update(lm3533, LM3533_REG_OUTPUT_CONF1, val, mask);
+ ret = regmap_update_bits(lm3533->regmap, LM3533_REG_OUTPUT_CONF1,
+ mask, val);
if (ret)
dev_err(lm3533->dev, "failed to set hvled config\n");
@@ -216,21 +105,32 @@ static int lm3533_set_lvled_config(struct lm3533 *lm3533, u8 lvled, u8 led)
mask = LM3533_LED_ID_MASK << shift;
val = led << shift;
- ret = lm3533_update(lm3533, reg, val, mask);
+ ret = regmap_update_bits(lm3533->regmap, reg, mask, val);
if (ret)
dev_err(lm3533->dev, "failed to set lvled config\n");
return ret;
}
-static void lm3533_enable(struct lm3533 *lm3533)
+static int lm3533_enable(struct lm3533 *lm3533)
{
+ int ret;
+
+ ret = regulator_enable(lm3533->vin_supply);
+ if (ret) {
+ dev_err(lm3533->dev, "failed to enable vin power supply\n");
+ return ret;
+ }
+
gpiod_set_value(lm3533->hwen, 1);
+
+ return 0;
}
static void lm3533_disable(struct lm3533 *lm3533)
{
gpiod_set_value(lm3533->hwen, 0);
+ regulator_disable(lm3533->vin_supply);
}
enum lm3533_attribute_type {
@@ -258,7 +158,7 @@ static ssize_t show_output(struct device *dev,
struct lm3533_device_attribute *lattr = to_lm3533_dev_attr(attr);
int id = lattr->u.output.id;
u8 reg;
- u8 val;
+ u32 val;
u8 mask;
int shift;
int ret;
@@ -278,7 +178,7 @@ static ssize_t show_output(struct device *dev,
mask = LM3533_LED_ID_MASK << shift;
}
- ret = lm3533_read(lm3533, reg, &val);
+ ret = regmap_read(lm3533->regmap, reg, &val);
if (ret)
return ret;
@@ -376,136 +276,102 @@ static struct attribute_group lm3533_attribute_group = {
.attrs = lm3533_attributes
};
-static int lm3533_device_als_init(struct lm3533 *lm3533)
-{
- struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev);
- int ret;
-
- if (!pdata->als)
- return 0;
-
- lm3533_als_devs[0].platform_data = pdata->als;
- lm3533_als_devs[0].pdata_size = sizeof(*pdata->als);
-
- ret = mfd_add_devices(lm3533->dev, 0, lm3533_als_devs, 1, NULL,
- 0, NULL);
- if (ret) {
- dev_err(lm3533->dev, "failed to add ALS device\n");
- return ret;
- }
-
- lm3533->have_als = 1;
-
- return 0;
-}
+static const struct attribute_group *lm3533_attribute_groups[] = {
+ &lm3533_attribute_group,
+ NULL,
+};
-static int lm3533_device_bl_init(struct lm3533 *lm3533)
+static int lm3533_device_init(struct lm3533 *lm3533)
{
- struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev);
- int i;
+ struct device *dev = lm3533->dev;
+ struct mfd_cell *lm3533_devices;
+ u32 reg, nchilds;
+ u32 count = 0;
int ret;
- if (!pdata->backlights || pdata->num_backlights == 0)
- return 0;
+ nchilds = device_get_child_node_count(dev);
+ if (!nchilds || nchilds > LM3533_CELLS_MAX)
+ return dev_err_probe(dev, -ENODEV,
+ "num of child nodes is not supported\n");
- if (pdata->num_backlights > ARRAY_SIZE(lm3533_bl_devs))
- pdata->num_backlights = ARRAY_SIZE(lm3533_bl_devs);
+ lm3533_devices = devm_kcalloc(dev, nchilds, sizeof(*lm3533_devices),
+ GFP_KERNEL);
+ if (!lm3533_devices)
+ return -ENOMEM;
- for (i = 0; i < pdata->num_backlights; ++i) {
- lm3533_bl_devs[i].platform_data = &pdata->backlights[i];
- lm3533_bl_devs[i].pdata_size = sizeof(pdata->backlights[i]);
+ device_for_each_child_node_scoped(dev, child) {
+ if (count >= nchilds)
+ break;
+
+ if (fwnode_device_is_compatible(child, "ti,lm3533-als")) {
+ lm3533_devices[count].name = "lm3533-als";
+ lm3533_devices[count].of_compatible = "ti,lm3533-als";
+ lm3533_devices[count].id = PLATFORM_DEVID_NONE;
+
+ lm3533->have_als = true;
+ count++;
+ } else if (fwnode_device_is_compatible(child, "ti,lm3533-backlight")) {
+ ret = fwnode_property_read_u32(child, "reg", &reg);
+ if (ret || reg >= LM3533_HVLED_ID_MAX) {
+ dev_err(dev, "invalid backlight node %pfw\n", child);
+ continue;
+ }
+
+ lm3533_devices[count].name = "lm3533-backlight";
+ lm3533_devices[count].of_compatible = "ti,lm3533-backlight";
+ lm3533_devices[count].id = reg;
+ lm3533_devices[count].of_reg = reg;
+ lm3533_devices[count].use_of_reg = true;
+
+ lm3533->have_backlights = true;
+ count++;
+ } else if (fwnode_device_is_compatible(child, "ti,lm3533-leds")) {
+ ret = fwnode_property_read_u32(child, "reg", &reg);
+ if (ret || reg < LM3533_HVLED_ID_MAX ||
+ reg > LM3533_LVLED_ID_MAX) {
+ dev_err(dev, "invalid LED node %pfw\n", child);
+ continue;
+ }
+
+ lm3533_devices[count].name = "lm3533-leds";
+ lm3533_devices[count].of_compatible = "ti,lm3533-leds";
+ lm3533_devices[count].id = reg - LM3533_HVLED_ID_MAX;
+ lm3533_devices[count].of_reg = reg;
+ lm3533_devices[count].use_of_reg = true;
+
+ lm3533->have_leds = true;
+ count++;
+ }
}
- ret = mfd_add_devices(lm3533->dev, 0, lm3533_bl_devs,
- pdata->num_backlights, NULL, 0, NULL);
- if (ret) {
- dev_err(lm3533->dev, "failed to add backlight devices\n");
+ ret = lm3533_enable(lm3533);
+ if (ret)
return ret;
- }
- lm3533->have_backlights = 1;
-
- return 0;
-}
-
-static int lm3533_device_led_init(struct lm3533 *lm3533)
-{
- struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev);
- int i;
- int ret;
-
- if (!pdata->leds || pdata->num_leds == 0)
- return 0;
-
- if (pdata->num_leds > ARRAY_SIZE(lm3533_led_devs))
- pdata->num_leds = ARRAY_SIZE(lm3533_led_devs);
-
- for (i = 0; i < pdata->num_leds; ++i) {
- lm3533_led_devs[i].platform_data = &pdata->leds[i];
- lm3533_led_devs[i].pdata_size = sizeof(pdata->leds[i]);
- }
-
- ret = mfd_add_devices(lm3533->dev, 0, lm3533_led_devs,
- pdata->num_leds, NULL, 0, NULL);
+ ret = regmap_update_bits(lm3533->regmap, LM3533_REG_BOOST_PWM,
+ LM3533_BOOST_FREQ_MASK,
+ FIELD_PREP(LM3533_BOOST_FREQ_MASK, lm3533->boost_freq));
if (ret) {
- dev_err(lm3533->dev, "failed to add LED devices\n");
- return ret;
+ dev_err(dev, "failed to set boost frequency\n");
+ goto err_disable;
}
- lm3533->have_leds = 1;
-
- return 0;
-}
-
-static int lm3533_device_setup(struct lm3533 *lm3533,
- struct lm3533_platform_data *pdata)
-{
- int ret;
-
- ret = lm3533_set_boost_freq(lm3533, pdata->boost_freq);
- if (ret)
- return ret;
-
- return lm3533_set_boost_ovp(lm3533, pdata->boost_ovp);
-}
-
-static int lm3533_device_init(struct lm3533 *lm3533)
-{
- struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev);
- int ret;
-
- dev_dbg(lm3533->dev, "%s\n", __func__);
-
- if (!pdata) {
- dev_err(lm3533->dev, "no platform data\n");
- return -EINVAL;
+ ret = regmap_update_bits(lm3533->regmap, LM3533_REG_BOOST_PWM,
+ LM3533_BOOST_OVP_MASK,
+ FIELD_PREP(LM3533_BOOST_OVP_MASK, lm3533->boost_ovp));
+ if (ret) {
+ dev_err(dev, "failed to set boost ovp\n");
+ goto err_disable;
}
- lm3533->hwen = devm_gpiod_get(lm3533->dev, NULL, GPIOD_OUT_LOW);
- if (IS_ERR(lm3533->hwen))
- return dev_err_probe(lm3533->dev, PTR_ERR(lm3533->hwen), "failed to request HWEN GPIO\n");
- gpiod_set_consumer_name(lm3533->hwen, "lm3533-hwen");
-
- lm3533_enable(lm3533);
-
- ret = lm3533_device_setup(lm3533, pdata);
- if (ret)
+ ret = mfd_add_devices(dev, 0, lm3533_devices, count, NULL, 0, NULL);
+ if (ret) {
+ dev_err(dev, "failed to add MFD devices: %d\n", ret);
goto err_disable;
-
- lm3533_device_als_init(lm3533);
- lm3533_device_bl_init(lm3533);
- lm3533_device_led_init(lm3533);
-
- ret = sysfs_create_group(&lm3533->dev->kobj, &lm3533_attribute_group);
- if (ret < 0) {
- dev_err(lm3533->dev, "failed to create sysfs attributes\n");
- goto err_unregister;
}
return 0;
-err_unregister:
- mfd_remove_devices(lm3533->dev);
err_disable:
lm3533_disable(lm3533);
@@ -516,8 +382,6 @@ static void lm3533_device_exit(struct lm3533 *lm3533)
{
dev_dbg(lm3533->dev, "%s\n", __func__);
- sysfs_remove_group(&lm3533->dev->kobj, &lm3533_attribute_group);
-
mfd_remove_devices(lm3533->dev);
lm3533_disable(lm3533);
}
@@ -589,7 +453,35 @@ static int lm3533_i2c_probe(struct i2c_client *i2c)
return PTR_ERR(lm3533->regmap);
lm3533->dev = &i2c->dev;
- lm3533->irq = i2c->irq;
+
+ lm3533->hwen = devm_gpiod_get_optional(lm3533->dev, "enable",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(lm3533->hwen))
+ return dev_err_probe(lm3533->dev, PTR_ERR(lm3533->hwen),
+ "failed to get HWEN GPIO\n");
+
+ lm3533->vin_supply = devm_regulator_get(lm3533->dev, "vin");
+ if (IS_ERR(lm3533->vin_supply))
+ return dev_err_probe(lm3533->dev, PTR_ERR(lm3533->vin_supply),
+ "failed to get vin-supply\n");
+
+ device_property_read_u32(lm3533->dev, "ti,boost-ovp-microvolt",
+ &lm3533->boost_ovp);
+
+ lm3533->boost_ovp = clamp(lm3533->boost_ovp, LM3533_BOOST_OVP_MIN,
+ LM3533_BOOST_OVP_MAX);
+ lm3533->boost_ovp = lm3533->boost_ovp / (8 * MICRO) - 2;
+
+ device_property_read_u32(lm3533->dev, "ti,boost-freq-hz",
+ &lm3533->boost_freq);
+
+ lm3533->boost_freq = clamp(lm3533->boost_freq, LM3533_BOOST_FREQ_MIN,
+ LM3533_BOOST_FREQ_MAX);
+ lm3533->boost_freq = lm3533->boost_freq / (500 * KILO) - 1;
+
+ /* LM3533 and child devices do not use DMA */
+ i2c->dev.coherent_dma_mask = 0;
+ i2c->dev.dma_mask = &i2c->dev.coherent_dma_mask;
return lm3533_device_init(lm3533);
}
@@ -603,6 +495,12 @@ static void lm3533_i2c_remove(struct i2c_client *i2c)
lm3533_device_exit(lm3533);
}
+static const struct of_device_id lm3533_match_table[] = {
+ { .compatible = "ti,lm3533" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, lm3533_match_table);
+
static const struct i2c_device_id lm3533_i2c_ids[] = {
{ "lm3533" },
{ }
@@ -612,6 +510,8 @@ MODULE_DEVICE_TABLE(i2c, lm3533_i2c_ids);
static struct i2c_driver lm3533_i2c_driver = {
.driver = {
.name = "lm3533",
+ .dev_groups = lm3533_attribute_groups,
+ .of_match_table = lm3533_match_table,
},
.id_table = lm3533_i2c_ids,
.probe = lm3533_i2c_probe,
diff --git a/drivers/mfd/lm3533-ctrlbank.c b/drivers/mfd/lm3533-ctrlbank.c
index 2537dfade51c..3aab8ece4e8c 100644
--- a/drivers/mfd/lm3533-ctrlbank.c
+++ b/drivers/mfd/lm3533-ctrlbank.c
@@ -9,14 +9,10 @@
#include <linux/device.h>
#include <linux/module.h>
+#include <linux/regmap.h>
#include <linux/mfd/lm3533.h>
-
-#define LM3533_MAX_CURRENT_MIN 5000
-#define LM3533_MAX_CURRENT_MAX 29800
-#define LM3533_MAX_CURRENT_STEP 800
-
#define LM3533_PWM_MAX 0x3f
#define LM3533_REG_PWM_BASE 0x14
@@ -38,8 +34,8 @@ int lm3533_ctrlbank_enable(struct lm3533_ctrlbank *cb)
dev_dbg(cb->dev, "%s - %d\n", __func__, cb->id);
mask = 1 << cb->id;
- ret = lm3533_update(cb->lm3533, LM3533_REG_CTRLBANK_ENABLE,
- mask, mask);
+ ret = regmap_set_bits(cb->regmap, LM3533_REG_CTRLBANK_ENABLE,
+ mask);
if (ret)
dev_err(cb->dev, "failed to enable ctrlbank %d\n", cb->id);
@@ -55,7 +51,8 @@ int lm3533_ctrlbank_disable(struct lm3533_ctrlbank *cb)
dev_dbg(cb->dev, "%s - %d\n", __func__, cb->id);
mask = 1 << cb->id;
- ret = lm3533_update(cb->lm3533, LM3533_REG_CTRLBANK_ENABLE, 0, mask);
+ ret = regmap_clear_bits(cb->regmap, LM3533_REG_CTRLBANK_ENABLE,
+ mask);
if (ret)
dev_err(cb->dev, "failed to disable ctrlbank %d\n", cb->id);
@@ -68,7 +65,7 @@ EXPORT_SYMBOL_GPL(lm3533_ctrlbank_disable);
*
* imax 5000 - 29800 uA (800 uA step)
*/
-int lm3533_ctrlbank_set_max_current(struct lm3533_ctrlbank *cb, u16 imax)
+int lm3533_ctrlbank_set_max_current(struct lm3533_ctrlbank *cb, u32 imax)
{
u8 reg;
u8 val;
@@ -80,7 +77,7 @@ int lm3533_ctrlbank_set_max_current(struct lm3533_ctrlbank *cb, u16 imax)
val = (imax - LM3533_MAX_CURRENT_MIN) / LM3533_MAX_CURRENT_STEP;
reg = lm3533_ctrlbank_get_reg(cb, LM3533_REG_MAX_CURRENT_BASE);
- ret = lm3533_write(cb->lm3533, reg, val);
+ ret = regmap_write(cb->regmap, reg, val);
if (ret)
dev_err(cb->dev, "failed to set max current\n");
@@ -88,13 +85,13 @@ int lm3533_ctrlbank_set_max_current(struct lm3533_ctrlbank *cb, u16 imax)
}
EXPORT_SYMBOL_GPL(lm3533_ctrlbank_set_max_current);
-int lm3533_ctrlbank_set_brightness(struct lm3533_ctrlbank *cb, u8 val)
+int lm3533_ctrlbank_set_brightness(struct lm3533_ctrlbank *cb, u32 val)
{
u8 reg;
int ret;
reg = lm3533_ctrlbank_get_reg(cb, LM3533_REG_BRIGHTNESS_BASE);
- ret = lm3533_write(cb->lm3533, reg, val);
+ ret = regmap_write(cb->regmap, reg, val);
if (ret)
dev_err(cb->dev, "failed to set brightness\n");
@@ -102,13 +99,13 @@ int lm3533_ctrlbank_set_brightness(struct lm3533_ctrlbank *cb, u8 val)
}
EXPORT_SYMBOL_GPL(lm3533_ctrlbank_set_brightness);
-int lm3533_ctrlbank_get_brightness(struct lm3533_ctrlbank *cb, u8 *val)
+int lm3533_ctrlbank_get_brightness(struct lm3533_ctrlbank *cb, u32 *val)
{
u8 reg;
int ret;
reg = lm3533_ctrlbank_get_reg(cb, LM3533_REG_BRIGHTNESS_BASE);
- ret = lm3533_read(cb->lm3533, reg, val);
+ ret = regmap_read(cb->regmap, reg, val);
if (ret)
dev_err(cb->dev, "failed to get brightness\n");
@@ -126,7 +123,7 @@ EXPORT_SYMBOL_GPL(lm3533_ctrlbank_get_brightness);
* bit 1 - PWM-input enabled in Zone 0
* bit 0 - PWM-input enabled
*/
-int lm3533_ctrlbank_set_pwm(struct lm3533_ctrlbank *cb, u8 val)
+int lm3533_ctrlbank_set_pwm(struct lm3533_ctrlbank *cb, u32 val)
{
u8 reg;
int ret;
@@ -135,7 +132,7 @@ int lm3533_ctrlbank_set_pwm(struct lm3533_ctrlbank *cb, u8 val)
return -EINVAL;
reg = lm3533_ctrlbank_get_reg(cb, LM3533_REG_PWM_BASE);
- ret = lm3533_write(cb->lm3533, reg, val);
+ ret = regmap_write(cb->regmap, reg, val);
if (ret)
dev_err(cb->dev, "failed to set PWM mask\n");
@@ -143,13 +140,13 @@ int lm3533_ctrlbank_set_pwm(struct lm3533_ctrlbank *cb, u8 val)
}
EXPORT_SYMBOL_GPL(lm3533_ctrlbank_set_pwm);
-int lm3533_ctrlbank_get_pwm(struct lm3533_ctrlbank *cb, u8 *val)
+int lm3533_ctrlbank_get_pwm(struct lm3533_ctrlbank *cb, u32 *val)
{
u8 reg;
int ret;
reg = lm3533_ctrlbank_get_reg(cb, LM3533_REG_PWM_BASE);
- ret = lm3533_read(cb->lm3533, reg, val);
+ ret = regmap_read(cb->regmap, reg, val);
if (ret)
dev_err(cb->dev, "failed to get PWM mask\n");
diff --git a/drivers/mfd/max77705.c b/drivers/mfd/max77705.c
index e98c76d6b699..2e9b81f26414 100644
--- a/drivers/mfd/max77705.c
+++ b/drivers/mfd/max77705.c
@@ -105,7 +105,7 @@ static int max77705_i2c_probe(struct i2c_client *i2c)
return -ENODEV;
pmic_rev = pmic_rev_value & MAX77705_REVISION_MASK;
- if (pmic_rev != MAX77705_PASS3)
+ if (pmic_rev != MAX77705_PASS2 && pmic_rev != MAX77705_PASS3)
return dev_err_probe(dev, -ENODEV, "Rev.0x%x is not tested\n", pmic_rev);
/* Active Discharge Enable */
diff --git a/drivers/mfd/max77843.c b/drivers/mfd/max77843.c
index 2a48577b1a79..9ae6715642ae 100644
--- a/drivers/mfd/max77843.c
+++ b/drivers/mfd/max77843.c
@@ -173,7 +173,7 @@ static const struct i2c_device_id max77843_id[] = {
{ },
};
-static int __maybe_unused max77843_suspend(struct device *dev)
+static int max77843_suspend(struct device *dev)
{
struct i2c_client *i2c = to_i2c_client(dev);
struct max77693_dev *max77843 = i2c_get_clientdata(i2c);
@@ -185,7 +185,7 @@ static int __maybe_unused max77843_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused max77843_resume(struct device *dev)
+static int max77843_resume(struct device *dev)
{
struct i2c_client *i2c = to_i2c_client(dev);
struct max77693_dev *max77843 = i2c_get_clientdata(i2c);
@@ -197,12 +197,12 @@ static int __maybe_unused max77843_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(max77843_pm, max77843_suspend, max77843_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(max77843_pm, max77843_suspend, max77843_resume);
static struct i2c_driver max77843_i2c_driver = {
.driver = {
.name = "max77843",
- .pm = &max77843_pm,
+ .pm = pm_sleep_ptr(&max77843_pm),
.of_match_table = max77843_dt_match,
.suppress_bind_attrs = true,
},
diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c
index eb13bbaeda55..5032eab05bb4 100644
--- a/drivers/mfd/max8998.c
+++ b/drivers/mfd/max8998.c
@@ -146,7 +146,7 @@ static struct max8998_platform_data *max8998_i2c_parse_dt_pdata(
/*
* ToDo: the 'wakeup' member in the platform data is more of a linux
- * specfic information. Hence, there is no binding for that yet and
+ * specific information. Hence, there is no binding for that yet and
* not parsed here.
*/
return pd;
diff --git a/drivers/mfd/motorola-cpcap.c b/drivers/mfd/motorola-cpcap.c
index 4ed8704c985a..65d5eb18aa00 100644
--- a/drivers/mfd/motorola-cpcap.c
+++ b/drivers/mfd/motorola-cpcap.c
@@ -11,6 +11,7 @@
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/sysfs.h>
@@ -29,6 +30,7 @@ struct cpcap_ddata {
struct regmap_irq_chip_data *irqdata[CPCAP_NR_IRQ_CHIPS];
const struct regmap_config *regmap_conf;
struct regmap *regmap;
+ enum cpcap_variant variant;
};
static int cpcap_sense_irq(struct regmap *regmap, int irq)
@@ -194,20 +196,6 @@ static int cpcap_init_irq(struct cpcap_ddata *cpcap)
return 0;
}
-static const struct of_device_id cpcap_of_match[] = {
- { .compatible = "motorola,cpcap", },
- { .compatible = "st,6556002", },
- {},
-};
-MODULE_DEVICE_TABLE(of, cpcap_of_match);
-
-static const struct spi_device_id cpcap_spi_ids[] = {
- { .name = "cpcap" },
- { .name = "6556002" },
- { }
-};
-MODULE_DEVICE_TABLE(spi, cpcap_spi_ids);
-
static const struct regmap_config cpcap_regmap_config = {
.reg_bits = 16,
.reg_stride = 4,
@@ -240,62 +228,74 @@ static int cpcap_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(cpcap_pm, cpcap_suspend, cpcap_resume);
-static const struct mfd_cell cpcap_mfd_devices[] = {
- {
- .name = "cpcap_adc",
- .of_compatible = "motorola,mapphone-cpcap-adc",
- }, {
- .name = "cpcap_battery",
- .of_compatible = "motorola,cpcap-battery",
- }, {
- .name = "cpcap-charger",
- .of_compatible = "motorola,mapphone-cpcap-charger",
- }, {
- .name = "cpcap-regulator",
- .of_compatible = "motorola,mapphone-cpcap-regulator",
- }, {
- .name = "cpcap-rtc",
- .of_compatible = "motorola,cpcap-rtc",
- }, {
- .name = "cpcap-pwrbutton",
- .of_compatible = "motorola,cpcap-pwrbutton",
- }, {
- .name = "cpcap-usb-phy",
- .of_compatible = "motorola,mapphone-cpcap-usb-phy",
- }, {
- .name = "cpcap-led",
- .id = 0,
- .of_compatible = "motorola,cpcap-led-red",
- }, {
- .name = "cpcap-led",
- .id = 1,
- .of_compatible = "motorola,cpcap-led-green",
- }, {
- .name = "cpcap-led",
- .id = 2,
- .of_compatible = "motorola,cpcap-led-blue",
- }, {
- .name = "cpcap-led",
- .id = 3,
- .of_compatible = "motorola,cpcap-led-adl",
- }, {
- .name = "cpcap-led",
- .id = 4,
- .of_compatible = "motorola,cpcap-led-cp",
- }, {
- .name = "cpcap-codec",
- }
+static const struct mfd_cell cpcap_common_devices[] = {
+ MFD_CELL_OF("cpcap_battery", NULL, NULL, 0, 0, "motorola,cpcap-battery"),
+ MFD_CELL_OF("cpcap-rtc", NULL, NULL, 0, 0, "motorola,cpcap-rtc"),
+ MFD_CELL_OF("cpcap-pwrbutton", NULL, NULL, 0, 0, "motorola,cpcap-pwrbutton"),
+ MFD_CELL_OF("cpcap-led", NULL, NULL, 0, 0, "motorola,cpcap-led-red"),
+ MFD_CELL_OF("cpcap-led", NULL, NULL, 0, 1, "motorola,cpcap-led-green"),
+ MFD_CELL_OF("cpcap-led", NULL, NULL, 0, 2, "motorola,cpcap-led-blue"),
+ MFD_CELL_OF("cpcap-led", NULL, NULL, 0, 3, "motorola,cpcap-led-adl"),
+ MFD_CELL_NAME("cpcap-codec"),
+};
+
+static const struct mfd_cell cpcap_default_devices[] = {
+ MFD_CELL_OF("cpcap_adc", NULL, NULL, 0, 0, "motorola,cpcap-adc"),
+ MFD_CELL_OF("cpcap-regulator", NULL, NULL, 0, 0, "motorola,cpcap-regulator"),
+ MFD_CELL_OF("cpcap-usb-phy", NULL, NULL, 0, 0, "motorola,cpcap-usb-phy"),
+ MFD_CELL_OF("cpcap-led", NULL, NULL, 0, 4, "motorola,cpcap-led-cp"),
+};
+
+static const struct mfd_cell cpcap_mapphone_devices[] = {
+ MFD_CELL_OF("cpcap_adc", NULL, NULL, 0, 0, "motorola,mapphone-cpcap-adc"),
+ MFD_CELL_OF("cpcap-charger", NULL, NULL, 0, 0, "motorola,mapphone-cpcap-charger"),
+ MFD_CELL_OF("cpcap-regulator", NULL, NULL, 0, 0, "motorola,mapphone-cpcap-regulator"),
+ MFD_CELL_OF("cpcap-usb-phy", NULL, NULL, 0, 0, "motorola,mapphone-cpcap-usb-phy"),
+ MFD_CELL_OF("cpcap-led", NULL, NULL, 0, 4, "motorola,cpcap-led-cp"),
+};
+
+/*
+ * The Mot board features a USB-PHY and charger similar to the ones in
+ * Mapphone; however, because Mot is based on Tegra20, it is incompatible
+ * with the existing implementation, which is tightly interconnected with
+ * the OMAP USB PHY.
+ */
+static const struct mfd_cell cpcap_mot_devices[] = {
+ MFD_CELL_OF("cpcap_adc", NULL, NULL, 0, 0, "motorola,mot-cpcap-adc"),
+ MFD_CELL_OF("cpcap-regulator", NULL, NULL, 0, 0, "motorola,mot-cpcap-regulator"),
};
static int cpcap_probe(struct spi_device *spi)
{
struct cpcap_ddata *cpcap;
+ const struct mfd_cell *cells;
+ unsigned int num_cells;
int ret;
cpcap = devm_kzalloc(&spi->dev, sizeof(*cpcap), GFP_KERNEL);
if (!cpcap)
return -ENOMEM;
+ cpcap->variant = (enum cpcap_variant)spi_get_device_match_data(spi);
+
+ switch (cpcap->variant) {
+ case CPCAP_DEFAULT:
+ cells = cpcap_default_devices;
+ num_cells = ARRAY_SIZE(cpcap_default_devices);
+ break;
+ case CPCAP_MAPPHONE:
+ cells = cpcap_mapphone_devices;
+ num_cells = ARRAY_SIZE(cpcap_mapphone_devices);
+ break;
+ case CPCAP_MOT:
+ cells = cpcap_mot_devices;
+ num_cells = ARRAY_SIZE(cpcap_mot_devices);
+ break;
+ default:
+ return dev_err_probe(&spi->dev, -ENODEV,
+ "Unknown device %d\n", cpcap->variant);
+ }
+
cpcap->spi = spi;
spi_set_drvdata(spi, cpcap);
@@ -330,10 +330,31 @@ static int cpcap_probe(struct spi_device *spi)
spi->dev.coherent_dma_mask = 0;
spi->dev.dma_mask = &spi->dev.coherent_dma_mask;
- return devm_mfd_add_devices(&spi->dev, 0, cpcap_mfd_devices,
- ARRAY_SIZE(cpcap_mfd_devices), NULL, 0, NULL);
+ ret = devm_mfd_add_devices(&spi->dev, 0, cpcap_common_devices,
+ ARRAY_SIZE(cpcap_common_devices), NULL, 0, NULL);
+ if (ret)
+ return dev_err_probe(&spi->dev, ret,
+ "Failed to add common child devices\n");
+
+ return devm_mfd_add_devices(&spi->dev, 0, cells, num_cells, NULL, 0, NULL);
}
+static const struct of_device_id cpcap_of_match[] = {
+ { .compatible = "motorola,cpcap", .data = (void *)CPCAP_DEFAULT },
+ { .compatible = "motorola,mapphone-cpcap", .data = (void *)CPCAP_MAPPHONE },
+ { .compatible = "motorola,mot-cpcap", .data = (void *)CPCAP_MOT },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, cpcap_of_match);
+
+static const struct spi_device_id cpcap_spi_ids[] = {
+ { .name = "cpcap", .driver_data = CPCAP_DEFAULT },
+ { .name = "mapphone-cpcap", .driver_data = CPCAP_MAPPHONE },
+ { .name = "mot-cpcap", .driver_data = CPCAP_MOT },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(spi, cpcap_spi_ids);
+
static struct spi_driver cpcap_driver = {
.driver = {
.name = "cpcap-core",
diff --git a/drivers/mfd/mt6360-core.c b/drivers/mfd/mt6360-core.c
index b9b1036c8ff4..8a97c30cad3f 100644
--- a/drivers/mfd/mt6360-core.c
+++ b/drivers/mfd/mt6360-core.c
@@ -583,7 +583,7 @@ static int mt6360_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused mt6360_suspend(struct device *dev)
+static int mt6360_suspend(struct device *dev)
{
struct i2c_client *i2c = to_i2c_client(dev);
@@ -593,7 +593,7 @@ static int __maybe_unused mt6360_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused mt6360_resume(struct device *dev)
+static int mt6360_resume(struct device *dev)
{
struct i2c_client *i2c = to_i2c_client(dev);
@@ -604,7 +604,7 @@ static int __maybe_unused mt6360_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(mt6360_pm_ops, mt6360_suspend, mt6360_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(mt6360_pm_ops, mt6360_suspend, mt6360_resume);
static const struct of_device_id __maybe_unused mt6360_of_id[] = {
{ .compatible = "mediatek,mt6360", },
@@ -615,7 +615,7 @@ MODULE_DEVICE_TABLE(of, mt6360_of_id);
static struct i2c_driver mt6360_driver = {
.driver = {
.name = "mt6360",
- .pm = &mt6360_pm_ops,
+ .pm = pm_sleep_ptr(&mt6360_pm_ops),
.of_match_table = of_match_ptr(mt6360_of_id),
},
.probe = mt6360_probe,
diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c
index 9ec951996588..5d5f816492aa 100644
--- a/drivers/mfd/mt6397-core.c
+++ b/drivers/mfd/mt6397-core.c
@@ -261,6 +261,9 @@ static const struct mfd_cell mt6359_devs[] = {
static const struct mfd_cell mt6397_devs[] = {
{
+ .name = "mt6397-auxadc",
+ .of_compatible = "mediatek,mt6397-auxadc",
+ }, {
.name = "mt6397-rtc",
.num_resources = ARRAY_SIZE(mt6397_rtc_resources),
.resources = mt6397_rtc_resources,
diff --git a/drivers/mfd/rave-sp.c b/drivers/mfd/rave-sp.c
index 05d26d92df03..53c57bafea8f 100644
--- a/drivers/mfd/rave-sp.c
+++ b/drivers/mfd/rave-sp.c
@@ -331,7 +331,7 @@ static u8 rave_sp_reply_code(u8 command)
return command + 0x20;
case 0xE0 ... 0xEF:
/*
- * Events emitted by all versions of the firmare use
+ * Events emitted by all versions of the firmware use
* least significant bit to get an ACK code
*/
return command | 0x01;
@@ -544,7 +544,7 @@ static size_t rave_sp_receive_buf(struct serdev_device *serdev,
* NOTE: The above means that only the
* frame started by third SOF, sent
* after this one will have a chance
- * to get throught.
+ * to get through.
*/
goto reset_framer;
case RAVE_SP_DLE:
@@ -595,7 +595,7 @@ static size_t rave_sp_receive_buf(struct serdev_device *serdev,
/*
* The only way to get out of the above loop and end up here
- * is throught consuming all of the supplied data, so here we
+ * is through consuming all of the supplied data, so here we
* report that we processed it all.
*/
return size;
diff --git a/drivers/mfd/rk8xx-core.c b/drivers/mfd/rk8xx-core.c
index 3dcf6abfda74..21182df45d1b 100644
--- a/drivers/mfd/rk8xx-core.c
+++ b/drivers/mfd/rk8xx-core.c
@@ -875,7 +875,7 @@ int rk8xx_probe(struct device *dev, int variant, unsigned int irq, struct regmap
if (device_property_read_bool(dev, "system-power-controller") ||
device_property_read_bool(dev, "rockchip,system-power-controller")) {
ret = devm_register_sys_off_handler(dev,
- SYS_OFF_MODE_POWER_OFF_PREPARE, SYS_OFF_PRIO_HIGH,
+ SYS_OFF_MODE_POWER_OFF, SYS_OFF_PRIO_HIGH,
&rk808_power_off, rk808);
if (ret)
return dev_err_probe(dev, ret,
diff --git a/drivers/mfd/rk8xx-i2c.c b/drivers/mfd/rk8xx-i2c.c
index 2951b2911a37..161b25fbe146 100644
--- a/drivers/mfd/rk8xx-i2c.c
+++ b/drivers/mfd/rk8xx-i2c.c
@@ -251,7 +251,7 @@ static void rk8xx_i2c_shutdown(struct i2c_client *client)
rk8xx_shutdown(&client->dev);
}
-static SIMPLE_DEV_PM_OPS(rk8xx_i2c_pm_ops, rk8xx_suspend, rk8xx_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(rk8xx_i2c_pm_ops, rk8xx_suspend, rk8xx_resume);
static const struct of_device_id rk8xx_i2c_of_match[] = {
{ .compatible = "rockchip,rk801", .data = &rk801_data },
@@ -270,7 +270,7 @@ static struct i2c_driver rk8xx_i2c_driver = {
.driver = {
.name = "rk8xx-i2c",
.of_match_table = rk8xx_i2c_of_match,
- .pm = &rk8xx_i2c_pm_ops,
+ .pm = pm_sleep_ptr(&rk8xx_i2c_pm_ops),
},
.probe = rk8xx_i2c_probe,
.shutdown = rk8xx_i2c_shutdown,
diff --git a/drivers/mfd/rn5t618.c b/drivers/mfd/rn5t618.c
index 23ca00d2c624..8c68dd16bb9e 100644
--- a/drivers/mfd/rn5t618.c
+++ b/drivers/mfd/rn5t618.c
@@ -243,7 +243,7 @@ static void rn5t618_i2c_remove(struct i2c_client *i2c)
unregister_restart_handler(&rn5t618_restart_handler);
}
-static int __maybe_unused rn5t618_i2c_suspend(struct device *dev)
+static int rn5t618_i2c_suspend(struct device *dev)
{
struct rn5t618 *priv = dev_get_drvdata(dev);
@@ -253,7 +253,7 @@ static int __maybe_unused rn5t618_i2c_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused rn5t618_i2c_resume(struct device *dev)
+static int rn5t618_i2c_resume(struct device *dev)
{
struct rn5t618 *priv = dev_get_drvdata(dev);
@@ -263,7 +263,7 @@ static int __maybe_unused rn5t618_i2c_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(rn5t618_i2c_dev_pm_ops,
+static DEFINE_SIMPLE_DEV_PM_OPS(rn5t618_i2c_dev_pm_ops,
rn5t618_i2c_suspend,
rn5t618_i2c_resume);
@@ -271,7 +271,7 @@ static struct i2c_driver rn5t618_i2c_driver = {
.driver = {
.name = "rn5t618",
.of_match_table = rn5t618_of_match,
- .pm = &rn5t618_i2c_dev_pm_ops,
+ .pm = pm_sleep_ptr(&rn5t618_i2c_dev_pm_ops),
},
.probe = rn5t618_i2c_probe,
.remove = rn5t618_i2c_remove,
diff --git a/drivers/mfd/si476x-i2c.c b/drivers/mfd/si476x-i2c.c
index 9bce720a0a08..6351aef2d3bb 100644
--- a/drivers/mfd/si476x-i2c.c
+++ b/drivers/mfd/si476x-i2c.c
@@ -222,7 +222,7 @@ int si476x_core_stop(struct si476x_core *core, bool soft)
atomic_set(&core->is_alive, 0);
if (soft) {
- /* TODO: This probably shoud be a configurable option,
+ /* TODO: This probably should be a configurable option,
* so it is possible to have the chips keep their
* oscillators running
*/
diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c
index 068c25401c6c..81f07a1d780c 100644
--- a/drivers/mfd/ti_am335x_tscadc.c
+++ b/drivers/mfd/ti_am335x_tscadc.c
@@ -313,7 +313,7 @@ static int __maybe_unused ti_tscadc_can_wakeup(struct device *dev, void *data)
return device_may_wakeup(dev);
}
-static int __maybe_unused tscadc_suspend(struct device *dev)
+static int tscadc_suspend(struct device *dev)
{
struct ti_tscadc_dev *tscadc = dev_get_drvdata(dev);
@@ -331,7 +331,7 @@ static int __maybe_unused tscadc_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused tscadc_resume(struct device *dev)
+static int tscadc_resume(struct device *dev)
{
struct ti_tscadc_dev *tscadc = dev_get_drvdata(dev);
@@ -345,7 +345,7 @@ static int __maybe_unused tscadc_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(tscadc_pm_ops, tscadc_suspend, tscadc_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(tscadc_pm_ops, tscadc_suspend, tscadc_resume);
static const struct ti_tscadc_data tscdata = {
.adc_feature_name = "TI-am335x-adc",
@@ -373,7 +373,7 @@ MODULE_DEVICE_TABLE(of, ti_tscadc_dt_ids);
static struct platform_driver ti_tscadc_driver = {
.driver = {
.name = "ti_am3359-tscadc",
- .pm = &tscadc_pm_ops,
+ .pm = pm_sleep_ptr(&tscadc_pm_ops),
.of_match_table = ti_tscadc_dt_ids,
},
.probe = ti_tscadc_probe,
diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c
index c240fac0ede7..569c28c8b20f 100644
--- a/drivers/mfd/tps65217.c
+++ b/drivers/mfd/tps65217.c
@@ -146,6 +146,31 @@ static const struct irq_domain_ops tps65217_irq_domain_ops = {
.map = tps65217_irq_map,
};
+static void tps65217_irq_cleanup(void *data)
+{
+ struct tps65217 *tps = data;
+ unsigned int virq;
+
+ if (!tps->irq_domain)
+ return;
+
+ for (int i = 0; i < TPS65217_NUM_IRQ; i++) {
+ virq = irq_find_mapping(tps->irq_domain, i);
+ if (virq)
+ irq_dispose_mapping(virq);
+ }
+
+ irq_domain_remove(tps->irq_domain);
+ tps->irq_domain = NULL;
+}
+
+static void tps65217_irq_wake_disable(void *data)
+{
+ unsigned long irq = (unsigned long)data;
+
+ disable_irq_wake(irq);
+}
+
static int tps65217_irq_init(struct tps65217 *tps, int irq)
{
int ret;
@@ -155,8 +180,12 @@ static int tps65217_irq_init(struct tps65217 *tps, int irq)
/* Mask all interrupt sources */
tps->irq_mask = TPS65217_INT_MASK;
- tps65217_set_bits(tps, TPS65217_REG_INT, TPS65217_INT_MASK,
- TPS65217_INT_MASK, TPS65217_PROTECT_NONE);
+ ret = tps65217_set_bits(tps, TPS65217_REG_INT, TPS65217_INT_MASK,
+ TPS65217_INT_MASK, TPS65217_PROTECT_NONE);
+ if (ret) {
+ dev_err(tps->dev, "Failed to mask interrupt sources: %d\n", ret);
+ return ret;
+ }
tps->irq_domain = irq_domain_create_linear(dev_fwnode(tps->dev), TPS65217_NUM_IRQ,
&tps65217_irq_domain_ops, tps);
@@ -165,6 +194,10 @@ static int tps65217_irq_init(struct tps65217 *tps, int irq)
return -ENOMEM;
}
+ ret = devm_add_action_or_reset(tps->dev, tps65217_irq_cleanup, tps);
+ if (ret)
+ return ret;
+
ret = devm_request_threaded_irq(tps->dev, irq, NULL,
tps65217_irq_thread, IRQF_ONESHOT,
"tps65217-irq", tps);
@@ -174,7 +207,16 @@ static int tps65217_irq_init(struct tps65217 *tps, int irq)
return ret;
}
- enable_irq_wake(irq);
+ ret = enable_irq_wake(irq);
+ if (ret) {
+ dev_warn(tps->dev, "failed to enable IRQ wake: %d\n", ret);
+ return 0;
+ }
+
+ ret = devm_add_action_or_reset(tps->dev, tps65217_irq_wake_disable,
+ (void *)(unsigned long)irq);
+ if (ret)
+ return ret;
return 0;
}
@@ -333,7 +375,9 @@ static int tps65217_probe(struct i2c_client *client)
}
if (client->irq) {
- tps65217_irq_init(tps, client->irq);
+ ret = tps65217_irq_init(tps, client->irq);
+ if (ret)
+ return ret;
} else {
int i;
@@ -373,22 +417,6 @@ static int tps65217_probe(struct i2c_client *client)
return 0;
}
-static void tps65217_remove(struct i2c_client *client)
-{
- struct tps65217 *tps = i2c_get_clientdata(client);
- unsigned int virq;
- int i;
-
- for (i = 0; i < TPS65217_NUM_IRQ; i++) {
- virq = irq_find_mapping(tps->irq_domain, i);
- if (virq)
- irq_dispose_mapping(virq);
- }
-
- irq_domain_remove(tps->irq_domain);
- tps->irq_domain = NULL;
-}
-
static const struct i2c_device_id tps65217_id_table[] = {
{"tps65217", TPS65217},
{ /* sentinel */ }
@@ -402,7 +430,6 @@ static struct i2c_driver tps65217_driver = {
},
.id_table = tps65217_id_table,
.probe = tps65217_probe,
- .remove = tps65217_remove,
};
static int __init tps65217_init(void)
diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c
index 3cfd2f02b62f..600186b1e8cb 100644
--- a/drivers/mfd/tps6586x.c
+++ b/drivers/mfd/tps6586x.c
@@ -618,7 +618,7 @@ static void tps6586x_i2c_remove(struct i2c_client *client)
free_irq(client->irq, tps6586x);
}
-static int __maybe_unused tps6586x_i2c_suspend(struct device *dev)
+static int tps6586x_i2c_suspend(struct device *dev)
{
struct tps6586x *tps6586x = dev_get_drvdata(dev);
@@ -628,7 +628,7 @@ static int __maybe_unused tps6586x_i2c_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused tps6586x_i2c_resume(struct device *dev)
+static int tps6586x_i2c_resume(struct device *dev)
{
struct tps6586x *tps6586x = dev_get_drvdata(dev);
@@ -638,7 +638,7 @@ static int __maybe_unused tps6586x_i2c_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(tps6586x_pm_ops, tps6586x_i2c_suspend,
+static DEFINE_SIMPLE_DEV_PM_OPS(tps6586x_pm_ops, tps6586x_i2c_suspend,
tps6586x_i2c_resume);
static const struct i2c_device_id tps6586x_id_table[] = {
@@ -651,7 +651,7 @@ static struct i2c_driver tps6586x_driver = {
.driver = {
.name = "tps6586x",
.of_match_table = of_match_ptr(tps6586x_of_match),
- .pm = &tps6586x_pm_ops,
+ .pm = pm_sleep_ptr(&tps6586x_pm_ops),
},
.probe = tps6586x_i2c_probe,
.remove = tps6586x_i2c_remove,
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index c024a28b057e..7fbce76efd30 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -719,6 +719,11 @@ static const struct mfd_cell twl6032_cells[] = {
{ .name = "twl6032-clk" },
};
+static void twl_unregister_device(void *data)
+{
+ platform_device_unregister(data);
+}
+
/* NOTE: This driver only handles a single twl4030/tps659x0 chip */
static int
twl_probe(struct i2c_client *client)
@@ -754,17 +759,22 @@ twl_probe(struct i2c_client *client)
return status;
}
+ status = devm_add_action_or_reset(&client->dev, twl_unregister_device,
+ pdev);
+ if (status)
+ return status;
+
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
dev_dbg(&client->dev, "can't talk I2C?\n");
status = -EIO;
- goto free;
+ goto out;
}
twl_priv = devm_kzalloc(&client->dev, sizeof(struct twl_private),
GFP_KERNEL);
if (!twl_priv) {
status = -ENOMEM;
- goto free;
+ goto out;
}
if ((id->driver_data) & TWL6030_CLASS) {
@@ -784,7 +794,7 @@ twl_probe(struct i2c_client *client)
GFP_KERNEL);
if (!twl_priv->twl_modules) {
status = -ENOMEM;
- goto free;
+ goto out;
}
for (i = 0; i < num_slaves; i++) {
@@ -880,7 +890,7 @@ twl_probe(struct i2c_client *client)
status = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE,
cells, num_cells, NULL, 0, NULL);
if (status < 0)
- goto free;
+ goto out;
if (of_device_is_system_power_controller(node)) {
if (!pm_power_off)
@@ -896,14 +906,11 @@ twl_probe(struct i2c_client *client)
fail:
if (status < 0)
twl_remove(client);
-free:
- if (status < 0)
- platform_device_unregister(pdev);
-
+out:
return status;
}
-static int __maybe_unused twl_suspend(struct device *dev)
+static int twl_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -913,7 +920,7 @@ static int __maybe_unused twl_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused twl_resume(struct device *dev)
+static int twl_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -923,7 +930,7 @@ static int __maybe_unused twl_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(twl_dev_pm_ops, twl_suspend, twl_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(twl_dev_pm_ops, twl_suspend, twl_resume);
static const struct i2c_device_id twl_ids[] = {
{ "twl4030", TWL4030_VAUX2 }, /* "Triton 2" */
@@ -942,7 +949,7 @@ static const struct i2c_device_id twl_ids[] = {
/* One Client Driver , 4 Clients */
static struct i2c_driver twl_driver = {
.driver.name = DRIVER_NAME,
- .driver.pm = &twl_dev_pm_ops,
+ .driver.pm = pm_sleep_ptr(&twl_dev_pm_ops),
.id_table = twl_ids,
.probe = twl_probe,
.remove = twl_remove,
diff --git a/drivers/mfd/wcd934x.c b/drivers/mfd/wcd934x.c
index 3c3080e8c8cf..d57796933d87 100644
--- a/drivers/mfd/wcd934x.c
+++ b/drivers/mfd/wcd934x.c
@@ -2,6 +2,7 @@
// Copyright (c) 2019, Linaro Limited
#include <linux/clk.h>
+#include <linux/dma-mapping.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
@@ -217,13 +218,18 @@ static int wcd934x_slim_probe(struct slim_device *sdev)
struct gpio_desc *reset_gpio;
int ret;
+ ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to set DMA mask\n");
+
ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
if (!ddata)
return -ENOMEM;
ddata->irq = of_irq_get(np, 0);
if (ddata->irq < 0)
- return dev_err_probe(ddata->dev, ddata->irq,
+ return dev_err_probe(dev, ddata->irq,
"Failed to get IRQ\n");
ddata->extclk = devm_clk_get(dev, "extclk");
diff --git a/drivers/mfd/wm831x-auxadc.c b/drivers/mfd/wm831x-auxadc.c
index 744e1d161c5a..6280d4f38981 100644
--- a/drivers/mfd/wm831x-auxadc.c
+++ b/drivers/mfd/wm831x-auxadc.c
@@ -132,7 +132,7 @@ static irqreturn_t wm831x_auxadc_irq(int irq, void *irq_data)
1 << input, 0);
wm831x->auxadc_active &= ~(1 << input);
- /* Turn off the entire convertor if idle */
+ /* Turn off the entire converter if idle */
if (!wm831x->auxadc_active)
wm831x_reg_write(wm831x, WM831X_AUXADC_CONTROL, 0);
diff --git a/drivers/thermal/khadas_mcu_fan.c b/drivers/thermal/khadas_mcu_fan.c
index 21b3d0a71bd0..1da639d05497 100644
--- a/drivers/thermal/khadas_mcu_fan.c
+++ b/drivers/thermal/khadas_mcu_fan.c
@@ -13,34 +13,33 @@
#include <linux/regmap.h>
#include <linux/sysfs.h>
#include <linux/thermal.h>
+#include <linux/regulator/consumer.h>
+#include <linux/minmax.h>
-#define MAX_LEVEL 3
+#define MAX_LEVEL 5
struct khadas_mcu_fan_ctx {
struct khadas_mcu *mcu;
+ unsigned int fan_reg;
unsigned int level;
+ const unsigned int *levels;
+ unsigned int nlevels;
struct thermal_cooling_device *cdev;
+ struct regulator *power;
};
static int khadas_mcu_fan_set_level(struct khadas_mcu_fan_ctx *ctx,
unsigned int level)
{
- int ret;
-
- ret = regmap_write(ctx->mcu->regmap, KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG,
- level);
- if (ret)
- return ret;
-
- ctx->level = level;
-
- return 0;
+ return regmap_write(ctx->mcu->regmap, ctx->fan_reg, level);
}
static int khadas_mcu_fan_get_max_state(struct thermal_cooling_device *cdev,
unsigned long *state)
{
- *state = MAX_LEVEL;
+ struct khadas_mcu_fan_ctx *ctx = cdev->devdata;
+
+ *state = min_t(unsigned int, MAX_LEVEL, ctx->nlevels - 1);
return 0;
}
@@ -60,14 +59,21 @@ khadas_mcu_fan_set_cur_state(struct thermal_cooling_device *cdev,
unsigned long state)
{
struct khadas_mcu_fan_ctx *ctx = cdev->devdata;
+ int ret;
- if (state > MAX_LEVEL)
+ if (state > MAX_LEVEL || state >= ctx->nlevels)
return -EINVAL;
if (state == ctx->level)
return 0;
- return khadas_mcu_fan_set_level(ctx, state);
+ ret = khadas_mcu_fan_set_level(ctx, ctx->levels[state]);
+ if (ret)
+ return ret;
+
+ ctx->level = state;
+
+ return 0;
}
static const struct thermal_cooling_device_ops khadas_mcu_fan_cooling_ops = {
@@ -76,22 +82,71 @@ static const struct thermal_cooling_device_ops khadas_mcu_fan_cooling_ops = {
.set_cur_state = khadas_mcu_fan_set_cur_state,
};
+static void khadas_mcu_fan_regulator_disable(void *data)
+{
+ struct regulator *power = data;
+
+ regulator_disable(power);
+}
+
+static const unsigned int khadas_mcu_fan_levels[] = { 0, 1, 2, 3 };
+
+static const unsigned int khadas_mcu_vim4_fan_levels[] = { 0, 30, 40, 55, 75, 100 };
+
static int khadas_mcu_fan_probe(struct platform_device *pdev)
{
+ const struct platform_device_id *id = platform_get_device_id(pdev);
struct khadas_mcu *mcu = dev_get_drvdata(pdev->dev.parent);
struct thermal_cooling_device *cdev;
struct device *dev = &pdev->dev;
struct khadas_mcu_fan_ctx *ctx;
int ret;
+
+ if (!dev->of_node)
+ dev->of_node = of_node_get(dev->parent->of_node);
+
+ if (!id)
+ return -EINVAL;
+
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
+
ctx->mcu = mcu;
+ switch (id->driver_data) {
+ case KHADAS_MCU_GENERIC:
+ ctx->fan_reg = KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG;
+ ctx->levels = khadas_mcu_fan_levels;
+ ctx->nlevels = ARRAY_SIZE(khadas_mcu_fan_levels);
+ break;
+ case KHADAS_MCU_VIM4:
+ ctx->fan_reg = KHADAS_MCU_VIM4_FAN_CTRL_REG;
+ ctx->levels = khadas_mcu_vim4_fan_levels;
+ ctx->nlevels = ARRAY_SIZE(khadas_mcu_vim4_fan_levels);
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ ctx->power = devm_regulator_get(dev, "fan");
+ if (IS_ERR(ctx->power))
+ return PTR_ERR(ctx->power);
+
+ ret = regulator_enable(ctx->power);
+ if (ret) {
+ dev_err(dev, "Failed to enable fan power supply: %d\n", ret);
+ return ret;
+ }
+
+ ret = devm_add_action_or_reset(dev, khadas_mcu_fan_regulator_disable, ctx->power);
+ if (ret)
+ return ret;
+
platform_set_drvdata(pdev, ctx);
- cdev = devm_thermal_of_child_cooling_device_register(dev->parent,
- dev->parent->of_node,
+ cdev = devm_thermal_of_child_cooling_device_register(dev,
+ dev->of_node,
"khadas-mcu-fan", ctx,
&khadas_mcu_fan_cooling_ops);
if (IS_ERR(cdev)) {
@@ -109,21 +164,24 @@ static void khadas_mcu_fan_shutdown(struct platform_device *pdev)
{
struct khadas_mcu_fan_ctx *ctx = platform_get_drvdata(pdev);
- khadas_mcu_fan_set_level(ctx, 0);
+ khadas_mcu_fan_set_level(ctx, ctx->levels[0]);
}
#ifdef CONFIG_PM_SLEEP
static int khadas_mcu_fan_suspend(struct device *dev)
{
struct khadas_mcu_fan_ctx *ctx = dev_get_drvdata(dev);
- unsigned int level_save = ctx->level;
int ret;
- ret = khadas_mcu_fan_set_level(ctx, 0);
+ ret = khadas_mcu_fan_set_level(ctx, ctx->levels[0]);
if (ret)
return ret;
- ctx->level = level_save;
+ ret = regulator_disable(ctx->power);
+ if (ret) {
+ khadas_mcu_fan_set_level(ctx, ctx->levels[ctx->level]);
+ return ret;
+ }
return 0;
}
@@ -131,8 +189,13 @@ static int khadas_mcu_fan_suspend(struct device *dev)
static int khadas_mcu_fan_resume(struct device *dev)
{
struct khadas_mcu_fan_ctx *ctx = dev_get_drvdata(dev);
+ int ret;
+
+ ret = regulator_enable(ctx->power);
+ if (ret)
+ return ret;
- return khadas_mcu_fan_set_level(ctx, ctx->level);
+ return khadas_mcu_fan_set_level(ctx, ctx->levels[ctx->level]);
}
#endif
@@ -140,7 +203,8 @@ static SIMPLE_DEV_PM_OPS(khadas_mcu_fan_pm, khadas_mcu_fan_suspend,
khadas_mcu_fan_resume);
static const struct platform_device_id khadas_mcu_fan_id_table[] = {
- { .name = "khadas-mcu-fan-ctrl", },
+ { .name = "khadas-mcu-fan-ctrl", .driver_data = KHADAS_MCU_GENERIC },
+ { .name = "khadas-mcu-vim4-fan", .driver_data = KHADAS_MCU_VIM4 },
{},
};
MODULE_DEVICE_TABLE(platform, khadas_mcu_fan_id_table);
diff --git a/drivers/video/backlight/lm3533_bl.c b/drivers/video/backlight/lm3533_bl.c
index babfd3ceec86..adcd6ac7cf22 100644
--- a/drivers/video/backlight/lm3533_bl.c
+++ b/drivers/video/backlight/lm3533_bl.c
@@ -10,7 +10,9 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/backlight.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/mfd/lm3533.h>
@@ -20,13 +22,21 @@
#define LM3533_BL_MAX_BRIGHTNESS 255
#define LM3533_REG_CTRLBANK_AB_BCONF 0x1a
+#define CTRLBANK_AB_BCONF_ALS(n) BIT(2 * (n))
+#define CTRLBANK_AB_BCONF_MODE(n) BIT(2 * (n) + 1)
struct lm3533_bl {
- struct lm3533 *lm3533;
+ struct regmap *regmap;
struct lm3533_ctrlbank cb;
struct backlight_device *bd;
int id;
+
+ u32 max_current;
+ u32 pwm;
+
+ bool have_als;
+ bool linear;
};
@@ -45,7 +55,7 @@ static int lm3533_bl_update_status(struct backlight_device *bd)
static int lm3533_bl_get_brightness(struct backlight_device *bd)
{
struct lm3533_bl *bl = bl_get_data(bd);
- u8 val;
+ u32 val;
int ret;
ret = lm3533_ctrlbank_get_brightness(&bl->cb, &val);
@@ -77,103 +87,75 @@ static ssize_t show_als_channel(struct device *dev,
return scnprintf(buf, PAGE_SIZE, "%u\n", channel);
}
-static ssize_t show_als_en(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t show_als_en(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct lm3533_bl *bl = dev_get_drvdata(dev);
int ctrlbank = lm3533_bl_get_ctrlbank_id(bl);
- u8 val;
- u8 mask;
- bool enable;
int ret;
- ret = lm3533_read(bl->lm3533, LM3533_REG_CTRLBANK_AB_BCONF, &val);
- if (ret)
+ ret = regmap_test_bits(bl->regmap, LM3533_REG_CTRLBANK_AB_BCONF,
+ CTRLBANK_AB_BCONF_ALS(ctrlbank));
+ if (ret < 0)
return ret;
- mask = 1 << (2 * ctrlbank);
- enable = val & mask;
-
- return scnprintf(buf, PAGE_SIZE, "%d\n", enable);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", ret);
}
-static ssize_t store_als_en(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
+static ssize_t store_als_en(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t len)
{
struct lm3533_bl *bl = dev_get_drvdata(dev);
int ctrlbank = lm3533_bl_get_ctrlbank_id(bl);
int enable;
- u8 val;
- u8 mask;
int ret;
if (kstrtoint(buf, 0, &enable))
return -EINVAL;
- mask = 1 << (2 * ctrlbank);
-
- if (enable)
- val = mask;
- else
- val = 0;
-
- ret = lm3533_update(bl->lm3533, LM3533_REG_CTRLBANK_AB_BCONF, val,
- mask);
+ ret = regmap_assign_bits(bl->regmap, LM3533_REG_CTRLBANK_AB_BCONF,
+ CTRLBANK_AB_BCONF_ALS(ctrlbank), enable);
if (ret)
return ret;
return len;
}
-static ssize_t show_linear(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t show_linear(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct lm3533_bl *bl = dev_get_drvdata(dev);
- u8 val;
- u8 mask;
- int linear;
+ int ctrlbank = lm3533_bl_get_ctrlbank_id(bl);
int ret;
- ret = lm3533_read(bl->lm3533, LM3533_REG_CTRLBANK_AB_BCONF, &val);
- if (ret)
+ ret = regmap_test_bits(bl->regmap, LM3533_REG_CTRLBANK_AB_BCONF,
+ CTRLBANK_AB_BCONF_MODE(ctrlbank));
+ if (ret < 0)
return ret;
- mask = 1 << (2 * lm3533_bl_get_ctrlbank_id(bl) + 1);
-
- if (val & mask)
- linear = 1;
- else
- linear = 0;
-
- return scnprintf(buf, PAGE_SIZE, "%x\n", linear);
+ return scnprintf(buf, PAGE_SIZE, "%x\n", ret);
}
-static ssize_t store_linear(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
+static ssize_t store_linear(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t len)
{
struct lm3533_bl *bl = dev_get_drvdata(dev);
+ int ctrlbank = lm3533_bl_get_ctrlbank_id(bl);
+ struct backlight_device *bd = bl->bd;
unsigned long linear;
- u8 mask;
- u8 val;
int ret;
if (kstrtoul(buf, 0, &linear))
return -EINVAL;
- mask = 1 << (2 * lm3533_bl_get_ctrlbank_id(bl) + 1);
-
- if (linear)
- val = mask;
- else
- val = 0;
-
- ret = lm3533_update(bl->lm3533, LM3533_REG_CTRLBANK_AB_BCONF, val,
- mask);
+ ret = regmap_assign_bits(bl->regmap, LM3533_REG_CTRLBANK_AB_BCONF,
+ CTRLBANK_AB_BCONF_MODE(ctrlbank), linear);
if (ret)
return ret;
+ bd->props.scale = linear ? BACKLIGHT_SCALE_LINEAR :
+ BACKLIGHT_SCALE_NON_LINEAR;
+
return len;
}
@@ -182,7 +164,7 @@ static ssize_t show_pwm(struct device *dev,
char *buf)
{
struct lm3533_bl *bl = dev_get_drvdata(dev);
- u8 val;
+ u32 val;
int ret;
ret = lm3533_ctrlbank_get_pwm(&bl->cb, &val);
@@ -197,10 +179,10 @@ static ssize_t store_pwm(struct device *dev,
const char *buf, size_t len)
{
struct lm3533_bl *bl = dev_get_drvdata(dev);
- u8 val;
+ u32 val;
int ret;
- if (kstrtou8(buf, 0, &val))
+ if (kstrtou32(buf, 0, &val))
return -EINVAL;
ret = lm3533_ctrlbank_set_pwm(&bl->cb, val);
@@ -234,7 +216,7 @@ static umode_t lm3533_bl_attr_is_visible(struct kobject *kobj,
if (attr == &dev_attr_als_channel.attr ||
attr == &dev_attr_als_en.attr) {
- if (!bl->lm3533->have_als)
+ if (!bl->have_als)
mode = 0;
}
@@ -246,25 +228,36 @@ static struct attribute_group lm3533_bl_attribute_group = {
.attrs = lm3533_bl_attributes
};
-static int lm3533_bl_setup(struct lm3533_bl *bl,
- struct lm3533_bl_platform_data *pdata)
+static const struct attribute_group *lm3533_bl_attribute_groups[] = {
+ &lm3533_bl_attribute_group,
+ NULL,
+};
+
+static int lm3533_bl_setup(struct lm3533_bl *bl)
{
+ int ctrlbank = lm3533_bl_get_ctrlbank_id(bl);
int ret;
- ret = lm3533_ctrlbank_set_max_current(&bl->cb, pdata->max_current);
+ ret = regmap_assign_bits(bl->regmap, LM3533_REG_CTRLBANK_AB_BCONF,
+ CTRLBANK_AB_BCONF_MODE(ctrlbank), bl->linear);
+ if (ret)
+ return ret;
+
+ ret = lm3533_ctrlbank_set_max_current(&bl->cb, bl->max_current);
if (ret)
return ret;
- return lm3533_ctrlbank_set_pwm(&bl->cb, pdata->pwm);
+ return lm3533_ctrlbank_set_pwm(&bl->cb, bl->pwm);
}
static int lm3533_bl_probe(struct platform_device *pdev)
{
struct lm3533 *lm3533;
- struct lm3533_bl_platform_data *pdata;
struct lm3533_bl *bl;
struct backlight_device *bd;
struct backlight_properties props;
+ char *name = NULL;
+ u32 default_brightness = LM3533_BL_MAX_BRIGHTNESS;
int ret;
dev_dbg(&pdev->dev, "%s\n", __func__);
@@ -273,12 +266,6 @@ static int lm3533_bl_probe(struct platform_device *pdev)
if (!lm3533)
return -EINVAL;
- pdata = dev_get_platdata(&pdev->dev);
- if (!pdata) {
- dev_err(&pdev->dev, "no platform data\n");
- return -EINVAL;
- }
-
if (pdev->id < 0 || pdev->id >= LM3533_HVCTRLBANK_COUNT) {
dev_err(&pdev->dev, "illegal backlight id %d\n", pdev->id);
return -EINVAL;
@@ -288,20 +275,34 @@ static int lm3533_bl_probe(struct platform_device *pdev)
if (!bl)
return -ENOMEM;
- bl->lm3533 = lm3533;
+ bl->regmap = lm3533->regmap;
+ bl->have_als = lm3533->have_als;
bl->id = pdev->id;
- bl->cb.lm3533 = lm3533;
+ bl->cb.regmap = lm3533->regmap;
bl->cb.id = lm3533_bl_get_ctrlbank_id(bl);
bl->cb.dev = NULL; /* until registered */
+ name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s-%d",
+ pdev->name, pdev->id);
+ if (!name)
+ return -ENOMEM;
+
+ device_property_read_u32(&pdev->dev, "default-brightness",
+ &default_brightness);
+
memset(&props, 0, sizeof(props));
props.type = BACKLIGHT_RAW;
props.max_brightness = LM3533_BL_MAX_BRIGHTNESS;
- props.brightness = pdata->default_brightness;
- bd = devm_backlight_device_register(&pdev->dev, pdata->name,
- pdev->dev.parent, bl, &lm3533_bl_ops,
- &props);
+ props.brightness = default_brightness;
+
+ bl->linear = device_property_read_bool(&pdev->dev,
+ "ti,linear-mapping-mode");
+ props.scale = bl->linear ? BACKLIGHT_SCALE_LINEAR :
+ BACKLIGHT_SCALE_NON_LINEAR;
+
+ bd = devm_backlight_device_register(&pdev->dev, name, &pdev->dev,
+ bl, &lm3533_bl_ops, &props);
if (IS_ERR(bd)) {
dev_err(&pdev->dev, "failed to register backlight device\n");
return PTR_ERR(bd);
@@ -312,28 +313,24 @@ static int lm3533_bl_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, bl);
- ret = sysfs_create_group(&bd->dev.kobj, &lm3533_bl_attribute_group);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to create sysfs attributes\n");
- return ret;
- }
+ device_property_read_u32(&pdev->dev, "led-max-microamp",
+ &bl->max_current);
+ bl->max_current = clamp(bl->max_current, LM3533_MAX_CURRENT_MIN,
+ LM3533_MAX_CURRENT_MAX);
- backlight_update_status(bd);
+ device_property_read_u32(&pdev->dev, "ti,pwm-config-mask", &bl->pwm);
- ret = lm3533_bl_setup(bl, pdata);
+ ret = lm3533_bl_setup(bl);
if (ret)
- goto err_sysfs_remove;
+ return ret;
+
+ backlight_update_status(bd);
ret = lm3533_ctrlbank_enable(&bl->cb);
if (ret)
- goto err_sysfs_remove;
+ return ret;
return 0;
-
-err_sysfs_remove:
- sysfs_remove_group(&bd->dev.kobj, &lm3533_bl_attribute_group);
-
- return ret;
}
static void lm3533_bl_remove(struct platform_device *pdev)
@@ -347,7 +344,6 @@ static void lm3533_bl_remove(struct platform_device *pdev)
bd->props.brightness = 0;
lm3533_ctrlbank_disable(&bl->cb);
- sysfs_remove_group(&bd->dev.kobj, &lm3533_bl_attribute_group);
}
#ifdef CONFIG_PM_SLEEP
@@ -381,10 +377,18 @@ static void lm3533_bl_shutdown(struct platform_device *pdev)
lm3533_ctrlbank_disable(&bl->cb);
}
+static const struct of_device_id lm3533_bl_match_table[] = {
+ { .compatible = "ti,lm3533-backlight" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, lm3533_bl_match_table);
+
static struct platform_driver lm3533_bl_driver = {
.driver = {
.name = "lm3533-backlight",
.pm = &lm3533_bl_pm_ops,
+ .dev_groups = lm3533_bl_attribute_groups,
+ .of_match_table = lm3533_bl_match_table,
},
.probe = lm3533_bl_probe,
.remove = lm3533_bl_remove,