diff options
Diffstat (limited to 'drivers')
125 files changed, 1590 insertions, 198 deletions
diff --git a/drivers/fpga/intel-m10-bmc-sec-update.c b/drivers/fpga/intel-m10-bmc-sec-update.c index d7e2f9f461bc..31af2e08c825 100644 --- a/drivers/fpga/intel-m10-bmc-sec-update.c +++ b/drivers/fpga/intel-m10-bmc-sec-update.c @@ -376,12 +376,11 @@ static enum fw_upload_err rsu_update_init(struct m10bmc_sec *sec) u32 doorbell_reg, progress, status; int ret, err; - ret = regmap_update_bits(sec->m10bmc->regmap, - csr_map->base + csr_map->doorbell, - DRBL_RSU_REQUEST | DRBL_HOST_STATUS, - DRBL_RSU_REQUEST | - FIELD_PREP(DRBL_HOST_STATUS, - HOST_STATUS_IDLE)); + ret = m10bmc_sys_update_bits(sec->m10bmc, csr_map->doorbell, + DRBL_RSU_REQUEST | DRBL_HOST_STATUS, + DRBL_RSU_REQUEST | + FIELD_PREP(DRBL_HOST_STATUS, + HOST_STATUS_IDLE)); if (ret) return FW_UPLOAD_ERR_RW_ERROR; @@ -450,11 +449,10 @@ static enum fw_upload_err rsu_send_data(struct m10bmc_sec *sec) u32 doorbell_reg, status; int ret; - ret = regmap_update_bits(sec->m10bmc->regmap, - csr_map->base + csr_map->doorbell, - DRBL_HOST_STATUS, - FIELD_PREP(DRBL_HOST_STATUS, - HOST_STATUS_WRITE_DONE)); + ret = m10bmc_sys_update_bits(sec->m10bmc, csr_map->doorbell, + DRBL_HOST_STATUS, + FIELD_PREP(DRBL_HOST_STATUS, + HOST_STATUS_WRITE_DONE)); if (ret) return FW_UPLOAD_ERR_RW_ERROR; @@ -517,11 +515,10 @@ static enum fw_upload_err rsu_cancel(struct m10bmc_sec *sec) if (rsu_prog(doorbell) != RSU_PROG_READY) return FW_UPLOAD_ERR_BUSY; - ret = regmap_update_bits(sec->m10bmc->regmap, - csr_map->base + csr_map->doorbell, - DRBL_HOST_STATUS, - FIELD_PREP(DRBL_HOST_STATUS, - HOST_STATUS_ABORT_RSU)); + ret = m10bmc_sys_update_bits(sec->m10bmc, csr_map->doorbell, + DRBL_HOST_STATUS, + FIELD_PREP(DRBL_HOST_STATUS, + HOST_STATUS_ABORT_RSU)); if (ret) return FW_UPLOAD_ERR_RW_ERROR; @@ -547,21 +544,28 @@ static enum fw_upload_err m10bmc_sec_prepare(struct fw_upload *fwl, if (ret != FW_UPLOAD_ERR_NONE) goto unlock_flash; + m10bmc_fw_state_set(sec->m10bmc, M10BMC_FW_STATE_SEC_UPDATE_PREPARE); + ret = rsu_update_init(sec); if (ret != FW_UPLOAD_ERR_NONE) - goto unlock_flash; + goto fw_state_exit; ret = rsu_prog_ready(sec); if (ret != FW_UPLOAD_ERR_NONE) - goto unlock_flash; + goto fw_state_exit; if (sec->cancel_request) { ret = rsu_cancel(sec); - goto unlock_flash; + goto fw_state_exit; } + m10bmc_fw_state_set(sec->m10bmc, M10BMC_FW_STATE_SEC_UPDATE_WRITE); + return FW_UPLOAD_ERR_NONE; +fw_state_exit: + m10bmc_fw_state_set(sec->m10bmc, M10BMC_FW_STATE_NORMAL); + unlock_flash: if (sec->m10bmc->flash_bulk_ops) sec->m10bmc->flash_bulk_ops->unlock_write(sec->m10bmc); @@ -610,6 +614,8 @@ static enum fw_upload_err m10bmc_sec_poll_complete(struct fw_upload *fwl) if (sec->cancel_request) return rsu_cancel(sec); + m10bmc_fw_state_set(sec->m10bmc, M10BMC_FW_STATE_SEC_UPDATE_PROGRAM); + result = rsu_send_data(sec); if (result != FW_UPLOAD_ERR_NONE) return result; @@ -653,6 +659,8 @@ static void m10bmc_sec_cleanup(struct fw_upload *fwl) (void)rsu_cancel(sec); + m10bmc_fw_state_set(sec->m10bmc, M10BMC_FW_STATE_NORMAL); + if (sec->m10bmc->flash_bulk_ops) sec->m10bmc->flash_bulk_ops->unlock_write(sec->m10bmc); } @@ -764,3 +772,4 @@ module_platform_driver(intel_m10bmc_sec_driver); MODULE_AUTHOR("Intel Corporation"); MODULE_DESCRIPTION("Intel MAX10 BMC Secure Update"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(INTEL_M10_BMC_CORE); diff --git a/drivers/hwmon/intel-m10-bmc-hwmon.c b/drivers/hwmon/intel-m10-bmc-hwmon.c index 6512f4bec79a..6500ca548f9c 100644 --- a/drivers/hwmon/intel-m10-bmc-hwmon.c +++ b/drivers/hwmon/intel-m10-bmc-hwmon.c @@ -794,3 +794,4 @@ MODULE_DEVICE_TABLE(platform, intel_m10bmc_hwmon_ids); MODULE_AUTHOR("Intel Corporation"); MODULE_DESCRIPTION("Intel MAX 10 BMC hardware monitor"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(INTEL_M10_BMC_CORE); diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index eb2b09ef5d5b..08b8f27afbbf 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -735,6 +735,17 @@ config MAX1363 To compile this driver as a module, choose M here: the module will be called max1363. +config MAX77541_ADC + tristate "Analog Devices MAX77541 ADC driver" + depends on MFD_MAX77541 + help + This driver controls a Analog Devices MAX77541 ADC + via I2C bus. This device has one adc. Say yes here to build + support for Analog Devices MAX77541 ADC interface. + + To compile this driver as a module, choose M here: + the module will be called max77541-adc. + config MAX9611 tristate "Maxim max9611/max9612 ADC driver" depends on I2C diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index e07e4a3e6237..eb6e891790fb 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -67,6 +67,7 @@ obj-$(CONFIG_MAX11205) += max11205.o obj-$(CONFIG_MAX11410) += max11410.o obj-$(CONFIG_MAX1241) += max1241.o obj-$(CONFIG_MAX1363) += max1363.o +obj-$(CONFIG_MAX77541_ADC) += max77541-adc.o obj-$(CONFIG_MAX9611) += max9611.o obj-$(CONFIG_MCP320X) += mcp320x.o obj-$(CONFIG_MCP3422) += mcp3422.o diff --git a/drivers/iio/adc/max77541-adc.c b/drivers/iio/adc/max77541-adc.c new file mode 100644 index 000000000000..21d024bde16b --- /dev/null +++ b/drivers/iio/adc/max77541-adc.c @@ -0,0 +1,194 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 Analog Devices, Inc. + * ADI MAX77541 ADC Driver with IIO interface + */ + +#include <linux/bitfield.h> +#include <linux/iio/iio.h> +#include <linux/mod_devicetable.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/units.h> + +#include <linux/mfd/max77541.h> + +enum max77541_adc_range { + LOW_RANGE, + MID_RANGE, + HIGH_RANGE, +}; + +enum max77541_adc_channel { + MAX77541_ADC_VSYS_V, + MAX77541_ADC_VOUT1_V, + MAX77541_ADC_VOUT2_V, + MAX77541_ADC_TEMP, +}; + +static int max77541_adc_offset(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2) +{ + switch (chan->channel) { + case MAX77541_ADC_TEMP: + *val = DIV_ROUND_CLOSEST(ABSOLUTE_ZERO_MILLICELSIUS, 1725); + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static int max77541_adc_scale(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2) +{ + struct regmap **regmap = iio_priv(indio_dev); + unsigned int reg_val; + int ret; + + switch (chan->channel) { + case MAX77541_ADC_VSYS_V: + *val = 25; + return IIO_VAL_INT; + case MAX77541_ADC_VOUT1_V: + case MAX77541_ADC_VOUT2_V: + ret = regmap_read(*regmap, MAX77541_REG_M2_CFG1, ®_val); + if (ret) + return ret; + + reg_val = FIELD_GET(MAX77541_BITS_MX_CFG1_RNG, reg_val); + switch (reg_val) { + case LOW_RANGE: + *val = 6; + *val2 = 250000; + break; + case MID_RANGE: + *val = 12; + *val2 = 500000; + break; + case HIGH_RANGE: + *val = 25; + return IIO_VAL_INT; + default: + return -EINVAL; + } + + return IIO_VAL_INT_PLUS_MICRO; + case MAX77541_ADC_TEMP: + *val = 1725; + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static int max77541_adc_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val) +{ + struct regmap **regmap = iio_priv(indio_dev); + int ret; + + ret = regmap_read(*regmap, chan->address, val); + if (ret) + return ret; + + return IIO_VAL_INT; +} + +#define MAX77541_ADC_CHANNEL_V(_channel, _name, _type, _reg) \ + { \ + .type = _type, \ + .indexed = 1, \ + .channel = _channel, \ + .address = _reg, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .datasheet_name = _name, \ + } + +#define MAX77541_ADC_CHANNEL_TEMP(_channel, _name, _type, _reg) \ + { \ + .type = _type, \ + .indexed = 1, \ + .channel = _channel, \ + .address = _reg, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) |\ + BIT(IIO_CHAN_INFO_OFFSET),\ + .datasheet_name = _name, \ + } + +static const struct iio_chan_spec max77541_adc_channels[] = { + MAX77541_ADC_CHANNEL_V(MAX77541_ADC_VSYS_V, "vsys_v", IIO_VOLTAGE, + MAX77541_REG_ADC_DATA_CH1), + MAX77541_ADC_CHANNEL_V(MAX77541_ADC_VOUT1_V, "vout1_v", IIO_VOLTAGE, + MAX77541_REG_ADC_DATA_CH2), + MAX77541_ADC_CHANNEL_V(MAX77541_ADC_VOUT2_V, "vout2_v", IIO_VOLTAGE, + MAX77541_REG_ADC_DATA_CH3), + MAX77541_ADC_CHANNEL_TEMP(MAX77541_ADC_TEMP, "temp", IIO_TEMP, + MAX77541_REG_ADC_DATA_CH6), +}; + +static int max77541_adc_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_OFFSET: + return max77541_adc_offset(indio_dev, chan, val, val2); + case IIO_CHAN_INFO_SCALE: + return max77541_adc_scale(indio_dev, chan, val, val2); + case IIO_CHAN_INFO_RAW: + return max77541_adc_raw(indio_dev, chan, val); + default: + return -EINVAL; + } +} + +static const struct iio_info max77541_adc_info = { + .read_raw = max77541_adc_read_raw, +}; + +static int max77541_adc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct iio_dev *indio_dev; + struct regmap **regmap; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*regmap)); + if (!indio_dev) + return -ENOMEM; + + regmap = iio_priv(indio_dev); + + *regmap = dev_get_regmap(dev->parent, NULL); + indio_dev->modes = INDIO_DIRECT_MODE; + + indio_dev->name = "max77541"; + indio_dev->info = &max77541_adc_info; + indio_dev->channels = max77541_adc_channels; + indio_dev->num_channels = ARRAY_SIZE(max77541_adc_channels); + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct platform_device_id max77541_adc_platform_id[] = { + { "max77541-adc" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, max77541_adc_platform_id); + +static struct platform_driver max77541_adc_driver = { + .driver = { + .name = "max77541-adc", + }, + .probe = max77541_adc_probe, + .id_table = max77541_adc_platform_id, +}; +module_platform_driver(max77541_adc_driver); + +MODULE_AUTHOR("Okan Sahin <Okan.Sahin@analog.com>"); +MODULE_DESCRIPTION("MAX77541 ADC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/88pm800.c b/drivers/mfd/88pm800.c index 4d9b61b92754..300caa067335 100644 --- a/drivers/mfd/88pm800.c +++ b/drivers/mfd/88pm800.c @@ -597,7 +597,7 @@ static struct i2c_driver pm800_driver = { .name = "88PM800", .pm = pm_sleep_ptr(&pm80x_pm_ops), }, - .probe_new = pm800_probe, + .probe = pm800_probe, .remove = pm800_remove, .id_table = pm80x_id_table, }; diff --git a/drivers/mfd/88pm805.c b/drivers/mfd/88pm805.c index 352f13cb1481..68417c3c4f5a 100644 --- a/drivers/mfd/88pm805.c +++ b/drivers/mfd/88pm805.c @@ -253,7 +253,7 @@ static struct i2c_driver pm805_driver = { .name = "88PM805", .pm = pm_sleep_ptr(&pm80x_pm_ops), }, - .probe_new = pm805_probe, + .probe = pm805_probe, .remove = pm805_remove, .id_table = pm80x_id_table, }; diff --git a/drivers/mfd/88pm80x.c b/drivers/mfd/88pm80x.c index ac4f08565f29..bbc1a87f0c8f 100644 --- a/drivers/mfd/88pm80x.c +++ b/drivers/mfd/88pm80x.c @@ -74,7 +74,6 @@ int pm80x_init(struct i2c_client *client) chip->irq = client->irq; chip->dev = &client->dev; - dev_set_drvdata(chip->dev, chip); i2c_set_clientdata(chip->client, chip); ret = regmap_read(chip->regmap, PM80X_CHIP_ID, &val); diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index aabac37c3502..151bf03e772d 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -1166,7 +1166,6 @@ static int pm860x_probe(struct i2c_client *client) chip->client = client; i2c_set_clientdata(client, chip); chip->dev = &client->dev; - dev_set_drvdata(chip->dev, chip); /* * Both client and companion client shares same platform driver. @@ -1251,7 +1250,7 @@ static struct i2c_driver pm860x_driver = { .pm = pm_sleep_ptr(&pm860x_pm_ops), .of_match_table = pm860x_dt_ids, }, - .probe_new = pm860x_probe, + .probe = pm860x_probe, .remove = pm860x_remove, .id_table = pm860x_id_table, }; diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index f89f455c130a..6f5b259a6d6a 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -266,8 +266,8 @@ config MFD_MADERA_SPI Support for the Cirrus Logic Madera platform audio SoC core functionality controlled via SPI. -config MFD_MAX597X - tristate "Maxim 597x power switch and monitor" +config MFD_MAX5970 + tristate "Maxim 5970/5978 power switch and monitor" depends on (I2C && OF) select MFD_SIMPLE_MFD_I2C help @@ -784,6 +784,19 @@ config MFD_MAX14577 additional drivers must be enabled in order to use the functionality of the device. +config MFD_MAX77541 + tristate "Analog Devices MAX77541/77540 PMIC Support" + depends on I2C=y + select MFD_CORE + select REGMAP_I2C + select REGMAP_IRQ + help + Say yes here to add support for Analog Devices MAX77541 and + MAX77540 Power Management ICs. This driver provides + common support for accessing the device; additional drivers + must be enabled in order to use the functionality of the device. + There are regulators and adc. + config MFD_MAX77620 bool "Maxim Semiconductor MAX77620 and MAX20024 PMIC Support" depends on I2C=y diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 39c461536181..f3d1f1dc73b5 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -154,6 +154,7 @@ obj-$(CONFIG_MFD_DA9063) += da9063.o obj-$(CONFIG_MFD_DA9150) += da9150-core.o obj-$(CONFIG_MFD_MAX14577) += max14577.o +obj-$(CONFIG_MFD_MAX77541) += max77541.o obj-$(CONFIG_MFD_MAX77620) += max77620.o obj-$(CONFIG_MFD_MAX77650) += max77650.o obj-$(CONFIG_MFD_MAX77686) += max77686.o diff --git a/drivers/mfd/aat2870-core.c b/drivers/mfd/aat2870-core.c index f253da5b246b..2fee62f1016c 100644 --- a/drivers/mfd/aat2870-core.c +++ b/drivers/mfd/aat2870-core.c @@ -345,8 +345,6 @@ static int aat2870_i2c_probe(struct i2c_client *client) return -ENOMEM; aat2870->dev = &client->dev; - dev_set_drvdata(aat2870->dev, aat2870); - aat2870->client = client; i2c_set_clientdata(client, aat2870); @@ -451,7 +449,7 @@ static struct i2c_driver aat2870_i2c_driver = { .pm = pm_sleep_ptr(&aat2870_pm_ops), .suppress_bind_attrs = true, }, - .probe_new = aat2870_i2c_probe, + .probe = aat2870_i2c_probe, .id_table = aat2870_i2c_id_table, }; diff --git a/drivers/mfd/acer-ec-a500.c b/drivers/mfd/acer-ec-a500.c index 7fd8b9988075..feb757e90dc3 100644 --- a/drivers/mfd/acer-ec-a500.c +++ b/drivers/mfd/acer-ec-a500.c @@ -190,7 +190,7 @@ static struct i2c_driver a500_ec_driver = { .name = "acer-a500-embedded-controller", .of_match_table = a500_ec_match, }, - .probe_new = a500_ec_probe, + .probe = a500_ec_probe, .remove = a500_ec_remove, }; module_i2c_driver(a500_ec_driver); diff --git a/drivers/mfd/act8945a.c b/drivers/mfd/act8945a.c index bcf0fda15f0c..2406fcdff5f9 100644 --- a/drivers/mfd/act8945a.c +++ b/drivers/mfd/act8945a.c @@ -70,7 +70,7 @@ static struct i2c_driver act8945a_i2c_driver = { .name = "act8945a", .of_match_table = of_match_ptr(act8945a_of_match), }, - .probe_new = act8945a_i2c_probe, + .probe = act8945a_i2c_probe, .id_table = act8945a_i2c_id, }; diff --git a/drivers/mfd/adp5520.c b/drivers/mfd/adp5520.c index cb168efdbafe..bd6f4965ebc8 100644 --- a/drivers/mfd/adp5520.c +++ b/drivers/mfd/adp5520.c @@ -340,7 +340,7 @@ static struct i2c_driver adp5520_driver = { .pm = pm_sleep_ptr(&adp5520_pm), .suppress_bind_attrs = true, }, - .probe_new = adp5520_probe, + .probe = adp5520_probe, .id_table = adp5520_id, }; builtin_i2c_driver(adp5520_driver); diff --git a/drivers/mfd/arizona-i2c.c b/drivers/mfd/arizona-i2c.c index 43e393c8608d..9b7183ffc928 100644 --- a/drivers/mfd/arizona-i2c.c +++ b/drivers/mfd/arizona-i2c.c @@ -121,7 +121,7 @@ static struct i2c_driver arizona_i2c_driver = { .pm = pm_ptr(&arizona_pm_ops), .of_match_table = of_match_ptr(arizona_i2c_of_match), }, - .probe_new = arizona_i2c_probe, + .probe = arizona_i2c_probe, .remove = arizona_i2c_remove, .id_table = arizona_i2c_id, }; diff --git a/drivers/mfd/as3711.c b/drivers/mfd/as3711.c index 3facfdd28e81..c7e85ff38013 100644 --- a/drivers/mfd/as3711.c +++ b/drivers/mfd/as3711.c @@ -201,7 +201,7 @@ static struct i2c_driver as3711_i2c_driver = { .name = "as3711", .of_match_table = of_match_ptr(as3711_of_match), }, - .probe_new = as3711_i2c_probe, + .probe = as3711_i2c_probe, .id_table = as3711_i2c_id, }; diff --git a/drivers/mfd/as3722.c b/drivers/mfd/as3722.c index b6dda0eb8645..a2bf68afc131 100644 --- a/drivers/mfd/as3722.c +++ b/drivers/mfd/as3722.c @@ -445,7 +445,7 @@ static struct i2c_driver as3722_i2c_driver = { .of_match_table = as3722_of_match, .pm = &as3722_pm_ops, }, - .probe_new = as3722_i2c_probe, + .probe = as3722_i2c_probe, .id_table = as3722_i2c_id, }; diff --git a/drivers/mfd/atc260x-i2c.c b/drivers/mfd/atc260x-i2c.c index 8e1491167160..fb53b0432a31 100644 --- a/drivers/mfd/atc260x-i2c.c +++ b/drivers/mfd/atc260x-i2c.c @@ -53,7 +53,7 @@ static struct i2c_driver atc260x_i2c_driver = { .name = "atc260x", .of_match_table = atc260x_i2c_of_match, }, - .probe_new = atc260x_i2c_probe, + .probe = atc260x_i2c_probe, }; module_i2c_driver(atc260x_i2c_driver); diff --git a/drivers/mfd/axp20x-i2c.c b/drivers/mfd/axp20x-i2c.c index a49e5e217554..68d3560cfe4a 100644 --- a/drivers/mfd/axp20x-i2c.c +++ b/drivers/mfd/axp20x-i2c.c @@ -59,6 +59,7 @@ static void axp20x_i2c_remove(struct i2c_client *i2c) #ifdef CONFIG_OF static const struct of_device_id axp20x_i2c_of_match[] = { { .compatible = "x-powers,axp152", .data = (void *)AXP152_ID }, + { .compatible = "x-powers,axp192", .data = (void *)AXP192_ID }, { .compatible = "x-powers,axp202", .data = (void *)AXP202_ID }, { .compatible = "x-powers,axp209", .data = (void *)AXP209_ID }, { .compatible = "x-powers,axp221", .data = (void *)AXP221_ID }, @@ -74,6 +75,7 @@ MODULE_DEVICE_TABLE(of, axp20x_i2c_of_match); static const struct i2c_device_id axp20x_i2c_id[] = { { "axp152", 0 }, + { "axp192", 0 }, { "axp202", 0 }, { "axp209", 0 }, { "axp221", 0 }, @@ -103,7 +105,7 @@ static struct i2c_driver axp20x_i2c_driver = { .of_match_table = of_match_ptr(axp20x_i2c_of_match), .acpi_match_table = ACPI_PTR(axp20x_i2c_acpi_match), }, - .probe_new = axp20x_i2c_probe, + .probe = axp20x_i2c_probe, .remove = axp20x_i2c_remove, .id_table = axp20x_i2c_id, }; diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c index 07a846ecbf18..c03bc5cda080 100644 --- a/drivers/mfd/axp20x.c +++ b/drivers/mfd/axp20x.c @@ -34,6 +34,7 @@ static const char * const axp20x_model_names[] = { "AXP152", + "AXP192", "AXP202", "AXP209", "AXP221", @@ -94,6 +95,35 @@ static const struct regmap_access_table axp20x_volatile_table = { .n_yes_ranges = ARRAY_SIZE(axp20x_volatile_ranges), }; +static const struct regmap_range axp192_writeable_ranges[] = { + regmap_reg_range(AXP192_DATACACHE(0), AXP192_DATACACHE(5)), + regmap_reg_range(AXP192_PWR_OUT_CTRL, AXP192_IRQ5_STATE), + regmap_reg_range(AXP20X_DCDC_MODE, AXP192_N_RSTO_CTRL), + regmap_reg_range(AXP20X_CC_CTRL, AXP20X_CC_CTRL), +}; + +static const struct regmap_range axp192_volatile_ranges[] = { + regmap_reg_range(AXP20X_PWR_INPUT_STATUS, AXP192_USB_OTG_STATUS), + regmap_reg_range(AXP192_IRQ1_STATE, AXP192_IRQ4_STATE), + regmap_reg_range(AXP192_IRQ5_STATE, AXP192_IRQ5_STATE), + regmap_reg_range(AXP20X_ACIN_V_ADC_H, AXP20X_IPSOUT_V_HIGH_L), + regmap_reg_range(AXP20X_TIMER_CTRL, AXP20X_TIMER_CTRL), + regmap_reg_range(AXP192_GPIO2_0_STATE, AXP192_GPIO2_0_STATE), + regmap_reg_range(AXP192_GPIO4_3_STATE, AXP192_GPIO4_3_STATE), + regmap_reg_range(AXP192_N_RSTO_CTRL, AXP192_N_RSTO_CTRL), + regmap_reg_range(AXP20X_CHRG_CC_31_24, AXP20X_CC_CTRL), +}; + +static const struct regmap_access_table axp192_writeable_table = { + .yes_ranges = axp192_writeable_ranges, + .n_yes_ranges = ARRAY_SIZE(axp192_writeable_ranges), +}; + +static const struct regmap_access_table axp192_volatile_table = { + .yes_ranges = axp192_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(axp192_volatile_ranges), +}; + /* AXP22x ranges are shared with the AXP809, as they cover the same range */ static const struct regmap_range axp22x_writeable_ranges[] = { regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ5_STATE), @@ -220,6 +250,19 @@ static const struct resource axp152_pek_resources[] = { DEFINE_RES_IRQ_NAMED(AXP152_IRQ_PEK_FAL_EDGE, "PEK_DBF"), }; +static const struct resource axp192_ac_power_supply_resources[] = { + DEFINE_RES_IRQ_NAMED(AXP192_IRQ_ACIN_PLUGIN, "ACIN_PLUGIN"), + DEFINE_RES_IRQ_NAMED(AXP192_IRQ_ACIN_REMOVAL, "ACIN_REMOVAL"), + DEFINE_RES_IRQ_NAMED(AXP192_IRQ_ACIN_OVER_V, "ACIN_OVER_V"), +}; + +static const struct resource axp192_usb_power_supply_resources[] = { + DEFINE_RES_IRQ_NAMED(AXP192_IRQ_VBUS_PLUGIN, "VBUS_PLUGIN"), + DEFINE_RES_IRQ_NAMED(AXP192_IRQ_VBUS_REMOVAL, "VBUS_REMOVAL"), + DEFINE_RES_IRQ_NAMED(AXP192_IRQ_VBUS_VALID, "VBUS_VALID"), + DEFINE_RES_IRQ_NAMED(AXP192_IRQ_VBUS_NOT_VALID, "VBUS_NOT_VALID"), +}; + static const struct resource axp20x_ac_power_supply_resources[] = { DEFINE_RES_IRQ_NAMED(AXP20X_IRQ_ACIN_PLUGIN, "ACIN_PLUGIN"), DEFINE_RES_IRQ_NAMED(AXP20X_IRQ_ACIN_REMOVAL, "ACIN_REMOVAL"), @@ -302,6 +345,15 @@ static const struct regmap_config axp152_regmap_config = { .cache_type = REGCACHE_RBTREE, }; +static const struct regmap_config axp192_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .wr_table = &axp192_writeable_table, + .volatile_table = &axp192_volatile_table, + .max_register = AXP20X_CC_CTRL, + .cache_type = REGCACHE_RBTREE, +}; + static const struct regmap_config axp20x_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -379,6 +431,42 @@ static const struct regmap_irq axp152_regmap_irqs[] = { INIT_REGMAP_IRQ(AXP152, GPIO0_INPUT, 2, 0), }; +static const struct regmap_irq axp192_regmap_irqs[] = { + INIT_REGMAP_IRQ(AXP192, ACIN_OVER_V, 0, 7), + INIT_REGMAP_IRQ(AXP192, ACIN_PLUGIN, 0, 6), + INIT_REGMAP_IRQ(AXP192, ACIN_REMOVAL, 0, 5), + INIT_REGMAP_IRQ(AXP192, VBUS_OVER_V, 0, 4), + INIT_REGMAP_IRQ(AXP192, VBUS_PLUGIN, 0, 3), + INIT_REGMAP_IRQ(AXP192, VBUS_REMOVAL, 0, 2), + INIT_REGMAP_IRQ(AXP192, VBUS_V_LOW, 0, 1), + INIT_REGMAP_IRQ(AXP192, BATT_PLUGIN, 1, 7), + INIT_REGMAP_IRQ(AXP192, BATT_REMOVAL, 1, 6), + INIT_REGMAP_IRQ(AXP192, BATT_ENT_ACT_MODE, 1, 5), + INIT_REGMAP_IRQ(AXP192, BATT_EXIT_ACT_MODE, 1, 4), + INIT_REGMAP_IRQ(AXP192, CHARG, 1, 3), + INIT_REGMAP_IRQ(AXP192, CHARG_DONE, 1, 2), + INIT_REGMAP_IRQ(AXP192, BATT_TEMP_HIGH, 1, 1), + INIT_REGMAP_IRQ(AXP192, BATT_TEMP_LOW, 1, 0), + INIT_REGMAP_IRQ(AXP192, DIE_TEMP_HIGH, 2, 7), + INIT_REGMAP_IRQ(AXP192, CHARG_I_LOW, 2, 6), + INIT_REGMAP_IRQ(AXP192, DCDC1_V_LONG, 2, 5), + INIT_REGMAP_IRQ(AXP192, DCDC2_V_LONG, 2, 4), + INIT_REGMAP_IRQ(AXP192, DCDC3_V_LONG, 2, 3), + INIT_REGMAP_IRQ(AXP192, PEK_SHORT, 2, 1), + INIT_REGMAP_IRQ(AXP192, PEK_LONG, 2, 0), + INIT_REGMAP_IRQ(AXP192, N_OE_PWR_ON, 3, 7), + INIT_REGMAP_IRQ(AXP192, N_OE_PWR_OFF, 3, 6), + INIT_REGMAP_IRQ(AXP192, VBUS_VALID, 3, 5), + INIT_REGMAP_IRQ(AXP192, VBUS_NOT_VALID, 3, 4), + INIT_REGMAP_IRQ(AXP192, VBUS_SESS_VALID, 3, 3), + INIT_REGMAP_IRQ(AXP192, VBUS_SESS_END, 3, 2), + INIT_REGMAP_IRQ(AXP192, LOW_PWR_LVL, 3, 0), + INIT_REGMAP_IRQ(AXP192, TIMER, 4, 7), + INIT_REGMAP_IRQ(AXP192, GPIO2_INPUT, 4, 2), + INIT_REGMAP_IRQ(AXP192, GPIO1_INPUT, 4, 1), + INIT_REGMAP_IRQ(AXP192, GPIO0_INPUT, 4, 0), +}; + static const struct regmap_irq axp20x_regmap_irqs[] = { INIT_REGMAP_IRQ(AXP20X, ACIN_OVER_V, 0, 7), INIT_REGMAP_IRQ(AXP20X, ACIN_PLUGIN, 0, 6), @@ -615,6 +703,32 @@ static const struct regmap_irq_chip axp152_regmap_irq_chip = { .num_regs = 3, }; +static unsigned int axp192_get_irq_reg(struct regmap_irq_chip_data *data, + unsigned int base, int index) +{ + /* linear mapping for IRQ1 to IRQ4 */ + if (index < 4) + return base + index; + + /* handle IRQ5 separately */ + if (base == AXP192_IRQ1_EN) + return AXP192_IRQ5_EN; + + return AXP192_IRQ5_STATE; +} + +static const struct regmap_irq_chip axp192_regmap_irq_chip = { + .name = "axp192_irq_chip", + .status_base = AXP192_IRQ1_STATE, + .ack_base = AXP192_IRQ1_STATE, + .unmask_base = AXP192_IRQ1_EN, + .init_ack_masked = true, + .irqs = axp192_regmap_irqs, + .num_irqs = ARRAY_SIZE(axp192_regmap_irqs), + .num_regs = 5, + .get_irq_reg = axp192_get_irq_reg, +}; + static const struct regmap_irq_chip axp20x_regmap_irq_chip = { .name = "axp20x_irq_chip", .status_base = AXP20X_IRQ1_STATE, @@ -705,6 +819,27 @@ static const struct regmap_irq_chip axp15060_regmap_irq_chip = { .num_regs = 2, }; +static const struct mfd_cell axp192_cells[] = { + { + .name = "axp192-adc", + .of_compatible = "x-powers,axp192-adc", + }, { + .name = "axp20x-battery-power-supply", + .of_compatible = "x-powers,axp192-battery-power-supply", + }, { + .name = "axp20x-ac-power-supply", + .of_compatible = "x-powers,axp202-ac-power-supply", + .num_resources = ARRAY_SIZE(axp192_ac_power_supply_resources), + .resources = axp192_ac_power_supply_resources, + }, { + .name = "axp20x-usb-power-supply", + .of_compatible = "x-powers,axp192-usb-power-supply", + .num_resources = ARRAY_SIZE(axp192_usb_power_supply_resources), + .resources = axp192_usb_power_supply_resources, + }, + { .name = "axp20x-regulator" }, +}; + static const struct mfd_cell axp20x_cells[] = { { .name = "axp20x-gpio", @@ -1022,6 +1157,12 @@ int axp20x_match_device(struct axp20x_dev *axp20x) axp20x->regmap_cfg = &axp152_regmap_config; axp20x->regmap_irq_chip = &axp152_regmap_irq_chip; break; + case AXP192_ID: + axp20x->nr_cells = ARRAY_SIZE(axp192_cells); + axp20x->cells = axp192_cells; + axp20x->regmap_cfg = &axp192_regmap_config; + axp20x->regmap_irq_chip = &axp192_regmap_irq_chip; + break; case AXP202_ID: case AXP209_ID: axp20x->nr_cells = ARRAY_SIZE(axp20x_cells); diff --git a/drivers/mfd/bcm590xx.c b/drivers/mfd/bcm590xx.c index 251d515478d5..9f39b46b87f4 100644 --- a/drivers/mfd/bcm590xx.c +++ b/drivers/mfd/bcm590xx.c @@ -108,7 +108,7 @@ static struct i2c_driver bcm590xx_i2c_driver = { .name = "bcm590xx", .of_match_table = bcm590xx_of_match, }, - .probe_new = bcm590xx_i2c_probe, + .probe = bcm590xx_i2c_probe, .id_table = bcm590xx_i2c_id, }; module_i2c_driver(bcm590xx_i2c_driver); diff --git a/drivers/mfd/bd9571mwv.c b/drivers/mfd/bd9571mwv.c index 60dc858c8117..819d09e4d100 100644 --- a/drivers/mfd/bd9571mwv.c +++ b/drivers/mfd/bd9571mwv.c @@ -278,7 +278,7 @@ static struct i2c_driver bd9571mwv_driver = { .name = "bd9571mwv", .of_match_table = bd9571mwv_of_match_table, }, - .probe_new = bd9571mwv_probe, + .probe = bd9571mwv_probe, .id_table = bd9571mwv_id_table, }; module_i2c_driver(bd9571mwv_driver); diff --git a/drivers/mfd/da903x.c b/drivers/mfd/da903x.c index 6570b33a5a77..e86b39de3303 100644 --- a/drivers/mfd/da903x.c +++ b/drivers/mfd/da903x.c @@ -543,7 +543,7 @@ static struct i2c_driver da903x_driver = { .driver = { .name = "da903x", }, - .probe_new = da903x_probe, + .probe = da903x_probe, .remove = da903x_remove, .id_table = da903x_id_table, }; diff --git a/drivers/mfd/da9052-i2c.c b/drivers/mfd/da9052-i2c.c index 03db7a2ccf7a..541e2d47677e 100644 --- a/drivers/mfd/da9052-i2c.c +++ b/drivers/mfd/da9052-i2c.c @@ -176,7 +176,7 @@ static void da9052_i2c_remove(struct i2c_client *client) } static struct i2c_driver da9052_i2c_driver = { - .probe_new = da9052_i2c_probe, + .probe = da9052_i2c_probe, .remove = da9052_i2c_remove, .id_table = da9052_i2c_id, .driver = { diff --git a/drivers/mfd/da9055-i2c.c b/drivers/mfd/da9055-i2c.c index 537fd5de3e6d..bbaf4f07f274 100644 --- a/drivers/mfd/da9055-i2c.c +++ b/drivers/mfd/da9055-i2c.c @@ -66,7 +66,7 @@ static const struct of_device_id da9055_of_match[] = { }; static struct i2c_driver da9055_i2c_driver = { - .probe_new = da9055_i2c_probe, + .probe = da9055_i2c_probe, .remove = da9055_i2c_remove, .id_table = da9055_i2c_id, .driver = { diff --git a/drivers/mfd/da9062-core.c b/drivers/mfd/da9062-core.c index d073d5f106ec..48f58b6f5629 100644 --- a/drivers/mfd/da9062-core.c +++ b/drivers/mfd/da9062-core.c @@ -726,7 +726,7 @@ static struct i2c_driver da9062_i2c_driver = { .name = "da9062", .of_match_table = da9062_dt_ids, }, - .probe_new = da9062_i2c_probe, + .probe = da9062_i2c_probe, .remove = da9062_i2c_remove, .id_table = da9062_i2c_id, }; diff --git a/drivers/mfd/da9063-i2c.c b/drivers/mfd/da9063-i2c.c index 03f8f95a1d62..d715cf9a9e68 100644 --- a/drivers/mfd/da9063-i2c.c +++ b/drivers/mfd/da9063-i2c.c @@ -469,7 +469,7 @@ static struct i2c_driver da9063_i2c_driver = { .name = "da9063", .of_match_table = da9063_dt_ids, }, - .probe_new = da9063_i2c_probe, + .probe = da9063_i2c_probe, .id_table = da9063_i2c_id, }; diff --git a/drivers/mfd/da9150-core.c b/drivers/mfd/da9150-core.c index d2c954103b2f..94d621e20635 100644 --- a/drivers/mfd/da9150-core.c +++ b/drivers/mfd/da9150-core.c @@ -510,7 +510,7 @@ static struct i2c_driver da9150_driver = { .name = "da9150", .of_match_table = da9150_of_match, }, - .probe_new = da9150_probe, + .probe = da9150_probe, .remove = da9150_remove, .shutdown = da9150_shutdown, .id_table = da9150_i2c_id, diff --git a/drivers/mfd/dln2.c b/drivers/mfd/dln2.c index c3149729cec2..c7510434380a 100644 --- a/drivers/mfd/dln2.c +++ b/drivers/mfd/dln2.c @@ -14,7 +14,6 @@ #include <linux/types.h> #include <linux/slab.h> #include <linux/usb.h> -#include <linux/i2c.h> #include <linux/mutex.h> #include <linux/platform_device.h> #include <linux/mfd/core.h> diff --git a/drivers/mfd/ene-kb3930.c b/drivers/mfd/ene-kb3930.c index 3eff98e26bea..fa0ad2f14a39 100644 --- a/drivers/mfd/ene-kb3930.c +++ b/drivers/mfd/ene-kb3930.c @@ -196,7 +196,7 @@ static const struct of_device_id kb3930_dt_ids[] = { MODULE_DEVICE_TABLE(of, kb3930_dt_ids); static struct i2c_driver kb3930_driver = { - .probe_new = kb3930_probe, + .probe = kb3930_probe, .remove = kb3930_remove, .driver = { .name = "ene-kb3930", diff --git a/drivers/mfd/gateworks-gsc.c b/drivers/mfd/gateworks-gsc.c index c954ed265de8..b02bfdc871e9 100644 --- a/drivers/mfd/gateworks-gsc.c +++ b/drivers/mfd/gateworks-gsc.c @@ -264,7 +264,7 @@ static struct i2c_driver gsc_driver = { .name = "gateworks-gsc", .of_match_table = gsc_of_match, }, - .probe_new = gsc_probe, + .probe = gsc_probe, .remove = gsc_remove, }; module_i2c_driver(gsc_driver); diff --git a/drivers/mfd/intel-lpss-acpi.c b/drivers/mfd/intel-lpss-acpi.c index a143c8dca2d9..212818aef93e 100644 --- a/drivers/mfd/intel-lpss-acpi.c +++ b/drivers/mfd/intel-lpss-acpi.c @@ -183,6 +183,9 @@ static int intel_lpss_acpi_probe(struct platform_device *pdev) return -ENOMEM; info->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!info->mem) + return -ENODEV; + info->irq = platform_get_irq(pdev, 0); ret = intel_lpss_probe(&pdev->dev, info); diff --git a/drivers/mfd/intel-lpss.c b/drivers/mfd/intel-lpss.c index cfbee2cfba6b..9591b354072a 100644 --- a/drivers/mfd/intel-lpss.c +++ b/drivers/mfd/intel-lpss.c @@ -460,6 +460,7 @@ void intel_lpss_remove(struct device *dev) } EXPORT_SYMBOL_GPL(intel_lpss_remove); +#ifdef CONFIG_PM static int resume_lpss_device(struct device *dev, void *data) { if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND)) @@ -514,6 +515,7 @@ int intel_lpss_resume(struct device *dev) return 0; } EXPORT_SYMBOL_GPL(intel_lpss_resume); +#endif static int __init intel_lpss_init(void) { diff --git a/drivers/mfd/intel-m10-bmc-core.c b/drivers/mfd/intel-m10-bmc-core.c index dac9cf7bcb4a..8ad5b3821584 100644 --- a/drivers/mfd/intel-m10-bmc-core.c +++ b/drivers/mfd/intel-m10-bmc-core.c @@ -12,6 +12,91 @@ #include <linux/mfd/intel-m10-bmc.h> #include <linux/module.h> +void m10bmc_fw_state_set(struct intel_m10bmc *m10bmc, enum m10bmc_fw_state new_state) +{ + /* bmcfw_state is only needed if handshake_sys_reg_nranges > 0 */ + if (!m10bmc->info->handshake_sys_reg_nranges) + return; + + down_write(&m10bmc->bmcfw_lock); + m10bmc->bmcfw_state = new_state; + up_write(&m10bmc->bmcfw_lock); +} +EXPORT_SYMBOL_NS_GPL(m10bmc_fw_state_set, INTEL_M10_BMC_CORE); + +/* + * For some Intel FPGA devices, the BMC firmware is not available to service + * handshake registers during a secure update. + */ +static bool m10bmc_reg_always_available(struct intel_m10bmc *m10bmc, unsigned int offset) +{ + if (!m10bmc->info->handshake_sys_reg_nranges) + return true; + + return !regmap_reg_in_ranges(offset, m10bmc->info->handshake_sys_reg_ranges, + m10bmc->info->handshake_sys_reg_nranges); +} + +/* + * m10bmc_handshake_reg_unavailable - Checks if reg access collides with secure update state + * @m10bmc: M10 BMC structure + * + * For some Intel FPGA devices, the BMC firmware is not available to service + * handshake registers during a secure update erase and write phases. + * + * Context: @m10bmc->bmcfw_lock must be held. + */ +static bool m10bmc_handshake_reg_unavailable(struct intel_m10bmc *m10bmc) +{ + return m10bmc->bmcfw_state == M10BMC_FW_STATE_SEC_UPDATE_PREPARE || + m10bmc->bmcfw_state == M10BMC_FW_STATE_SEC_UPDATE_WRITE; +} + +/* + * This function helps to simplify the accessing of the system registers. + * + * The base of the system registers is configured through the struct + * csr_map. + */ +int m10bmc_sys_read(struct intel_m10bmc *m10bmc, unsigned int offset, unsigned int *val) +{ + const struct m10bmc_csr_map *csr_map = m10bmc->info->csr_map; + int ret; + + if (m10bmc_reg_always_available(m10bmc, offset)) + return m10bmc_raw_read(m10bmc, csr_map->base + offset, val); + + down_read(&m10bmc->bmcfw_lock); + if (m10bmc_handshake_reg_unavailable(m10bmc)) + ret = -EBUSY; /* Reg not available during secure update */ + else + ret = m10bmc_raw_read(m10bmc, csr_map->base + offset, val); + up_read(&m10bmc->bmcfw_lock); + + return ret; +} +EXPORT_SYMBOL_NS_GPL(m10bmc_sys_read, INTEL_M10_BMC_CORE); + +int m10bmc_sys_update_bits(struct intel_m10bmc *m10bmc, unsigned int offset, + unsigned int msk, unsigned int val) +{ + const struct m10bmc_csr_map *csr_map = m10bmc->info->csr_map; + int ret; + + if (m10bmc_reg_always_available(m10bmc, offset)) + return regmap_update_bits(m10bmc->regmap, csr_map->base + offset, msk, val); + + down_read(&m10bmc->bmcfw_lock); + if (m10bmc_handshake_reg_unavailable(m10bmc)) + ret = -EBUSY; /* Reg not available during secure update */ + else + ret = regmap_update_bits(m10bmc->regmap, csr_map->base + offset, msk, val); + up_read(&m10bmc->bmcfw_lock); + + return ret; +} +EXPORT_SYMBOL_NS_GPL(m10bmc_sys_update_bits, INTEL_M10_BMC_CORE); + static ssize_t bmc_version_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -98,7 +183,7 @@ const struct attribute_group *m10bmc_dev_groups[] = { &m10bmc_group, NULL, }; -EXPORT_SYMBOL_GPL(m10bmc_dev_groups); +EXPORT_SYMBOL_NS_GPL(m10bmc_dev_groups, INTEL_M10_BMC_CORE); int m10bmc_dev_init(struct intel_m10bmc *m10bmc, const struct intel_m10bmc_platform_info *info) { @@ -106,6 +191,7 @@ int m10bmc_dev_init(struct intel_m10bmc *m10bmc, const struct intel_m10bmc_platf m10bmc->info = info; dev_set_drvdata(m10bmc->dev, m10bmc); + init_rwsem(&m10bmc->bmcfw_lock); ret = devm_mfd_add_devices(m10bmc->dev, PLATFORM_DEVID_AUTO, info->cells, info->n_cells, @@ -115,7 +201,7 @@ int m10bmc_dev_init(struct intel_m10bmc *m10bmc, const struct intel_m10bmc_platf return ret; } -EXPORT_SYMBOL_GPL(m10bmc_dev_init); +EXPORT_SYMBOL_NS_GPL(m10bmc_dev_init, INTEL_M10_BMC_CORE); MODULE_DESCRIPTION("Intel MAX 10 BMC core driver"); MODULE_AUTHOR("Intel Corporation"); diff --git a/drivers/mfd/intel-m10-bmc-pmci.c b/drivers/mfd/intel-m10-bmc-pmci.c index 8821f1876dd6..0392ef8b57d8 100644 --- a/drivers/mfd/intel-m10-bmc-pmci.c +++ b/drivers/mfd/intel-m10-bmc-pmci.c @@ -453,3 +453,4 @@ module_dfl_driver(m10bmc_pmci_driver); MODULE_DESCRIPTION("MAX10 BMC PMCI-based interface"); MODULE_AUTHOR("Intel Corporation"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(INTEL_M10_BMC_CORE); diff --git a/drivers/mfd/intel-m10-bmc-spi.c b/drivers/mfd/intel-m10-bmc-spi.c index 957200e17fed..cbeb7de9e041 100644 --- a/drivers/mfd/intel-m10-bmc-spi.c +++ b/drivers/mfd/intel-m10-bmc-spi.c @@ -116,12 +116,20 @@ static struct mfd_cell m10bmc_d5005_subdevs[] = { { .name = "d5005bmc-sec-update" }, }; +static const struct regmap_range m10bmc_d5005_fw_handshake_regs[] = { + regmap_reg_range(M10BMC_N3000_TELEM_START, M10BMC_D5005_TELEM_END), +}; + static struct mfd_cell m10bmc_pacn3000_subdevs[] = { { .name = "n3000bmc-hwmon" }, { .name = "n3000bmc-retimer" }, { .name = "n3000bmc-sec-update" }, }; +static const struct regmap_range m10bmc_n3000_fw_handshake_regs[] = { + regmap_reg_range(M10BMC_N3000_TELEM_START, M10BMC_N3000_TELEM_END), +}; + static struct mfd_cell m10bmc_n5010_subdevs[] = { { .name = "n5010bmc-hwmon" }, }; @@ -129,18 +137,24 @@ static struct mfd_cell m10bmc_n5010_subdevs[] = { static const struct intel_m10bmc_platform_info m10bmc_spi_n3000 = { .cells = m10bmc_pacn3000_subdevs, .n_cells = ARRAY_SIZE(m10bmc_pacn3000_subdevs), + .handshake_sys_reg_ranges = m10bmc_n3000_fw_handshake_regs, + .handshake_sys_reg_nranges = ARRAY_SIZE(m10bmc_n3000_fw_handshake_regs), .csr_map = &m10bmc_n3000_csr_map, }; static const struct intel_m10bmc_platform_info m10bmc_spi_d5005 = { .cells = m10bmc_d5005_subdevs, .n_cells = ARRAY_SIZE(m10bmc_d5005_subdevs), + .handshake_sys_reg_ranges = m10bmc_d5005_fw_handshake_regs, + .handshake_sys_reg_nranges = ARRAY_SIZE(m10bmc_d5005_fw_handshake_regs), .csr_map = &m10bmc_n3000_csr_map, }; static const struct intel_m10bmc_platform_info m10bmc_spi_n5010 = { .cells = m10bmc_n5010_subdevs, .n_cells = ARRAY_SIZE(m10bmc_n5010_subdevs), + .handshake_sys_reg_ranges = m10bmc_n3000_fw_handshake_regs, + .handshake_sys_reg_nranges = ARRAY_SIZE(m10bmc_n3000_fw_handshake_regs), .csr_map = &m10bmc_n3000_csr_map, }; @@ -166,3 +180,4 @@ MODULE_DESCRIPTION("Intel MAX 10 BMC SPI bus interface"); MODULE_AUTHOR("Intel Corporation"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("spi:intel-m10-bmc"); +MODULE_IMPORT_NS(INTEL_M10_BMC_CORE); diff --git a/drivers/mfd/intel_soc_pmic_chtdc_ti.c b/drivers/mfd/intel_soc_pmic_chtdc_ti.c index 282b8fd08009..992855bfda3e 100644 --- a/drivers/mfd/intel_soc_pmic_chtdc_ti.c +++ b/drivers/mfd/intel_soc_pmic_chtdc_ti.c @@ -172,7 +172,7 @@ static struct i2c_driver chtdc_ti_i2c_driver = { .pm = pm_sleep_ptr(&chtdc_ti_pm_ops), .acpi_match_table = chtdc_ti_acpi_ids, }, - .probe_new = chtdc_ti_probe, + .probe = chtdc_ti_probe, .shutdown = chtdc_ti_shutdown, }; module_i2c_driver(chtdc_ti_i2c_driver); diff --git a/drivers/mfd/intel_soc_pmic_chtwc.c b/drivers/mfd/intel_soc_pmic_chtwc.c index 871776d511e3..7fce3ef7ab45 100644 --- a/drivers/mfd/intel_soc_pmic_chtwc.c +++ b/drivers/mfd/intel_soc_pmic_chtwc.c @@ -272,7 +272,7 @@ static struct i2c_driver cht_wc_driver = { .pm = pm_sleep_ptr(&cht_wc_pm_ops), .acpi_match_table = cht_wc_acpi_ids, }, - .probe_new = cht_wc_probe, + .probe = cht_wc_probe, .shutdown = cht_wc_shutdown, .id_table = cht_wc_i2c_id, }; diff --git a/drivers/mfd/intel_soc_pmic_crc.c b/drivers/mfd/intel_soc_pmic_crc.c index b745ace46e5b..581f81cbaa24 100644 --- a/drivers/mfd/intel_soc_pmic_crc.c +++ b/drivers/mfd/intel_soc_pmic_crc.c @@ -263,7 +263,7 @@ static struct i2c_driver crystal_cove_i2c_driver = { .pm = pm_sleep_ptr(&crystal_cove_pm_ops), .acpi_match_table = crystal_cove_acpi_match, }, - .probe_new = crystal_cove_i2c_probe, + .probe = crystal_cove_i2c_probe, .remove = crystal_cove_i2c_remove, .shutdown = crystal_cove_shutdown, }; diff --git a/drivers/mfd/iqs62x.c b/drivers/mfd/iqs62x.c index 1895fce25b06..dfe9cb79e6a1 100644 --- a/drivers/mfd/iqs62x.c +++ b/drivers/mfd/iqs62x.c @@ -1069,7 +1069,7 @@ static struct i2c_driver iqs62x_i2c_driver = { .of_match_table = iqs62x_of_match, .pm = &iqs62x_pm, }, - .probe_new = iqs62x_probe, + .probe = iqs62x_probe, .remove = iqs62x_remove, }; module_i2c_driver(iqs62x_i2c_driver); diff --git a/drivers/mfd/khadas-mcu.c b/drivers/mfd/khadas-mcu.c index 1c807c0e6d25..61396d824f16 100644 --- a/drivers/mfd/khadas-mcu.c +++ b/drivers/mfd/khadas-mcu.c @@ -134,7 +134,7 @@ static struct i2c_driver khadas_mcu_driver = { .name = "khadas-mcu-core", .of_match_table = of_match_ptr(khadas_mcu_of_match), }, - .probe_new = khadas_mcu_probe, + .probe = khadas_mcu_probe, }; module_i2c_driver(khadas_mcu_driver); diff --git a/drivers/mfd/lm3533-core.c b/drivers/mfd/lm3533-core.c index 946f94f3a3c3..c211183cecb2 100644 --- a/drivers/mfd/lm3533-core.c +++ b/drivers/mfd/lm3533-core.c @@ -485,8 +485,6 @@ static int lm3533_device_init(struct lm3533 *lm3533) lm3533->gpio_hwen = pdata->gpio_hwen; - dev_set_drvdata(lm3533->dev, lm3533); - if (gpio_is_valid(lm3533->gpio_hwen)) { ret = devm_gpio_request_one(lm3533->dev, lm3533->gpio_hwen, GPIOF_OUT_INIT_LOW, "lm3533-hwen"); @@ -626,7 +624,7 @@ static struct i2c_driver lm3533_i2c_driver = { .name = "lm3533", }, .id_table = lm3533_i2c_ids, - .probe_new = lm3533_i2c_probe, + .probe = lm3533_i2c_probe, .remove = lm3533_i2c_remove, }; diff --git a/drivers/mfd/lochnagar-i2c.c b/drivers/mfd/lochnagar-i2c.c index 3a65d9938902..3c8843117080 100644 --- a/drivers/mfd/lochnagar-i2c.c +++ b/drivers/mfd/lochnagar-i2c.c @@ -382,7 +382,7 @@ static struct i2c_driver lochnagar_i2c_driver = { .of_match_table = of_match_ptr(lochnagar_of_match), .suppress_bind_attrs = true, }, - .probe_new = lochnagar_i2c_probe, + .probe = lochnagar_i2c_probe, }; static int __init lochnagar_i2c_init(void) diff --git a/drivers/mfd/lp3943.c b/drivers/mfd/lp3943.c index f9f39b53d030..7f749a23dca8 100644 --- a/drivers/mfd/lp3943.c +++ b/drivers/mfd/lp3943.c @@ -140,7 +140,7 @@ MODULE_DEVICE_TABLE(of, lp3943_of_match); #endif static struct i2c_driver lp3943_driver = { - .probe_new = lp3943_probe, + .probe = lp3943_probe, .driver = { .name = "lp3943", .of_match_table = of_match_ptr(lp3943_of_match), diff --git a/drivers/mfd/lp873x.c b/drivers/mfd/lp873x.c index c81c5c9ad748..6639f0fad4ea 100644 --- a/drivers/mfd/lp873x.c +++ b/drivers/mfd/lp873x.c @@ -78,7 +78,7 @@ static struct i2c_driver lp873x_driver = { .name = "lp873x", .of_match_table = of_lp873x_match_table, }, - .probe_new = lp873x_probe, + .probe = lp873x_probe, .id_table = lp873x_id_table, }; module_i2c_driver(lp873x_driver); diff --git a/drivers/mfd/lp87565.c b/drivers/mfd/lp87565.c index 568f0f01ea0d..88ce4d7c50a7 100644 --- a/drivers/mfd/lp87565.c +++ b/drivers/mfd/lp87565.c @@ -119,7 +119,7 @@ static struct i2c_driver lp87565_driver = { .name = "lp87565", .of_match_table = of_lp87565_match_table, }, - .probe_new = lp87565_probe, + .probe = lp87565_probe, .shutdown = lp87565_shutdown, .id_table = lp87565_id_table, }; diff --git a/drivers/mfd/lp8788.c b/drivers/mfd/lp8788.c index 18583addaae2..f371eeb042e0 100644 --- a/drivers/mfd/lp8788.c +++ b/drivers/mfd/lp8788.c @@ -225,7 +225,7 @@ static struct i2c_driver lp8788_driver = { .driver = { .name = "lp8788", }, - .probe_new = lp8788_probe, + .probe = lp8788_probe, .remove = lp8788_remove, .id_table = lp8788_ids, }; diff --git a/drivers/mfd/madera-i2c.c b/drivers/mfd/madera-i2c.c index 47e65d88feb0..0968aa9733ac 100644 --- a/drivers/mfd/madera-i2c.c +++ b/drivers/mfd/madera-i2c.c @@ -139,7 +139,7 @@ static struct i2c_driver madera_i2c_driver = { .pm = &madera_pm_ops, .of_match_table = of_match_ptr(madera_of_match), }, - .probe_new = madera_i2c_probe, + .probe = madera_i2c_probe, .remove = madera_i2c_remove, .id_table = madera_i2c_id, }; diff --git a/drivers/mfd/max14577.c b/drivers/mfd/max14577.c index 0e3731e9e9b5..25ed8846b7fb 100644 --- a/drivers/mfd/max14577.c +++ b/drivers/mfd/max14577.c @@ -518,7 +518,7 @@ static struct i2c_driver max14577_i2c_driver = { .pm = pm_sleep_ptr(&max14577_pm), .of_match_table = max14577_dt_match, }, - .probe_new = max14577_i2c_probe, + .probe = max14577_i2c_probe, .remove = max14577_i2c_remove, .id_table = max14577_i2c_id, }; diff --git a/drivers/mfd/max77541.c b/drivers/mfd/max77541.c new file mode 100644 index 000000000000..e147e949c2b3 --- /dev/null +++ b/drivers/mfd/max77541.c @@ -0,0 +1,224 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 Analog Devices, Inc. + * Driver for the MAX77540 and MAX77541 + */ + +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/mfd/core.h> +#include <linux/mfd/max77541.h> +#include <linux/property.h> +#include <linux/regmap.h> + +static const struct regmap_config max77541_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + +static const struct regmap_irq max77541_src_irqs[] = { + { .mask = MAX77541_BIT_INT_SRC_TOPSYS }, + { .mask = MAX77541_BIT_INT_SRC_BUCK }, +}; + +static const struct regmap_irq_chip max77541_src_irq_chip = { + .name = "max77541-src", + .status_base = MAX77541_REG_INT_SRC, + .mask_base = MAX77541_REG_INT_SRC_M, + .num_regs = 1, + .irqs = max77541_src_irqs, + .num_irqs = ARRAY_SIZE(max77541_src_irqs), +}; + +static const struct regmap_irq max77541_topsys_irqs[] = { + { .mask = MAX77541_BIT_TOPSYS_INT_TJ_120C }, + { .mask = MAX77541_BIT_TOPSYS_INT_TJ_140C }, + { .mask = MAX77541_BIT_TOPSYS_INT_TSHDN }, + { .mask = MAX77541_BIT_TOPSYS_INT_UVLO }, + { .mask = MAX77541_BIT_TOPSYS_INT_ALT_SWO }, + { .mask = MAX77541_BIT_TOPSYS_INT_EXT_FREQ_DET }, +}; + +static const struct regmap_irq_chip max77541_topsys_irq_chip = { + .name = "max77541-topsys", + .status_base = MAX77541_REG_TOPSYS_INT, + .mask_base = MAX77541_REG_TOPSYS_INT_M, + .num_regs = 1, + .irqs = max77541_topsys_irqs, + .num_irqs = ARRAY_SIZE(max77541_topsys_irqs), +}; + +static const struct regmap_irq max77541_buck_irqs[] = { + { .mask = MAX77541_BIT_BUCK_INT_M1_POK_FLT }, + { .mask = MAX77541_BIT_BUCK_INT_M2_POK_FLT }, + { .mask = MAX77541_BIT_BUCK_INT_M1_SCFLT }, + { .mask = MAX77541_BIT_BUCK_INT_M2_SCFLT }, +}; + +static const struct regmap_irq_chip max77541_buck_irq_chip = { + .name = "max77541-buck", + .status_base = MAX77541_REG_BUCK_INT, + .mask_base = MAX77541_REG_BUCK_INT_M, + .num_regs = 1, + .irqs = max77541_buck_irqs, + .num_irqs = ARRAY_SIZE(max77541_buck_irqs), +}; + +static const struct regmap_irq max77541_adc_irqs[] = { + { .mask = MAX77541_BIT_ADC_INT_CH1_I }, + { .mask = MAX77541_BIT_ADC_INT_CH2_I }, + { .mask = MAX77541_BIT_ADC_INT_CH3_I }, + { .mask = MAX77541_BIT_ADC_INT_CH6_I }, +}; + +static const struct regmap_irq_chip max77541_adc_irq_chip = { + .name = "max77541-adc", + .status_base = MAX77541_REG_ADC_INT, + .mask_base = MAX77541_REG_ADC_INT_M, + .num_regs = 1, + .irqs = max77541_adc_irqs, + .num_irqs = ARRAY_SIZE(max77541_adc_irqs), +}; + +static const struct mfd_cell max77540_devs[] = { + MFD_CELL_OF("max77540-regulator", NULL, NULL, 0, 0, NULL), +}; + +static const struct mfd_cell max77541_devs[] = { + MFD_CELL_OF("max77541-regulator", NULL, NULL, 0, 0, NULL), + MFD_CELL_OF("max77541-adc", NULL, NULL, 0, 0, NULL), +}; + +static int max77541_pmic_irq_init(struct device *dev) +{ + struct max77541 *max77541 = dev_get_drvdata(dev); + int irq = max77541->i2c->irq; + int ret; + + ret = devm_regmap_add_irq_chip(dev, max77541->regmap, irq, + IRQF_ONESHOT | IRQF_SHARED, 0, + &max77541_src_irq_chip, + &max77541->irq_data); + if (ret) + return ret; + + ret = devm_regmap_add_irq_chip(dev, max77541->regmap, irq, + IRQF_ONESHOT | IRQF_SHARED, 0, + &max77541_topsys_irq_chip, + &max77541->irq_topsys); + if (ret) + return ret; + + ret = devm_regmap_add_irq_chip(dev, max77541->regmap, irq, + IRQF_ONESHOT | IRQF_SHARED, 0, + &max77541_buck_irq_chip, + &max77541->irq_buck); + if (ret) + return ret; + + if (max77541->id == MAX77541) { + ret = devm_regmap_add_irq_chip(dev, max77541->regmap, irq, + IRQF_ONESHOT | IRQF_SHARED, 0, + &max77541_adc_irq_chip, + &max77541->irq_adc); + if (ret) + return ret; + } + + return 0; +} + +static int max77541_pmic_setup(struct device *dev) +{ + struct max77541 *max77541 = dev_get_drvdata(dev); + const struct mfd_cell *cells; + int n_devs; + int ret; + + switch (max77541->id) { + case MAX77540: + cells = max77540_devs; + n_devs = ARRAY_SIZE(max77540_devs); + break; + case MAX77541: + cells = max77541_devs; + n_devs = ARRAY_SIZE(max77541_devs); + break; + default: + return -EINVAL; + } + + ret = max77541_pmic_irq_init(dev); + if (ret) + return dev_err_probe(dev, ret, "Failed to initialize IRQ\n"); + + ret = device_init_wakeup(dev, true); + if (ret) + return dev_err_probe(dev, ret, "Unable to init wakeup\n"); + + return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, + cells, n_devs, NULL, 0, NULL); +} + +static int max77541_probe(struct i2c_client *client) +{ + const struct i2c_device_id *id = i2c_client_get_device_id(client); + struct device *dev = &client->dev; + struct max77541 *max77541; + + max77541 = devm_kzalloc(dev, sizeof(*max77541), GFP_KERNEL); + if (!max77541) + return -ENOMEM; + + i2c_set_clientdata(client, max77541); + max77541->i2c = client; + + max77541->id = (enum max7754x_ids)device_get_match_data(dev); + if (!max77541->id) + max77541->id = (enum max7754x_ids)id->driver_data; + + if (!max77541->id) + return -EINVAL; + + max77541->regmap = devm_regmap_init_i2c(client, + &max77541_regmap_config); + if (IS_ERR(max77541->regmap)) + return dev_err_probe(dev, PTR_ERR(max77541->regmap), + "Failed to allocate register map\n"); + + return max77541_pmic_setup(dev); +} + +static const struct of_device_id max77541_of_id[] = { + { + .compatible = "adi,max77540", + .data = (void *)MAX77540, + }, + { + .compatible = "adi,max77541", + .data = (void *)MAX77541, + }, + { } +}; +MODULE_DEVICE_TABLE(of, max77541_of_id); + +static const struct i2c_device_id max77541_id[] = { + { "max77540", MAX77540 }, + { "max77541", MAX77541 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max77541_id); + +static struct i2c_driver max77541_driver = { + .driver = { + .name = "max77541", + .of_match_table = max77541_of_id, + }, + .probe = max77541_probe, + .id_table = max77541_id, +}; +module_i2c_driver(max77541_driver); + +MODULE_DESCRIPTION("MAX7740/MAX7741 Driver"); +MODULE_AUTHOR("Okan Sahin <okan.sahin@analog.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/max77620.c b/drivers/mfd/max77620.c index cbd2297126f0..5811ed8f4840 100644 --- a/drivers/mfd/max77620.c +++ b/drivers/mfd/max77620.c @@ -698,7 +698,7 @@ static struct i2c_driver max77620_driver = { .name = "max77620", .pm = pm_sleep_ptr(&max77620_pm_ops), }, - .probe_new = max77620_probe, + .probe = max77620_probe, .id_table = max77620_id, }; builtin_i2c_driver(max77620_driver); diff --git a/drivers/mfd/max77650.c b/drivers/mfd/max77650.c index 3c07fcdd9d07..75b5dc44e38c 100644 --- a/drivers/mfd/max77650.c +++ b/drivers/mfd/max77650.c @@ -222,7 +222,7 @@ static struct i2c_driver max77650_i2c_driver = { .name = "max77650", .of_match_table = max77650_of_match, }, - .probe_new = max77650_i2c_probe, + .probe = max77650_i2c_probe, }; module_i2c_driver(max77650_i2c_driver); diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c index f8e863f3fc95..01833086ca7d 100644 --- a/drivers/mfd/max77686.c +++ b/drivers/mfd/max77686.c @@ -269,7 +269,7 @@ static struct i2c_driver max77686_i2c_driver = { .pm = pm_sleep_ptr(&max77686_pm), .of_match_table = max77686_pmic_dt_match, }, - .probe_new = max77686_i2c_probe, + .probe = max77686_i2c_probe, }; module_i2c_driver(max77686_i2c_driver); diff --git a/drivers/mfd/max77693.c b/drivers/mfd/max77693.c index 3995e8769f49..1c485a4c3dcf 100644 --- a/drivers/mfd/max77693.c +++ b/drivers/mfd/max77693.c @@ -356,7 +356,7 @@ static struct i2c_driver max77693_i2c_driver = { .pm = &max77693_pm, .of_match_table = of_match_ptr(max77693_dt_match), }, - .probe_new = max77693_i2c_probe, + .probe = max77693_i2c_probe, .remove = max77693_i2c_remove, .id_table = max77693_i2c_id, }; diff --git a/drivers/mfd/max77714.c b/drivers/mfd/max77714.c index 143a432ea343..c618605a3fb2 100644 --- a/drivers/mfd/max77714.c +++ b/drivers/mfd/max77714.c @@ -143,7 +143,7 @@ static struct i2c_driver max77714_driver = { .name = "max77714", .of_match_table = max77714_dt_match, }, - .probe_new = max77714_probe, + .probe = max77714_probe, }; module_i2c_driver(max77714_driver); diff --git a/drivers/mfd/max77843.c b/drivers/mfd/max77843.c index 8ff0723808c8..b3689c13a14d 100644 --- a/drivers/mfd/max77843.c +++ b/drivers/mfd/max77843.c @@ -207,7 +207,7 @@ static struct i2c_driver max77843_i2c_driver = { .of_match_table = max77843_dt_match, .suppress_bind_attrs = true, }, - .probe_new = max77843_probe, + .probe = max77843_probe, .id_table = max77843_id, }; diff --git a/drivers/mfd/max8907.c b/drivers/mfd/max8907.c index a69b865c6eac..78b5ee688dec 100644 --- a/drivers/mfd/max8907.c +++ b/drivers/mfd/max8907.c @@ -201,8 +201,6 @@ static int max8907_i2c_probe(struct i2c_client *i2c) } max8907->dev = &i2c->dev; - dev_set_drvdata(max8907->dev, max8907); - max8907->i2c_gen = i2c; i2c_set_clientdata(i2c, max8907); max8907->regmap_gen = devm_regmap_init_i2c(i2c, @@ -313,7 +311,7 @@ static struct i2c_driver max8907_i2c_driver = { .name = "max8907", .of_match_table = of_match_ptr(max8907_of_match), }, - .probe_new = max8907_i2c_probe, + .probe = max8907_i2c_probe, .remove = max8907_i2c_remove, .id_table = max8907_i2c_id, }; diff --git a/drivers/mfd/max8925-i2c.c b/drivers/mfd/max8925-i2c.c index 4057fd15c29e..7608000488f9 100644 --- a/drivers/mfd/max8925-i2c.c +++ b/drivers/mfd/max8925-i2c.c @@ -172,7 +172,6 @@ static int max8925_probe(struct i2c_client *client) chip->i2c = client; chip->dev = &client->dev; i2c_set_clientdata(client, chip); - dev_set_drvdata(chip->dev, chip); mutex_init(&chip->io_lock); chip->rtc = i2c_new_dummy_device(chip->i2c->adapter, RTC_I2C_ADDR); @@ -240,7 +239,7 @@ static struct i2c_driver max8925_driver = { .pm = pm_sleep_ptr(&max8925_pm_ops), .of_match_table = max8925_dt_ids, }, - .probe_new = max8925_probe, + .probe = max8925_probe, .remove = max8925_remove, .id_table = max8925_id_table, }; diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c index 79d551b86150..94c09a5eab32 100644 --- a/drivers/mfd/max8997.c +++ b/drivers/mfd/max8997.c @@ -478,7 +478,7 @@ static struct i2c_driver max8997_i2c_driver = { .suppress_bind_attrs = true, .of_match_table = of_match_ptr(max8997_pmic_dt_match), }, - .probe_new = max8997_i2c_probe, + .probe = max8997_i2c_probe, .id_table = max8997_i2c_id, }; diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c index 122f7b931f5a..33a3ec5464fb 100644 --- a/drivers/mfd/max8998.c +++ b/drivers/mfd/max8998.c @@ -348,7 +348,7 @@ static struct i2c_driver max8998_i2c_driver = { .suppress_bind_attrs = true, .of_match_table = of_match_ptr(max8998_dt_match), }, - .probe_new = max8998_i2c_probe, + .probe = max8998_i2c_probe, .id_table = max8998_i2c_id, }; diff --git a/drivers/mfd/mc13xxx-i2c.c b/drivers/mfd/mc13xxx-i2c.c index 633b973a5ba7..de59b498c925 100644 --- a/drivers/mfd/mc13xxx-i2c.c +++ b/drivers/mfd/mc13xxx-i2c.c @@ -95,7 +95,7 @@ static struct i2c_driver mc13xxx_i2c_driver = { .name = "mc13xxx", .of_match_table = mc13xxx_dt_ids, }, - .probe_new = mc13xxx_i2c_probe, + .probe = mc13xxx_i2c_probe, .remove = mc13xxx_i2c_remove, }; diff --git a/drivers/mfd/menelaus.c b/drivers/mfd/menelaus.c index c2866a11c1d2..662604ea97f2 100644 --- a/drivers/mfd/menelaus.c +++ b/drivers/mfd/menelaus.c @@ -1240,7 +1240,7 @@ static struct i2c_driver menelaus_i2c_driver = { .driver = { .name = DRIVER_NAME, }, - .probe_new = menelaus_probe, + .probe = menelaus_probe, .remove = menelaus_remove, .id_table = menelaus_id, }; diff --git a/drivers/mfd/menf21bmc.c b/drivers/mfd/menf21bmc.c index 9092fac46e35..1d36095155e0 100644 --- a/drivers/mfd/menf21bmc.c +++ b/drivers/mfd/menf21bmc.c @@ -111,7 +111,7 @@ MODULE_DEVICE_TABLE(i2c, menf21bmc_id_table); static struct i2c_driver menf21bmc_driver = { .driver.name = "menf21bmc", .id_table = menf21bmc_id_table, - .probe_new = menf21bmc_probe, + .probe = menf21bmc_probe, }; module_i2c_driver(menf21bmc_driver); diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 695d50b3bac6..0ed7c0d7784e 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -102,7 +102,6 @@ static int mfd_match_of_node_to_dev(struct platform_device *pdev, { #if IS_ENABLED(CONFIG_OF) struct mfd_of_node_entry *of_entry; - const __be32 *reg; u64 of_node_addr; /* Skip if OF node has previously been allocated to a device */ @@ -115,13 +114,10 @@ static int mfd_match_of_node_to_dev(struct platform_device *pdev, goto allocate_of_node; /* We only care about each node's first defined address */ - reg = of_get_address(np, 0, NULL, NULL); - if (!reg) + if (of_property_read_reg(np, 0, &of_node_addr, NULL)) /* OF node does not contatin a 'reg' property to match to */ return -EAGAIN; - of_node_addr = of_read_number(reg, of_n_addr_cells(np)); - if (cell->of_reg != of_node_addr) /* No match */ return -EAGAIN; diff --git a/drivers/mfd/mp2629.c b/drivers/mfd/mp2629.c index 16840ec5fd1c..717b704c3c6b 100644 --- a/drivers/mfd/mp2629.c +++ b/drivers/mfd/mp2629.c @@ -70,7 +70,7 @@ static struct i2c_driver mp2629_driver = { .name = "mp2629", .of_match_table = mp2629_of_match, }, - .probe_new = mp2629_probe, + .probe = mp2629_probe, }; module_i2c_driver(mp2629_driver); diff --git a/drivers/mfd/mt6360-core.c b/drivers/mfd/mt6360-core.c index d3b32eb79837..2685efa5c9e2 100644 --- a/drivers/mfd/mt6360-core.c +++ b/drivers/mfd/mt6360-core.c @@ -623,7 +623,7 @@ static struct i2c_driver mt6360_driver = { .pm = &mt6360_pm_ops, .of_match_table = of_match_ptr(mt6360_of_id), }, - .probe_new = mt6360_probe, + .probe = mt6360_probe, }; module_i2c_driver(mt6360_driver); diff --git a/drivers/mfd/mt6370.c b/drivers/mfd/mt6370.c index cf19cce2fdc0..c126ccb25d66 100644 --- a/drivers/mfd/mt6370.c +++ b/drivers/mfd/mt6370.c @@ -303,7 +303,7 @@ static struct i2c_driver mt6370_driver = { .name = "mt6370", .of_match_table = mt6370_match_table, }, - .probe_new = mt6370_probe, + .probe = mt6370_probe, }; module_i2c_driver(mt6370_driver); diff --git a/drivers/mfd/ntxec.c b/drivers/mfd/ntxec.c index b02785b10d48..4416cd37e539 100644 --- a/drivers/mfd/ntxec.c +++ b/drivers/mfd/ntxec.c @@ -260,7 +260,7 @@ static struct i2c_driver ntxec_driver = { .name = "ntxec", .of_match_table = of_ntxec_match_table, }, - .probe_new = ntxec_probe, + .probe = ntxec_probe, .remove = ntxec_remove, }; module_i2c_driver(ntxec_driver); diff --git a/drivers/mfd/palmas.c b/drivers/mfd/palmas.c index b8383c6cba3f..a36f12402987 100644 --- a/drivers/mfd/palmas.c +++ b/drivers/mfd/palmas.c @@ -725,7 +725,7 @@ static struct i2c_driver palmas_i2c_driver = { .name = "palmas", .of_match_table = of_palmas_match_tbl, }, - .probe_new = palmas_i2c_probe, + .probe = palmas_i2c_probe, .remove = palmas_i2c_remove, .id_table = palmas_i2c_id, }; diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c index 0e4fc99e9f49..014a68711b18 100644 --- a/drivers/mfd/pcf50633-core.c +++ b/drivers/mfd/pcf50633-core.c @@ -282,7 +282,7 @@ static struct i2c_driver pcf50633_driver = { .pm = pm_sleep_ptr(&pcf50633_pm), }, .id_table = pcf50633_id_table, - .probe_new = pcf50633_probe, + .probe = pcf50633_probe, .remove = pcf50633_remove, }; diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c index 837246aab4ac..94a8cca1d955 100644 --- a/drivers/mfd/qcom-pm8008.c +++ b/drivers/mfd/qcom-pm8008.c @@ -199,15 +199,15 @@ static const struct of_device_id pm8008_match[] = { { .compatible = "qcom,pm8008", }, { }, }; +MODULE_DEVICE_TABLE(of, pm8008_match); static struct i2c_driver pm8008_mfd_driver = { .driver = { .name = "pm8008", .of_match_table = pm8008_match, }, - .probe_new = pm8008_probe, + .probe = pm8008_probe, }; module_i2c_driver(pm8008_mfd_driver); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("i2c:qcom-pm8008"); diff --git a/drivers/mfd/rc5t583-irq.c b/drivers/mfd/rc5t583-irq.c index 621ea61fa7c6..97f52b671520 100644 --- a/drivers/mfd/rc5t583-irq.c +++ b/drivers/mfd/rc5t583-irq.c @@ -8,9 +8,9 @@ * based on code * Copyright (C) 2011 RICOH COMPANY,LTD */ +#include <linux/device.h> #include <linux/interrupt.h> #include <linux/irq.h> -#include <linux/i2c.h> #include <linux/mfd/rc5t583.h> enum int_type { diff --git a/drivers/mfd/rc5t583.c b/drivers/mfd/rc5t583.c index df83cc399315..5e81f011363f 100644 --- a/drivers/mfd/rc5t583.c +++ b/drivers/mfd/rc5t583.c @@ -288,7 +288,7 @@ static struct i2c_driver rc5t583_i2c_driver = { .driver = { .name = "rc5t583", }, - .probe_new = rc5t583_i2c_probe, + .probe = rc5t583_i2c_probe, .id_table = rc5t583_i2c_id, }; diff --git a/drivers/mfd/retu-mfd.c b/drivers/mfd/retu-mfd.c index d71483859e2e..b50cfa7f4b8f 100644 --- a/drivers/mfd/retu-mfd.c +++ b/drivers/mfd/retu-mfd.c @@ -318,7 +318,7 @@ static struct i2c_driver retu_driver = { .name = "retu-mfd", .of_match_table = retu_of_match, }, - .probe_new = retu_probe, + .probe = retu_probe, .remove = retu_remove, .id_table = retu_id, }; diff --git a/drivers/mfd/rk8xx-i2c.c b/drivers/mfd/rk8xx-i2c.c index 2822bfa8a04a..1a98feea97e2 100644 --- a/drivers/mfd/rk8xx-i2c.c +++ b/drivers/mfd/rk8xx-i2c.c @@ -173,7 +173,7 @@ static struct i2c_driver rk8xx_i2c_driver = { .of_match_table = rk8xx_i2c_of_match, .pm = &rk8xx_i2c_pm_ops, }, - .probe_new = rk8xx_i2c_probe, + .probe = rk8xx_i2c_probe, .shutdown = rk8xx_i2c_shutdown, }; module_i2c_driver(rk8xx_i2c_driver); diff --git a/drivers/mfd/rn5t618.c b/drivers/mfd/rn5t618.c index 2f59230749cd..333fef8729a5 100644 --- a/drivers/mfd/rn5t618.c +++ b/drivers/mfd/rn5t618.c @@ -280,7 +280,7 @@ static struct i2c_driver rn5t618_i2c_driver = { .of_match_table = of_match_ptr(rn5t618_of_match), .pm = &rn5t618_i2c_dev_pm_ops, }, - .probe_new = rn5t618_i2c_probe, + .probe = rn5t618_i2c_probe, .remove = rn5t618_i2c_remove, }; diff --git a/drivers/mfd/rohm-bd71828.c b/drivers/mfd/rohm-bd71828.c index 7eb920633ee9..93d80a79b901 100644 --- a/drivers/mfd/rohm-bd71828.c +++ b/drivers/mfd/rohm-bd71828.c @@ -564,7 +564,7 @@ static struct i2c_driver bd71828_drv = { .name = "rohm-bd71828", .of_match_table = bd71828_of_match, }, - .probe_new = &bd71828_i2c_probe, + .probe = bd71828_i2c_probe, }; module_i2c_driver(bd71828_drv); diff --git a/drivers/mfd/rohm-bd718x7.c b/drivers/mfd/rohm-bd718x7.c index 378eb1a692e4..0b58ecc78334 100644 --- a/drivers/mfd/rohm-bd718x7.c +++ b/drivers/mfd/rohm-bd718x7.c @@ -208,7 +208,7 @@ static struct i2c_driver bd718xx_i2c_driver = { .name = "rohm-bd718x7", .of_match_table = bd718xx_of_match, }, - .probe_new = bd718xx_i2c_probe, + .probe = bd718xx_i2c_probe, }; static int __init bd718xx_i2c_init(void) diff --git a/drivers/mfd/rohm-bd9576.c b/drivers/mfd/rohm-bd9576.c index 6491e385d980..645673322ec0 100644 --- a/drivers/mfd/rohm-bd9576.c +++ b/drivers/mfd/rohm-bd9576.c @@ -178,7 +178,7 @@ static struct i2c_driver bd957x_drv = { .name = "rohm-bd957x", .of_match_table = bd957x_of_match, }, - .probe_new = &bd957x_i2c_probe, + .probe = bd957x_i2c_probe, }; module_i2c_driver(bd957x_drv); diff --git a/drivers/mfd/rsmu_i2c.c b/drivers/mfd/rsmu_i2c.c index 807c32101460..26972a5aff45 100644 --- a/drivers/mfd/rsmu_i2c.c +++ b/drivers/mfd/rsmu_i2c.c @@ -279,7 +279,7 @@ static struct i2c_driver rsmu_i2c_driver = { .name = "rsmu-i2c", .of_match_table = of_match_ptr(rsmu_i2c_of_match), }, - .probe_new = rsmu_i2c_probe, + .probe = rsmu_i2c_probe, .remove = rsmu_i2c_remove, .id_table = rsmu_i2c_id, }; diff --git a/drivers/mfd/rt4831.c b/drivers/mfd/rt4831.c index c6d34dc2b520..f8d6dc55b558 100644 --- a/drivers/mfd/rt4831.c +++ b/drivers/mfd/rt4831.c @@ -109,7 +109,7 @@ static struct i2c_driver rt4831_driver = { .name = "rt4831", .of_match_table = rt4831_of_match, }, - .probe_new = rt4831_probe, + .probe = rt4831_probe, .remove = rt4831_remove, }; module_i2c_driver(rt4831_driver); diff --git a/drivers/mfd/rt5033.c b/drivers/mfd/rt5033.c index a5e520fe50a1..67b0a228db24 100644 --- a/drivers/mfd/rt5033.c +++ b/drivers/mfd/rt5033.c @@ -41,9 +41,6 @@ static const struct mfd_cell rt5033_devs[] = { .name = "rt5033-charger", .of_compatible = "richtek,rt5033-charger", }, { - .name = "rt5033-battery", - .of_compatible = "richtek,rt5033-battery", - }, { .name = "rt5033-led", .of_compatible = "richtek,rt5033-led", }, @@ -58,7 +55,7 @@ static const struct regmap_config rt5033_regmap_config = { static int rt5033_i2c_probe(struct i2c_client *i2c) { struct rt5033_dev *rt5033; - unsigned int dev_id; + unsigned int dev_id, chip_rev; int ret; rt5033 = devm_kzalloc(&i2c->dev, sizeof(*rt5033), GFP_KERNEL); @@ -81,7 +78,8 @@ static int rt5033_i2c_probe(struct i2c_client *i2c) dev_err(&i2c->dev, "Device not found\n"); return -ENODEV; } - dev_info(&i2c->dev, "Device found Device ID: %04x\n", dev_id); + chip_rev = dev_id & RT5033_CHIP_REV_MASK; + dev_info(&i2c->dev, "Device found (rev. %d)\n", chip_rev); ret = regmap_add_irq_chip(rt5033->regmap, rt5033->irq, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, @@ -122,7 +120,7 @@ static struct i2c_driver rt5033_driver = { .name = "rt5033", .of_match_table = rt5033_dt_match, }, - .probe_new = rt5033_i2c_probe, + .probe = rt5033_i2c_probe, .id_table = rt5033_i2c_id, }; module_i2c_driver(rt5033_driver); diff --git a/drivers/mfd/rt5120.c b/drivers/mfd/rt5120.c index 829b7a0a0781..58d9a124d795 100644 --- a/drivers/mfd/rt5120.c +++ b/drivers/mfd/rt5120.c @@ -114,7 +114,7 @@ static struct i2c_driver rt5120_driver = { .name = "rt5120", .of_match_table = rt5120_device_match_table, }, - .probe_new = rt5120_probe, + .probe = rt5120_probe, }; module_i2c_driver(rt5120_driver); diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c index c2d0ed496959..d2f631901886 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c @@ -450,7 +450,7 @@ static struct i2c_driver sec_pmic_driver = { .pm = pm_sleep_ptr(&sec_pmic_pm_ops), .of_match_table = sec_dt_match, }, - .probe_new = sec_pmic_probe, + .probe = sec_pmic_probe, .shutdown = sec_pmic_shutdown, }; module_i2c_driver(sec_pmic_driver); diff --git a/drivers/mfd/si476x-i2c.c b/drivers/mfd/si476x-i2c.c index 22131cf85e3f..899c0b5ea3aa 100644 --- a/drivers/mfd/si476x-i2c.c +++ b/drivers/mfd/si476x-i2c.c @@ -866,7 +866,7 @@ static struct i2c_driver si476x_core_driver = { .driver = { .name = "si476x-core", }, - .probe_new = si476x_core_probe, + .probe = si476x_core_probe, .remove = si476x_core_remove, .id_table = si476x_id, }; diff --git a/drivers/mfd/simple-mfd-i2c.c b/drivers/mfd/simple-mfd-i2c.c index 20782b4dd172..6eda79533208 100644 --- a/drivers/mfd/simple-mfd-i2c.c +++ b/drivers/mfd/simple-mfd-i2c.c @@ -72,28 +72,28 @@ static const struct simple_mfd_data silergy_sy7636a = { .mfd_cell_size = ARRAY_SIZE(sy7636a_cells), }; -static const struct mfd_cell max597x_cells[] = { - { .name = "max597x-regulator", }, - { .name = "max597x-iio", }, - { .name = "max597x-led", }, +static const struct mfd_cell max5970_cells[] = { + { .name = "max5970-regulator", }, + { .name = "max5970-iio", }, + { .name = "max5970-led", }, }; -static const struct simple_mfd_data maxim_max597x = { - .mfd_cell = max597x_cells, - .mfd_cell_size = ARRAY_SIZE(max597x_cells), +static const struct simple_mfd_data maxim_max5970 = { + .mfd_cell = max5970_cells, + .mfd_cell_size = ARRAY_SIZE(max5970_cells), }; static const struct of_device_id simple_mfd_i2c_of_match[] = { { .compatible = "kontron,sl28cpld" }, { .compatible = "silergy,sy7636a", .data = &silergy_sy7636a}, - { .compatible = "maxim,max5970", .data = &maxim_max597x}, - { .compatible = "maxim,max5978", .data = &maxim_max597x}, + { .compatible = "maxim,max5970", .data = &maxim_max5970}, + { .compatible = "maxim,max5978", .data = &maxim_max5970}, {} }; MODULE_DEVICE_TABLE(of, simple_mfd_i2c_of_match); static struct i2c_driver simple_mfd_i2c_driver = { - .probe_new = simple_mfd_i2c_probe, + .probe = simple_mfd_i2c_probe, .driver = { .name = "simple-mfd-i2c", .of_match_table = simple_mfd_i2c_of_match, diff --git a/drivers/mfd/sky81452.c b/drivers/mfd/sky81452.c index 2515ecae1d3f..771b62a5c70f 100644 --- a/drivers/mfd/sky81452.c +++ b/drivers/mfd/sky81452.c @@ -77,7 +77,7 @@ static struct i2c_driver sky81452_driver = { .name = "sky81452", .of_match_table = of_match_ptr(sky81452_of_match), }, - .probe_new = sky81452_probe, + .probe = sky81452_probe, .id_table = sky81452_ids, }; diff --git a/drivers/mfd/smpro-core.c b/drivers/mfd/smpro-core.c index d7729cf70378..59d31590c69b 100644 --- a/drivers/mfd/smpro-core.c +++ b/drivers/mfd/smpro-core.c @@ -125,7 +125,7 @@ static const struct of_device_id smpro_core_of_match[] = { MODULE_DEVICE_TABLE(of, smpro_core_of_match); static struct i2c_driver smpro_core_driver = { - .probe_new = smpro_core_probe, + .probe = smpro_core_probe, .driver = { .name = "smpro-core", .of_match_table = smpro_core_of_match, diff --git a/drivers/mfd/stmfx.c b/drivers/mfd/stmfx.c index e281971ba54e..c02cbd9c2f5d 100644 --- a/drivers/mfd/stmfx.c +++ b/drivers/mfd/stmfx.c @@ -330,9 +330,8 @@ static int stmfx_chip_init(struct i2c_client *client) stmfx->vdd = devm_regulator_get_optional(&client->dev, "vdd"); ret = PTR_ERR_OR_ZERO(stmfx->vdd); if (ret) { - if (ret == -ENODEV) - stmfx->vdd = NULL; - else + stmfx->vdd = NULL; + if (ret != -ENODEV) return dev_err_probe(&client->dev, ret, "Failed to get VDD regulator\n"); } @@ -387,7 +386,7 @@ static int stmfx_chip_init(struct i2c_client *client) err: if (stmfx->vdd) - return regulator_disable(stmfx->vdd); + regulator_disable(stmfx->vdd); return ret; } @@ -553,7 +552,7 @@ static struct i2c_driver stmfx_driver = { .of_match_table = stmfx_of_match, .pm = pm_sleep_ptr(&stmfx_dev_pm_ops), }, - .probe_new = stmfx_probe, + .probe = stmfx_probe, .remove = stmfx_remove, }; module_i2c_driver(stmfx_driver); diff --git a/drivers/mfd/stmpe-i2c.c b/drivers/mfd/stmpe-i2c.c index 7998e0db1e15..1d7b401776d1 100644 --- a/drivers/mfd/stmpe-i2c.c +++ b/drivers/mfd/stmpe-i2c.c @@ -118,7 +118,7 @@ static struct i2c_driver stmpe_i2c_driver = { .pm = pm_sleep_ptr(&stmpe_dev_pm_ops), .of_match_table = stmpe_of_match, }, - .probe_new = stmpe_i2c_probe, + .probe = stmpe_i2c_probe, .remove = stmpe_i2c_remove, .id_table = stmpe_i2c_id, }; diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index a92301dfc712..9c3cf58457a7 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c @@ -1485,9 +1485,9 @@ int stmpe_probe(struct stmpe_client_info *ci, enum stmpe_partnum partnum) void stmpe_remove(struct stmpe *stmpe) { - if (!IS_ERR(stmpe->vio)) + if (!IS_ERR(stmpe->vio) && regulator_is_enabled(stmpe->vio)) regulator_disable(stmpe->vio); - if (!IS_ERR(stmpe->vcc)) + if (!IS_ERR(stmpe->vcc) && regulator_is_enabled(stmpe->vcc)) regulator_disable(stmpe->vcc); __stmpe_disable(stmpe, STMPE_BLOCK_ADC); diff --git a/drivers/mfd/stpmic1.c b/drivers/mfd/stpmic1.c index 8db1530d9bac..3cc7492f828f 100644 --- a/drivers/mfd/stpmic1.c +++ b/drivers/mfd/stpmic1.c @@ -7,6 +7,7 @@ #include <linux/mfd/core.h> #include <linux/mfd/stpmic1.h> #include <linux/module.h> +#include <linux/reboot.h> #include <linux/of.h> #include <linux/of_irq.h> #include <linux/of_platform.h> @@ -19,7 +20,7 @@ static const struct regmap_range stpmic1_readable_ranges[] = { regmap_reg_range(TURN_ON_SR, VERSION_SR), - regmap_reg_range(SWOFF_PWRCTRL_CR, LDO6_STDBY_CR), + regmap_reg_range(MAIN_CR, LDO6_STDBY_CR), regmap_reg_range(BST_SW_CR, BST_SW_CR), regmap_reg_range(INT_PENDING_R1, INT_PENDING_R4), regmap_reg_range(INT_CLEAR_R1, INT_CLEAR_R4), @@ -30,7 +31,7 @@ static const struct regmap_range stpmic1_readable_ranges[] = { }; static const struct regmap_range stpmic1_writeable_ranges[] = { - regmap_reg_range(SWOFF_PWRCTRL_CR, LDO6_STDBY_CR), + regmap_reg_range(MAIN_CR, LDO6_STDBY_CR), regmap_reg_range(BST_SW_CR, BST_SW_CR), regmap_reg_range(INT_CLEAR_R1, INT_CLEAR_R4), regmap_reg_range(INT_SET_MASK_R1, INT_SET_MASK_R4), @@ -117,6 +118,16 @@ static const struct regmap_irq_chip stpmic1_regmap_irq_chip = { .num_irqs = ARRAY_SIZE(stpmic1_irqs), }; +static int stpmic1_power_off(struct sys_off_data *data) +{ + struct stpmic1 *ddata = data->cb_data; + + regmap_update_bits(ddata->regmap, MAIN_CR, + SOFTWARE_SWITCH_OFF, SOFTWARE_SWITCH_OFF); + + return NOTIFY_DONE; +} + static int stpmic1_probe(struct i2c_client *i2c) { struct stpmic1 *ddata; @@ -159,6 +170,16 @@ static int stpmic1_probe(struct i2c_client *i2c) return ret; } + ret = devm_register_sys_off_handler(ddata->dev, + SYS_OFF_MODE_POWER_OFF, + SYS_OFF_PRIO_DEFAULT, + stpmic1_power_off, + ddata); + if (ret) { + dev_err(ddata->dev, "failed to register sys-off handler: %d\n", ret); + return ret; + } + return devm_of_platform_populate(dev); } @@ -201,7 +222,7 @@ static struct i2c_driver stpmic1_driver = { .of_match_table = of_match_ptr(stpmic1_of_match), .pm = pm_sleep_ptr(&stpmic1_pm), }, - .probe_new = stpmic1_probe, + .probe = stpmic1_probe, }; module_i2c_driver(stpmic1_driver); diff --git a/drivers/mfd/stw481x.c b/drivers/mfd/stw481x.c index 2a8fc9d1c806..f35c3af680dd 100644 --- a/drivers/mfd/stw481x.c +++ b/drivers/mfd/stw481x.c @@ -239,7 +239,7 @@ static struct i2c_driver stw481x_driver = { .name = "stw481x", .of_match_table = stw481x_match, }, - .probe_new = stw481x_probe, + .probe = stw481x_probe, .id_table = stw481x_id, }; diff --git a/drivers/mfd/tc3589x.c b/drivers/mfd/tc3589x.c index cbfe19d1b145..16df64e3c0be 100644 --- a/drivers/mfd/tc3589x.c +++ b/drivers/mfd/tc3589x.c @@ -485,7 +485,7 @@ static struct i2c_driver tc3589x_driver = { .pm = pm_sleep_ptr(&tc3589x_dev_pm_ops), .of_match_table = of_match_ptr(tc3589x_match), }, - .probe_new = tc3589x_probe, + .probe = tc3589x_probe, .remove = tc3589x_remove, .id_table = tc3589x_id, }; diff --git a/drivers/mfd/ti-lmu.c b/drivers/mfd/ti-lmu.c index 9921320be255..4f06adad7b5e 100644 --- a/drivers/mfd/ti-lmu.c +++ b/drivers/mfd/ti-lmu.c @@ -217,7 +217,7 @@ static const struct i2c_device_id ti_lmu_ids[] = { MODULE_DEVICE_TABLE(i2c, ti_lmu_ids); static struct i2c_driver ti_lmu_driver = { - .probe_new = ti_lmu_probe, + .probe = ti_lmu_probe, .driver = { .name = "ti-lmu", .of_match_table = ti_lmu_of_match, diff --git a/drivers/mfd/tps6105x.c b/drivers/mfd/tps6105x.c index a66cb911998d..5601f6d0d874 100644 --- a/drivers/mfd/tps6105x.c +++ b/drivers/mfd/tps6105x.c @@ -209,7 +209,7 @@ static struct i2c_driver tps6105x_driver = { .name = "tps6105x", .of_match_table = tps6105x_of_match, }, - .probe_new = tps6105x_probe, + .probe = tps6105x_probe, .remove = tps6105x_remove, .id_table = tps6105x_id, }; diff --git a/drivers/mfd/tps65010.c b/drivers/mfd/tps65010.c index faea4ff44c6f..2b9105295f30 100644 --- a/drivers/mfd/tps65010.c +++ b/drivers/mfd/tps65010.c @@ -664,7 +664,7 @@ static struct i2c_driver tps65010_driver = { .driver = { .name = "tps65010", }, - .probe_new = tps65010_probe, + .probe = tps65010_probe, .remove = tps65010_remove, .id_table = tps65010_id, }; diff --git a/drivers/mfd/tps6507x.c b/drivers/mfd/tps6507x.c index 500b594de316..9716bf703c7a 100644 --- a/drivers/mfd/tps6507x.c +++ b/drivers/mfd/tps6507x.c @@ -122,7 +122,7 @@ static struct i2c_driver tps6507x_i2c_driver = { .name = "tps6507x", .of_match_table = of_match_ptr(tps6507x_of_match), }, - .probe_new = tps6507x_i2c_probe, + .probe = tps6507x_i2c_probe, .id_table = tps6507x_i2c_id, }; diff --git a/drivers/mfd/tps65086.c b/drivers/mfd/tps65086.c index 9494c1d71b86..6a21000aad4a 100644 --- a/drivers/mfd/tps65086.c +++ b/drivers/mfd/tps65086.c @@ -129,7 +129,7 @@ static struct i2c_driver tps65086_driver = { .name = "tps65086", .of_match_table = tps65086_of_match_table, }, - .probe_new = tps65086_probe, + .probe = tps65086_probe, .remove = tps65086_remove, .id_table = tps65086_id_table, }; diff --git a/drivers/mfd/tps65090.c b/drivers/mfd/tps65090.c index af718a9c58b3..a35ad70755fb 100644 --- a/drivers/mfd/tps65090.c +++ b/drivers/mfd/tps65090.c @@ -236,7 +236,7 @@ static struct i2c_driver tps65090_driver = { .suppress_bind_attrs = true, .of_match_table = of_match_ptr(tps65090_of_match), }, - .probe_new = tps65090_i2c_probe, + .probe = tps65090_i2c_probe, .id_table = tps65090_id_table, }; diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c index eebd60601b01..60599291b315 100644 --- a/drivers/mfd/tps65217.c +++ b/drivers/mfd/tps65217.c @@ -402,7 +402,7 @@ static struct i2c_driver tps65217_driver = { .of_match_table = tps65217_of_match, }, .id_table = tps65217_id_table, - .probe_new = tps65217_probe, + .probe = tps65217_probe, .remove = tps65217_remove, }; diff --git a/drivers/mfd/tps65218.c b/drivers/mfd/tps65218.c index ea69dcef91ec..619bf7adb20c 100644 --- a/drivers/mfd/tps65218.c +++ b/drivers/mfd/tps65218.c @@ -347,7 +347,7 @@ static struct i2c_driver tps65218_driver = { .name = "tps65218", .of_match_table = of_tps65218_match_table, }, - .probe_new = tps65218_probe, + .probe = tps65218_probe, .id_table = tps65218_id_table, }; diff --git a/drivers/mfd/tps65219.c b/drivers/mfd/tps65219.c index 0e402fda206b..0e0c42e4fdfc 100644 --- a/drivers/mfd/tps65219.c +++ b/drivers/mfd/tps65219.c @@ -25,13 +25,21 @@ static int tps65219_cold_reset(struct tps65219 *tps) TPS65219_MFP_COLD_RESET_I2C_CTRL_MASK); } -static int tps65219_restart(struct notifier_block *this, - unsigned long reboot_mode, void *cmd) +static int tps65219_soft_shutdown(struct tps65219 *tps) { - struct tps65219 *tps; + return regmap_update_bits(tps->regmap, TPS65219_REG_MFP_CTRL, + TPS65219_MFP_I2C_OFF_REQ_MASK, + TPS65219_MFP_I2C_OFF_REQ_MASK); +} - tps = container_of(this, struct tps65219, nb); +static int tps65219_power_off_handler(struct sys_off_data *data) +{ + tps65219_soft_shutdown(data->cb_data); + return NOTIFY_DONE; +} +static int tps65219_restart(struct tps65219 *tps, unsigned long reboot_mode) +{ if (reboot_mode == REBOOT_WARM) tps65219_warm_reset(tps); else @@ -40,10 +48,11 @@ static int tps65219_restart(struct notifier_block *this, return NOTIFY_DONE; } -static struct notifier_block pmic_rst_restart_nb = { - .notifier_call = tps65219_restart, - .priority = 200, -}; +static int tps65219_restart_handler(struct sys_off_data *data) +{ + tps65219_restart(data->cb_data, data->mode); + return NOTIFY_DONE; +} static const struct resource tps65219_pwrbutton_resources[] = { DEFINE_RES_IRQ_NAMED(TPS65219_INT_PB_FALLING_EDGE_DETECT, "falling"), @@ -106,7 +115,7 @@ static const struct mfd_cell tps65219_cells[] = { .resources = tps65219_regulator_resources, .num_resources = ARRAY_SIZE(tps65219_regulator_resources), }, - { .name = "tps65219-gpios", }, + { .name = "tps65219-gpio", }, }; static const struct mfd_cell tps65219_pwrbutton_cell = { @@ -269,13 +278,22 @@ static int tps65219_probe(struct i2c_client *client) } } - tps->nb = pmic_rst_restart_nb; - ret = register_restart_handler(&tps->nb); + ret = devm_register_restart_handler(tps->dev, + tps65219_restart_handler, + tps); + if (ret) { dev_err(tps->dev, "cannot register restart handler, %d\n", ret); return ret; } + ret = devm_register_power_off_handler(tps->dev, + tps65219_power_off_handler, + tps); + if (ret) { + dev_err(tps->dev, "failed to register power-off handler: %d\n", ret); + return ret; + } return 0; } @@ -290,7 +308,7 @@ static struct i2c_driver tps65219_driver = { .name = "tps65219", .of_match_table = of_tps65219_match_table, }, - .probe_new = tps65219_probe, + .probe = tps65219_probe, }; module_i2c_driver(tps65219_driver); diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index 90e23232b6b0..55675ceedcd3 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c @@ -619,7 +619,7 @@ static struct i2c_driver tps6586x_driver = { .of_match_table = of_match_ptr(tps6586x_of_match), .pm = &tps6586x_pm_ops, }, - .probe_new = tps6586x_i2c_probe, + .probe = tps6586x_i2c_probe, .remove = tps6586x_i2c_remove, .id_table = tps6586x_id_table, }; diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index 821c0277a2ed..41408df1712f 100644 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -535,7 +535,7 @@ static struct i2c_driver tps65910_i2c_driver = { .name = "tps65910", .of_match_table = of_match_ptr(tps65910_of_match), }, - .probe_new = tps65910_i2c_probe, + .probe = tps65910_i2c_probe, .id_table = tps65910_i2c_id, }; diff --git a/drivers/mfd/tps65912-i2c.c b/drivers/mfd/tps65912-i2c.c index 1bf945966bf7..3c5ac781b6c1 100644 --- a/drivers/mfd/tps65912-i2c.c +++ b/drivers/mfd/tps65912-i2c.c @@ -60,7 +60,7 @@ static struct i2c_driver tps65912_i2c_driver = { .name = "tps65912", .of_match_table = tps65912_i2c_of_match_table, }, - .probe_new = tps65912_i2c_probe, + .probe = tps65912_i2c_probe, .remove = tps65912_i2c_remove, .id_table = tps65912_i2c_id_table, }; diff --git a/drivers/mfd/tps6594-i2c.c b/drivers/mfd/tps6594-i2c.c index 449d5c61bc9f..899c88c0fe77 100644 --- a/drivers/mfd/tps6594-i2c.c +++ b/drivers/mfd/tps6594-i2c.c @@ -222,7 +222,7 @@ static int tps6594_i2c_probe(struct i2c_client *client) match = of_match_device(tps6594_i2c_of_match_table, dev); if (!match) - return dev_err_probe(dev, PTR_ERR(match), "Failed to find matching chip ID\n"); + return dev_err_probe(dev, -EINVAL, "Failed to find matching chip ID\n"); tps->chip_id = (unsigned long)match->data; crc8_populate_msb(tps6594_i2c_crc_table, TPS6594_CRC8_POLYNOMIAL); @@ -235,7 +235,7 @@ static struct i2c_driver tps6594_i2c_driver = { .name = "tps6594", .of_match_table = tps6594_i2c_of_match_table, }, - .probe_new = tps6594_i2c_probe, + .probe = tps6594_i2c_probe, }; module_i2c_driver(tps6594_i2c_driver); diff --git a/drivers/mfd/tps6594-spi.c b/drivers/mfd/tps6594-spi.c index a938a191744f..f4b4f37f957f 100644 --- a/drivers/mfd/tps6594-spi.c +++ b/drivers/mfd/tps6594-spi.c @@ -107,7 +107,7 @@ static int tps6594_spi_probe(struct spi_device *spi) match = of_match_device(tps6594_spi_of_match_table, dev); if (!match) - return dev_err_probe(dev, PTR_ERR(match), "Failed to find matching chip ID\n"); + return dev_err_probe(dev, -EINVAL, "Failed to find matching chip ID\n"); tps->chip_id = (unsigned long)match->data; crc8_populate_msb(tps6594_spi_crc_table, TPS6594_CRC8_POLYNOMIAL); diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index e801b7ce010f..ce01a87f8dc3 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -890,7 +890,7 @@ static struct i2c_driver twl_driver = { .driver.name = DRIVER_NAME, .driver.pm = &twl_dev_pm_ops, .id_table = twl_ids, - .probe_new = twl_probe, + .probe = twl_probe, .remove = twl_remove, }; builtin_i2c_driver(twl_driver); diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c index e982119bbefa..d85675a4d9a8 100644 --- a/drivers/mfd/twl6040.c +++ b/drivers/mfd/twl6040.c @@ -608,7 +608,7 @@ static const struct regmap_config twl6040_regmap_config = { .volatile_reg = twl6040_volatile_reg, .writeable_reg = twl6040_writeable_reg, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .use_single_read = true, .use_single_write = true, }; @@ -829,7 +829,7 @@ static struct i2c_driver twl6040_driver = { .driver = { .name = "twl6040", }, - .probe_new = twl6040_probe, + .probe = twl6040_probe, .remove = twl6040_remove, .id_table = twl6040_i2c_id, }; diff --git a/drivers/mfd/wcd934x.c b/drivers/mfd/wcd934x.c index 07e884087f2c..6b942d5270c1 100644 --- a/drivers/mfd/wcd934x.c +++ b/drivers/mfd/wcd934x.c @@ -227,10 +227,9 @@ static int wcd934x_slim_probe(struct slim_device *sdev) "Failed to get IRQ\n"); ddata->extclk = devm_clk_get(dev, "extclk"); - if (IS_ERR(ddata->extclk)) { - dev_err(dev, "Failed to get extclk"); - return PTR_ERR(ddata->extclk); - } + if (IS_ERR(ddata->extclk)) + return dev_err_probe(dev, PTR_ERR(ddata->extclk), + "Failed to get extclk"); ddata->supplies[0].supply = "vdd-buck"; ddata->supplies[1].supply = "vdd-buck-sido"; @@ -239,16 +238,12 @@ static int wcd934x_slim_probe(struct slim_device *sdev) ddata->supplies[4].supply = "vdd-io"; ret = regulator_bulk_get(dev, WCD934X_MAX_SUPPLY, ddata->supplies); - if (ret) { - dev_err(dev, "Failed to get supplies: err = %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "Failed to get supplies\n"); ret = regulator_bulk_enable(WCD934X_MAX_SUPPLY, ddata->supplies); - if (ret) { - dev_err(dev, "Failed to enable supplies: err = %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "Failed to enable supplies\n"); /* * For WCD934X, it takes about 600us for the Vout_A and @@ -258,8 +253,9 @@ static int wcd934x_slim_probe(struct slim_device *sdev) usleep_range(600, 650); reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(reset_gpio)) { - return dev_err_probe(dev, PTR_ERR(reset_gpio), - "Failed to get reset gpio: err = %ld\n", PTR_ERR(reset_gpio)); + ret = dev_err_probe(dev, PTR_ERR(reset_gpio), + "Failed to get reset gpio\n"); + goto err_disable_regulators; } msleep(20); gpiod_set_value(reset_gpio, 1); @@ -269,6 +265,10 @@ static int wcd934x_slim_probe(struct slim_device *sdev) dev_set_drvdata(dev, ddata); return 0; + +err_disable_regulators: + regulator_bulk_disable(WCD934X_MAX_SUPPLY, ddata->supplies); + return ret; } static void wcd934x_slim_remove(struct slim_device *sdev) diff --git a/drivers/mfd/wl1273-core.c b/drivers/mfd/wl1273-core.c index a5d6128fc67d..e2a7fccaed01 100644 --- a/drivers/mfd/wl1273-core.c +++ b/drivers/mfd/wl1273-core.c @@ -232,7 +232,7 @@ static struct i2c_driver wl1273_core_driver = { .driver = { .name = WL1273_FM_DRIVER_NAME, }, - .probe_new = wl1273_core_probe, + .probe = wl1273_core_probe, .id_table = wl1273_driver_id_table, }; diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index d2f444d2ae78..e86b6a4896a6 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c @@ -1430,7 +1430,7 @@ struct regmap_config wm831x_regmap_config = { .reg_bits = 16, .val_bits = 16, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .max_register = WM831X_DBE_CHECK_DATA, .readable_reg = wm831x_reg_readable, diff --git a/drivers/mfd/wm831x-i2c.c b/drivers/mfd/wm831x-i2c.c index 9dbe96e2d46a..997837f13180 100644 --- a/drivers/mfd/wm831x-i2c.c +++ b/drivers/mfd/wm831x-i2c.c @@ -102,7 +102,7 @@ static struct i2c_driver wm831x_i2c_driver = { .of_match_table = of_match_ptr(wm831x_of_match), .suppress_bind_attrs = true, }, - .probe_new = wm831x_i2c_probe, + .probe = wm831x_i2c_probe, .id_table = wm831x_i2c_id, }; diff --git a/drivers/mfd/wm8350-i2c.c b/drivers/mfd/wm8350-i2c.c index 1fa1dfbc9e31..c2a7d7069975 100644 --- a/drivers/mfd/wm8350-i2c.c +++ b/drivers/mfd/wm8350-i2c.c @@ -52,7 +52,7 @@ static struct i2c_driver wm8350_i2c_driver = { .name = "wm8350", .suppress_bind_attrs = true, }, - .probe_new = wm8350_i2c_probe, + .probe = wm8350_i2c_probe, .id_table = wm8350_i2c_id, }; diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c index 5e1599ac9abc..75483c9be0c4 100644 --- a/drivers/mfd/wm8400-core.c +++ b/drivers/mfd/wm8400-core.c @@ -54,8 +54,6 @@ static int wm8400_init(struct wm8400 *wm8400, unsigned int reg; int ret; - dev_set_drvdata(wm8400->dev, wm8400); - /* Check that this is actually a WM8400 */ ret = regmap_read(wm8400->regmap, WM8400_RESET_ID, ®); if (ret != 0) { @@ -145,7 +143,7 @@ static struct i2c_driver wm8400_i2c_driver = { .driver = { .name = "WM8400", }, - .probe_new = wm8400_i2c_probe, + .probe = wm8400_i2c_probe, .id_table = wm8400_i2c_id, }; #endif diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index c419ab0c0eae..1e4f1694f065 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -320,8 +320,6 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) if (ret != 0) return ret; - dev_set_drvdata(wm8994->dev, wm8994); - /* Add the on-chip regulators first for bootstrapping */ ret = mfd_add_devices(wm8994->dev, 0, wm8994_regulator_devs, @@ -672,7 +670,7 @@ static struct i2c_driver wm8994_i2c_driver = { .pm = pm_ptr(&wm8994_pm_ops), .of_match_table = wm8994_of_match, }, - .probe_new = wm8994_i2c_probe, + .probe = wm8994_i2c_probe, .remove = wm8994_i2c_remove, .id_table = wm8994_i2c_id, }; diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index 4a5e8e1d1237..862f9fe93120 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -766,6 +766,14 @@ config BATTERY_RT5033 The fuelgauge calculates and determines the battery state of charge according to battery open circuit voltage. +config CHARGER_RT5033 + tristate "RT5033 battery charger support" + depends on MFD_RT5033 + help + This adds support for battery charger in Richtek RT5033 PMIC. + The device supports pre-charge mode, fast charge mode and + constant voltage mode. + config CHARGER_RT9455 tristate "Richtek RT9455 battery charger driver" depends on I2C diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile index 4adbfba02d05..dfc624bbcf1d 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile @@ -54,6 +54,7 @@ obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o obj-$(CONFIG_BATTERY_MAX1721X) += max1721x_battery.o obj-$(CONFIG_BATTERY_RT5033) += rt5033_battery.o +obj-$(CONFIG_CHARGER_RT5033) += rt5033_charger.o obj-$(CONFIG_CHARGER_RT9455) += rt9455_charger.o obj-$(CONFIG_CHARGER_RT9467) += rt9467-charger.o obj-$(CONFIG_CHARGER_RT9471) += rt9471.o diff --git a/drivers/power/supply/rt5033_battery.c b/drivers/power/supply/rt5033_battery.c index 5c04cf305219..94d2dea7ef5e 100644 --- a/drivers/power/supply/rt5033_battery.c +++ b/drivers/power/supply/rt5033_battery.c @@ -6,11 +6,33 @@ * Author: Beomho Seo <beomho.seo@samsung.com> */ +#include <linux/i2c.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/power_supply.h> +#include <linux/regmap.h> #include <linux/mfd/rt5033-private.h> -#include <linux/mfd/rt5033.h> + +struct rt5033_battery { + struct i2c_client *client; + struct regmap *regmap; + struct power_supply *psy; +}; + +static int rt5033_battery_get_status(struct i2c_client *client) +{ + struct rt5033_battery *battery = i2c_get_clientdata(client); + union power_supply_propval val; + int ret; + + ret = power_supply_get_property_from_supplier(battery->psy, + POWER_SUPPLY_PROP_STATUS, + &val); + if (ret) + val.intval = POWER_SUPPLY_STATUS_UNKNOWN; + + return val.intval; +} static int rt5033_battery_get_capacity(struct i2c_client *client) { @@ -84,6 +106,9 @@ static int rt5033_battery_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CAPACITY: val->intval = rt5033_battery_get_capacity(battery->client); break; + case POWER_SUPPLY_PROP_STATUS: + val->intval = rt5033_battery_get_status(battery->client); + break; default: return -EINVAL; } @@ -96,6 +121,7 @@ static enum power_supply_property rt5033_battery_props[] = { POWER_SUPPLY_PROP_VOLTAGE_OCV, POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_STATUS, }; static const struct regmap_config rt5033_battery_regmap_config = { @@ -117,7 +143,6 @@ static int rt5033_battery_probe(struct i2c_client *client) struct i2c_adapter *adapter = client->adapter; struct power_supply_config psy_cfg = {}; struct rt5033_battery *battery; - u32 ret; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) return -EIO; @@ -135,15 +160,14 @@ static int rt5033_battery_probe(struct i2c_client *client) } i2c_set_clientdata(client, battery); + psy_cfg.of_node = client->dev.of_node; psy_cfg.drv_data = battery; battery->psy = power_supply_register(&client->dev, &rt5033_battery_desc, &psy_cfg); - if (IS_ERR(battery->psy)) { - dev_err(&client->dev, "Failed to register power supply\n"); - ret = PTR_ERR(battery->psy); - return ret; - } + if (IS_ERR(battery->psy)) + return dev_err_probe(&client->dev, PTR_ERR(battery->psy), + "Failed to register power supply\n"); return 0; } diff --git a/drivers/power/supply/rt5033_charger.c b/drivers/power/supply/rt5033_charger.c new file mode 100644 index 000000000000..5218dfbf5e1b --- /dev/null +++ b/drivers/power/supply/rt5033_charger.c @@ -0,0 +1,472 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Battery charger driver for RT5033 + * + * Copyright (C) 2014 Samsung Electronics, Co., Ltd. + * Author: Beomho Seo <beomho.seo@samsung.com> + */ + +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/power_supply.h> +#include <linux/regmap.h> +#include <linux/mfd/rt5033-private.h> + +struct rt5033_charger_data { + unsigned int pre_uamp; + unsigned int pre_uvolt; + unsigned int const_uvolt; + unsigned int eoc_uamp; + unsigned int fast_uamp; +}; + +struct rt5033_charger { + struct device *dev; + struct regmap *regmap; + struct power_supply *psy; + struct rt5033_charger_data *chg; +}; + +static int rt5033_get_charger_state(struct rt5033_charger *charger) +{ + struct regmap *regmap = charger->regmap; + unsigned int reg_data; + int state; + + if (!regmap) + return POWER_SUPPLY_STATUS_UNKNOWN; + + regmap_read(regmap, RT5033_REG_CHG_STAT, ®_data); + + switch (reg_data & RT5033_CHG_STAT_MASK) { + case RT5033_CHG_STAT_DISCHARGING: + state = POWER_SUPPLY_STATUS_DISCHARGING; + break; + case RT5033_CHG_STAT_CHARGING: + state = POWER_SUPPLY_STATUS_CHARGING; + break; + case RT5033_CHG_STAT_FULL: + state = POWER_SUPPLY_STATUS_FULL; + break; + case RT5033_CHG_STAT_NOT_CHARGING: + state = POWER_SUPPLY_STATUS_NOT_CHARGING; + break; + default: + state = POWER_SUPPLY_STATUS_UNKNOWN; + } + + return state; +} + +static int rt5033_get_charger_type(struct rt5033_charger *charger) +{ + struct regmap *regmap = charger->regmap; + unsigned int reg_data; + int state; + + regmap_read(regmap, RT5033_REG_CHG_STAT, ®_data); + + switch (reg_data & RT5033_CHG_STAT_TYPE_MASK) { + case RT5033_CHG_STAT_TYPE_FAST: + state = POWER_SUPPLY_CHARGE_TYPE_FAST; + break; + case RT5033_CHG_STAT_TYPE_PRE: + state = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; + break; + default: + state = POWER_SUPPLY_CHARGE_TYPE_NONE; + } + + return state; +} + +static int rt5033_get_charger_current_limit(struct rt5033_charger *charger) +{ + struct regmap *regmap = charger->regmap; + unsigned int state, reg_data, data; + + regmap_read(regmap, RT5033_REG_CHG_CTRL5, ®_data); + + state = (reg_data & RT5033_CHGCTRL5_ICHG_MASK) + >> RT5033_CHGCTRL5_ICHG_SHIFT; + + data = RT5033_CHARGER_FAST_CURRENT_MIN + + RT5033_CHARGER_FAST_CURRENT_STEP_NUM * state; + + return data; +} + +static int rt5033_get_charger_const_voltage(struct rt5033_charger *charger) +{ + struct regmap *regmap = charger->regmap; + unsigned int state, reg_data, data; + + regmap_read(regmap, RT5033_REG_CHG_CTRL2, ®_data); + + state = (reg_data & RT5033_CHGCTRL2_CV_MASK) + >> RT5033_CHGCTRL2_CV_SHIFT; + + data = RT5033_CHARGER_CONST_VOLTAGE_LIMIT_MIN + + RT5033_CHARGER_CONST_VOLTAGE_STEP_NUM * state; + + return data; +} + +static inline int rt5033_init_const_charge(struct rt5033_charger *charger) +{ + struct rt5033_charger_data *chg = charger->chg; + int ret; + unsigned int val; + u8 reg_data; + + /* Set constant voltage mode */ + if (chg->const_uvolt < RT5033_CHARGER_CONST_VOLTAGE_LIMIT_MIN || + chg->const_uvolt > RT5033_CHARGER_CONST_VOLTAGE_LIMIT_MAX) { + dev_err(charger->dev, + "Value 'constant-charge-voltage-max-microvolt' out of range\n"); + return -EINVAL; + } + + if (chg->const_uvolt == RT5033_CHARGER_CONST_VOLTAGE_LIMIT_MIN) + reg_data = 0x00; + else if (chg->const_uvolt == RT5033_CHARGER_CONST_VOLTAGE_LIMIT_MAX) + reg_data = RT5033_CV_MAX_VOLTAGE; + else { + val = chg->const_uvolt; + val -= RT5033_CHARGER_CONST_VOLTAGE_LIMIT_MIN; + val /= RT5033_CHARGER_CONST_VOLTAGE_STEP_NUM; + reg_data = val; + } + + ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL2, + RT5033_CHGCTRL2_CV_MASK, + reg_data << RT5033_CHGCTRL2_CV_SHIFT); + if (ret) { + dev_err(charger->dev, "Failed regmap update\n"); + return -EINVAL; + } + + /* Set end of charge current */ + if (chg->eoc_uamp < RT5033_CHARGER_EOC_MIN || + chg->eoc_uamp > RT5033_CHARGER_EOC_MAX) { + dev_err(charger->dev, + "Value 'charge-term-current-microamp' out of range\n"); + return -EINVAL; + } + + if (chg->eoc_uamp == RT5033_CHARGER_EOC_MIN) + reg_data = 0x01; + else if (chg->eoc_uamp == RT5033_CHARGER_EOC_MAX) + reg_data = 0x07; + else { + val = chg->eoc_uamp; + if (val < RT5033_CHARGER_EOC_REF) { + val -= RT5033_CHARGER_EOC_MIN; + val /= RT5033_CHARGER_EOC_STEP_NUM1; + reg_data = 0x01 + val; + } else if (val > RT5033_CHARGER_EOC_REF) { + val -= RT5033_CHARGER_EOC_REF; + val /= RT5033_CHARGER_EOC_STEP_NUM2; + reg_data = 0x04 + val; + } else { + reg_data = 0x04; + } + } + + ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL4, + RT5033_CHGCTRL4_EOC_MASK, reg_data); + if (ret) { + dev_err(charger->dev, "Failed regmap update\n"); + return -EINVAL; + } + + return 0; +} + +static inline int rt5033_init_fast_charge(struct rt5033_charger *charger) +{ + struct rt5033_charger_data *chg = charger->chg; + int ret; + unsigned int val; + u8 reg_data; + + /* Set limit input current */ + ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL1, + RT5033_CHGCTRL1_IAICR_MASK, RT5033_AICR_2000_MODE); + if (ret) { + dev_err(charger->dev, "Failed regmap update\n"); + return -EINVAL; + } + + /* Set fast-charge mode charging current */ + if (chg->fast_uamp < RT5033_CHARGER_FAST_CURRENT_MIN || + chg->fast_uamp > RT5033_CHARGER_FAST_CURRENT_MAX) { + dev_err(charger->dev, + "Value 'constant-charge-current-max-microamp' out of range\n"); + return -EINVAL; + } + + if (chg->fast_uamp == RT5033_CHARGER_FAST_CURRENT_MIN) + reg_data = 0x00; + else if (chg->fast_uamp == RT5033_CHARGER_FAST_CURRENT_MAX) + reg_data = RT5033_CHG_MAX_CURRENT; + else { + val = chg->fast_uamp; + val -= RT5033_CHARGER_FAST_CURRENT_MIN; + val /= RT5033_CHARGER_FAST_CURRENT_STEP_NUM; + reg_data = val; + } + + ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL5, + RT5033_CHGCTRL5_ICHG_MASK, + reg_data << RT5033_CHGCTRL5_ICHG_SHIFT); + if (ret) { + dev_err(charger->dev, "Failed regmap update\n"); + return -EINVAL; + } + + return 0; +} + +static inline int rt5033_init_pre_charge(struct rt5033_charger *charger) +{ + struct rt5033_charger_data *chg = charger->chg; + int ret; + unsigned int val; + u8 reg_data; + + /* Set pre-charge threshold voltage */ + if (chg->pre_uvolt < RT5033_CHARGER_PRE_THRESHOLD_LIMIT_MIN || + chg->pre_uvolt > RT5033_CHARGER_PRE_THRESHOLD_LIMIT_MAX) { + dev_err(charger->dev, + "Value 'precharge-upper-limit-microvolt' out of range\n"); + return -EINVAL; + } + + if (chg->pre_uvolt == RT5033_CHARGER_PRE_THRESHOLD_LIMIT_MIN) + reg_data = 0x00; + else if (chg->pre_uvolt == RT5033_CHARGER_PRE_THRESHOLD_LIMIT_MAX) + reg_data = 0x0f; + else { + val = chg->pre_uvolt; + val -= RT5033_CHARGER_PRE_THRESHOLD_LIMIT_MIN; + val /= RT5033_CHARGER_PRE_THRESHOLD_STEP_NUM; + reg_data = val; + } + + ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL5, + RT5033_CHGCTRL5_VPREC_MASK, reg_data); + if (ret) { + dev_err(charger->dev, "Failed regmap update\n"); + return -EINVAL; + } + + /* Set pre-charge mode charging current */ + if (chg->pre_uamp < RT5033_CHARGER_PRE_CURRENT_LIMIT_MIN || + chg->pre_uamp > RT5033_CHARGER_PRE_CURRENT_LIMIT_MAX) { + dev_err(charger->dev, + "Value 'precharge-current-microamp' out of range\n"); + return -EINVAL; + } + + if (chg->pre_uamp == RT5033_CHARGER_PRE_CURRENT_LIMIT_MIN) + reg_data = 0x00; + else if (chg->pre_uamp == RT5033_CHARGER_PRE_CURRENT_LIMIT_MAX) + reg_data = RT5033_CHG_MAX_PRE_CURRENT; + else { + val = chg->pre_uamp; + val -= RT5033_CHARGER_PRE_CURRENT_LIMIT_MIN; + val /= RT5033_CHARGER_PRE_CURRENT_STEP_NUM; + reg_data = val; + } + + ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL4, + RT5033_CHGCTRL4_IPREC_MASK, + reg_data << RT5033_CHGCTRL4_IPREC_SHIFT); + if (ret) { + dev_err(charger->dev, "Failed regmap update\n"); + return -EINVAL; + } + + return 0; +} + +static int rt5033_charger_reg_init(struct rt5033_charger *charger) +{ + int ret = 0; + + /* Enable charging termination */ + ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL1, + RT5033_CHGCTRL1_TE_EN_MASK, RT5033_TE_ENABLE); + if (ret) { + dev_err(charger->dev, "Failed to enable charging termination.\n"); + return -EINVAL; + } + + /* + * Disable minimum input voltage regulation (MIVR), this improves + * the charging performance. + */ + ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL4, + RT5033_CHGCTRL4_MIVR_MASK, RT5033_CHARGER_MIVR_DISABLE); + if (ret) { + dev_err(charger->dev, "Failed to disable MIVR.\n"); + return -EINVAL; + } + + ret = rt5033_init_pre_charge(charger); + if (ret) + return ret; + + ret = rt5033_init_fast_charge(charger); + if (ret) + return ret; + + ret = rt5033_init_const_charge(charger); + if (ret) + return ret; + + return 0; +} + +static enum power_supply_property rt5033_charger_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_CHARGE_TYPE, + POWER_SUPPLY_PROP_CURRENT_MAX, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, + POWER_SUPPLY_PROP_MODEL_NAME, + POWER_SUPPLY_PROP_MANUFACTURER, + POWER_SUPPLY_PROP_ONLINE, +}; + +static int rt5033_charger_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct rt5033_charger *charger = power_supply_get_drvdata(psy); + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + val->intval = rt5033_get_charger_state(charger); + break; + case POWER_SUPPLY_PROP_CHARGE_TYPE: + val->intval = rt5033_get_charger_type(charger); + break; + case POWER_SUPPLY_PROP_CURRENT_MAX: + val->intval = rt5033_get_charger_current_limit(charger); + break; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: + val->intval = rt5033_get_charger_const_voltage(charger); + break; + case POWER_SUPPLY_PROP_MODEL_NAME: + val->strval = RT5033_CHARGER_MODEL; + break; + case POWER_SUPPLY_PROP_MANUFACTURER: + val->strval = RT5033_MANUFACTURER; + break; + case POWER_SUPPLY_PROP_ONLINE: + val->intval = (rt5033_get_charger_state(charger) == + POWER_SUPPLY_STATUS_CHARGING); + break; + default: + return -EINVAL; + } + + return 0; +} + +static struct rt5033_charger_data *rt5033_charger_dt_init( + struct rt5033_charger *charger) +{ + struct rt5033_charger_data *chg; + struct power_supply_battery_info *info; + int ret; + + chg = devm_kzalloc(charger->dev, sizeof(*chg), GFP_KERNEL); + if (!chg) + return ERR_PTR(-ENOMEM); + + ret = power_supply_get_battery_info(charger->psy, &info); + if (ret) + return ERR_PTR(dev_err_probe(charger->dev, -EINVAL, + "missing battery info\n")); + + /* Assign data. Validity will be checked in the init functions. */ + chg->pre_uamp = info->precharge_current_ua; + chg->fast_uamp = info->constant_charge_current_max_ua; + chg->eoc_uamp = info->charge_term_current_ua; + chg->pre_uvolt = info->precharge_voltage_max_uv; + chg->const_uvolt = info->constant_charge_voltage_max_uv; + + return chg; +} + +static const struct power_supply_desc rt5033_charger_desc = { + .name = "rt5033-charger", + .type = POWER_SUPPLY_TYPE_USB, + .properties = rt5033_charger_props, + .num_properties = ARRAY_SIZE(rt5033_charger_props), + .get_property = rt5033_charger_get_property, +}; + +static int rt5033_charger_probe(struct platform_device *pdev) +{ + struct rt5033_charger *charger; + struct power_supply_config psy_cfg = {}; + int ret; + + charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL); + if (!charger) + return -ENOMEM; + + platform_set_drvdata(pdev, charger); + charger->dev = &pdev->dev; + charger->regmap = dev_get_regmap(pdev->dev.parent, NULL); + + psy_cfg.of_node = pdev->dev.of_node; + psy_cfg.drv_data = charger; + + charger->psy = devm_power_supply_register(&pdev->dev, + &rt5033_charger_desc, + &psy_cfg); + if (IS_ERR(charger->psy)) + return dev_err_probe(&pdev->dev, PTR_ERR(charger->psy), + "Failed to register power supply\n"); + + charger->chg = rt5033_charger_dt_init(charger); + if (IS_ERR_OR_NULL(charger->chg)) + return PTR_ERR(charger->chg); + + ret = rt5033_charger_reg_init(charger); + if (ret) + return ret; + + return 0; +} + +static const struct platform_device_id rt5033_charger_id[] = { + { "rt5033-charger", }, + { } +}; +MODULE_DEVICE_TABLE(platform, rt5033_charger_id); + +static const struct of_device_id rt5033_charger_of_match[] = { + { .compatible = "richtek,rt5033-charger", }, + { } +}; +MODULE_DEVICE_TABLE(of, rt5033_charger_of_match); + +static struct platform_driver rt5033_charger_driver = { + .driver = { + .name = "rt5033-charger", + .of_match_table = rt5033_charger_of_match, + }, + .probe = rt5033_charger_probe, + .id_table = rt5033_charger_id, +}; +module_platform_driver(rt5033_charger_driver); + +MODULE_DESCRIPTION("Richtek RT5033 charger driver"); +MODULE_AUTHOR("Beomho Seo <beomho.seo@samsung.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 2c2405024ace..08d33290296b 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -556,6 +556,17 @@ config REGULATOR_MAX597X The MAX5970/5978 is a smart switch with no output regulation, but fault protection and voltage and current monitoring capabilities. +config REGULATOR_MAX77541 + tristate "Analog Devices MAX77541/77540 Regulator" + depends on MFD_MAX77541 + help + This driver controls a Analog Devices MAX77541/77540 regulators + via I2C bus. Both MAX77540 and MAX77541 are dual-phase + high-efficiency buck converter. Say Y here to + enable the regulator driver. + Say M here if you want to include support for the regulator as a + module. + config REGULATOR_MAX77620 tristate "Maxim 77620/MAX20024 voltage regulator" depends on MFD_MAX77620 || COMPILE_TEST diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index ebfa75379c20..15e0d614ff66 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -68,6 +68,7 @@ obj-$(CONFIG_REGULATOR_LTC3676) += ltc3676.o obj-$(CONFIG_REGULATOR_MAX14577) += max14577-regulator.o obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o obj-$(CONFIG_REGULATOR_MAX597X) += max597x-regulator.o +obj-$(CONFIG_REGULATOR_MAX77541) += max77541-regulator.o obj-$(CONFIG_REGULATOR_MAX77620) += max77620-regulator.o obj-$(CONFIG_REGULATOR_MAX77650) += max77650-regulator.o obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o diff --git a/drivers/regulator/max77541-regulator.c b/drivers/regulator/max77541-regulator.c new file mode 100644 index 000000000000..2976f9cb3e26 --- /dev/null +++ b/drivers/regulator/max77541-regulator.c @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 Analog Devices, Inc. + * ADI Regulator driver for the MAX77540 and MAX77541 + */ + +#include <linux/mfd/max77541.h> +#include <linux/mod_devicetable.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> + +static const struct regulator_ops max77541_buck_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_pickable_linear_range, + .get_voltage_sel = regulator_get_voltage_sel_pickable_regmap, + .set_voltage_sel = regulator_set_voltage_sel_pickable_regmap, +}; + +static const struct linear_range max77540_buck_ranges[] = { + /* Ranges when VOLT_SEL bits are 0x00 */ + REGULATOR_LINEAR_RANGE(500000, 0x00, 0x8B, 5000), + REGULATOR_LINEAR_RANGE(1200000, 0x8C, 0xFF, 0), + /* Ranges when VOLT_SEL bits are 0x40 */ + REGULATOR_LINEAR_RANGE(1200000, 0x00, 0x8B, 10000), + REGULATOR_LINEAR_RANGE(2400000, 0x8C, 0xFF, 0), + /* Ranges when VOLT_SEL bits are 0x80 */ + REGULATOR_LINEAR_RANGE(2000000, 0x00, 0x9F, 20000), + REGULATOR_LINEAR_RANGE(5200000, 0xA0, 0xFF, 0), +}; + +static const struct linear_range max77541_buck_ranges[] = { + /* Ranges when VOLT_SEL bits are 0x00 */ + REGULATOR_LINEAR_RANGE(300000, 0x00, 0xB3, 5000), + REGULATOR_LINEAR_RANGE(1200000, 0xB4, 0xFF, 0), + /* Ranges when VOLT_SEL bits are 0x40 */ + REGULATOR_LINEAR_RANGE(1200000, 0x00, 0x8B, 10000), + REGULATOR_LINEAR_RANGE(2400000, 0x8C, 0xFF, 0), + /* Ranges when VOLT_SEL bits are 0x80 */ + REGULATOR_LINEAR_RANGE(2000000, 0x00, 0x9F, 20000), + REGULATOR_LINEAR_RANGE(5200000, 0xA0, 0xFF, 0), +}; + +static const unsigned int max77541_buck_volt_range_sel[] = { + 0x00, 0x00, 0x40, 0x40, 0x80, 0x80, +}; + +enum max77541_regulators { + MAX77541_BUCK1 = 1, + MAX77541_BUCK2, +}; + +#define MAX77540_BUCK(_id, _ops) \ + { .id = MAX77541_BUCK ## _id, \ + .name = "buck"#_id, \ + .of_match = "buck"#_id, \ + .regulators_node = "regulators", \ + .enable_reg = MAX77541_REG_EN_CTRL, \ + .enable_mask = MAX77541_BIT_M ## _id ## _EN, \ + .ops = &(_ops), \ + .type = REGULATOR_VOLTAGE, \ + .linear_ranges = max77540_buck_ranges, \ + .n_linear_ranges = ARRAY_SIZE(max77540_buck_ranges), \ + .vsel_reg = MAX77541_REG_M ## _id ## _VOUT, \ + .vsel_mask = MAX77541_BITS_MX_VOUT, \ + .vsel_range_reg = MAX77541_REG_M ## _id ## _CFG1, \ + .vsel_range_mask = MAX77541_BITS_MX_CFG1_RNG, \ + .linear_range_selectors = max77541_buck_volt_range_sel, \ + .owner = THIS_MODULE, \ + } + +#define MAX77541_BUCK(_id, _ops) \ + { .id = MAX77541_BUCK ## _id, \ + .name = "buck"#_id, \ + .of_match = "buck"#_id, \ + .regulators_node = "regulators", \ + .enable_reg = MAX77541_REG_EN_CTRL, \ + .enable_mask = MAX77541_BIT_M ## _id ## _EN, \ + .ops = &(_ops), \ + .type = REGULATOR_VOLTAGE, \ + .linear_ranges = max77541_buck_ranges, \ + .n_linear_ranges = ARRAY_SIZE(max77541_buck_ranges), \ + .vsel_reg = MAX77541_REG_M ## _id ## _VOUT, \ + .vsel_mask = MAX77541_BITS_MX_VOUT, \ + .vsel_range_reg = MAX77541_REG_M ## _id ## _CFG1, \ + .vsel_range_mask = MAX77541_BITS_MX_CFG1_RNG, \ + .linear_range_selectors = max77541_buck_volt_range_sel, \ + .owner = THIS_MODULE, \ + } + +static const struct regulator_desc max77540_regulators_desc[] = { + MAX77540_BUCK(1, max77541_buck_ops), + MAX77540_BUCK(2, max77541_buck_ops), +}; + +static const struct regulator_desc max77541_regulators_desc[] = { + MAX77541_BUCK(1, max77541_buck_ops), + MAX77541_BUCK(2, max77541_buck_ops), +}; + +static int max77541_regulator_probe(struct platform_device *pdev) +{ + struct regulator_config config = {}; + const struct regulator_desc *desc; + struct device *dev = &pdev->dev; + struct regulator_dev *rdev; + struct max77541 *max77541 = dev_get_drvdata(dev->parent); + unsigned int i; + + config.dev = dev->parent; + + switch (max77541->id) { + case MAX77540: + desc = max77540_regulators_desc; + break; + case MAX77541: + desc = max77541_regulators_desc; + break; + default: + return -EINVAL; + } + + for (i = 0; i < MAX77541_MAX_REGULATORS; i++) { + rdev = devm_regulator_register(dev, &desc[i], &config); + if (IS_ERR(rdev)) + return dev_err_probe(dev, PTR_ERR(rdev), + "Failed to register regulator\n"); + } + + return 0; +} + +static const struct platform_device_id max77541_regulator_platform_id[] = { + { "max77540-regulator" }, + { "max77541-regulator" }, + { } +}; +MODULE_DEVICE_TABLE(platform, max77541_regulator_platform_id); + +static struct platform_driver max77541_regulator_driver = { + .driver = { + .name = "max77541-regulator", + }, + .probe = max77541_regulator_probe, + .id_table = max77541_regulator_platform_id, +}; +module_platform_driver(max77541_regulator_driver); + +MODULE_AUTHOR("Okan Sahin <Okan.Sahin@analog.com>"); +MODULE_DESCRIPTION("MAX77540/MAX77541 regulator driver"); +MODULE_LICENSE("GPL"); |