diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-10-26 08:38:17 -1000 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-10-26 08:38:17 -1000 |
| commit | d857e1f3faf998f2614dcdb52a90a27bc83bd71d (patch) | |
| tree | cb8bcdc792c62a8542e7d48ecc8198e4d69f0922 /drivers | |
| parent | fb2c3f44a7e14627b9dca8e6b568e6cdc234b40b (diff) | |
| parent | c8132247fe4df52e9982d74c986bb199d792b85b (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')
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", ®); + 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", ®); + 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, |
