diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-08-31 15:49:19 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-08-31 15:49:19 -0700 |
commit | cf9d615f7f5842ca1ef0f28ed9f67a97d20cf6fc (patch) | |
tree | e380861c807152427a21fce9ee669d87900f6634 /drivers | |
parent | e2701603f72cd38e99c6b1da13c8e99bc27b2f34 (diff) | |
parent | f5164b8833498825b3197cb34150b142a9fc5bbf (diff) |
Merge tag 'regulator-v4.3' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator
Pull regulator updates from Mark Brown:
"The biggest changes in the core this time around have been some
refactorings that move us towards being able to drop the list of
regulators maintained by the core and instead just use the driver
model list maintained for the class devices for regulators which will
make the code smaller and avoid some potential bugs.
Otherwise another fairly quiet release for the regulator API,
highlights include:
- a new API for setting voltages based on a minimum, target, maximum
triplet
- support for continuous voltage ranges rather than tables of
explicit steps in the PWM regulator, requiring less explicit
configuration
- new driver support for Dialog DA9215, Maxim 77843, Mediatek MT6311
and Qualcomm RPM"
* tag 'regulator-v4.3' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator: (70 commits)
regulator: mt6311: fix platform_no_drv_owner.cocci warnings
regulator: ltc3589: Remove unnecessary MODULE_ALIAS()
regulator: ad5398: Remove unnecessary MODULE_ALIAS()
regulator: pfuze100: Remove unnecessary MODULE_ALIAS()
regulator: core: use debug level print in regulator_check_drms
regulator: lp872x: handle error case
regulator: lp872x: use the private data instead of updating I2C device platform data
regulator: isl9305: Export OF module alias information
regulators: max77693: register driver earlier to avoid deferred probe
regulator: qcom_smd: Set n_voltages for pm8941_lnldo
regulator: core: Use IS_ERR_OR_NULL()
regulator: core: Define regulator_set_voltage_triplet()
regulator: Regulator driver for the Qualcomm RPM
regulator: pbias: Fix broken pbias disable functionality
regulator: core: Spelling fix
regulator: core: Use class device list for regulator_list in late init
regulator: core: Move more deallocation into class unregister
regulator: core: Reduce rdev locking region when releasing regulator
Input: Remove the max77843 haptic driver
Input: max77693: Add support for Maxim 77843
...
Diffstat (limited to 'drivers')
46 files changed, 1876 insertions, 1044 deletions
diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c index f4f3b3d53928..35b9e118b2fb 100644 --- a/drivers/extcon/extcon-max77693.c +++ b/drivers/extcon/extcon-max77693.c @@ -24,6 +24,7 @@ #include <linux/err.h> #include <linux/platform_device.h> #include <linux/mfd/max77693.h> +#include <linux/mfd/max77693-common.h> #include <linux/mfd/max77693-private.h> #include <linux/extcon.h> #include <linux/regmap.h> @@ -42,7 +43,7 @@ static struct max77693_reg_data default_init_data[] = { { /* STATUS2 - [3]ChgDetRun */ .addr = MAX77693_MUIC_REG_STATUS2, - .data = STATUS2_CHGDETRUN_MASK, + .data = MAX77693_STATUS2_CHGDETRUN_MASK, }, { /* INTMASK1 - Unmask [3]ADC1KM,[0]ADCM */ .addr = MAX77693_MUIC_REG_INTMASK1, @@ -235,7 +236,7 @@ static int max77693_muic_set_debounce_time(struct max77693_muic_info *info, */ ret = regmap_write(info->max77693->regmap_muic, MAX77693_MUIC_REG_CTRL3, - time << CONTROL3_ADCDBSET_SHIFT); + time << MAX77693_CONTROL3_ADCDBSET_SHIFT); if (ret) { dev_err(info->dev, "failed to set ADC debounce time\n"); return ret; @@ -268,7 +269,7 @@ static int max77693_muic_set_path(struct max77693_muic_info *info, if (attached) ctrl1 = val; else - ctrl1 = CONTROL1_SW_OPEN; + ctrl1 = MAX77693_CONTROL1_SW_OPEN; ret = regmap_update_bits(info->max77693->regmap_muic, MAX77693_MUIC_REG_CTRL1, COMP_SW_MASK, ctrl1); @@ -278,13 +279,14 @@ static int max77693_muic_set_path(struct max77693_muic_info *info, } if (attached) - ctrl2 |= CONTROL2_CPEN_MASK; /* LowPwr=0, CPEn=1 */ + ctrl2 |= MAX77693_CONTROL2_CPEN_MASK; /* LowPwr=0, CPEn=1 */ else - ctrl2 |= CONTROL2_LOWPWR_MASK; /* LowPwr=1, CPEn=0 */ + ctrl2 |= MAX77693_CONTROL2_LOWPWR_MASK; /* LowPwr=1, CPEn=0 */ ret = regmap_update_bits(info->max77693->regmap_muic, MAX77693_MUIC_REG_CTRL2, - CONTROL2_LOWPWR_MASK | CONTROL2_CPEN_MASK, ctrl2); + MAX77693_CONTROL2_LOWPWR_MASK | MAX77693_CONTROL2_CPEN_MASK, + ctrl2); if (ret < 0) { dev_err(info->dev, "failed to update MUIC register\n"); return ret; @@ -326,8 +328,8 @@ static int max77693_muic_get_cable_type(struct max77693_muic_info *info, * Read ADC value to check cable type and decide cable state * according to cable type */ - adc = info->status[0] & STATUS1_ADC_MASK; - adc >>= STATUS1_ADC_SHIFT; + adc = info->status[0] & MAX77693_STATUS1_ADC_MASK; + adc >>= MAX77693_STATUS1_ADC_SHIFT; /* * Check current cable state/cable type and store cable type @@ -350,8 +352,8 @@ static int max77693_muic_get_cable_type(struct max77693_muic_info *info, * Read ADC value to check cable type and decide cable state * according to cable type */ - adc = info->status[0] & STATUS1_ADC_MASK; - adc >>= STATUS1_ADC_SHIFT; + adc = info->status[0] & MAX77693_STATUS1_ADC_MASK; + adc >>= MAX77693_STATUS1_ADC_SHIFT; /* * Check current cable state/cable type and store cable type @@ -366,13 +368,13 @@ static int max77693_muic_get_cable_type(struct max77693_muic_info *info, } else { *attached = true; - adclow = info->status[0] & STATUS1_ADCLOW_MASK; - adclow >>= STATUS1_ADCLOW_SHIFT; - adc1k = info->status[0] & STATUS1_ADC1K_MASK; - adc1k >>= STATUS1_ADC1K_SHIFT; + adclow = info->status[0] & MAX77693_STATUS1_ADCLOW_MASK; + adclow >>= MAX77693_STATUS1_ADCLOW_SHIFT; + adc1k = info->status[0] & MAX77693_STATUS1_ADC1K_MASK; + adc1k >>= MAX77693_STATUS1_ADC1K_SHIFT; - vbvolt = info->status[1] & STATUS2_VBVOLT_MASK; - vbvolt >>= STATUS2_VBVOLT_SHIFT; + vbvolt = info->status[1] & MAX77693_STATUS2_VBVOLT_MASK; + vbvolt >>= MAX77693_STATUS2_VBVOLT_SHIFT; /** * [0x1|VBVolt|ADCLow|ADC1K] @@ -397,8 +399,8 @@ static int max77693_muic_get_cable_type(struct max77693_muic_info *info, * Read charger type to check cable type and decide cable state * according to type of charger cable. */ - chg_type = info->status[1] & STATUS2_CHGTYP_MASK; - chg_type >>= STATUS2_CHGTYP_SHIFT; + chg_type = info->status[1] & MAX77693_STATUS2_CHGTYP_MASK; + chg_type >>= MAX77693_STATUS2_CHGTYP_SHIFT; if (chg_type == MAX77693_CHARGER_TYPE_NONE) { *attached = false; @@ -422,10 +424,10 @@ static int max77693_muic_get_cable_type(struct max77693_muic_info *info, * Read ADC value to check cable type and decide cable state * according to cable type */ - adc = info->status[0] & STATUS1_ADC_MASK; - adc >>= STATUS1_ADC_SHIFT; - chg_type = info->status[1] & STATUS2_CHGTYP_MASK; - chg_type >>= STATUS2_CHGTYP_SHIFT; + adc = info->status[0] & MAX77693_STATUS1_ADC_MASK; + adc >>= MAX77693_STATUS1_ADC_SHIFT; + chg_type = info->status[1] & MAX77693_STATUS2_CHGTYP_MASK; + chg_type >>= MAX77693_STATUS2_CHGTYP_SHIFT; if (adc == MAX77693_MUIC_ADC_OPEN && chg_type == MAX77693_CHARGER_TYPE_NONE) @@ -437,8 +439,8 @@ static int max77693_muic_get_cable_type(struct max77693_muic_info *info, * Read vbvolt field, if vbvolt is 1, * this cable is used for charging. */ - vbvolt = info->status[1] & STATUS2_VBVOLT_MASK; - vbvolt >>= STATUS2_VBVOLT_SHIFT; + vbvolt = info->status[1] & MAX77693_STATUS2_VBVOLT_MASK; + vbvolt >>= MAX77693_STATUS2_VBVOLT_SHIFT; cable_type = vbvolt; break; @@ -520,7 +522,8 @@ static int max77693_muic_dock_handler(struct max77693_muic_info *info, } /* Dock-Car/Desk/Audio, PATH:AUDIO */ - ret = max77693_muic_set_path(info, CONTROL1_SW_AUDIO, attached); + ret = max77693_muic_set_path(info, MAX77693_CONTROL1_SW_AUDIO, + attached); if (ret < 0) return ret; extcon_set_cable_state_(info->edev, dock_id, attached); @@ -585,14 +588,16 @@ static int max77693_muic_adc_ground_handler(struct max77693_muic_info *info) case MAX77693_MUIC_GND_USB_HOST: case MAX77693_MUIC_GND_USB_HOST_VB: /* USB_HOST, PATH: AP_USB */ - ret = max77693_muic_set_path(info, CONTROL1_SW_USB, attached); + ret = max77693_muic_set_path(info, MAX77693_CONTROL1_SW_USB, + attached); if (ret < 0) return ret; extcon_set_cable_state_(info->edev, EXTCON_USB_HOST, attached); break; case MAX77693_MUIC_GND_AV_CABLE_LOAD: /* Audio Video Cable with load, PATH:AUDIO */ - ret = max77693_muic_set_path(info, CONTROL1_SW_AUDIO, attached); + ret = max77693_muic_set_path(info, MAX77693_CONTROL1_SW_AUDIO, + attached); if (ret < 0) return ret; extcon_set_cable_state_(info->edev, EXTCON_USB, attached); @@ -615,7 +620,7 @@ static int max77693_muic_jig_handler(struct max77693_muic_info *info, int cable_type, bool attached) { int ret = 0; - u8 path = CONTROL1_SW_OPEN; + u8 path = MAX77693_CONTROL1_SW_OPEN; dev_info(info->dev, "external connector is %s (adc:0x%02x)\n", @@ -625,12 +630,12 @@ static int max77693_muic_jig_handler(struct max77693_muic_info *info, case MAX77693_MUIC_ADC_FACTORY_MODE_USB_OFF: /* ADC_JIG_USB_OFF */ case MAX77693_MUIC_ADC_FACTORY_MODE_USB_ON: /* ADC_JIG_USB_ON */ /* PATH:AP_USB */ - path = CONTROL1_SW_USB; + path = MAX77693_CONTROL1_SW_USB; break; case MAX77693_MUIC_ADC_FACTORY_MODE_UART_OFF: /* ADC_JIG_UART_OFF */ case MAX77693_MUIC_ADC_FACTORY_MODE_UART_ON: /* ADC_JIG_UART_ON */ /* PATH:AP_UART */ - path = CONTROL1_SW_UART; + path = MAX77693_CONTROL1_SW_UART; break; default: dev_err(info->dev, "failed to detect %s jig cable\n", @@ -1077,7 +1082,7 @@ static int max77693_muic_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "allocate register map\n"); } else { info->max77693->regmap_muic = devm_regmap_init_i2c( - info->max77693->muic, + info->max77693->i2c_muic, &max77693_muic_regmap_config); if (IS_ERR(info->max77693->regmap_muic)) { ret = PTR_ERR(info->max77693->regmap_muic); @@ -1164,28 +1169,9 @@ static int max77693_muic_probe(struct platform_device *pdev) } for (i = 0; i < num_init_data; i++) { - enum max77693_irq_source irq_src - = MAX77693_IRQ_GROUP_NR; - regmap_write(info->max77693->regmap_muic, init_data[i].addr, init_data[i].data); - - switch (init_data[i].addr) { - case MAX77693_MUIC_REG_INTMASK1: - irq_src = MUIC_INT1; - break; - case MAX77693_MUIC_REG_INTMASK2: - irq_src = MUIC_INT2; - break; - case MAX77693_MUIC_REG_INTMASK3: - irq_src = MUIC_INT3; - break; - } - - if (irq_src < MAX77693_IRQ_GROUP_NR) - info->max77693->irq_masks_cur[irq_src] - = init_data[i].data; } if (pdata && pdata->muic_data) { @@ -1199,12 +1185,12 @@ static int max77693_muic_probe(struct platform_device *pdev) if (muic_pdata->path_uart) info->path_uart = muic_pdata->path_uart; else - info->path_uart = CONTROL1_SW_UART; + info->path_uart = MAX77693_CONTROL1_SW_UART; if (muic_pdata->path_usb) info->path_usb = muic_pdata->path_usb; else - info->path_usb = CONTROL1_SW_USB; + info->path_usb = MAX77693_CONTROL1_SW_USB; /* * Default delay time for detecting cable state @@ -1216,8 +1202,8 @@ static int max77693_muic_probe(struct platform_device *pdev) else delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT); } else { - info->path_usb = CONTROL1_SW_USB; - info->path_uart = CONTROL1_SW_UART; + info->path_usb = MAX77693_CONTROL1_SW_USB; + info->path_uart = MAX77693_CONTROL1_SW_UART; delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT); } diff --git a/drivers/extcon/extcon-max77843.c b/drivers/extcon/extcon-max77843.c index cc5e7bca38c8..fdd928542c19 100644 --- a/drivers/extcon/extcon-max77843.c +++ b/drivers/extcon/extcon-max77843.c @@ -15,6 +15,7 @@ #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/kernel.h> +#include <linux/mfd/max77693-common.h> #include <linux/mfd/max77843-private.h> #include <linux/module.h> #include <linux/platform_device.h> @@ -32,7 +33,7 @@ enum max77843_muic_status { struct max77843_muic_info { struct device *dev; - struct max77843 *max77843; + struct max77693_dev *max77843; struct extcon_dev *edev; struct mutex mutex; @@ -198,18 +199,18 @@ static const struct regmap_irq_chip max77843_muic_irq_chip = { static int max77843_muic_set_path(struct max77843_muic_info *info, u8 val, bool attached) { - struct max77843 *max77843 = info->max77843; + struct max77693_dev *max77843 = info->max77843; int ret = 0; unsigned int ctrl1, ctrl2; if (attached) ctrl1 = val; else - ctrl1 = CONTROL1_SW_OPEN; + ctrl1 = MAX77843_MUIC_CONTROL1_SW_OPEN; ret = regmap_update_bits(max77843->regmap_muic, MAX77843_MUIC_REG_CONTROL1, - CONTROL1_COM_SW, ctrl1); + MAX77843_MUIC_CONTROL1_COM_SW, ctrl1); if (ret < 0) { dev_err(info->dev, "Cannot switch MUIC port\n"); return ret; @@ -243,7 +244,7 @@ static int max77843_muic_get_cable_type(struct max77843_muic_info *info, adc = info->status[MAX77843_MUIC_STATUS1] & MAX77843_MUIC_STATUS1_ADC_MASK; - adc >>= STATUS1_ADC_SHIFT; + adc >>= MAX77843_MUIC_STATUS1_ADC_SHIFT; switch (group) { case MAX77843_CABLE_GROUP_ADC: @@ -309,7 +310,7 @@ static int max77843_muic_get_cable_type(struct max77843_muic_info *info, /* Get VBVolt register bit */ gnd_type |= (info->status[MAX77843_MUIC_STATUS2] & MAX77843_MUIC_STATUS2_VBVOLT_MASK); - gnd_type >>= STATUS2_VBVOLT_SHIFT; + gnd_type >>= MAX77843_MUIC_STATUS2_VBVOLT_SHIFT; /* Offset of GND cable */ gnd_type |= MAX77843_MUIC_GND_USB_HOST; @@ -338,7 +339,9 @@ static int max77843_muic_adc_gnd_handler(struct max77843_muic_info *info) switch (gnd_cable_type) { case MAX77843_MUIC_GND_USB_HOST: case MAX77843_MUIC_GND_USB_HOST_VB: - ret = max77843_muic_set_path(info, CONTROL1_SW_USB, attached); + ret = max77843_muic_set_path(info, + MAX77843_MUIC_CONTROL1_SW_USB, + attached); if (ret < 0) return ret; @@ -346,7 +349,9 @@ static int max77843_muic_adc_gnd_handler(struct max77843_muic_info *info) break; case MAX77843_MUIC_GND_MHL_VB: case MAX77843_MUIC_GND_MHL: - ret = max77843_muic_set_path(info, CONTROL1_SW_OPEN, attached); + ret = max77843_muic_set_path(info, + MAX77843_MUIC_CONTROL1_SW_OPEN, + attached); if (ret < 0) return ret; @@ -365,7 +370,7 @@ static int max77843_muic_jig_handler(struct max77843_muic_info *info, int cable_type, bool attached) { int ret; - u8 path = CONTROL1_SW_OPEN; + u8 path = MAX77843_MUIC_CONTROL1_SW_OPEN; dev_dbg(info->dev, "external connector is %s (adc:0x%02x)\n", attached ? "attached" : "detached", cable_type); @@ -373,10 +378,10 @@ static int max77843_muic_jig_handler(struct max77843_muic_info *info, switch (cable_type) { case MAX77843_MUIC_ADC_FACTORY_MODE_USB_OFF: case MAX77843_MUIC_ADC_FACTORY_MODE_USB_ON: - path = CONTROL1_SW_USB; + path = MAX77843_MUIC_CONTROL1_SW_USB; break; case MAX77843_MUIC_ADC_FACTORY_MODE_UART_OFF: - path = CONTROL1_SW_UART; + path = MAX77843_MUIC_CONTROL1_SW_UART; break; default: return -EINVAL; @@ -474,14 +479,18 @@ static int max77843_muic_chg_handler(struct max77843_muic_info *info) switch (chg_type) { case MAX77843_MUIC_CHG_USB: - ret = max77843_muic_set_path(info, CONTROL1_SW_USB, attached); + ret = max77843_muic_set_path(info, + MAX77843_MUIC_CONTROL1_SW_USB, + attached); if (ret < 0) return ret; extcon_set_cable_state_(info->edev, EXTCON_USB, attached); break; case MAX77843_MUIC_CHG_DOWNSTREAM: - ret = max77843_muic_set_path(info, CONTROL1_SW_OPEN, attached); + ret = max77843_muic_set_path(info, + MAX77843_MUIC_CONTROL1_SW_OPEN, + attached); if (ret < 0) return ret; @@ -489,14 +498,18 @@ static int max77843_muic_chg_handler(struct max77843_muic_info *info) attached); break; case MAX77843_MUIC_CHG_DEDICATED: - ret = max77843_muic_set_path(info, CONTROL1_SW_OPEN, attached); + ret = max77843_muic_set_path(info, + MAX77843_MUIC_CONTROL1_SW_OPEN, + attached); if (ret < 0) return ret; extcon_set_cable_state_(info->edev, EXTCON_TA, attached); break; case MAX77843_MUIC_CHG_SPECIAL_500MA: - ret = max77843_muic_set_path(info, CONTROL1_SW_OPEN, attached); + ret = max77843_muic_set_path(info, + MAX77843_MUIC_CONTROL1_SW_OPEN, + attached); if (ret < 0) return ret; @@ -504,7 +517,9 @@ static int max77843_muic_chg_handler(struct max77843_muic_info *info) attached); break; case MAX77843_MUIC_CHG_SPECIAL_1A: - ret = max77843_muic_set_path(info, CONTROL1_SW_OPEN, attached); + ret = max77843_muic_set_path(info, + MAX77843_MUIC_CONTROL1_SW_OPEN, + attached); if (ret < 0) return ret; @@ -528,7 +543,8 @@ static int max77843_muic_chg_handler(struct max77843_muic_info *info) "failed to detect %s accessory (chg_type:0x%x)\n", attached ? "attached" : "detached", chg_type); - max77843_muic_set_path(info, CONTROL1_SW_OPEN, attached); + max77843_muic_set_path(info, MAX77843_MUIC_CONTROL1_SW_OPEN, + attached); return -EINVAL; } @@ -539,7 +555,7 @@ static void max77843_muic_irq_work(struct work_struct *work) { struct max77843_muic_info *info = container_of(work, struct max77843_muic_info, irq_work); - struct max77843 *max77843 = info->max77843; + struct max77693_dev *max77843 = info->max77843; int ret = 0; mutex_lock(&info->mutex); @@ -615,7 +631,7 @@ static void max77843_muic_detect_cable_wq(struct work_struct *work) { struct max77843_muic_info *info = container_of(to_delayed_work(work), struct max77843_muic_info, wq_detcable); - struct max77843 *max77843 = info->max77843; + struct max77693_dev *max77843 = info->max77843; int chg_type, adc, ret; bool attached; @@ -656,7 +672,7 @@ err_cable_wq: static int max77843_muic_set_debounce_time(struct max77843_muic_info *info, enum max77843_muic_adc_debounce_time time) { - struct max77843 *max77843 = info->max77843; + struct max77693_dev *max77843 = info->max77843; int ret; switch (time) { @@ -667,7 +683,7 @@ static int max77843_muic_set_debounce_time(struct max77843_muic_info *info, ret = regmap_update_bits(max77843->regmap_muic, MAX77843_MUIC_REG_CONTROL4, MAX77843_MUIC_CONTROL4_ADCDBSET_MASK, - time << CONTROL4_ADCDBSET_SHIFT); + time << MAX77843_MUIC_CONTROL4_ADCDBSET_SHIFT); if (ret < 0) { dev_err(info->dev, "Cannot write MUIC regmap\n"); return ret; @@ -681,7 +697,7 @@ static int max77843_muic_set_debounce_time(struct max77843_muic_info *info, return 0; } -static int max77843_init_muic_regmap(struct max77843 *max77843) +static int max77843_init_muic_regmap(struct max77693_dev *max77843) { int ret; @@ -720,7 +736,7 @@ err_muic_i2c: static int max77843_muic_probe(struct platform_device *pdev) { - struct max77843 *max77843 = dev_get_drvdata(pdev->dev.parent); + struct max77693_dev *max77843 = dev_get_drvdata(pdev->dev.parent); struct max77843_muic_info *info; unsigned int id; int i, ret; @@ -768,7 +784,7 @@ static int max77843_muic_probe(struct platform_device *pdev) max77843_muic_set_debounce_time(info, MAX77843_DEBOUNCE_TIME_25MS); /* Set initial path for UART */ - max77843_muic_set_path(info, CONTROL1_SW_UART, true); + max77843_muic_set_path(info, MAX77843_MUIC_CONTROL1_SW_UART, true); /* Check revision number of MUIC device */ ret = regmap_read(max77843->regmap_muic, MAX77843_MUIC_REG_ID, &id); @@ -830,7 +846,7 @@ err_muic_irq: static int max77843_muic_remove(struct platform_device *pdev) { struct max77843_muic_info *info = platform_get_drvdata(pdev); - struct max77843 *max77843 = info->max77843; + struct max77693_dev *max77843 = info->max77843; cancel_work_sync(&info->irq_work); regmap_del_irq_chip(max77843->irq, max77843->irq_data_muic); diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index d4f0a817e858..c41dec819cdf 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -167,28 +167,16 @@ config INPUT_M68K_BEEP depends on M68K config INPUT_MAX77693_HAPTIC - tristate "MAXIM MAX77693 haptic controller support" - depends on MFD_MAX77693 && PWM + tristate "MAXIM MAX77693/MAX77843 haptic controller support" + depends on (MFD_MAX77693 || MFD_MAX77843) && PWM select INPUT_FF_MEMLESS help This option enables support for the haptic controller on - MAXIM MAX77693 chip. + MAXIM MAX77693 and MAX77843 chips. To compile this driver as module, choose M here: the module will be called max77693-haptic. -config INPUT_MAX77843_HAPTIC - tristate "MAXIM MAX77843 haptic controller support" - depends on MFD_MAX77843 && REGULATOR - select INPUT_FF_MEMLESS - help - This option enables support for the haptic controller on - MAXIM MAX77843 chip. The driver supports ff-memless interface - from input framework. - - To compile this driver as module, choose M here: the - module will be called max77843-haptic. - config INPUT_MAX8925_ONKEY tristate "MAX8925 ONKEY support" depends on MFD_MAX8925 diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 53df07dcc23c..0357a088c6a9 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -41,7 +41,6 @@ obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o obj-$(CONFIG_INPUT_MAX77693_HAPTIC) += max77693-haptic.o -obj-$(CONFIG_INPUT_MAX77843_HAPTIC) += max77843-haptic.o obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o obj-$(CONFIG_INPUT_MAX8997_HAPTIC) += max8997_haptic.o obj-$(CONFIG_INPUT_MC13783_PWRBUTTON) += mc13783-pwrbutton.o diff --git a/drivers/input/misc/max77693-haptic.c b/drivers/input/misc/max77693-haptic.c index 39e930c10ebb..6d96bff32a0e 100644 --- a/drivers/input/misc/max77693-haptic.c +++ b/drivers/input/misc/max77693-haptic.c @@ -1,8 +1,9 @@ /* - * MAXIM MAX77693 Haptic device driver + * MAXIM MAX77693/MAX77843 Haptic device driver * - * Copyright (C) 2014 Samsung Electronics + * Copyright (C) 2014,2015 Samsung Electronics * Jaewon Kim <jaewon02.kim@samsung.com> + * Krzysztof Kozlowski <k.kozlowski@samsung.com> * * This program is not provided / owned by Maxim Integrated Products. * @@ -24,7 +25,9 @@ #include <linux/workqueue.h> #include <linux/regulator/consumer.h> #include <linux/mfd/max77693.h> +#include <linux/mfd/max77693-common.h> #include <linux/mfd/max77693-private.h> +#include <linux/mfd/max77843-private.h> #define MAX_MAGNITUDE_SHIFT 16 @@ -46,6 +49,8 @@ enum max77693_haptic_pwm_divisor { }; struct max77693_haptic { + enum max77693_types dev_type; + struct regmap *regmap_pmic; struct regmap *regmap_haptic; struct device *dev; @@ -59,7 +64,6 @@ struct max77693_haptic { unsigned int pwm_duty; enum max77693_haptic_motor_type type; enum max77693_haptic_pulse_mode mode; - enum max77693_haptic_pwm_divisor pwm_divisor; struct work_struct work; }; @@ -78,19 +82,52 @@ static int max77693_haptic_set_duty_cycle(struct max77693_haptic *haptic) return 0; } +static int max77843_haptic_bias(struct max77693_haptic *haptic, bool on) +{ + int error; + + if (haptic->dev_type != TYPE_MAX77843) + return 0; + + error = regmap_update_bits(haptic->regmap_haptic, + MAX77843_SYS_REG_MAINCTRL1, + MAX77843_MAINCTRL1_BIASEN_MASK, + on << MAINCTRL1_BIASEN_SHIFT); + if (error) { + dev_err(haptic->dev, "failed to %s bias: %d\n", + on ? "enable" : "disable", error); + return error; + } + + return 0; +} + static int max77693_haptic_configure(struct max77693_haptic *haptic, bool enable) { - unsigned int value; + unsigned int value, config_reg; int error; - value = ((haptic->type << MAX77693_CONFIG2_MODE) | - (enable << MAX77693_CONFIG2_MEN) | - (haptic->mode << MAX77693_CONFIG2_HTYP) | - (haptic->pwm_divisor)); + switch (haptic->dev_type) { + case TYPE_MAX77693: + value = ((haptic->type << MAX77693_CONFIG2_MODE) | + (enable << MAX77693_CONFIG2_MEN) | + (haptic->mode << MAX77693_CONFIG2_HTYP) | + MAX77693_HAPTIC_PWM_DIVISOR_128); + config_reg = MAX77693_HAPTIC_REG_CONFIG2; + break; + case TYPE_MAX77843: + value = (haptic->type << MCONFIG_MODE_SHIFT) | + (enable << MCONFIG_MEN_SHIFT) | + MAX77693_HAPTIC_PWM_DIVISOR_128; + config_reg = MAX77843_HAP_REG_MCONFIG; + break; + default: + return -EINVAL; + } error = regmap_write(haptic->regmap_haptic, - MAX77693_HAPTIC_REG_CONFIG2, value); + config_reg, value); if (error) { dev_err(haptic->dev, "failed to update haptic config: %d\n", error); @@ -104,6 +141,9 @@ static int max77693_haptic_lowsys(struct max77693_haptic *haptic, bool enable) { int error; + if (haptic->dev_type != TYPE_MAX77693) + return 0; + error = regmap_update_bits(haptic->regmap_pmic, MAX77693_PMIC_REG_LSCNFG, MAX77693_PMIC_LOW_SYS_MASK, @@ -219,6 +259,10 @@ static int max77693_haptic_open(struct input_dev *dev) struct max77693_haptic *haptic = input_get_drvdata(dev); int error; + error = max77843_haptic_bias(haptic, true); + if (error) + return error; + error = regulator_enable(haptic->motor_reg); if (error) { dev_err(haptic->dev, @@ -241,6 +285,8 @@ static void max77693_haptic_close(struct input_dev *dev) if (error) dev_err(haptic->dev, "failed to disable regulator: %d\n", error); + + max77843_haptic_bias(haptic, false); } static int max77693_haptic_probe(struct platform_device *pdev) @@ -254,13 +300,26 @@ static int max77693_haptic_probe(struct platform_device *pdev) return -ENOMEM; haptic->regmap_pmic = max77693->regmap; - haptic->regmap_haptic = max77693->regmap_haptic; haptic->dev = &pdev->dev; haptic->type = MAX77693_HAPTIC_LRA; haptic->mode = MAX77693_HAPTIC_EXTERNAL_MODE; - haptic->pwm_divisor = MAX77693_HAPTIC_PWM_DIVISOR_128; haptic->suspend_state = false; + /* Variant-specific init */ + haptic->dev_type = platform_get_device_id(pdev)->driver_data; + switch (haptic->dev_type) { + case TYPE_MAX77693: + haptic->regmap_haptic = max77693->regmap_haptic; + break; + case TYPE_MAX77843: + haptic->regmap_haptic = max77693->regmap; + break; + default: + dev_err(&pdev->dev, "unsupported device type: %u\n", + haptic->dev_type); + return -EINVAL; + } + INIT_WORK(&haptic->work, max77693_haptic_play_work); /* Get pwm and regulatot for haptic device */ @@ -338,16 +397,25 @@ static int __maybe_unused max77693_haptic_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(max77693_haptic_pm_ops, max77693_haptic_suspend, max77693_haptic_resume); +static const struct platform_device_id max77693_haptic_id[] = { + { "max77693-haptic", TYPE_MAX77693 }, + { "max77843-haptic", TYPE_MAX77843 }, + {}, +}; +MODULE_DEVICE_TABLE(platform, max77693_haptic_id); + static struct platform_driver max77693_haptic_driver = { .driver = { .name = "max77693-haptic", .pm = &max77693_haptic_pm_ops, }, .probe = max77693_haptic_probe, + .id_table = max77693_haptic_id, }; module_platform_driver(max77693_haptic_driver); MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>"); -MODULE_DESCRIPTION("MAXIM MAX77693 Haptic driver"); +MODULE_AUTHOR("Krzysztof Kozlowski <k.kozlowski@samsung.com>"); +MODULE_DESCRIPTION("MAXIM 77693/77843 Haptic driver"); MODULE_ALIAS("platform:max77693-haptic"); MODULE_LICENSE("GPL"); diff --git a/drivers/input/misc/max77843-haptic.c b/drivers/input/misc/max77843-haptic.c deleted file mode 100644 index dccbb465a055..000000000000 --- a/drivers/input/misc/max77843-haptic.c +++ /dev/null @@ -1,358 +0,0 @@ -/* - * MAXIM MAX77693 Haptic device driver - * - * Copyright (C) 2015 Samsung Electronics - * Author: Jaewon Kim <jaewon02.kim@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include <linux/err.h> -#include <linux/i2c.h> -#include <linux/init.h> -#include <linux/input.h> -#include <linux/mfd/max77843-private.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/pwm.h> -#include <linux/regmap.h> -#include <linux/regulator/consumer.h> -#include <linux/slab.h> -#include <linux/workqueue.h> - -#define MAX_MAGNITUDE_SHIFT 16 - -enum max77843_haptic_motor_type { - MAX77843_HAPTIC_ERM = 0, - MAX77843_HAPTIC_LRA, -}; - -enum max77843_haptic_pwm_divisor { - MAX77843_HAPTIC_PWM_DIVISOR_32 = 0, - MAX77843_HAPTIC_PWM_DIVISOR_64, - MAX77843_HAPTIC_PWM_DIVISOR_128, - MAX77843_HAPTIC_PWM_DIVISOR_256, -}; - -struct max77843_haptic { - struct regmap *regmap_haptic; - struct device *dev; - struct input_dev *input_dev; - struct pwm_device *pwm_dev; - struct regulator *motor_reg; - struct work_struct work; - struct mutex mutex; - - unsigned int magnitude; - unsigned int pwm_duty; - - bool active; - bool suspended; - - enum max77843_haptic_motor_type type; - enum max77843_haptic_pwm_divisor pwm_divisor; -}; - -static int max77843_haptic_set_duty_cycle(struct max77843_haptic *haptic) -{ - int delta = (haptic->pwm_dev->period + haptic->pwm_duty) / 2; - int error; - - error = pwm_config(haptic->pwm_dev, delta, haptic->pwm_dev->period); - if (error) { - dev_err(haptic->dev, "failed to configure pwm: %d\n", error); - return error; - } - - return 0; -} - -static int max77843_haptic_bias(struct max77843_haptic *haptic, bool on) -{ - int error; - - error = regmap_update_bits(haptic->regmap_haptic, - MAX77843_SYS_REG_MAINCTRL1, - MAX77843_MAINCTRL1_BIASEN_MASK, - on << MAINCTRL1_BIASEN_SHIFT); - if (error) { - dev_err(haptic->dev, "failed to %s bias: %d\n", - on ? "enable" : "disable", error); - return error; - } - - return 0; -} - -static int max77843_haptic_config(struct max77843_haptic *haptic, bool enable) -{ - unsigned int value; - int error; - - value = (haptic->type << MCONFIG_MODE_SHIFT) | - (enable << MCONFIG_MEN_SHIFT) | - (haptic->pwm_divisor << MCONFIG_PDIV_SHIFT); - - error = regmap_write(haptic->regmap_haptic, - MAX77843_HAP_REG_MCONFIG, value); - if (error) { - dev_err(haptic->dev, - "failed to update haptic config: %d\n", error); - return error; - } - - return 0; -} - -static int max77843_haptic_enable(struct max77843_haptic *haptic) -{ - int error; - - if (haptic->active) - return 0; - - error = pwm_enable(haptic->pwm_dev); - if (error) { - dev_err(haptic->dev, - "failed to enable pwm device: %d\n", error); - return error; - } - - error = max77843_haptic_config(haptic, true); - if (error) - goto err_config; - - haptic->active = true; - - return 0; - -err_config: - pwm_disable(haptic->pwm_dev); - - return error; -} - -static int max77843_haptic_disable(struct max77843_haptic *haptic) -{ - int error; - - if (!haptic->active) - return 0; - - error = max77843_haptic_config(haptic, false); - if (error) - return error; - - pwm_disable(haptic->pwm_dev); - - haptic->active = false; - - return 0; -} - -static void max77843_haptic_play_work(struct work_struct *work) -{ - struct max77843_haptic *haptic = - container_of(work, struct max77843_haptic, work); - int error; - - mutex_lock(&haptic->mutex); - - if (haptic->suspended) - goto out_unlock; - - if (haptic->magnitude) { - error = max77843_haptic_set_duty_cycle(haptic); - if (error) { - dev_err(haptic->dev, - "failed to set duty cycle: %d\n", error); - goto out_unlock; - } - - error = max77843_haptic_enable(haptic); - if (error) - dev_err(haptic->dev, - "cannot enable haptic: %d\n", error); - } else { - error = max77843_haptic_disable(haptic); - if (error) - dev_err(haptic->dev, - "cannot disable haptic: %d\n", error); - } - -out_unlock: - mutex_unlock(&haptic->mutex); -} - -static int max77843_haptic_play_effect(struct input_dev *dev, void *data, - struct ff_effect *effect) -{ - struct max77843_haptic *haptic = input_get_drvdata(dev); - u64 period_mag_multi; - - haptic->magnitude = effect->u.rumble.strong_magnitude; - if (!haptic->magnitude) - haptic->magnitude = effect->u.rumble.weak_magnitude; - - period_mag_multi = (u64)haptic->pwm_dev->period * haptic->magnitude; - haptic->pwm_duty = (unsigned int)(period_mag_multi >> - MAX_MAGNITUDE_SHIFT); - - schedule_work(&haptic->work); - - return 0; -} - -static int max77843_haptic_open(struct input_dev *dev) -{ - struct max77843_haptic *haptic = input_get_drvdata(dev); - int error; - - error = max77843_haptic_bias(haptic, true); - if (error) - return error; - - error = regulator_enable(haptic->motor_reg); - if (error) { - dev_err(haptic->dev, - "failed to enable regulator: %d\n", error); - return error; - } - - return 0; -} - -static void max77843_haptic_close(struct input_dev *dev) -{ - struct max77843_haptic *haptic = input_get_drvdata(dev); - int error; - - cancel_work_sync(&haptic->work); - max77843_haptic_disable(haptic); - - error = regulator_disable(haptic->motor_reg); - if (error) - dev_err(haptic->dev, - "failed to disable regulator: %d\n", error); - - max77843_haptic_bias(haptic, false); -} - -static int max77843_haptic_probe(struct platform_device *pdev) -{ - struct max77843 *max77843 = dev_get_drvdata(pdev->dev.parent); - struct max77843_haptic *haptic; - int error; - - haptic = devm_kzalloc(&pdev->dev, sizeof(*haptic), GFP_KERNEL); - if (!haptic) - return -ENOMEM; - - haptic->regmap_haptic = max77843->regmap; - haptic->dev = &pdev->dev; - haptic->type = MAX77843_HAPTIC_LRA; - haptic->pwm_divisor = MAX77843_HAPTIC_PWM_DIVISOR_128; - - INIT_WORK(&haptic->work, max77843_haptic_play_work); - mutex_init(&haptic->mutex); - - haptic->pwm_dev = devm_pwm_get(&pdev->dev, NULL); - if (IS_ERR(haptic->pwm_dev)) { - dev_err(&pdev->dev, "failed to get pwm device\n"); - return PTR_ERR(haptic->pwm_dev); - } - - haptic->motor_reg = devm_regulator_get_exclusive(&pdev->dev, "haptic"); - if (IS_ERR(haptic->motor_reg)) { - dev_err(&pdev->dev, "failed to get regulator\n"); - return PTR_ERR(haptic->motor_reg); - } - - haptic->input_dev = devm_input_allocate_device(&pdev->dev); - if (!haptic->input_dev) { - dev_err(&pdev->dev, "failed to allocate input device\n"); - return -ENOMEM; - } - - haptic->input_dev->name = "max77843-haptic"; - haptic->input_dev->id.version = 1; - haptic->input_dev->dev.parent = &pdev->dev; - haptic->input_dev->open = max77843_haptic_open; - haptic->input_dev->close = max77843_haptic_close; - input_set_drvdata(haptic->input_dev, haptic); - input_set_capability(haptic->input_dev, EV_FF, FF_RUMBLE); - - error = input_ff_create_memless(haptic->input_dev, NULL, - max77843_haptic_play_effect); - if (error) { - dev_err(&pdev->dev, "failed to create force-feedback\n"); - return error; - } - - error = input_register_device(haptic->input_dev); - if (error) { - dev_err(&pdev->dev, "failed to register input device\n"); - return error; - } - - platform_set_drvdata(pdev, haptic); - - return 0; -} - -static int __maybe_unused max77843_haptic_suspend(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct max77843_haptic *haptic = platform_get_drvdata(pdev); - int error; - - error = mutex_lock_interruptible(&haptic->mutex); - if (error) - return error; - - max77843_haptic_disable(haptic); - - haptic->suspended = true; - - mutex_unlock(&haptic->mutex); - - return 0; -} - -static int __maybe_unused max77843_haptic_resume(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct max77843_haptic *haptic = platform_get_drvdata(pdev); - unsigned int magnitude; - - mutex_lock(&haptic->mutex); - - haptic->suspended = false; - - magnitude = ACCESS_ONCE(haptic->magnitude); - if (magnitude) - max77843_haptic_enable(haptic); - - mutex_unlock(&haptic->mutex); - - return 0; -} - -static SIMPLE_DEV_PM_OPS(max77843_haptic_pm_ops, - max77843_haptic_suspend, max77843_haptic_resume); - -static struct platform_driver max77843_haptic_driver = { - .driver = { - .name = "max77843-haptic", - .pm = &max77843_haptic_pm_ops, - }, - .probe = max77843_haptic_probe, -}; -module_platform_driver(max77843_haptic_driver); - -MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>"); -MODULE_DESCRIPTION("MAXIM MAX77843 Haptic driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/leds/leds-max77693.c b/drivers/leds/leds-max77693.c index b8b0eec7b540..df348a06d8c7 100644 --- a/drivers/leds/leds-max77693.c +++ b/drivers/leds/leds-max77693.c @@ -13,6 +13,7 @@ #include <linux/led-class-flash.h> #include <linux/mfd/max77693.h> +#include <linux/mfd/max77693-common.h> #include <linux/mfd/max77693-private.h> #include <linux/module.h> #include <linux/mutex.h> diff --git a/drivers/mfd/max77693.c b/drivers/mfd/max77693.c index cb14afa97e6f..67bc53fdc389 100644 --- a/drivers/mfd/max77693.c +++ b/drivers/mfd/max77693.c @@ -33,6 +33,7 @@ #include <linux/mutex.h> #include <linux/mfd/core.h> #include <linux/mfd/max77693.h> +#include <linux/mfd/max77693-common.h> #include <linux/mfd/max77693-private.h> #include <linux/regulator/machine.h> #include <linux/regmap.h> @@ -193,22 +194,22 @@ static int max77693_i2c_probe(struct i2c_client *i2c, } else dev_info(max77693->dev, "device ID: 0x%x\n", reg_data); - max77693->muic = i2c_new_dummy(i2c->adapter, I2C_ADDR_MUIC); - if (!max77693->muic) { + max77693->i2c_muic = i2c_new_dummy(i2c->adapter, I2C_ADDR_MUIC); + if (!max77693->i2c_muic) { dev_err(max77693->dev, "Failed to allocate I2C device for MUIC\n"); return -ENODEV; } - i2c_set_clientdata(max77693->muic, max77693); + i2c_set_clientdata(max77693->i2c_muic, max77693); - max77693->haptic = i2c_new_dummy(i2c->adapter, I2C_ADDR_HAPTIC); - if (!max77693->haptic) { + max77693->i2c_haptic = i2c_new_dummy(i2c->adapter, I2C_ADDR_HAPTIC); + if (!max77693->i2c_haptic) { dev_err(max77693->dev, "Failed to allocate I2C device for Haptic\n"); ret = -ENODEV; goto err_i2c_haptic; } - i2c_set_clientdata(max77693->haptic, max77693); + i2c_set_clientdata(max77693->i2c_haptic, max77693); - max77693->regmap_haptic = devm_regmap_init_i2c(max77693->haptic, + max77693->regmap_haptic = devm_regmap_init_i2c(max77693->i2c_haptic, &max77693_regmap_haptic_config); if (IS_ERR(max77693->regmap_haptic)) { ret = PTR_ERR(max77693->regmap_haptic); @@ -222,7 +223,7 @@ static int max77693_i2c_probe(struct i2c_client *i2c, * instance of MUIC device when irq of max77693 is initialized * before call max77693-muic probe() function. */ - max77693->regmap_muic = devm_regmap_init_i2c(max77693->muic, + max77693->regmap_muic = devm_regmap_init_i2c(max77693->i2c_muic, &max77693_regmap_muic_config); if (IS_ERR(max77693->regmap_muic)) { ret = PTR_ERR(max77693->regmap_muic); @@ -255,7 +256,7 @@ static int max77693_i2c_probe(struct i2c_client *i2c, IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_FALLING, 0, &max77693_charger_irq_chip, - &max77693->irq_data_charger); + &max77693->irq_data_chg); if (ret) { dev_err(max77693->dev, "failed to add irq chip: %d\n", ret); goto err_irq_charger; @@ -296,15 +297,15 @@ err_mfd: err_intsrc: regmap_del_irq_chip(max77693->irq, max77693->irq_data_muic); err_irq_muic: - regmap_del_irq_chip(max77693->irq, max77693->irq_data_charger); + regmap_del_irq_chip(max77693->irq, max77693->irq_data_chg); err_irq_charger: regmap_del_irq_chip(max77693->irq, max77693->irq_data_topsys); err_irq_topsys: regmap_del_irq_chip(max77693->irq, max77693->irq_data_led); err_regmap: - i2c_unregister_device(max77693->haptic); + i2c_unregister_device(max77693->i2c_haptic); err_i2c_haptic: - i2c_unregister_device(max77693->muic); + i2c_unregister_device(max77693->i2c_muic); return ret; } @@ -315,12 +316,12 @@ static int max77693_i2c_remove(struct i2c_client *i2c) mfd_remove_devices(max77693->dev); regmap_del_irq_chip(max77693->irq, max77693->irq_data_muic); - regmap_del_irq_chip(max77693->irq, max77693->irq_data_charger); + regmap_del_irq_chip(max77693->irq, max77693->irq_data_chg); regmap_del_irq_chip(max77693->irq, max77693->irq_data_topsys); regmap_del_irq_chip(max77693->irq, max77693->irq_data_led); - i2c_unregister_device(max77693->muic); - i2c_unregister_device(max77693->haptic); + i2c_unregister_device(max77693->i2c_muic); + i2c_unregister_device(max77693->i2c_haptic); return 0; } diff --git a/drivers/mfd/max77843.c b/drivers/mfd/max77843.c index a354ac677ec7..c52162ea3d0a 100644 --- a/drivers/mfd/max77843.c +++ b/drivers/mfd/max77843.c @@ -17,6 +17,7 @@ #include <linux/interrupt.h> #include <linux/module.h> #include <linux/mfd/core.h> +#include <linux/mfd/max77693-common.h> #include <linux/mfd/max77843-private.h> #include <linux/of_device.h> #include <linux/platform_device.h> @@ -71,7 +72,7 @@ static const struct regmap_irq_chip max77843_irq_chip = { }; /* Charger and Charger regulator use same regmap. */ -static int max77843_chg_init(struct max77843 *max77843) +static int max77843_chg_init(struct max77693_dev *max77843) { int ret; @@ -101,7 +102,7 @@ err_chg_i2c: static int max77843_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { - struct max77843 *max77843; + struct max77693_dev *max77843; unsigned int reg_data; int ret; @@ -113,6 +114,7 @@ static int max77843_probe(struct i2c_client *i2c, max77843->dev = &i2c->dev; max77843->i2c = i2c; max77843->irq = i2c->irq; + max77843->type = id->driver_data; max77843->regmap = devm_regmap_init_i2c(i2c, &max77843_regmap_config); @@ -123,7 +125,7 @@ static int max77843_probe(struct i2c_client *i2c, ret = regmap_add_irq_chip(max77843->regmap, max77843->irq, IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED, - 0, &max77843_irq_chip, &max77843->irq_data); + 0, &max77843_irq_chip, &max77843->irq_data_topsys); if (ret) { dev_err(&i2c->dev, "Failed to add TOPSYS IRQ chip\n"); return ret; @@ -164,18 +166,18 @@ static int max77843_probe(struct i2c_client *i2c, return 0; err_pmic_id: - regmap_del_irq_chip(max77843->irq, max77843->irq_data); + regmap_del_irq_chip(max77843->irq, max77843->irq_data_topsys); return ret; } static int max77843_remove(struct i2c_client *i2c) { - struct max77843 *max77843 = i2c_get_clientdata(i2c); + struct max77693_dev *max77843 = i2c_get_clientdata(i2c); mfd_remove_devices(max77843->dev); - regmap_del_irq_chip(max77843->irq, max77843->irq_data); + regmap_del_irq_chip(max77843->irq, max77843->irq_data_topsys); i2c_unregister_device(max77843->i2c_chg); @@ -188,7 +190,7 @@ static const struct of_device_id max77843_dt_match[] = { }; static const struct i2c_device_id max77843_id[] = { - { "max77843", }, + { "max77843", TYPE_MAX77843, }, { }, }; MODULE_DEVICE_TABLE(i2c, max77843_id); @@ -196,7 +198,7 @@ MODULE_DEVICE_TABLE(i2c, max77843_id); static int __maybe_unused max77843_suspend(struct device *dev) { struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); - struct max77843 *max77843 = i2c_get_clientdata(i2c); + struct max77693_dev *max77843 = i2c_get_clientdata(i2c); disable_irq(max77843->irq); if (device_may_wakeup(dev)) @@ -208,7 +210,7 @@ static int __maybe_unused max77843_suspend(struct device *dev) static int __maybe_unused max77843_resume(struct device *dev) { struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); - struct max77843 *max77843 = i2c_get_clientdata(i2c); + struct max77693_dev *max77843 = i2c_get_clientdata(i2c); if (device_may_wakeup(dev)) disable_irq_wake(max77843->irq); diff --git a/drivers/power/max77693_charger.c b/drivers/power/max77693_charger.c index 754879eb59f6..060cab5ae3aa 100644 --- a/drivers/power/max77693_charger.c +++ b/drivers/power/max77693_charger.c @@ -20,6 +20,7 @@ #include <linux/power_supply.h> #include <linux/regmap.h> #include <linux/mfd/max77693.h> +#include <linux/mfd/max77693-common.h> #include <linux/mfd/max77693-private.h> #define MAX77693_CHARGER_NAME "max77693-charger" diff --git a/drivers/regulator/88pm800.c b/drivers/regulator/88pm800.c index 7fd4f511d78f..a62a89674fb5 100644 --- a/drivers/regulator/88pm800.c +++ b/drivers/regulator/88pm800.c @@ -78,7 +78,6 @@ struct pm800_regulator_info { }; struct pm800_regulators { - struct regulator_dev *regulators[PM800_ID_RG_MAX]; struct pm80x_chip *chip; struct regmap *map; }; @@ -92,14 +91,16 @@ struct pm800_regulators { * not the constant voltage table. * n_volt - Number of available selectors */ -#define PM800_BUCK(vreg, ereg, ebit, amax, volt_ranges, n_volt) \ +#define PM800_BUCK(match, vreg, ereg, ebit, amax, volt_ranges, n_volt) \ { \ .desc = { \ - .name = #vreg, \ - .ops = &pm800_volt_range_ops, \ - .type = REGULATOR_VOLTAGE, \ - .id = PM800_ID_##vreg, \ - .owner = THIS_MODULE, \ + .name = #vreg, \ + .of_match = of_match_ptr(#match), \ + .regulators_node = of_match_ptr("regulators"), \ + .ops = &pm800_volt_range_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = PM800_ID_##vreg, \ + .owner = THIS_MODULE, \ .n_voltages = n_volt, \ .linear_ranges = volt_ranges, \ .n_linear_ranges = ARRAY_SIZE(volt_ranges), \ @@ -108,7 +109,7 @@ struct pm800_regulators { .enable_reg = PM800_##ereg, \ .enable_mask = 1 << (ebit), \ }, \ - .max_ua = (amax), \ + .max_ua = (amax), \ } /* @@ -120,22 +121,24 @@ struct pm800_regulators { * For all the LDOes, there are too many ranges. Using volt_table will be * simpler and faster. */ -#define PM800_LDO(vreg, ereg, ebit, amax, ldo_volt_table) \ +#define PM800_LDO(match, vreg, ereg, ebit, amax, ldo_volt_table) \ { \ .desc = { \ - .name = #vreg, \ - .ops = &pm800_volt_table_ops, \ - .type = REGULATOR_VOLTAGE, \ - .id = PM800_ID_##vreg, \ - .owner = THIS_MODULE, \ - .n_voltages = ARRAY_SIZE(ldo_volt_table), \ - .vsel_reg = PM800_##vreg##_VOUT, \ - .vsel_mask = 0xf, \ - .enable_reg = PM800_##ereg, \ - .enable_mask = 1 << (ebit), \ - .volt_table = ldo_volt_table, \ + .name = #vreg, \ + .of_match = of_match_ptr(#match), \ + .regulators_node = of_match_ptr("regulators"), \ + .ops = &pm800_volt_table_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = PM800_ID_##vreg, \ + .owner = THIS_MODULE, \ + .n_voltages = ARRAY_SIZE(ldo_volt_table), \ + .vsel_reg = PM800_##vreg##_VOUT, \ + .vsel_mask = 0xf, \ + .enable_reg = PM800_##ereg, \ + .enable_mask = 1 << (ebit), \ + .volt_table = ldo_volt_table, \ }, \ - .max_ua = (amax), \ + .max_ua = (amax), \ } /* Ranges are sorted in ascending order. */ @@ -178,122 +181,66 @@ static int pm800_get_current_limit(struct regulator_dev *rdev) } static struct regulator_ops pm800_volt_range_ops = { - .list_voltage = regulator_list_voltage_linear_range, - .map_voltage = regulator_map_voltage_linear_range, - .set_voltage_sel = regulator_set_voltage_sel_regmap, - .get_voltage_sel = regulator_get_voltage_sel_regmap, - .enable = regulator_enable_regmap, - .disable = regulator_disable_regmap, - .is_enabled = regulator_is_enabled_regmap, - .get_current_limit = pm800_get_current_limit, + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .get_current_limit = pm800_get_current_limit, }; static struct regulator_ops pm800_volt_table_ops = { - .list_voltage = regulator_list_voltage_table, - .map_voltage = regulator_map_voltage_iterate, - .set_voltage_sel = regulator_set_voltage_sel_regmap, - .get_voltage_sel = regulator_get_voltage_sel_regmap, - .enable = regulator_enable_regmap, - .disable = regulator_disable_regmap, - .is_enabled = regulator_is_enabled_regmap, - .get_current_limit = pm800_get_current_limit, + .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_iterate, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .get_current_limit = pm800_get_current_limit, }; /* The array is indexed by id(PM800_ID_XXX) */ static struct pm800_regulator_info pm800_regulator_info[] = { - PM800_BUCK(BUCK1, BUCK_ENA, 0, 3000000, buck1_volt_range, 0x55), - PM800_BUCK(BUCK2, BUCK_ENA, 1, 1200000, buck2_5_volt_range, 0x73), - PM800_BUCK(BUCK3, BUCK_ENA, 2, 1200000, buck2_5_volt_range, 0x73), - PM800_BUCK(BUCK4, BUCK_ENA, 3, 1200000, buck2_5_volt_range, 0x73), - PM800_BUCK(BUCK5, BUCK_ENA, 4, 1200000, buck2_5_volt_range, 0x73), - - PM800_LDO(LDO1, LDO_ENA1_1, 0, 200000, ldo1_volt_table), - PM800_LDO(LDO2, LDO_ENA1_1, 1, 10000, ldo2_volt_table), - PM800_LDO(LDO3, LDO_ENA1_1, 2, 300000, ldo3_17_volt_table), - PM800_LDO(LDO4, LDO_ENA1_1, 3, 300000, ldo3_17_volt_table), - PM800_LDO(LDO5, LDO_ENA1_1, 4, 300000, ldo3_17_volt_table), - PM800_LDO(LDO6, LDO_ENA1_1, 5, 300000, ldo3_17_volt_table), - PM800_LDO(LDO7, LDO_ENA1_1, 6, 300000, ldo3_17_volt_table), - PM800_LDO(LDO8, LDO_ENA1_1, 7, 300000, ldo3_17_volt_table), - PM800_LDO(LDO9, LDO_ENA1_2, 0, 300000, ldo3_17_volt_table), - PM800_LDO(LDO10, LDO_ENA1_2, 1, 300000, ldo3_17_volt_table), - PM800_LDO(LDO11, LDO_ENA1_2, 2, 300000, ldo3_17_volt_table), - PM800_LDO(LDO12, LDO_ENA1_2, 3, 300000, ldo3_17_volt_table), - PM800_LDO(LDO13, LDO_ENA1_2, 4, 300000, ldo3_17_volt_table), - PM800_LDO(LDO14, LDO_ENA1_2, 5, 300000, ldo3_17_volt_table), - PM800_LDO(LDO15, LDO_ENA1_2, 6, 300000, ldo3_17_volt_table), - PM800_LDO(LDO16, LDO_ENA1_2, 7, 300000, ldo3_17_volt_table), - PM800_LDO(LDO17, LDO_ENA1_3, 0, 300000, ldo3_17_volt_table), - PM800_LDO(LDO18, LDO_ENA1_3, 1, 200000, ldo18_19_volt_table), - PM800_LDO(LDO19, LDO_ENA1_3, 2, 200000, ldo18_19_volt_table), -}; - -#define PM800_REGULATOR_OF_MATCH(_name, _id) \ - [PM800_ID_##_id] = { \ - .name = #_name, \ - .driver_data = &pm800_regulator_info[PM800_ID_##_id], \ - } - -static struct of_regulator_match pm800_regulator_matches[] = { - PM800_REGULATOR_OF_MATCH(buck1, BUCK1), - PM800_REGULATOR_OF_MATCH(buck2, BUCK2), - PM800_REGULATOR_OF_MATCH(buck3, BUCK3), - PM800_REGULATOR_OF_MATCH(buck4, BUCK4), - PM800_REGULATOR_OF_MATCH(buck5, BUCK5), - PM800_REGULATOR_OF_MATCH(ldo1, LDO1), - PM800_REGULATOR_OF_MATCH(ldo2, LDO2), - PM800_REGULATOR_OF_MATCH(ldo3, LDO3), - PM800_REGULATOR_OF_MATCH(ldo4, LDO4), - PM800_REGULATOR_OF_MATCH(ldo5, LDO5), - PM800_REGULATOR_OF_MATCH(ldo6, LDO6), - PM800_REGULATOR_OF_MATCH(ldo7, LDO7), - PM800_REGULATOR_OF_MATCH(ldo8, LDO8), - PM800_REGULATOR_OF_MATCH(ldo9, LDO9), - PM800_REGULATOR_OF_MATCH(ldo10, LDO10), - PM800_REGULATOR_OF_MATCH(ldo11, LDO11), - PM800_REGULATOR_OF_MATCH(ldo12, LDO12), - PM800_REGULATOR_OF_MATCH(ldo13, LDO13), - PM800_REGULATOR_OF_MATCH(ldo14, LDO14), - PM800_REGULATOR_OF_MATCH(ldo15, LDO15), - PM800_REGULATOR_OF_MATCH(ldo16, LDO16), - PM800_REGULATOR_OF_MATCH(ldo17, LDO17), - PM800_REGULATOR_OF_MATCH(ldo18, LDO18), - PM800_REGULATOR_OF_MATCH(ldo19, LDO19), + PM800_BUCK(buck1, BUCK1, BUCK_ENA, 0, 3000000, buck1_volt_range, 0x55), + PM800_BUCK(buck2, BUCK2, BUCK_ENA, 1, 1200000, buck2_5_volt_range, 0x73), + PM800_BUCK(buck3, BUCK3, BUCK_ENA, 2, 1200000, buck2_5_volt_range, 0x73), + PM800_BUCK(buck4, BUCK4, BUCK_ENA, 3, 1200000, buck2_5_volt_range, 0x73), + PM800_BUCK(buck5, BUCK5, BUCK_ENA, 4, 1200000, buck2_5_volt_range, 0x73), + + PM800_LDO(ldo1, LDO1, LDO_ENA1_1, 0, 200000, ldo1_volt_table), + PM800_LDO(ldo2, LDO2, LDO_ENA1_1, 1, 10000, ldo2_volt_table), + PM800_LDO(ldo3, LDO3, LDO_ENA1_1, 2, 300000, ldo3_17_volt_table), + PM800_LDO(ldo4, LDO4, LDO_ENA1_1, 3, 300000, ldo3_17_volt_table), + PM800_LDO(ldo5, LDO5, LDO_ENA1_1, 4, 300000, ldo3_17_volt_table), + PM800_LDO(ldo6, LDO6, LDO_ENA1_1, 5, 300000, ldo3_17_volt_table), + PM800_LDO(ldo7, LDO7, LDO_ENA1_1, 6, 300000, ldo3_17_volt_table), + PM800_LDO(ldo8, LDO8, LDO_ENA1_1, 7, 300000, ldo3_17_volt_table), + PM800_LDO(ldo9, LDO9, LDO_ENA1_2, 0, 300000, ldo3_17_volt_table), + PM800_LDO(ldo10, LDO10, LDO_ENA1_2, 1, 300000, ldo3_17_volt_table), + PM800_LDO(ldo11, LDO11, LDO_ENA1_2, 2, 300000, ldo3_17_volt_table), + PM800_LDO(ldo12, LDO12, LDO_ENA1_2, 3, 300000, ldo3_17_volt_table), + PM800_LDO(ldo13, LDO13, LDO_ENA1_2, 4, 300000, ldo3_17_volt_table), + PM800_LDO(ldo14, LDO14, LDO_ENA1_2, 5, 300000, ldo3_17_volt_table), + PM800_LDO(ldo15, LDO15, LDO_ENA1_2, 6, 300000, ldo3_17_volt_table), + PM800_LDO(ldo16, LDO16, LDO_ENA1_2, 7, 300000, ldo3_17_volt_table), + PM800_LDO(ldo17, LDO17, LDO_ENA1_3, 0, 300000, ldo3_17_volt_table), + PM800_LDO(ldo18, LDO18, LDO_ENA1_3, 1, 200000, ldo18_19_volt_table), + PM800_LDO(ldo19, LDO19, LDO_ENA1_3, 2, 200000, ldo18_19_volt_table), }; -static int pm800_regulator_dt_init(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - int ret; - - ret = of_regulator_match(&pdev->dev, np, - pm800_regulator_matches, - ARRAY_SIZE(pm800_regulator_matches)); - if (ret < 0) - return ret; - - return 0; -} - static int pm800_regulator_probe(struct platform_device *pdev) { struct pm80x_chip *chip = dev_get_drvdata(pdev->dev.parent); struct pm80x_platform_data *pdata = dev_get_platdata(pdev->dev.parent); struct pm800_regulators *pm800_data; - struct pm800_regulator_info *info; struct regulator_config config = { }; struct regulator_init_data *init_data; int i, ret; - if (!pdata || pdata->num_regulators == 0) { - if (IS_ENABLED(CONFIG_OF)) { - ret = pm800_regulator_dt_init(pdev); - if (ret) - return ret; - } else { - return -ENODEV; - } - } else if (pdata->num_regulators) { + if (pdata && pdata->num_regulators) { unsigned int count = 0; /* Check whether num_regulator is valid. */ @@ -303,8 +250,6 @@ static int pm800_regulator_probe(struct platform_device *pdev) } if (count != pdata->num_regulators) return -EINVAL; - } else { - return -EINVAL; } pm800_data = devm_kzalloc(&pdev->dev, sizeof(*pm800_data), @@ -317,30 +262,27 @@ static int pm800_regulator_probe(struct platform_device *pdev) platform_set_drvdata(pdev, pm800_data); + config.dev = chip->dev; + config.regmap = pm800_data->map; for (i = 0; i < PM800_ID_RG_MAX; i++) { - if (!pdata || pdata->num_regulators == 0) - init_data = pm800_regulator_matches[i].init_data; - else + struct regulator_dev *regulator; + + if (pdata && pdata->num_regulators) { init_data = pdata->regulators[i]; - if (!init_data) - continue; - info = pm800_regulator_matches[i].driver_data; - config.dev = &pdev->dev; - config.init_data = init_data; - config.driver_data = info; - config.regmap = pm800_data->map; - config.of_node = pm800_regulator_matches[i].of_node; - - pm800_data->regulators[i] = - regulator_register(&info->desc, &config); - if (IS_ERR(pm800_data->regulators[i])) { - ret = PTR_ERR(pm800_data->regulators[i]); - dev_err(&pdev->dev, "Failed to register %s\n", - info->desc.name); + if (!init_data) + continue; - while (--i >= 0) - regulator_unregister(pm800_data->regulators[i]); + config.init_data = init_data; + } + + config.driver_data = &pm800_regulator_info[i]; + regulator = devm_regulator_register(&pdev->dev, + &pm800_regulator_info[i].desc, &config); + if (IS_ERR(regulator)) { + ret = PTR_ERR(regulator); + dev_err(&pdev->dev, "Failed to register %s\n", + pm800_regulator_info[i].desc.name); return ret; } } @@ -348,23 +290,11 @@ static int pm800_regulator_probe(struct platform_device *pdev) return 0; } -static int pm800_regulator_remove(struct platform_device *pdev) -{ - struct pm800_regulators *pm800_data = platform_get_drvdata(pdev); - int i; - - for (i = 0; i < PM800_ID_RG_MAX; i++) - regulator_unregister(pm800_data->regulators[i]); - - return 0; -} - static struct platform_driver pm800_regulator_driver = { .driver = { .name = "88pm80x-regulator", }, .probe = pm800_regulator_probe, - .remove = pm800_regulator_remove, }; module_platform_driver(pm800_regulator_driver); diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index bef3bde6971b..64bccff557be 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -209,13 +209,13 @@ config REGULATOR_DA9210 interface. config REGULATOR_DA9211 - tristate "Dialog Semiconductor DA9211/DA9212/DA9213/DA9214 regulator" + tristate "Dialog Semiconductor DA9211/DA9212/DA9213/DA9214/DA9215 regulator" depends on I2C select REGMAP_I2C help Say y here to support for the Dialog Semiconductor DA9211/DA9212 - /DA9213/DA9214. - The DA9211/DA9212/DA9213/DA9214 is a multi-phase synchronous + /DA9213/DA9214/DA9215. + The DA9211/DA9212/DA9213/DA9214/DA9215 is a multi-phase synchronous step down converter 12A or 16A DC-DC Buck controlled through an I2C interface. @@ -407,13 +407,13 @@ config REGULATOR_MAX77686 Exynos-4 chips to control VARM and VINT voltages. config REGULATOR_MAX77693 - tristate "Maxim MAX77693 regulator" - depends on MFD_MAX77693 + tristate "Maxim 77693/77843 regulator" + depends on (MFD_MAX77693 || MFD_MAX77843) help - This driver controls a Maxim 77693 regulator via I2C bus. + This driver controls a Maxim 77693/77843 regulators via I2C bus. The regulators include two LDOs, 'SAFEOUT1', 'SAFEOUT2' and one current regulator 'CHARGER'. This is suitable for - Exynos-4x12 chips. + Exynos-4x12 (MAX77693) or Exynos5433 (MAX77843) SoC chips. config REGULATOR_MAX77802 tristate "Maxim 77802 regulator" @@ -424,14 +424,6 @@ config REGULATOR_MAX77802 Exynos5420/Exynos5800 SoCs to control various voltages. It includes support for control of voltage and ramp speed. -config REGULATOR_MAX77843 - tristate "Maxim 77843 regulator" - depends on MFD_MAX77843 - help - This driver controls a Maxim 77843 regulator. - The regulator include two 'SAFEOUT' for USB(Universal Serial Bus) - This is suitable for Exynos5433 SoC chips. - config REGULATOR_MC13XXX_CORE tristate @@ -451,6 +443,15 @@ config REGULATOR_MC13892 Say y here to support the regulators found on the Freescale MC13892 PMIC. +config REGULATOR_MT6311 + tristate "MediaTek MT6311 PMIC" + depends on I2C + help + Say y here to select this option to enable the power regulator of + MediaTek MT6311 PMIC. + This driver supports the control of different power rails of device + through regulator interface. + config REGULATOR_MT6397 tristate "MediaTek MT6397 PMIC" depends on MFD_MT6397 @@ -522,6 +523,18 @@ config REGULATOR_QCOM_RPM Qualcomm RPM as a module. The module will be named "qcom_rpm-regulator". +config REGULATOR_QCOM_SMD_RPM + tristate "Qualcomm SMD based RPM regulator driver" + depends on QCOM_SMD_RPM + help + If you say yes to this option, support will be included for the + regulators exposed by the Resource Power Manager found in Qualcomm + 8974 based devices. + + Say M here if you want to include support for the regulators on the + Qualcomm RPM as a module. The module will be named + "qcom_smd-regulator". + config REGULATOR_QCOM_SPMI tristate "Qualcomm SPMI regulator driver" depends on SPMI || COMPILE_TEST diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 91bf76267404..0f8174913c17 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -56,12 +56,13 @@ obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o obj-$(CONFIG_REGULATOR_MAX77686) += max77686.o obj-$(CONFIG_REGULATOR_MAX77693) += max77693.o obj-$(CONFIG_REGULATOR_MAX77802) += max77802.o -obj-$(CONFIG_REGULATOR_MAX77843) += max77843.o obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o +obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o +obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o obj-$(CONFIG_REGULATOR_QCOM_SPMI) += qcom_spmi-regulator.o obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o diff --git a/drivers/regulator/act8865-regulator.c b/drivers/regulator/act8865-regulator.c index 2ff73d72ca34..896db168e4bd 100644 --- a/drivers/regulator/act8865-regulator.c +++ b/drivers/regulator/act8865-regulator.c @@ -530,7 +530,6 @@ MODULE_DEVICE_TABLE(i2c, act8865_ids); static struct i2c_driver act8865_pmic_driver = { .driver = { .name = "act8865", - .owner = THIS_MODULE, }, .probe = act8865_pmic_probe, .id_table = act8865_ids, diff --git a/drivers/regulator/ad5398.c b/drivers/regulator/ad5398.c index 48016a050d5f..ea50a886ba63 100644 --- a/drivers/regulator/ad5398.c +++ b/drivers/regulator/ad5398.c @@ -275,4 +275,3 @@ module_exit(ad5398_exit); MODULE_DESCRIPTION("AD5398 and AD5821 current regulator driver"); MODULE_AUTHOR("Sonic Zhang"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("i2c:ad5398-regulator"); diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c index 646829132b59..01bf3476a791 100644 --- a/drivers/regulator/axp20x-regulator.c +++ b/drivers/regulator/axp20x-regulator.c @@ -405,3 +405,4 @@ module_platform_driver(axp20x_regulator_driver); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Carlo Caione <carlo@caione.org>"); MODULE_DESCRIPTION("Regulator Driver for AXP20X PMIC"); +MODULE_ALIAS("platform:axp20x-regulator"); diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 78387a6cbae5..de9f272a0faf 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -111,6 +111,11 @@ static struct regulator *create_regulator(struct regulator_dev *rdev, const char *supply_name); static void _regulator_put(struct regulator *regulator); +static struct regulator_dev *dev_to_rdev(struct device *dev) +{ + return container_of(dev, struct regulator_dev, dev); +} + static const char *rdev_get_name(struct regulator_dev *rdev) { if (rdev->constraints && rdev->constraints->name) @@ -296,7 +301,7 @@ static int regulator_check_drms(struct regulator_dev *rdev) return -ENODEV; } if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS)) { - rdev_err(rdev, "operation not allowed\n"); + rdev_dbg(rdev, "operation not allowed\n"); return -EPERM; } return 0; @@ -641,6 +646,8 @@ static int drms_uA_update(struct regulator_dev *rdev) int current_uA = 0, output_uV, input_uV, err; unsigned int mode; + lockdep_assert_held_once(&rdev->mutex); + /* * first check to see if we can set modes at all, otherwise just * tell the consumer everything is OK. @@ -761,6 +768,8 @@ static int suspend_set_state(struct regulator_dev *rdev, /* locks held by caller */ static int suspend_prepare(struct regulator_dev *rdev, suspend_state_t state) { + lockdep_assert_held_once(&rdev->mutex); + if (!rdev->constraints) return -EINVAL; @@ -1082,6 +1091,15 @@ static int set_machine_constraints(struct regulator_dev *rdev, } } + if (rdev->constraints->over_current_protection + && ops->set_over_current_protection) { + ret = ops->set_over_current_protection(rdev); + if (ret < 0) { + rdev_err(rdev, "failed to set over current protection\n"); + goto out; + } + } + print_constraints(rdev); return 0; out: @@ -1595,9 +1613,11 @@ static void _regulator_put(struct regulator *regulator) { struct regulator_dev *rdev; - if (regulator == NULL || IS_ERR(regulator)) + if (IS_ERR_OR_NULL(regulator)) return; + lockdep_assert_held_once(®ulator_list_mutex); + rdev = regulator->rdev; debugfs_remove_recursive(regulator->debugfs); @@ -1606,14 +1626,15 @@ static void _regulator_put(struct regulator *regulator) if (regulator->dev) sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name); mutex_lock(&rdev->mutex); - kfree(regulator->supply_name); list_del(®ulator->list); - kfree(regulator); rdev->open_count--; rdev->exclusive = 0; mutex_unlock(&rdev->mutex); + kfree(regulator->supply_name); + kfree(regulator); + module_put(rdev->owner); } @@ -1976,6 +1997,8 @@ static int _regulator_enable(struct regulator_dev *rdev) { int ret; + lockdep_assert_held_once(&rdev->mutex); + /* check voltage and requested load before enabling */ if (rdev->constraints && (rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS)) @@ -2076,6 +2099,8 @@ static int _regulator_disable(struct regulator_dev *rdev) { int ret = 0; + lockdep_assert_held_once(&rdev->mutex); + if (WARN(rdev->use_count <= 0, "unbalanced disables for %s\n", rdev_get_name(rdev))) return -EIO; @@ -2154,6 +2179,8 @@ static int _regulator_force_disable(struct regulator_dev *rdev) { int ret = 0; + lockdep_assert_held_once(&rdev->mutex); + ret = _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE | REGULATOR_EVENT_PRE_DISABLE, NULL); if (ret & NOTIFY_STOP_MASK) @@ -2722,7 +2749,7 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) goto out; /* If we're trying to set a range that overlaps the current voltage, - * return succesfully even though the regulator does not support + * return successfully even though the regulator does not support * changing the voltage. */ if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) { @@ -3450,6 +3477,8 @@ EXPORT_SYMBOL_GPL(regulator_bulk_free); int regulator_notifier_call_chain(struct regulator_dev *rdev, unsigned long event, void *data) { + lockdep_assert_held_once(&rdev->mutex); + _notifier_call_chain(rdev, event, data); return NOTIFY_DONE; @@ -3594,6 +3623,9 @@ static const struct attribute_group *regulator_dev_groups[] = { static void regulator_dev_release(struct device *dev) { struct regulator_dev *rdev = dev_get_drvdata(dev); + + kfree(rdev->constraints); + of_node_put(rdev->dev.of_node); kfree(rdev); } @@ -3824,11 +3856,9 @@ void regulator_unregister(struct regulator_dev *rdev) WARN_ON(rdev->open_count); unset_regulator_supplies(rdev); list_del(&rdev->list); - kfree(rdev->constraints); + mutex_unlock(®ulator_list_mutex); regulator_ena_gpio_free(rdev); - of_node_put(rdev->dev.of_node); device_unregister(&rdev->dev); - mutex_unlock(®ulator_list_mutex); } EXPORT_SYMBOL_GPL(regulator_unregister); @@ -4147,13 +4177,57 @@ static int __init regulator_init(void) /* init early to allow our consumers to complete system booting */ core_initcall(regulator_init); -static int __init regulator_init_complete(void) +static int __init regulator_late_cleanup(struct device *dev, void *data) { - struct regulator_dev *rdev; - const struct regulator_ops *ops; - struct regulation_constraints *c; + struct regulator_dev *rdev = dev_to_rdev(dev); + const struct regulator_ops *ops = rdev->desc->ops; + struct regulation_constraints *c = rdev->constraints; int enabled, ret; + if (c && c->always_on) + return 0; + + if (c && !(c->valid_ops_mask & REGULATOR_CHANGE_STATUS)) + return 0; + + mutex_lock(&rdev->mutex); + + if (rdev->use_count) + goto unlock; + + /* If we can't read the status assume it's on. */ + if (ops->is_enabled) + enabled = ops->is_enabled(rdev); + else + enabled = 1; + + if (!enabled) + goto unlock; + + if (have_full_constraints()) { + /* We log since this may kill the system if it goes + * wrong. */ + rdev_info(rdev, "disabling\n"); + ret = _regulator_do_disable(rdev); + if (ret != 0) + rdev_err(rdev, "couldn't disable: %d\n", ret); + } else { + /* The intention is that in future we will + * assume that full constraints are provided + * so warn even if we aren't going to do + * anything here. + */ + rdev_warn(rdev, "incomplete constraints, leaving on\n"); + } + +unlock: + mutex_unlock(&rdev->mutex); + + return 0; +} + +static int __init regulator_init_complete(void) +{ /* * Since DT doesn't provide an idiomatic mechanism for * enabling full constraints and since it's much more natural @@ -4163,58 +4237,13 @@ static int __init regulator_init_complete(void) if (of_have_populated_dt()) has_full_constraints = true; - mutex_lock(®ulator_list_mutex); - /* If we have a full configuration then disable any regulators * we have permission to change the status for and which are * not in use or always_on. This is effectively the default * for DT and ACPI as they have full constraints. */ - list_for_each_entry(rdev, ®ulator_list, list) { - ops = rdev->desc->ops; - c = rdev->constraints; - - if (c && c->always_on) - continue; - - if (c && !(c->valid_ops_mask & REGULATOR_CHANGE_STATUS)) - continue; - - mutex_lock(&rdev->mutex); - - if (rdev->use_count) - goto unlock; - - /* If we can't read the status assume it's on. */ - if (ops->is_enabled) - enabled = ops->is_enabled(rdev); - else - enabled = 1; - - if (!enabled) - goto unlock; - - if (have_full_constraints()) { - /* We log since this may kill the system if it - * goes wrong. */ - rdev_info(rdev, "disabling\n"); - ret = _regulator_do_disable(rdev); - if (ret != 0) - rdev_err(rdev, "couldn't disable: %d\n", ret); - } else { - /* The intention is that in future we will - * assume that full constraints are provided - * so warn even if we aren't going to do - * anything here. - */ - rdev_warn(rdev, "incomplete constraints, leaving on\n"); - } - -unlock: - mutex_unlock(&rdev->mutex); - } - - mutex_unlock(®ulator_list_mutex); + class_for_each_device(®ulator_class, NULL, NULL, + regulator_late_cleanup); return 0; } diff --git a/drivers/regulator/da9062-regulator.c b/drivers/regulator/da9062-regulator.c index dd76da09b3c7..5638fe8d759d 100644 --- a/drivers/regulator/da9062-regulator.c +++ b/drivers/regulator/da9062-regulator.c @@ -818,7 +818,6 @@ static int da9062_regulator_probe(struct platform_device *pdev) static struct platform_driver da9062_regulator_driver = { .driver = { .name = "da9062-regulators", - .owner = THIS_MODULE, }, .probe = da9062_regulator_probe, }; diff --git a/drivers/regulator/da9210-regulator.c b/drivers/regulator/da9210-regulator.c index f0489cb9018b..b3517830edb6 100644 --- a/drivers/regulator/da9210-regulator.c +++ b/drivers/regulator/da9210-regulator.c @@ -22,6 +22,8 @@ #include <linux/i2c.h> #include <linux/module.h> #include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/irq.h> #include <linux/slab.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> @@ -120,6 +122,55 @@ static int da9210_get_current_limit(struct regulator_dev *rdev) return da9210_buck_limits[sel]; } +static irqreturn_t da9210_irq_handler(int irq, void *data) +{ + struct da9210 *chip = data; + unsigned int val, handled = 0; + int error, ret = IRQ_NONE; + + error = regmap_read(chip->regmap, DA9210_REG_EVENT_B, &val); + if (error < 0) + goto error_i2c; + + if (val & DA9210_E_OVCURR) { + regulator_notifier_call_chain(chip->rdev, + REGULATOR_EVENT_OVER_CURRENT, + NULL); + handled |= DA9210_E_OVCURR; + } + if (val & DA9210_E_NPWRGOOD) { + regulator_notifier_call_chain(chip->rdev, + REGULATOR_EVENT_UNDER_VOLTAGE, + NULL); + handled |= DA9210_E_NPWRGOOD; + } + if (val & (DA9210_E_TEMP_WARN | DA9210_E_TEMP_CRIT)) { + regulator_notifier_call_chain(chip->rdev, + REGULATOR_EVENT_OVER_TEMP, NULL); + handled |= val & (DA9210_E_TEMP_WARN | DA9210_E_TEMP_CRIT); + } + if (val & DA9210_E_VMAX) { + regulator_notifier_call_chain(chip->rdev, + REGULATOR_EVENT_REGULATION_OUT, + NULL); + handled |= DA9210_E_VMAX; + } + if (handled) { + /* Clear handled events */ + error = regmap_write(chip->regmap, DA9210_REG_EVENT_B, handled); + if (error < 0) + goto error_i2c; + + ret = IRQ_HANDLED; + } + + return ret; + +error_i2c: + dev_err(regmap_get_device(chip->regmap), "I2C error : %d\n", error); + return ret; +} + /* * I2C driver interface functions */ @@ -168,6 +219,30 @@ static int da9210_i2c_probe(struct i2c_client *i2c, } chip->rdev = rdev; + if (i2c->irq) { + error = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL, + da9210_irq_handler, + IRQF_TRIGGER_LOW | + IRQF_ONESHOT | IRQF_SHARED, + "da9210", chip); + if (error) { + dev_err(&i2c->dev, "Failed to request IRQ%u: %d\n", + i2c->irq, error); + return error; + } + + error = regmap_update_bits(chip->regmap, DA9210_REG_MASK_B, + DA9210_M_OVCURR | DA9210_M_NPWRGOOD | + DA9210_M_TEMP_WARN | + DA9210_M_TEMP_CRIT | DA9210_M_VMAX, 0); + if (error < 0) { + dev_err(&i2c->dev, "Failed to update mask reg: %d\n", + error); + return error; + } + } else { + dev_warn(&i2c->dev, "No IRQ configured\n"); + } i2c_set_clientdata(i2c, chip); @@ -184,7 +259,6 @@ MODULE_DEVICE_TABLE(i2c, da9210_i2c_id); static struct i2c_driver da9210_regulator_driver = { .driver = { .name = "da9210", - .owner = THIS_MODULE, }, .probe = da9210_i2c_probe, .id_table = da9210_i2c_id, diff --git a/drivers/regulator/da9211-regulator.c b/drivers/regulator/da9211-regulator.c index df79e4b1946e..04ef65b7eb3d 100644 --- a/drivers/regulator/da9211-regulator.c +++ b/drivers/regulator/da9211-regulator.c @@ -1,6 +1,6 @@ /* - * da9211-regulator.c - Regulator device driver for DA9211/DA9213 - * Copyright (C) 2014 Dialog Semiconductor Ltd. + * da9211-regulator.c - Regulator device driver for DA9211/DA9213/DA9215 + * Copyright (C) 2015 Dialog Semiconductor Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -32,6 +32,7 @@ /* DEVICE IDs */ #define DA9211_DEVICE_ID 0x22 #define DA9213_DEVICE_ID 0x23 +#define DA9215_DEVICE_ID 0x24 #define DA9211_BUCK_MODE_SLEEP 1 #define DA9211_BUCK_MODE_SYNC 2 @@ -90,6 +91,13 @@ static const int da9213_current_limits[] = { 3000000, 3200000, 3400000, 3600000, 3800000, 4000000, 4200000, 4400000, 4600000, 4800000, 5000000, 5200000, 5400000, 5600000, 5800000, 6000000 }; +/* Current limits for DA9215 buck (uA) indices + * corresponds with register values + */ +static const int da9215_current_limits[] = { + 4000000, 4200000, 4400000, 4600000, 4800000, 5000000, 5200000, 5400000, + 5600000, 5800000, 6000000, 6200000, 6400000, 6600000, 6800000, 7000000 +}; static unsigned int da9211_buck_get_mode(struct regulator_dev *rdev) { @@ -157,6 +165,10 @@ static int da9211_set_current_limit(struct regulator_dev *rdev, int min, current_limits = da9213_current_limits; max_size = ARRAY_SIZE(da9213_current_limits)-1; break; + case DA9215: + current_limits = da9215_current_limits; + max_size = ARRAY_SIZE(da9215_current_limits)-1; + break; default: return -EINVAL; } @@ -189,6 +201,9 @@ static int da9211_get_current_limit(struct regulator_dev *rdev) case DA9213: current_limits = da9213_current_limits; break; + case DA9215: + current_limits = da9215_current_limits; + break; default: return -EINVAL; } @@ -350,13 +365,11 @@ static int da9211_regulator_init(struct da9211 *chip) /* If configuration for 1/2 bucks is different between platform data * and the register, driver should exit. */ - if ((chip->pdata->num_buck == 2 && data == 0x40) - || (chip->pdata->num_buck == 1 && data == 0x00)) { - if (data == 0) - chip->num_regulator = 1; - else - chip->num_regulator = 2; - } else { + if (chip->pdata->num_buck == 1 && data == 0x00) + chip->num_regulator = 1; + else if (chip->pdata->num_buck == 2 && data != 0x00) + chip->num_regulator = 2; + else { dev_err(chip->dev, "Configuration is mismatched\n"); return -EINVAL; } @@ -438,6 +451,9 @@ static int da9211_i2c_probe(struct i2c_client *i2c, case DA9213_DEVICE_ID: chip->chip_id = DA9213; break; + case DA9215_DEVICE_ID: + chip->chip_id = DA9215; + break; default: dev_err(chip->dev, "Unsupported device id = 0x%x.\n", data); return -ENODEV; @@ -478,6 +494,7 @@ static int da9211_i2c_probe(struct i2c_client *i2c, static const struct i2c_device_id da9211_i2c_id[] = { {"da9211", DA9211}, {"da9213", DA9213}, + {"da9215", DA9215}, {}, }; MODULE_DEVICE_TABLE(i2c, da9211_i2c_id); @@ -486,6 +503,7 @@ MODULE_DEVICE_TABLE(i2c, da9211_i2c_id); static const struct of_device_id da9211_dt_ids[] = { { .compatible = "dlg,da9211", .data = &da9211_i2c_id[0] }, { .compatible = "dlg,da9213", .data = &da9211_i2c_id[1] }, + { .compatible = "dlg,da9215", .data = &da9211_i2c_id[2] }, {}, }; MODULE_DEVICE_TABLE(of, da9211_dt_ids); @@ -494,7 +512,6 @@ MODULE_DEVICE_TABLE(of, da9211_dt_ids); static struct i2c_driver da9211_regulator_driver = { .driver = { .name = "da9211", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(da9211_dt_ids), }, .probe = da9211_i2c_probe, @@ -504,5 +521,5 @@ static struct i2c_driver da9211_regulator_driver = { module_i2c_driver(da9211_regulator_driver); MODULE_AUTHOR("James Ban <James.Ban.opensource@diasemi.com>"); -MODULE_DESCRIPTION("Regulator device driver for Dialog DA9211/DA9213"); -MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Regulator device driver for Dialog DA9211/DA9213/DA9215"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/da9211-regulator.h b/drivers/regulator/da9211-regulator.h index 93fa9df2721c..d6ad96fc64d3 100644 --- a/drivers/regulator/da9211-regulator.h +++ b/drivers/regulator/da9211-regulator.h @@ -1,16 +1,16 @@ /* - * da9211-regulator.h - Regulator definitions for DA9211/DA9213 - * Copyright (C) 2014 Dialog Semiconductor Ltd. + * da9211-regulator.h - Regulator definitions for DA9211/DA9213/DA9215 + * Copyright (C) 2015 Dialog Semiconductor Ltd. * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * - * This library is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ #ifndef __DA9211_REGISTERS_H__ diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c index 42865681c00b..4940e8287df6 100644 --- a/drivers/regulator/fan53555.c +++ b/drivers/regulator/fan53555.c @@ -439,6 +439,7 @@ static const struct i2c_device_id fan53555_id[] = { }, { }, }; +MODULE_DEVICE_TABLE(i2c, fan53555_id); static struct i2c_driver fan53555_regulator_driver = { .driver = { diff --git a/drivers/regulator/isl6271a-regulator.c b/drivers/regulator/isl6271a-regulator.c index 6e5da95fa025..4abd8e9c81e5 100644 --- a/drivers/regulator/isl6271a-regulator.c +++ b/drivers/regulator/isl6271a-regulator.c @@ -156,7 +156,6 @@ MODULE_DEVICE_TABLE(i2c, isl6271a_id); static struct i2c_driver isl6271a_i2c_driver = { .driver = { .name = "isl6271a", - .owner = THIS_MODULE, }, .probe = isl6271a_probe, .id_table = isl6271a_id, diff --git a/drivers/regulator/isl9305.c b/drivers/regulator/isl9305.c index 6e3a15fe00f1..257c1943e753 100644 --- a/drivers/regulator/isl9305.c +++ b/drivers/regulator/isl9305.c @@ -183,6 +183,7 @@ static const struct of_device_id isl9305_dt_ids[] = { { .compatible = "isil,isl9305h" }, {}, }; +MODULE_DEVICE_TABLE(of, isl9305_dt_ids); #endif static const struct i2c_device_id isl9305_i2c_id[] = { @@ -195,7 +196,6 @@ MODULE_DEVICE_TABLE(i2c, isl9305_i2c_id); static struct i2c_driver isl9305_regulator_driver = { .driver = { .name = "isl9305", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(isl9305_dt_ids), }, .probe = isl9305_i2c_probe, diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c index 66fd2330dca0..15c25c622edf 100644 --- a/drivers/regulator/lp3971.c +++ b/drivers/regulator/lp3971.c @@ -452,7 +452,6 @@ MODULE_DEVICE_TABLE(i2c, lp3971_i2c_id); static struct i2c_driver lp3971_i2c_driver = { .driver = { .name = "LP3971", - .owner = THIS_MODULE, }, .probe = lp3971_i2c_probe, .id_table = lp3971_i2c_id, diff --git a/drivers/regulator/lp3972.c b/drivers/regulator/lp3972.c index aea485afcc1a..3a7e96e2c7b3 100644 --- a/drivers/regulator/lp3972.c +++ b/drivers/regulator/lp3972.c @@ -550,7 +550,6 @@ MODULE_DEVICE_TABLE(i2c, lp3972_i2c_id); static struct i2c_driver lp3972_i2c_driver = { .driver = { .name = "lp3972", - .owner = THIS_MODULE, }, .probe = lp3972_i2c_probe, .id_table = lp3972_i2c_id, diff --git a/drivers/regulator/lp872x.c b/drivers/regulator/lp872x.c index 3de328ab41f3..e5af07208f9d 100644 --- a/drivers/regulator/lp872x.c +++ b/drivers/regulator/lp872x.c @@ -849,7 +849,7 @@ static struct lp872x_platform_data pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) - goto out; + return ERR_PTR(-ENOMEM); of_property_read_u8(np, "ti,general-config", &pdata->general_config); if (of_find_property(np, "ti,update-config", NULL)) @@ -857,7 +857,7 @@ static struct lp872x_platform_data pdata->dvs = devm_kzalloc(dev, sizeof(struct lp872x_dvs), GFP_KERNEL); if (!pdata->dvs) - goto out; + return ERR_PTR(-ENOMEM); pdata->dvs->gpio = of_get_named_gpio(np, "ti,dvs-gpio", 0); of_property_read_u8(np, "ti,dvs-vsel", (u8 *)&pdata->dvs->vsel); @@ -903,15 +903,21 @@ static struct lp872x_platform_data static int lp872x_probe(struct i2c_client *cl, const struct i2c_device_id *id) { struct lp872x *lp; + struct lp872x_platform_data *pdata; int ret; const int lp872x_num_regulators[] = { [LP8720] = LP8720_NUM_REGULATORS, [LP8725] = LP8725_NUM_REGULATORS, }; - if (cl->dev.of_node) - cl->dev.platform_data = lp872x_populate_pdata_from_dt(&cl->dev, + if (cl->dev.of_node) { + pdata = lp872x_populate_pdata_from_dt(&cl->dev, (enum lp872x_id)id->driver_data); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); + } else { + pdata = dev_get_platdata(&cl->dev); + } lp = devm_kzalloc(&cl->dev, sizeof(struct lp872x), GFP_KERNEL); if (!lp) @@ -927,7 +933,7 @@ static int lp872x_probe(struct i2c_client *cl, const struct i2c_device_id *id) } lp->dev = &cl->dev; - lp->pdata = dev_get_platdata(&cl->dev); + lp->pdata = pdata; lp->chipid = id->driver_data; i2c_set_clientdata(cl, lp); @@ -955,7 +961,6 @@ MODULE_DEVICE_TABLE(i2c, lp872x_ids); static struct i2c_driver lp872x_driver = { .driver = { .name = "lp872x", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(lp872x_dt_ids), }, .probe = lp872x_probe, diff --git a/drivers/regulator/ltc3589.c b/drivers/regulator/ltc3589.c index 0ce8e4e0fa73..972c386b2690 100644 --- a/drivers/regulator/ltc3589.c +++ b/drivers/regulator/ltc3589.c @@ -378,7 +378,7 @@ static bool ltc3589_volatile_reg(struct device *dev, unsigned int reg) return false; } -static struct reg_default ltc3589_reg_defaults[] = { +static const struct reg_default ltc3589_reg_defaults[] = { { LTC3589_SCR1, 0x00 }, { LTC3589_OVEN, 0x00 }, { LTC3589_SCR2, 0x00 }, @@ -542,7 +542,6 @@ MODULE_DEVICE_TABLE(i2c, ltc3589_i2c_id); static struct i2c_driver ltc3589_driver = { .driver = { .name = DRIVER_NAME, - .owner = THIS_MODULE, }, .probe = ltc3589_probe, .id_table = ltc3589_i2c_id, @@ -552,4 +551,3 @@ module_i2c_driver(ltc3589_driver); MODULE_AUTHOR("Philipp Zabel <p.zabel@pengutronix.de>"); MODULE_DESCRIPTION("Regulator driver for Linear Technology LTC3589(-1,2)"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("i2c:ltc3589"); diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c index d2a8c64cae42..2c1228d5796a 100644 --- a/drivers/regulator/max1586.c +++ b/drivers/regulator/max1586.c @@ -304,7 +304,6 @@ static struct i2c_driver max1586_pmic_driver = { .probe = max1586_pmic_probe, .driver = { .name = "max1586", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(max1586_of_match), }, .id_table = max1586_id, diff --git a/drivers/regulator/max77693.c b/drivers/regulator/max77693.c index 38722c8311a5..de730fd3f8a5 100644 --- a/drivers/regulator/max77693.c +++ b/drivers/regulator/max77693.c @@ -1,8 +1,9 @@ /* - * max77693.c - Regulator driver for the Maxim 77693 + * max77693.c - Regulator driver for the Maxim 77693 and 77843 * - * Copyright (C) 2013 Samsung Electronics + * Copyright (C) 2013-2015 Samsung Electronics * Jonghwa Lee <jonghwa3.lee@samsung.com> + * Krzysztof Kozlowski <k.kozlowski.k@gmail.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,38 +30,64 @@ #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> #include <linux/mfd/max77693.h> +#include <linux/mfd/max77693-common.h> #include <linux/mfd/max77693-private.h> +#include <linux/mfd/max77843-private.h> #include <linux/regulator/of_regulator.h> #include <linux/regmap.h> -#define CHGIN_ILIM_STEP_20mA 20000 +/* + * ID for MAX77843 regulators. + * There is no need for such for MAX77693. + */ +enum max77843_regulator_type { + MAX77843_SAFEOUT1 = 0, + MAX77843_SAFEOUT2, + MAX77843_CHARGER, + + MAX77843_NUM, +}; + +/* Register differences between chargers: MAX77693 and MAX77843 */ +struct chg_reg_data { + unsigned int linear_reg; + unsigned int linear_mask; + unsigned int uA_step; + unsigned int min_sel; +}; /* - * CHARGER regulator - Min : 20mA, Max : 2580mA, step : 20mA + * MAX77693 CHARGER regulator - Min : 20mA, Max : 2580mA, step : 20mA * 0x00, 0x01, 0x2, 0x03 = 60 mA * 0x04 ~ 0x7E = (60 + (X - 3) * 20) mA + * Actually for MAX77693 the driver manipulates the maximum input current, + * not the fast charge current (output). This should be fixed. + * + * On MAX77843 the calculation formula is the same (except values). + * Fortunately it properly manipulates the fast charge current. */ static int max77693_chg_get_current_limit(struct regulator_dev *rdev) { + const struct chg_reg_data *reg_data = rdev_get_drvdata(rdev); unsigned int chg_min_uA = rdev->constraints->min_uA; unsigned int chg_max_uA = rdev->constraints->max_uA; unsigned int reg, sel; unsigned int val; int ret; - ret = regmap_read(rdev->regmap, MAX77693_CHG_REG_CHG_CNFG_09, ®); + ret = regmap_read(rdev->regmap, reg_data->linear_reg, ®); if (ret < 0) return ret; - sel = reg & CHG_CNFG_09_CHGIN_ILIM_MASK; + sel = reg & reg_data->linear_mask; /* the first four codes for charger current are all 60mA */ - if (sel <= 3) + if (sel <= reg_data->min_sel) sel = 0; else - sel -= 3; + sel -= reg_data->min_sel; - val = chg_min_uA + CHGIN_ILIM_STEP_20mA * sel; + val = chg_min_uA + reg_data->uA_step * sel; if (val > chg_max_uA) return -EINVAL; @@ -70,23 +97,43 @@ static int max77693_chg_get_current_limit(struct regulator_dev *rdev) static int max77693_chg_set_current_limit(struct regulator_dev *rdev, int min_uA, int max_uA) { + const struct chg_reg_data *reg_data = rdev_get_drvdata(rdev); unsigned int chg_min_uA = rdev->constraints->min_uA; int sel = 0; - while (chg_min_uA + CHGIN_ILIM_STEP_20mA * sel < min_uA) + while (chg_min_uA + reg_data->uA_step * sel < min_uA) sel++; - if (chg_min_uA + CHGIN_ILIM_STEP_20mA * sel > max_uA) + if (chg_min_uA + reg_data->uA_step * sel > max_uA) return -EINVAL; /* the first four codes for charger current are all 60mA */ - sel += 3; + sel += reg_data->min_sel; - return regmap_write(rdev->regmap, - MAX77693_CHG_REG_CHG_CNFG_09, sel); + return regmap_write(rdev->regmap, reg_data->linear_reg, sel); } /* end of CHARGER regulator ops */ +/* Returns regmap suitable for given regulator on chosen device */ +static struct regmap *max77693_get_regmap(enum max77693_types type, + struct max77693_dev *max77693, + int reg_id) +{ + if (type == TYPE_MAX77693) + return max77693->regmap; + + /* Else: TYPE_MAX77843 */ + switch (reg_id) { + case MAX77843_SAFEOUT1: + case MAX77843_SAFEOUT2: + return max77693->regmap; + case MAX77843_CHARGER: + return max77693->regmap_chg; + default: + return max77693->regmap; + } +} + static const unsigned int max77693_safeout_table[] = { 4850000, 4900000, @@ -111,7 +158,7 @@ static struct regulator_ops max77693_charger_ops = { .set_current_limit = max77693_chg_set_current_limit, }; -#define regulator_desc_esafeout(_num) { \ +#define max77693_regulator_desc_esafeout(_num) { \ .name = "ESAFEOUT"#_num, \ .id = MAX77693_ESAFEOUT##_num, \ .of_match = of_match_ptr("ESAFEOUT"#_num), \ @@ -127,9 +174,9 @@ static struct regulator_ops max77693_charger_ops = { .enable_mask = SAFEOUT_CTRL_ENSAFEOUT##_num##_MASK , \ } -static const struct regulator_desc regulators[] = { - regulator_desc_esafeout(1), - regulator_desc_esafeout(2), +static const struct regulator_desc max77693_supported_regulators[] = { + max77693_regulator_desc_esafeout(1), + max77693_regulator_desc_esafeout(2), { .name = "CHARGER", .id = MAX77693_CHARGER, @@ -145,18 +192,86 @@ static const struct regulator_desc regulators[] = { }, }; +static const struct chg_reg_data max77693_chg_reg_data = { + .linear_reg = MAX77693_CHG_REG_CHG_CNFG_09, + .linear_mask = CHG_CNFG_09_CHGIN_ILIM_MASK, + .uA_step = 20000, + .min_sel = 3, +}; + +#define max77843_regulator_desc_esafeout(num) { \ + .name = "SAFEOUT" # num, \ + .id = MAX77843_SAFEOUT ## num, \ + .ops = &max77693_safeout_ops, \ + .of_match = of_match_ptr("SAFEOUT" # num), \ + .regulators_node = of_match_ptr("regulators"), \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .n_voltages = ARRAY_SIZE(max77693_safeout_table), \ + .volt_table = max77693_safeout_table, \ + .enable_reg = MAX77843_SYS_REG_SAFEOUTCTRL, \ + .enable_mask = MAX77843_REG_SAFEOUTCTRL_ENSAFEOUT ## num, \ + .vsel_reg = MAX77843_SYS_REG_SAFEOUTCTRL, \ + .vsel_mask = MAX77843_REG_SAFEOUTCTRL_SAFEOUT ## num ## _MASK, \ +} + +static const struct regulator_desc max77843_supported_regulators[] = { + [MAX77843_SAFEOUT1] = max77843_regulator_desc_esafeout(1), + [MAX77843_SAFEOUT2] = max77843_regulator_desc_esafeout(2), + [MAX77843_CHARGER] = { + .name = "CHARGER", + .id = MAX77843_CHARGER, + .ops = &max77693_charger_ops, + .of_match = of_match_ptr("CHARGER"), + .regulators_node = of_match_ptr("regulators"), + .type = REGULATOR_CURRENT, + .owner = THIS_MODULE, + .enable_reg = MAX77843_CHG_REG_CHG_CNFG_00, + .enable_mask = MAX77843_CHG_MASK, + .enable_val = MAX77843_CHG_MASK, + }, +}; + +static const struct chg_reg_data max77843_chg_reg_data = { + .linear_reg = MAX77843_CHG_REG_CHG_CNFG_02, + .linear_mask = MAX77843_CHG_FAST_CHG_CURRENT_MASK, + .uA_step = MAX77843_CHG_FAST_CHG_CURRENT_STEP, + .min_sel = 2, +}; + static int max77693_pmic_probe(struct platform_device *pdev) { + enum max77693_types type = platform_get_device_id(pdev)->driver_data; struct max77693_dev *iodev = dev_get_drvdata(pdev->dev.parent); + const struct regulator_desc *regulators; + unsigned int regulators_size; int i; struct regulator_config config = { }; config.dev = iodev->dev; - config.regmap = iodev->regmap; - for (i = 0; i < ARRAY_SIZE(regulators); i++) { + switch (type) { + case TYPE_MAX77693: + regulators = max77693_supported_regulators; + regulators_size = ARRAY_SIZE(max77693_supported_regulators); + config.driver_data = (void *)&max77693_chg_reg_data; + break; + case TYPE_MAX77843: + regulators = max77843_supported_regulators; + regulators_size = ARRAY_SIZE(max77843_supported_regulators); + config.driver_data = (void *)&max77843_chg_reg_data; + break; + default: + dev_err(&pdev->dev, "Unsupported device type: %u\n", type); + return -ENODEV; + } + + for (i = 0; i < regulators_size; i++) { struct regulator_dev *rdev; + config.regmap = max77693_get_regmap(type, iodev, + regulators[i].id); + rdev = devm_regulator_register(&pdev->dev, ®ulators[i], &config); if (IS_ERR(rdev)) { @@ -170,7 +285,8 @@ static int max77693_pmic_probe(struct platform_device *pdev) } static const struct platform_device_id max77693_pmic_id[] = { - {"max77693-pmic", 0}, + { "max77693-pmic", TYPE_MAX77693 }, + { "max77843-regulator", TYPE_MAX77843 }, {}, }; @@ -184,8 +300,19 @@ static struct platform_driver max77693_pmic_driver = { .id_table = max77693_pmic_id, }; -module_platform_driver(max77693_pmic_driver); +static int __init max77693_pmic_init(void) +{ + return platform_driver_register(&max77693_pmic_driver); +} +subsys_initcall(max77693_pmic_init); + +static void __exit max77693_pmic_cleanup(void) +{ + platform_driver_unregister(&max77693_pmic_driver); +} +module_exit(max77693_pmic_cleanup); -MODULE_DESCRIPTION("MAXIM MAX77693 regulator driver"); +MODULE_DESCRIPTION("MAXIM 77693/77843 regulator driver"); MODULE_AUTHOR("Jonghwa Lee <jonghwa3.lee@samsung.com>"); +MODULE_AUTHOR("Krzysztof Kozlowski <k.kozlowski.k@gmail.com>"); MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/max77843.c b/drivers/regulator/max77843.c deleted file mode 100644 index f4fd0d3cfa6e..000000000000 --- a/drivers/regulator/max77843.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * max77843.c - Regulator driver for the Maxim MAX77843 - * - * Copyright (C) 2015 Samsung Electronics - * Author: Jaewon Kim <jaewon02.kim@samsung.com> - * Author: Beomho Seo <beomho.seo@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/regulator/driver.h> -#include <linux/regulator/machine.h> -#include <linux/mfd/max77843-private.h> -#include <linux/regulator/of_regulator.h> - -enum max77843_regulator_type { - MAX77843_SAFEOUT1 = 0, - MAX77843_SAFEOUT2, - MAX77843_CHARGER, - - MAX77843_NUM, -}; - -static const unsigned int max77843_safeout_voltage_table[] = { - 4850000, - 4900000, - 4950000, - 3300000, -}; - -static int max77843_reg_get_current_limit(struct regulator_dev *rdev) -{ - struct regmap *regmap = rdev->regmap; - unsigned int chg_min_uA = rdev->constraints->min_uA; - unsigned int chg_max_uA = rdev->constraints->max_uA; - unsigned int val; - int ret; - unsigned int reg, sel; - - ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_CNFG_02, ®); - if (ret) { - dev_err(&rdev->dev, "Failed to read charger register\n"); - return ret; - } - - sel = reg & MAX77843_CHG_FAST_CHG_CURRENT_MASK; - - if (sel < 0x03) - sel = 0; - else - sel -= 2; - - val = chg_min_uA + MAX77843_CHG_FAST_CHG_CURRENT_STEP * sel; - if (val > chg_max_uA) - return -EINVAL; - - return val; -} - -static int max77843_reg_set_current_limit(struct regulator_dev *rdev, - int min_uA, int max_uA) -{ - struct regmap *regmap = rdev->regmap; - unsigned int chg_min_uA = rdev->constraints->min_uA; - int sel = 0; - - while (chg_min_uA + MAX77843_CHG_FAST_CHG_CURRENT_STEP * sel < min_uA) - sel++; - - if (chg_min_uA + MAX77843_CHG_FAST_CHG_CURRENT_STEP * sel > max_uA) - return -EINVAL; - - sel += 2; - - return regmap_write(regmap, MAX77843_CHG_REG_CHG_CNFG_02, sel); -} - -static struct regulator_ops max77843_charger_ops = { - .is_enabled = regulator_is_enabled_regmap, - .enable = regulator_enable_regmap, - .disable = regulator_disable_regmap, - .get_current_limit = max77843_reg_get_current_limit, - .set_current_limit = max77843_reg_set_current_limit, -}; - -static struct regulator_ops max77843_regulator_ops = { - .is_enabled = regulator_is_enabled_regmap, - .enable = regulator_enable_regmap, - .disable = regulator_disable_regmap, - .list_voltage = regulator_list_voltage_table, - .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_sel = regulator_set_voltage_sel_regmap, -}; - -#define MAX77843_SAFEOUT(num) { \ - .name = "SAFEOUT" # num, \ - .id = MAX77843_SAFEOUT ## num, \ - .ops = &max77843_regulator_ops, \ - .of_match = of_match_ptr("SAFEOUT" # num), \ - .regulators_node = of_match_ptr("regulators"), \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - .n_voltages = ARRAY_SIZE(max77843_safeout_voltage_table), \ - .volt_table = max77843_safeout_voltage_table, \ - .enable_reg = MAX77843_SYS_REG_SAFEOUTCTRL, \ - .enable_mask = MAX77843_REG_SAFEOUTCTRL_ENSAFEOUT ## num, \ - .vsel_reg = MAX77843_SYS_REG_SAFEOUTCTRL, \ - .vsel_mask = MAX77843_REG_SAFEOUTCTRL_SAFEOUT ## num ## _MASK, \ -} - -static const struct regulator_desc max77843_supported_regulators[] = { - [MAX77843_SAFEOUT1] = MAX77843_SAFEOUT(1), - [MAX77843_SAFEOUT2] = MAX77843_SAFEOUT(2), - [MAX77843_CHARGER] = { - .name = "CHARGER", - .id = MAX77843_CHARGER, - .ops = &max77843_charger_ops, - .of_match = of_match_ptr("CHARGER"), - .regulators_node = of_match_ptr("regulators"), - .type = REGULATOR_CURRENT, - .owner = THIS_MODULE, - .enable_reg = MAX77843_CHG_REG_CHG_CNFG_00, - .enable_mask = MAX77843_CHG_MASK | MAX77843_CHG_BUCK_MASK, - .enable_val = MAX77843_CHG_MASK | MAX77843_CHG_BUCK_MASK, - }, -}; - -static struct regmap *max77843_get_regmap(struct max77843 *max77843, int reg_id) -{ - switch (reg_id) { - case MAX77843_SAFEOUT1: - case MAX77843_SAFEOUT2: - return max77843->regmap; - case MAX77843_CHARGER: - return max77843->regmap_chg; - default: - return max77843->regmap; - } -} - -static int max77843_regulator_probe(struct platform_device *pdev) -{ - struct max77843 *max77843 = dev_get_drvdata(pdev->dev.parent); - struct regulator_config config = {}; - int i; - - config.dev = max77843->dev; - config.driver_data = max77843; - - for (i = 0; i < ARRAY_SIZE(max77843_supported_regulators); i++) { - struct regulator_dev *regulator; - - config.regmap = max77843_get_regmap(max77843, - max77843_supported_regulators[i].id); - - regulator = devm_regulator_register(&pdev->dev, - &max77843_supported_regulators[i], &config); - if (IS_ERR(regulator)) { - dev_err(&pdev->dev, - "Failed to regiser regulator-%d\n", i); - return PTR_ERR(regulator); - } - } - - return 0; -} - -static const struct platform_device_id max77843_regulator_id[] = { - { "max77843-regulator", }, - { /* sentinel */ }, -}; - -static struct platform_driver max77843_regulator_driver = { - .driver = { - .name = "max77843-regulator", - }, - .probe = max77843_regulator_probe, - .id_table = max77843_regulator_id, -}; - -static int __init max77843_regulator_init(void) -{ - return platform_driver_register(&max77843_regulator_driver); -} -subsys_initcall(max77843_regulator_init); - -static void __exit max77843_regulator_exit(void) -{ - platform_driver_unregister(&max77843_regulator_driver); -} -module_exit(max77843_regulator_exit); - -MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>"); -MODULE_AUTHOR("Beomho Seo <beomho.seo@samsung.com>"); -MODULE_DESCRIPTION("Maxim MAX77843 regulator driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c index 4071d74fa828..b87f62dd484e 100644 --- a/drivers/regulator/max8660.c +++ b/drivers/regulator/max8660.c @@ -518,7 +518,6 @@ static struct i2c_driver max8660_driver = { .probe = max8660_probe, .driver = { .name = "max8660", - .owner = THIS_MODULE, }, .id_table = max8660_id, }; diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c index e94ddcf97722..5b75b7c2e3ea 100644 --- a/drivers/regulator/max8973-regulator.c +++ b/drivers/regulator/max8973-regulator.c @@ -75,6 +75,7 @@ #define MAX8973_DISCH_ENBABLE BIT(5) #define MAX8973_FT_ENABLE BIT(4) +#define MAX8973_CKKADV_TRIP_MASK 0xC #define MAX8973_CKKADV_TRIP_DISABLE 0xC #define MAX8973_CKKADV_TRIP_75mV_PER_US 0x0 #define MAX8973_CKKADV_TRIP_150mV_PER_US 0x4 @@ -282,6 +283,55 @@ static int max8973_set_ramp_delay(struct regulator_dev *rdev, return ret; } +static int max8973_set_current_limit(struct regulator_dev *rdev, + int min_ua, int max_ua) +{ + struct max8973_chip *max = rdev_get_drvdata(rdev); + unsigned int val; + int ret; + + if (max_ua <= 9000000) + val = MAX8973_CKKADV_TRIP_75mV_PER_US; + else if (max_ua <= 12000000) + val = MAX8973_CKKADV_TRIP_150mV_PER_US; + else + val = MAX8973_CKKADV_TRIP_DISABLE; + + ret = regmap_update_bits(max->regmap, MAX8973_CONTROL2, + MAX8973_CKKADV_TRIP_MASK, val); + if (ret < 0) { + dev_err(max->dev, "register %d update failed: %d\n", + MAX8973_CONTROL2, ret); + return ret; + } + return 0; +} + +static int max8973_get_current_limit(struct regulator_dev *rdev) +{ + struct max8973_chip *max = rdev_get_drvdata(rdev); + unsigned int control2; + int ret; + + ret = regmap_read(max->regmap, MAX8973_CONTROL2, &control2); + if (ret < 0) { + dev_err(max->dev, "register %d read failed: %d\n", + MAX8973_CONTROL2, ret); + return ret; + } + switch (control2 & MAX8973_CKKADV_TRIP_MASK) { + case MAX8973_CKKADV_TRIP_DISABLE: + return 15000000; + case MAX8973_CKKADV_TRIP_150mV_PER_US: + return 12000000; + case MAX8973_CKKADV_TRIP_75mV_PER_US: + return 9000000; + default: + break; + } + return 9000000; +} + static const struct regulator_ops max8973_dcdc_ops = { .get_voltage_sel = max8973_dcdc_get_voltage_sel, .set_voltage_sel = max8973_dcdc_set_voltage_sel, @@ -421,6 +471,8 @@ static struct max8973_regulator_platform_data *max8973_parse_dt( struct device_node *np = dev->of_node; int ret; u32 pval; + bool etr_enable; + bool etr_sensitivity_high; pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) @@ -452,6 +504,23 @@ static struct max8973_regulator_platform_data *max8973_parse_dt( if (of_property_read_bool(np, "maxim,enable-bias-control")) pdata->control_flags |= MAX8973_CONTROL_BIAS_ENABLE; + etr_enable = of_property_read_bool(np, "maxim,enable-etr"); + etr_sensitivity_high = of_property_read_bool(np, + "maxim,enable-high-etr-sensitivity"); + if (etr_sensitivity_high) + etr_enable = true; + + if (etr_enable) { + if (etr_sensitivity_high) + pdata->control_flags |= + MAX8973_CONTROL_CLKADV_TRIP_75mV_PER_US; + else + pdata->control_flags |= + MAX8973_CONTROL_CLKADV_TRIP_150mV_PER_US; + } else { + pdata->control_flags |= MAX8973_CONTROL_CLKADV_TRIP_DISABLED; + } + return pdata; } @@ -568,6 +637,15 @@ static int max8973_probe(struct i2c_client *client, max->lru_index[i] = i; max->lru_index[0] = max->curr_vout_reg; max->lru_index[max->curr_vout_reg] = 0; + } else { + /* + * If there is no DVS GPIO, the VOUT register + * address is fixed. + */ + max->ops.set_voltage_sel = regulator_set_voltage_sel_regmap; + max->ops.get_voltage_sel = regulator_get_voltage_sel_regmap; + max->desc.vsel_reg = max->curr_vout_reg; + max->desc.vsel_mask = MAX8973_VOUT_MASK; } if (pdata_from_dt) @@ -613,6 +691,8 @@ static int max8973_probe(struct i2c_client *client, max->ops.enable = regulator_enable_regmap; max->ops.disable = regulator_disable_regmap; max->ops.is_enabled = regulator_is_enabled_regmap; + max->ops.set_current_limit = max8973_set_current_limit; + max->ops.get_current_limit = max8973_get_current_limit; break; default: break; @@ -652,7 +732,6 @@ static struct i2c_driver max8973_i2c_driver = { .driver = { .name = "max8973", .of_match_table = of_max8973_match_tbl, - .owner = THIS_MODULE, }, .probe = max8973_probe, .id_table = max8973_id, diff --git a/drivers/regulator/mt6311-regulator.c b/drivers/regulator/mt6311-regulator.c new file mode 100644 index 000000000000..02c4e5feca8e --- /dev/null +++ b/drivers/regulator/mt6311-regulator.c @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2015 MediaTek Inc. + * Author: Henry Chen <henryc.chen@mediatek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/err.h> +#include <linux/gpio.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> +#include <linux/regulator/mt6311.h> +#include <linux/slab.h> +#include "mt6311-regulator.h" + +static const struct regmap_config mt6311_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = MT6311_FQMTR_CON4, +}; + +/* Default limits measured in millivolts and milliamps */ +#define MT6311_MIN_UV 600000 +#define MT6311_MAX_UV 1393750 +#define MT6311_STEP_UV 6250 + +static const struct regulator_linear_range buck_volt_range[] = { + REGULATOR_LINEAR_RANGE(MT6311_MIN_UV, 0, 0x7f, MT6311_STEP_UV), +}; + +static const struct regulator_ops mt6311_buck_ops = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + +static const struct regulator_ops mt6311_ldo_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + +#define MT6311_BUCK(_id) \ +{\ + .name = #_id,\ + .ops = &mt6311_buck_ops,\ + .of_match = of_match_ptr(#_id),\ + .regulators_node = of_match_ptr("regulators"),\ + .type = REGULATOR_VOLTAGE,\ + .id = MT6311_ID_##_id,\ + .n_voltages = (MT6311_MAX_UV - MT6311_MIN_UV) / MT6311_STEP_UV + 1,\ + .min_uV = MT6311_MIN_UV,\ + .uV_step = MT6311_STEP_UV,\ + .owner = THIS_MODULE,\ + .linear_ranges = buck_volt_range, \ + .n_linear_ranges = ARRAY_SIZE(buck_volt_range), \ + .enable_reg = MT6311_VDVFS11_CON9,\ + .enable_mask = MT6311_PMIC_VDVFS11_EN_MASK,\ + .vsel_reg = MT6311_VDVFS11_CON12,\ + .vsel_mask = MT6311_PMIC_VDVFS11_VOSEL_MASK,\ +} + +#define MT6311_LDO(_id) \ +{\ + .name = #_id,\ + .ops = &mt6311_ldo_ops,\ + .of_match = of_match_ptr(#_id),\ + .regulators_node = of_match_ptr("regulators"),\ + .type = REGULATOR_VOLTAGE,\ + .id = MT6311_ID_##_id,\ + .owner = THIS_MODULE,\ + .enable_reg = MT6311_LDO_CON3,\ + .enable_mask = MT6311_PMIC_RG_VBIASN_EN_MASK,\ +} + +static const struct regulator_desc mt6311_regulators[] = { + MT6311_BUCK(VDVFS), + MT6311_LDO(VBIASN), +}; + +/* + * I2C driver interface functions + */ +static int mt6311_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct regulator_config config = { }; + struct regulator_dev *rdev; + struct regmap *regmap; + int i, ret; + unsigned int data; + + regmap = devm_regmap_init_i2c(i2c, &mt6311_regmap_config); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + ret = regmap_read(regmap, MT6311_SWCID, &data); + if (ret < 0) { + dev_err(&i2c->dev, "Failed to read DEVICE_ID reg: %d\n", ret); + return ret; + } + + switch (data) { + case MT6311_E1_CID_CODE: + case MT6311_E2_CID_CODE: + case MT6311_E3_CID_CODE: + break; + default: + dev_err(&i2c->dev, "Unsupported device id = 0x%x.\n", data); + return -ENODEV; + } + + for (i = 0; i < MT6311_MAX_REGULATORS; i++) { + config.dev = &i2c->dev; + config.regmap = regmap; + + rdev = devm_regulator_register(&i2c->dev, + &mt6311_regulators[i], &config); + if (IS_ERR(rdev)) { + dev_err(&i2c->dev, + "Failed to register MT6311 regulator\n"); + return PTR_ERR(rdev); + } + } + + return 0; +} + +static const struct i2c_device_id mt6311_i2c_id[] = { + {"mt6311", 0}, + {}, +}; +MODULE_DEVICE_TABLE(i2c, mt6311_i2c_id); + +#ifdef CONFIG_OF +static const struct of_device_id mt6311_dt_ids[] = { + { .compatible = "mediatek,mt6311-regulator", + .data = &mt6311_i2c_id[0] }, + {}, +}; +MODULE_DEVICE_TABLE(of, mt6311_dt_ids); +#endif + +static struct i2c_driver mt6311_regulator_driver = { + .driver = { + .name = "mt6311", + .of_match_table = of_match_ptr(mt6311_dt_ids), + }, + .probe = mt6311_i2c_probe, + .id_table = mt6311_i2c_id, +}; + +module_i2c_driver(mt6311_regulator_driver); + +MODULE_AUTHOR("Henry Chen <henryc.chen@mediatek.com>"); +MODULE_DESCRIPTION("Regulator device driver for Mediatek MT6311"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/mt6311-regulator.h b/drivers/regulator/mt6311-regulator.h new file mode 100644 index 000000000000..5218db46a798 --- /dev/null +++ b/drivers/regulator/mt6311-regulator.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2015 MediaTek Inc. + * Author: Henry Chen <henryc.chen@mediatek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MT6311_REGULATOR_H__ +#define __MT6311_REGULATOR_H__ + +#define MT6311_SWCID 0x01 + +#define MT6311_TOP_INT_CON 0x18 +#define MT6311_TOP_INT_MON 0x19 + +#define MT6311_VDVFS11_CON0 0x87 +#define MT6311_VDVFS11_CON7 0x88 +#define MT6311_VDVFS11_CON8 0x89 +#define MT6311_VDVFS11_CON9 0x8A +#define MT6311_VDVFS11_CON10 0x8B +#define MT6311_VDVFS11_CON11 0x8C +#define MT6311_VDVFS11_CON12 0x8D +#define MT6311_VDVFS11_CON13 0x8E +#define MT6311_VDVFS11_CON14 0x8F +#define MT6311_VDVFS11_CON15 0x90 +#define MT6311_VDVFS11_CON16 0x91 +#define MT6311_VDVFS11_CON17 0x92 +#define MT6311_VDVFS11_CON18 0x93 +#define MT6311_VDVFS11_CON19 0x94 + +#define MT6311_LDO_CON0 0xCC +#define MT6311_LDO_OCFB0 0xCD +#define MT6311_LDO_CON2 0xCE +#define MT6311_LDO_CON3 0xCF +#define MT6311_LDO_CON4 0xD0 +#define MT6311_FQMTR_CON0 0xD1 +#define MT6311_FQMTR_CON1 0xD2 +#define MT6311_FQMTR_CON2 0xD3 +#define MT6311_FQMTR_CON3 0xD4 +#define MT6311_FQMTR_CON4 0xD5 + +#define MT6311_PMIC_RG_INT_POL_MASK 0x1 +#define MT6311_PMIC_RG_INT_EN_MASK 0x2 +#define MT6311_PMIC_RG_BUCK_OC_INT_STATUS_MASK 0x10 + +#define MT6311_PMIC_VDVFS11_EN_CTRL_MASK 0x1 +#define MT6311_PMIC_VDVFS11_VOSEL_CTRL_MASK 0x2 +#define MT6311_PMIC_VDVFS11_EN_SEL_MASK 0x3 +#define MT6311_PMIC_VDVFS11_VOSEL_SEL_MASK 0xc +#define MT6311_PMIC_VDVFS11_EN_MASK 0x1 +#define MT6311_PMIC_VDVFS11_VOSEL_MASK 0x7F +#define MT6311_PMIC_VDVFS11_VOSEL_ON_MASK 0x7F +#define MT6311_PMIC_VDVFS11_VOSEL_SLEEP_MASK 0x7F +#define MT6311_PMIC_NI_VDVFS11_VOSEL_MASK 0x7F + +#define MT6311_PMIC_RG_VBIASN_EN_MASK 0x1 + +#endif diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index b1c485b24ab2..250700c853bf 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -107,6 +107,9 @@ static void of_get_regulation_constraints(struct device_node *np, if (!of_property_read_u32(np, "regulator-system-load", &pval)) constraints->system_load = pval; + constraints->over_current_protection = of_property_read_bool(np, + "regulator-over-current-protection"); + for (i = 0; i < ARRAY_SIZE(regulator_states); i++) { switch (i) { case PM_SUSPEND_MEM: diff --git a/drivers/regulator/pbias-regulator.c b/drivers/regulator/pbias-regulator.c index bd2b75c0d1d1..4fa7bcaf454e 100644 --- a/drivers/regulator/pbias-regulator.c +++ b/drivers/regulator/pbias-regulator.c @@ -30,6 +30,7 @@ struct pbias_reg_info { u32 enable; u32 enable_mask; + u32 disable_val; u32 vmode; unsigned int enable_time; char *name; @@ -62,6 +63,7 @@ static const struct pbias_reg_info pbias_mmc_omap2430 = { .enable = BIT(1), .enable_mask = BIT(1), .vmode = BIT(0), + .disable_val = 0, .enable_time = 100, .name = "pbias_mmc_omap2430" }; @@ -77,6 +79,7 @@ static const struct pbias_reg_info pbias_sim_omap3 = { static const struct pbias_reg_info pbias_mmc_omap4 = { .enable = BIT(26) | BIT(22), .enable_mask = BIT(26) | BIT(25) | BIT(22), + .disable_val = BIT(25), .vmode = BIT(21), .enable_time = 100, .name = "pbias_mmc_omap4" @@ -85,6 +88,7 @@ static const struct pbias_reg_info pbias_mmc_omap4 = { static const struct pbias_reg_info pbias_mmc_omap5 = { .enable = BIT(27) | BIT(26), .enable_mask = BIT(27) | BIT(25) | BIT(26), + .disable_val = BIT(25), .vmode = BIT(21), .enable_time = 100, .name = "pbias_mmc_omap5" @@ -159,6 +163,7 @@ static int pbias_regulator_probe(struct platform_device *pdev) drvdata[data_idx].desc.enable_reg = res->start; drvdata[data_idx].desc.enable_mask = info->enable_mask; drvdata[data_idx].desc.enable_val = info->enable; + drvdata[data_idx].desc.disable_val = info->disable_val; cfg.init_data = pbias_matches[idx].init_data; cfg.driver_data = &drvdata[data_idx]; diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index 8cc8d1877c44..2a44e5dd9c2a 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -643,7 +643,6 @@ static struct i2c_driver pfuze_driver = { .id_table = pfuze_device_id, .driver = { .name = "pfuze100-regulator", - .owner = THIS_MODULE, .of_match_table = pfuze_dt_ids, }, .probe = pfuze100_regulator_probe, @@ -653,4 +652,3 @@ module_i2c_driver(pfuze_driver); MODULE_AUTHOR("Robin Gong <b38343@freescale.com>"); MODULE_DESCRIPTION("Regulator Driver for Freescale PFUZE100/PFUZE200 PMIC"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("i2c:pfuze100-regulator"); diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index ffa96124a5e7..fc3166dfcbfa 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -10,6 +10,7 @@ * published by the Free Software Foundation. */ +#include <linux/delay.h> #include <linux/module.h> #include <linux/init.h> #include <linux/err.h> @@ -21,9 +22,15 @@ #include <linux/pwm.h> struct pwm_regulator_data { - struct pwm_voltages *duty_cycle_table; + /* Shared */ struct pwm_device *pwm; + + /* Voltage table */ + struct pwm_voltages *duty_cycle_table; int state; + + /* Continuous voltage */ + int volt_uV; }; struct pwm_voltages { @@ -31,6 +38,9 @@ struct pwm_voltages { unsigned int dutycycle; }; +/** + * Voltage table call-backs + */ static int pwm_regulator_get_voltage_sel(struct regulator_dev *rdev) { struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); @@ -79,29 +89,129 @@ static int pwm_regulator_list_voltage(struct regulator_dev *rdev, return drvdata->duty_cycle_table[selector].uV; } -static struct regulator_ops pwm_regulator_voltage_ops = { +/** + * Continuous voltage call-backs + */ +static int pwm_voltage_to_duty_cycle_percentage(struct regulator_dev *rdev, int req_uV) +{ + int min_uV = rdev->constraints->min_uV; + int max_uV = rdev->constraints->max_uV; + int diff = max_uV - min_uV; + + return 100 - (((req_uV * 100) - (min_uV * 100)) / diff); +} + +static int pwm_regulator_get_voltage(struct regulator_dev *rdev) +{ + struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); + + return drvdata->volt_uV; +} + +static int pwm_regulator_set_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV, + unsigned *selector) +{ + struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); + unsigned int ramp_delay = rdev->constraints->ramp_delay; + unsigned int period = pwm_get_period(drvdata->pwm); + int duty_cycle; + int ret; + + duty_cycle = pwm_voltage_to_duty_cycle_percentage(rdev, min_uV); + + ret = pwm_config(drvdata->pwm, (period / 100) * duty_cycle, period); + if (ret) { + dev_err(&rdev->dev, "Failed to configure PWM\n"); + return ret; + } + + ret = pwm_enable(drvdata->pwm); + if (ret) { + dev_err(&rdev->dev, "Failed to enable PWM\n"); + return ret; + } + drvdata->volt_uV = min_uV; + + /* Delay required by PWM regulator to settle to the new voltage */ + usleep_range(ramp_delay, ramp_delay + 1000); + + return 0; +} + +static struct regulator_ops pwm_regulator_voltage_table_ops = { .set_voltage_sel = pwm_regulator_set_voltage_sel, .get_voltage_sel = pwm_regulator_get_voltage_sel, .list_voltage = pwm_regulator_list_voltage, .map_voltage = regulator_map_voltage_iterate, }; +static struct regulator_ops pwm_regulator_voltage_continuous_ops = { + .get_voltage = pwm_regulator_get_voltage, + .set_voltage = pwm_regulator_set_voltage, +}; + static struct regulator_desc pwm_regulator_desc = { .name = "pwm-regulator", - .ops = &pwm_regulator_voltage_ops, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, .supply_name = "pwm", }; +static int pwm_regulator_init_table(struct platform_device *pdev, + struct pwm_regulator_data *drvdata) +{ + struct device_node *np = pdev->dev.of_node; + struct pwm_voltages *duty_cycle_table; + unsigned int length = 0; + int ret; + + of_find_property(np, "voltage-table", &length); + + if ((length < sizeof(*duty_cycle_table)) || + (length % sizeof(*duty_cycle_table))) { + dev_err(&pdev->dev, + "voltage-table length(%d) is invalid\n", + length); + return -EINVAL; + } + + duty_cycle_table = devm_kzalloc(&pdev->dev, length, GFP_KERNEL); + if (!duty_cycle_table) + return -ENOMEM; + + ret = of_property_read_u32_array(np, "voltage-table", + (u32 *)duty_cycle_table, + length / sizeof(u32)); + if (ret) { + dev_err(&pdev->dev, "Failed to read voltage-table\n"); + return ret; + } + + drvdata->duty_cycle_table = duty_cycle_table; + pwm_regulator_desc.ops = &pwm_regulator_voltage_table_ops; + pwm_regulator_desc.n_voltages = length / sizeof(*duty_cycle_table); + + return 0; +} + +static int pwm_regulator_init_continuous(struct platform_device *pdev, + struct pwm_regulator_data *drvdata) +{ + pwm_regulator_desc.ops = &pwm_regulator_voltage_continuous_ops; + pwm_regulator_desc.continuous_voltage_range = true; + + return 0; +} + static int pwm_regulator_probe(struct platform_device *pdev) { + const struct regulator_init_data *init_data; struct pwm_regulator_data *drvdata; - struct property *prop; struct regulator_dev *regulator; struct regulator_config config = { }; struct device_node *np = pdev->dev.of_node; - int length, ret; + int ret; if (!np) { dev_err(&pdev->dev, "Device Tree node missing\n"); @@ -112,44 +222,22 @@ static int pwm_regulator_probe(struct platform_device *pdev) if (!drvdata) return -ENOMEM; - /* determine the number of voltage-table */ - prop = of_find_property(np, "voltage-table", &length); - if (!prop) { - dev_err(&pdev->dev, "No voltage-table\n"); - return -EINVAL; - } - - if ((length < sizeof(*drvdata->duty_cycle_table)) || - (length % sizeof(*drvdata->duty_cycle_table))) { - dev_err(&pdev->dev, "voltage-table length(%d) is invalid\n", - length); - return -EINVAL; - } - - pwm_regulator_desc.n_voltages = length / sizeof(*drvdata->duty_cycle_table); - - drvdata->duty_cycle_table = devm_kzalloc(&pdev->dev, - length, GFP_KERNEL); - if (!drvdata->duty_cycle_table) - return -ENOMEM; - - /* read voltage table from DT property */ - ret = of_property_read_u32_array(np, "voltage-table", - (u32 *)drvdata->duty_cycle_table, - length / sizeof(u32)); - if (ret < 0) { - dev_err(&pdev->dev, "read voltage-table failed\n"); + if (of_find_property(np, "voltage-table", NULL)) + ret = pwm_regulator_init_table(pdev, drvdata); + else + ret = pwm_regulator_init_continuous(pdev, drvdata); + if (ret) return ret; - } - config.init_data = of_get_regulator_init_data(&pdev->dev, np, - &pwm_regulator_desc); - if (!config.init_data) + init_data = of_get_regulator_init_data(&pdev->dev, np, + &pwm_regulator_desc); + if (!init_data) return -ENOMEM; config.of_node = np; config.dev = &pdev->dev; config.driver_data = drvdata; + config.init_data = init_data; drvdata->pwm = devm_pwm_get(&pdev->dev, NULL); if (IS_ERR(drvdata->pwm)) { diff --git a/drivers/regulator/qcom_smd-regulator.c b/drivers/regulator/qcom_smd-regulator.c new file mode 100644 index 000000000000..9c6167dd2c8b --- /dev/null +++ b/drivers/regulator/qcom_smd-regulator.c @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2015, Sony Mobile Communications AB. + * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> +#include <linux/soc/qcom/smd-rpm.h> + +struct qcom_rpm_reg { + struct device *dev; + + struct qcom_smd_rpm *rpm; + + u32 type; + u32 id; + + struct regulator_desc desc; + + int is_enabled; + int uV; +}; + +struct rpm_regulator_req { + u32 key; + u32 nbytes; + u32 value; +}; + +#define RPM_KEY_SWEN 0x6e657773 /* "swen" */ +#define RPM_KEY_UV 0x00007675 /* "uv" */ +#define RPM_KEY_MA 0x0000616d /* "ma" */ + +static int rpm_reg_write_active(struct qcom_rpm_reg *vreg, + struct rpm_regulator_req *req, + size_t size) +{ + return qcom_rpm_smd_write(vreg->rpm, + QCOM_SMD_RPM_ACTIVE_STATE, + vreg->type, + vreg->id, + req, size); +} + +static int rpm_reg_enable(struct regulator_dev *rdev) +{ + struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev); + struct rpm_regulator_req req; + int ret; + + req.key = RPM_KEY_SWEN; + req.nbytes = sizeof(u32); + req.value = 1; + + ret = rpm_reg_write_active(vreg, &req, sizeof(req)); + if (!ret) + vreg->is_enabled = 1; + + return ret; +} + +static int rpm_reg_is_enabled(struct regulator_dev *rdev) +{ + struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev); + + return vreg->is_enabled; +} + +static int rpm_reg_disable(struct regulator_dev *rdev) +{ + struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev); + struct rpm_regulator_req req; + int ret; + + req.key = RPM_KEY_SWEN; + req.nbytes = sizeof(u32); + req.value = 0; + + ret = rpm_reg_write_active(vreg, &req, sizeof(req)); + if (!ret) + vreg->is_enabled = 0; + + return ret; +} + +static int rpm_reg_get_voltage(struct regulator_dev *rdev) +{ + struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev); + + return vreg->uV; +} + +static int rpm_reg_set_voltage(struct regulator_dev *rdev, + int min_uV, + int max_uV, + unsigned *selector) +{ + struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev); + struct rpm_regulator_req req; + int ret = 0; + + req.key = RPM_KEY_UV; + req.nbytes = sizeof(u32); + req.value = min_uV; + + ret = rpm_reg_write_active(vreg, &req, sizeof(req)); + if (!ret) + vreg->uV = min_uV; + + return ret; +} + +static int rpm_reg_set_load(struct regulator_dev *rdev, int load_uA) +{ + struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev); + struct rpm_regulator_req req; + + req.key = RPM_KEY_MA; + req.nbytes = sizeof(u32); + req.value = load_uA; + + return rpm_reg_write_active(vreg, &req, sizeof(req)); +} + +static const struct regulator_ops rpm_smps_ldo_ops = { + .enable = rpm_reg_enable, + .disable = rpm_reg_disable, + .is_enabled = rpm_reg_is_enabled, + + .get_voltage = rpm_reg_get_voltage, + .set_voltage = rpm_reg_set_voltage, + + .set_load = rpm_reg_set_load, +}; + +static const struct regulator_ops rpm_switch_ops = { + .enable = rpm_reg_enable, + .disable = rpm_reg_disable, + .is_enabled = rpm_reg_is_enabled, +}; + +static const struct regulator_desc pm8x41_hfsmps = { + .linear_ranges = (struct regulator_linear_range[]) { + REGULATOR_LINEAR_RANGE( 375000, 0, 95, 12500), + REGULATOR_LINEAR_RANGE(1550000, 96, 158, 25000), + }, + .n_linear_ranges = 2, + .n_voltages = 159, + .ops = &rpm_smps_ldo_ops, +}; + +static const struct regulator_desc pm8841_ftsmps = { + .linear_ranges = (struct regulator_linear_range[]) { + REGULATOR_LINEAR_RANGE(350000, 0, 184, 5000), + REGULATOR_LINEAR_RANGE(700000, 185, 339, 10000), + }, + .n_linear_ranges = 2, + .n_voltages = 340, + .ops = &rpm_smps_ldo_ops, +}; + +static const struct regulator_desc pm8941_boost = { + .linear_ranges = (struct regulator_linear_range[]) { + REGULATOR_LINEAR_RANGE(4000000, 0, 15, 100000), + }, + .n_linear_ranges = 1, + .n_voltages = 16, + .ops = &rpm_smps_ldo_ops, +}; + +static const struct regulator_desc pm8941_pldo = { + .linear_ranges = (struct regulator_linear_range[]) { + REGULATOR_LINEAR_RANGE( 750000, 0, 30, 25000), + REGULATOR_LINEAR_RANGE(1500000, 31, 99, 50000), + }, + .n_linear_ranges = 2, + .n_voltages = 100, + .ops = &rpm_smps_ldo_ops, +}; + +static const struct regulator_desc pm8941_nldo = { + .linear_ranges = (struct regulator_linear_range[]) { + REGULATOR_LINEAR_RANGE(750000, 0, 63, 12500), + }, + .n_linear_ranges = 1, + .n_voltages = 64, + .ops = &rpm_smps_ldo_ops, +}; + +static const struct regulator_desc pm8941_lnldo = { + .fixed_uV = 1740000, + .n_voltages = 1, + .ops = &rpm_smps_ldo_ops, +}; + +static const struct regulator_desc pm8941_switch = { + .ops = &rpm_switch_ops, +}; + +struct rpm_regulator_data { + const char *name; + u32 type; + u32 id; + const struct regulator_desc *desc; + const char *supply; +}; + +static const struct rpm_regulator_data rpm_pm8841_regulators[] = { + { "s1", QCOM_SMD_RPM_SMPB, 1, &pm8x41_hfsmps, "vdd_s1" }, + { "s2", QCOM_SMD_RPM_SMPB, 2, &pm8841_ftsmps, "vdd_s2" }, + { "s3", QCOM_SMD_RPM_SMPB, 3, &pm8x41_hfsmps, "vdd_s3" }, + { "s4", QCOM_SMD_RPM_SMPB, 4, &pm8841_ftsmps, "vdd_s4" }, + { "s5", QCOM_SMD_RPM_SMPB, 5, &pm8841_ftsmps, "vdd_s5" }, + { "s6", QCOM_SMD_RPM_SMPB, 6, &pm8841_ftsmps, "vdd_s6" }, + { "s7", QCOM_SMD_RPM_SMPB, 7, &pm8841_ftsmps, "vdd_s7" }, + { "s8", QCOM_SMD_RPM_SMPB, 8, &pm8841_ftsmps, "vdd_s8" }, + {} +}; + +static const struct rpm_regulator_data rpm_pm8941_regulators[] = { + { "s1", QCOM_SMD_RPM_SMPA, 1, &pm8x41_hfsmps, "vdd_s1" }, + { "s2", QCOM_SMD_RPM_SMPA, 2, &pm8x41_hfsmps, "vdd_s2" }, + { "s3", QCOM_SMD_RPM_SMPA, 3, &pm8x41_hfsmps, "vdd_s3" }, + { "s4", QCOM_SMD_RPM_BOOST, 1, &pm8941_boost }, + + { "l1", QCOM_SMD_RPM_LDOA, 1, &pm8941_nldo, "vdd_l1_l3" }, + { "l2", QCOM_SMD_RPM_LDOA, 2, &pm8941_nldo, "vdd_l2_lvs1_2_3" }, + { "l3", QCOM_SMD_RPM_LDOA, 3, &pm8941_nldo, "vdd_l1_l3" }, + { "l4", QCOM_SMD_RPM_LDOA, 4, &pm8941_nldo, "vdd_l4_l11" }, + { "l5", QCOM_SMD_RPM_LDOA, 5, &pm8941_lnldo, "vdd_l5_l7" }, + { "l6", QCOM_SMD_RPM_LDOA, 6, &pm8941_pldo, "vdd_l6_l12_l14_l15" }, + { "l7", QCOM_SMD_RPM_LDOA, 7, &pm8941_lnldo, "vdd_l5_l7" }, + { "l8", QCOM_SMD_RPM_LDOA, 8, &pm8941_pldo, "vdd_l8_l16_l18_l19" }, + { "l9", QCOM_SMD_RPM_LDOA, 9, &pm8941_pldo, "vdd_l9_l10_l17_l22" }, + { "l10", QCOM_SMD_RPM_LDOA, 10, &pm8941_pldo, "vdd_l9_l10_l17_l22" }, + { "l11", QCOM_SMD_RPM_LDOA, 11, &pm8941_nldo, "vdd_l4_l11" }, + { "l12", QCOM_SMD_RPM_LDOA, 12, &pm8941_pldo, "vdd_l6_l12_l14_l15" }, + { "l13", QCOM_SMD_RPM_LDOA, 13, &pm8941_pldo, "vdd_l13_l20_l23_l24" }, + { "l14", QCOM_SMD_RPM_LDOA, 14, &pm8941_pldo, "vdd_l6_l12_l14_l15" }, + { "l15", QCOM_SMD_RPM_LDOA, 15, &pm8941_pldo, "vdd_l6_l12_l14_l15" }, + { "l16", QCOM_SMD_RPM_LDOA, 16, &pm8941_pldo, "vdd_l8_l16_l18_l19" }, + { "l17", QCOM_SMD_RPM_LDOA, 17, &pm8941_pldo, "vdd_l9_l10_l17_l22" }, + { "l18", QCOM_SMD_RPM_LDOA, 18, &pm8941_pldo, "vdd_l8_l16_l18_l19" }, + { "l19", QCOM_SMD_RPM_LDOA, 19, &pm8941_pldo, "vdd_l8_l16_l18_l19" }, + { "l20", QCOM_SMD_RPM_LDOA, 20, &pm8941_pldo, "vdd_l13_l20_l23_l24" }, + { "l21", QCOM_SMD_RPM_LDOA, 21, &pm8941_pldo, "vdd_l21" }, + { "l22", QCOM_SMD_RPM_LDOA, 22, &pm8941_pldo, "vdd_l9_l10_l17_l22" }, + { "l23", QCOM_SMD_RPM_LDOA, 23, &pm8941_pldo, "vdd_l13_l20_l23_l24" }, + { "l24", QCOM_SMD_RPM_LDOA, 24, &pm8941_pldo, "vdd_l13_l20_l23_l24" }, + + { "lvs1", QCOM_SMD_RPM_VSA, 1, &pm8941_switch, "vdd_l2_lvs1_2_3" }, + { "lvs2", QCOM_SMD_RPM_VSA, 2, &pm8941_switch, "vdd_l2_lvs1_2_3" }, + { "lvs3", QCOM_SMD_RPM_VSA, 3, &pm8941_switch, "vdd_l2_lvs1_2_3" }, + + { "5vs1", QCOM_SMD_RPM_VSA, 4, &pm8941_switch, "vin_5vs" }, + { "5vs2", QCOM_SMD_RPM_VSA, 5, &pm8941_switch, "vin_5vs" }, + + {} +}; + +static const struct of_device_id rpm_of_match[] = { + { .compatible = "qcom,rpm-pm8841-regulators", .data = &rpm_pm8841_regulators }, + { .compatible = "qcom,rpm-pm8941-regulators", .data = &rpm_pm8941_regulators }, + {} +}; +MODULE_DEVICE_TABLE(of, rpm_of_match); + +static int rpm_reg_probe(struct platform_device *pdev) +{ + const struct rpm_regulator_data *reg; + const struct of_device_id *match; + struct regulator_config config = { }; + struct regulator_dev *rdev; + struct qcom_rpm_reg *vreg; + struct qcom_smd_rpm *rpm; + + rpm = dev_get_drvdata(pdev->dev.parent); + if (!rpm) { + dev_err(&pdev->dev, "unable to retrieve handle to rpm\n"); + return -ENODEV; + } + + match = of_match_device(rpm_of_match, &pdev->dev); + for (reg = match->data; reg->name; reg++) { + vreg = devm_kzalloc(&pdev->dev, sizeof(*vreg), GFP_KERNEL); + if (!vreg) + return -ENOMEM; + + vreg->dev = &pdev->dev; + vreg->type = reg->type; + vreg->id = reg->id; + vreg->rpm = rpm; + + memcpy(&vreg->desc, reg->desc, sizeof(vreg->desc)); + + vreg->desc.id = -1; + vreg->desc.owner = THIS_MODULE; + vreg->desc.type = REGULATOR_VOLTAGE; + vreg->desc.name = reg->name; + vreg->desc.supply_name = reg->supply; + vreg->desc.of_match = reg->name; + + config.dev = &pdev->dev; + config.driver_data = vreg; + rdev = devm_regulator_register(&pdev->dev, &vreg->desc, &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "failed to register %s\n", reg->name); + return PTR_ERR(rdev); + } + } + + return 0; +} + +static struct platform_driver rpm_reg_driver = { + .probe = rpm_reg_probe, + .driver = { + .name = "qcom_rpm_smd_regulator", + .of_match_table = rpm_of_match, + }, +}; + +static int __init rpm_reg_init(void) +{ + return platform_driver_register(&rpm_reg_driver); +} +subsys_initcall(rpm_reg_init); + +static void __exit rpm_reg_exit(void) +{ + platform_driver_unregister(&rpm_reg_driver); +} +module_exit(rpm_reg_exit) + +MODULE_DESCRIPTION("Qualcomm RPM regulator driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/qcom_spmi-regulator.c b/drivers/regulator/qcom_spmi-regulator.c index 850a30a95b5b..88a5dc88badc 100644 --- a/drivers/regulator/qcom_spmi-regulator.c +++ b/drivers/regulator/qcom_spmi-regulator.c @@ -26,6 +26,70 @@ #include <linux/regmap.h> #include <linux/list.h> +/* Pin control enable input pins. */ +#define SPMI_REGULATOR_PIN_CTRL_ENABLE_NONE 0x00 +#define SPMI_REGULATOR_PIN_CTRL_ENABLE_EN0 0x01 +#define SPMI_REGULATOR_PIN_CTRL_ENABLE_EN1 0x02 +#define SPMI_REGULATOR_PIN_CTRL_ENABLE_EN2 0x04 +#define SPMI_REGULATOR_PIN_CTRL_ENABLE_EN3 0x08 +#define SPMI_REGULATOR_PIN_CTRL_ENABLE_HW_DEFAULT 0x10 + +/* Pin control high power mode input pins. */ +#define SPMI_REGULATOR_PIN_CTRL_HPM_NONE 0x00 +#define SPMI_REGULATOR_PIN_CTRL_HPM_EN0 0x01 +#define SPMI_REGULATOR_PIN_CTRL_HPM_EN1 0x02 +#define SPMI_REGULATOR_PIN_CTRL_HPM_EN2 0x04 +#define SPMI_REGULATOR_PIN_CTRL_HPM_EN3 0x08 +#define SPMI_REGULATOR_PIN_CTRL_HPM_SLEEP_B 0x10 +#define SPMI_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT 0x20 + +/* + * Used with enable parameters to specify that hardware default register values + * should be left unaltered. + */ +#define SPMI_REGULATOR_USE_HW_DEFAULT 2 + +/* Soft start strength of a voltage switch type regulator */ +enum spmi_vs_soft_start_str { + SPMI_VS_SOFT_START_STR_0P05_UA = 0, + SPMI_VS_SOFT_START_STR_0P25_UA, + SPMI_VS_SOFT_START_STR_0P55_UA, + SPMI_VS_SOFT_START_STR_0P75_UA, + SPMI_VS_SOFT_START_STR_HW_DEFAULT, +}; + +/** + * struct spmi_regulator_init_data - spmi-regulator initialization data + * @pin_ctrl_enable: Bit mask specifying which hardware pins should be + * used to enable the regulator, if any + * Value should be an ORing of + * SPMI_REGULATOR_PIN_CTRL_ENABLE_* constants. If + * the bit specified by + * SPMI_REGULATOR_PIN_CTRL_ENABLE_HW_DEFAULT is + * set, then pin control enable hardware registers + * will not be modified. + * @pin_ctrl_hpm: Bit mask specifying which hardware pins should be + * used to force the regulator into high power + * mode, if any + * Value should be an ORing of + * SPMI_REGULATOR_PIN_CTRL_HPM_* constants. If + * the bit specified by + * SPMI_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT is + * set, then pin control mode hardware registers + * will not be modified. + * @vs_soft_start_strength: This parameter sets the soft start strength for + * voltage switch type regulators. Its value + * should be one of SPMI_VS_SOFT_START_STR_*. If + * its value is SPMI_VS_SOFT_START_STR_HW_DEFAULT, + * then the soft start strength will be left at its + * default hardware value. + */ +struct spmi_regulator_init_data { + unsigned pin_ctrl_enable; + unsigned pin_ctrl_hpm; + enum spmi_vs_soft_start_str vs_soft_start_strength; +}; + /* These types correspond to unique register layouts. */ enum spmi_regulator_logical_type { SPMI_REGULATOR_LOGICAL_TYPE_SMPS, @@ -458,6 +522,14 @@ static int spmi_regulator_vs_enable(struct regulator_dev *rdev) return spmi_regulator_common_enable(rdev); } +static int spmi_regulator_vs_ocp(struct regulator_dev *rdev) +{ + struct spmi_regulator *vreg = rdev_get_drvdata(rdev); + u8 reg = SPMI_VS_OCP_OVERRIDE; + + return spmi_vreg_write(vreg, SPMI_VS_REG_OCP, ®, 1); +} + static int spmi_regulator_common_disable(struct regulator_dev *rdev) { struct spmi_regulator *vreg = rdev_get_drvdata(rdev); @@ -504,8 +576,7 @@ static int spmi_regulator_select_voltage(struct spmi_regulator *vreg, * Force uV to be an allowed set point by applying a ceiling function to * the uV value. */ - *voltage_sel = (uV - range->min_uV + range->step_uV - 1) - / range->step_uV; + *voltage_sel = DIV_ROUND_UP(uV - range->min_uV, range->step_uV); uV = *voltage_sel * range->step_uV + range->min_uV; if (uV > max_uV) { @@ -792,6 +863,9 @@ static unsigned int spmi_regulator_common_get_mode(struct regulator_dev *rdev) if (reg & SPMI_COMMON_MODE_HPM_MASK) return REGULATOR_MODE_NORMAL; + if (reg & SPMI_COMMON_MODE_AUTO_MASK) + return REGULATOR_MODE_FAST; + return REGULATOR_MODE_IDLE; } @@ -799,11 +873,13 @@ static int spmi_regulator_common_set_mode(struct regulator_dev *rdev, unsigned int mode) { struct spmi_regulator *vreg = rdev_get_drvdata(rdev); - u8 mask = SPMI_COMMON_MODE_HPM_MASK; + u8 mask = SPMI_COMMON_MODE_HPM_MASK | SPMI_COMMON_MODE_AUTO_MASK; u8 val = 0; if (mode == REGULATOR_MODE_NORMAL) - val = mask; + val = SPMI_COMMON_MODE_HPM_MASK; + else if (mode == REGULATOR_MODE_FAST) + val = SPMI_COMMON_MODE_AUTO_MASK; return spmi_vreg_update_bits(vreg, SPMI_COMMON_REG_MODE, val, mask); } @@ -973,6 +1049,7 @@ static struct regulator_ops spmi_vs_ops = { .is_enabled = spmi_regulator_common_is_enabled, .set_pull_down = spmi_regulator_common_set_pull_down, .set_soft_start = spmi_regulator_common_set_soft_start, + .set_over_current_protection = spmi_regulator_vs_ocp, }; static struct regulator_ops spmi_boost_ops = { @@ -1203,10 +1280,111 @@ static int spmi_regulator_ftsmps_init_slew_rate(struct spmi_regulator *vreg) return ret; } +static int spmi_regulator_init_registers(struct spmi_regulator *vreg, + const struct spmi_regulator_init_data *data) +{ + int ret; + enum spmi_regulator_logical_type type; + u8 ctrl_reg[8], reg, mask; + + type = vreg->logical_type; + + ret = spmi_vreg_read(vreg, SPMI_COMMON_REG_VOLTAGE_RANGE, ctrl_reg, 8); + if (ret) + return ret; + + /* Set up enable pin control. */ + if ((type == SPMI_REGULATOR_LOGICAL_TYPE_SMPS + || type == SPMI_REGULATOR_LOGICAL_TYPE_LDO + || type == SPMI_REGULATOR_LOGICAL_TYPE_VS) + && !(data->pin_ctrl_enable + & SPMI_REGULATOR_PIN_CTRL_ENABLE_HW_DEFAULT)) { + ctrl_reg[SPMI_COMMON_IDX_ENABLE] &= + ~SPMI_COMMON_ENABLE_FOLLOW_ALL_MASK; + ctrl_reg[SPMI_COMMON_IDX_ENABLE] |= + data->pin_ctrl_enable & SPMI_COMMON_ENABLE_FOLLOW_ALL_MASK; + } + + /* Set up mode pin control. */ + if ((type == SPMI_REGULATOR_LOGICAL_TYPE_SMPS + || type == SPMI_REGULATOR_LOGICAL_TYPE_LDO) + && !(data->pin_ctrl_hpm + & SPMI_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT)) { + ctrl_reg[SPMI_COMMON_IDX_MODE] &= + ~SPMI_COMMON_MODE_FOLLOW_ALL_MASK; + ctrl_reg[SPMI_COMMON_IDX_MODE] |= + data->pin_ctrl_hpm & SPMI_COMMON_MODE_FOLLOW_ALL_MASK; + } + + if (type == SPMI_REGULATOR_LOGICAL_TYPE_VS + && !(data->pin_ctrl_hpm & SPMI_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT)) { + ctrl_reg[SPMI_COMMON_IDX_MODE] &= + ~SPMI_COMMON_MODE_FOLLOW_AWAKE_MASK; + ctrl_reg[SPMI_COMMON_IDX_MODE] |= + data->pin_ctrl_hpm & SPMI_COMMON_MODE_FOLLOW_AWAKE_MASK; + } + + if ((type == SPMI_REGULATOR_LOGICAL_TYPE_ULT_LO_SMPS + || type == SPMI_REGULATOR_LOGICAL_TYPE_ULT_HO_SMPS + || type == SPMI_REGULATOR_LOGICAL_TYPE_ULT_LDO) + && !(data->pin_ctrl_hpm + & SPMI_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT)) { + ctrl_reg[SPMI_COMMON_IDX_MODE] &= + ~SPMI_COMMON_MODE_FOLLOW_AWAKE_MASK; + ctrl_reg[SPMI_COMMON_IDX_MODE] |= + data->pin_ctrl_hpm & SPMI_COMMON_MODE_FOLLOW_AWAKE_MASK; + } + + /* Write back any control register values that were modified. */ + ret = spmi_vreg_write(vreg, SPMI_COMMON_REG_VOLTAGE_RANGE, ctrl_reg, 8); + if (ret) + return ret; + + /* Set soft start strength and over current protection for VS. */ + if (type == SPMI_REGULATOR_LOGICAL_TYPE_VS) { + if (data->vs_soft_start_strength + != SPMI_VS_SOFT_START_STR_HW_DEFAULT) { + reg = data->vs_soft_start_strength + & SPMI_VS_SOFT_START_SEL_MASK; + mask = SPMI_VS_SOFT_START_SEL_MASK; + return spmi_vreg_update_bits(vreg, + SPMI_VS_REG_SOFT_START, + reg, mask); + } + } + + return 0; +} + +static void spmi_regulator_get_dt_config(struct spmi_regulator *vreg, + struct device_node *node, struct spmi_regulator_init_data *data) +{ + /* + * Initialize configuration parameters to use hardware default in case + * no value is specified via device tree. + */ + data->pin_ctrl_enable = SPMI_REGULATOR_PIN_CTRL_ENABLE_HW_DEFAULT; + data->pin_ctrl_hpm = SPMI_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT; + data->vs_soft_start_strength = SPMI_VS_SOFT_START_STR_HW_DEFAULT; + + /* These bindings are optional, so it is okay if they aren't found. */ + of_property_read_u32(node, "qcom,ocp-max-retries", + &vreg->ocp_max_retries); + of_property_read_u32(node, "qcom,ocp-retry-delay", + &vreg->ocp_retry_delay_ms); + of_property_read_u32(node, "qcom,pin-ctrl-enable", + &data->pin_ctrl_enable); + of_property_read_u32(node, "qcom,pin-ctrl-hpm", &data->pin_ctrl_hpm); + of_property_read_u32(node, "qcom,vs-soft-start-strength", + &data->vs_soft_start_strength); +} + static unsigned int spmi_regulator_of_map_mode(unsigned int mode) { - if (mode) + if (mode == 1) return REGULATOR_MODE_NORMAL; + if (mode == 2) + return REGULATOR_MODE_FAST; return REGULATOR_MODE_IDLE; } @@ -1215,12 +1393,23 @@ static int spmi_regulator_of_parse(struct device_node *node, const struct regulator_desc *desc, struct regulator_config *config) { + struct spmi_regulator_init_data data = { }; struct spmi_regulator *vreg = config->driver_data; struct device *dev = config->dev; int ret; - vreg->ocp_max_retries = SPMI_VS_OCP_DEFAULT_MAX_RETRIES; - vreg->ocp_retry_delay_ms = SPMI_VS_OCP_DEFAULT_RETRY_DELAY_MS; + spmi_regulator_get_dt_config(vreg, node, &data); + + if (!vreg->ocp_max_retries) + vreg->ocp_max_retries = SPMI_VS_OCP_DEFAULT_MAX_RETRIES; + if (!vreg->ocp_retry_delay_ms) + vreg->ocp_retry_delay_ms = SPMI_VS_OCP_DEFAULT_RETRY_DELAY_MS; + + ret = spmi_regulator_init_registers(vreg, &data); + if (ret) { + dev_err(dev, "common initialization failed, ret=%d\n", ret); + return ret; + } if (vreg->logical_type == SPMI_REGULATOR_LOGICAL_TYPE_FTSMPS) { ret = spmi_regulator_ftsmps_init_slew_rate(vreg); diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c index 3fd44353cc80..d86a3dcd61e2 100644 --- a/drivers/regulator/rk808-regulator.c +++ b/drivers/regulator/rk808-regulator.c @@ -16,12 +16,16 @@ * more details. */ -#include <linux/module.h> +#include <linux/delay.h> +#include <linux/gpio.h> #include <linux/i2c.h> -#include <linux/mfd/rk808.h> +#include <linux/module.h> #include <linux/of_device.h> +#include <linux/of_gpio.h> +#include <linux/mfd/rk808.h> #include <linux/regulator/driver.h> #include <linux/regulator/of_regulator.h> +#include <linux/gpio/consumer.h> /* Field Definitions */ #define RK808_BUCK_VSEL_MASK 0x3f @@ -36,12 +40,25 @@ #define RK808_RAMP_RATE_6MV_PER_US (2 << RK808_RAMP_RATE_OFFSET) #define RK808_RAMP_RATE_10MV_PER_US (3 << RK808_RAMP_RATE_OFFSET) +#define RK808_DVS2_POL BIT(2) +#define RK808_DVS1_POL BIT(1) + /* Offset from XXX_ON_VSEL to XXX_SLP_VSEL */ #define RK808_SLP_REG_OFFSET 1 +/* Offset from XXX_ON_VSEL to XXX_DVS_VSEL */ +#define RK808_DVS_REG_OFFSET 2 + /* Offset from XXX_EN_REG to SLEEP_SET_OFF_XXX */ #define RK808_SLP_SET_OFF_REG_OFFSET 2 +/* max steps for increase voltage of Buck1/2, equal 100mv*/ +#define MAX_STEPS_ONE_TIME 8 + +struct rk808_regulator_data { + struct gpio_desc *dvs_gpio[2]; +}; + static const int rk808_buck_config_regs[] = { RK808_BUCK1_CONFIG_REG, RK808_BUCK2_CONFIG_REG, @@ -70,6 +87,131 @@ static const struct regulator_linear_range rk808_ldo6_voltage_ranges[] = { REGULATOR_LINEAR_RANGE(800000, 0, 17, 100000), }; +static int rk808_buck1_2_get_voltage_sel_regmap(struct regulator_dev *rdev) +{ + struct rk808_regulator_data *pdata = rdev_get_drvdata(rdev); + int id = rdev->desc->id - RK808_ID_DCDC1; + struct gpio_desc *gpio = pdata->dvs_gpio[id]; + unsigned int val; + int ret; + + if (!gpio || gpiod_get_value(gpio) == 0) + return regulator_get_voltage_sel_regmap(rdev); + + ret = regmap_read(rdev->regmap, + rdev->desc->vsel_reg + RK808_DVS_REG_OFFSET, + &val); + if (ret != 0) + return ret; + + val &= rdev->desc->vsel_mask; + val >>= ffs(rdev->desc->vsel_mask) - 1; + + return val; +} + +static int rk808_buck1_2_i2c_set_voltage_sel(struct regulator_dev *rdev, + unsigned sel) +{ + int ret, delta_sel; + unsigned int old_sel, tmp, val, mask = rdev->desc->vsel_mask; + + ret = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &val); + if (ret != 0) + return ret; + + tmp = val & ~mask; + old_sel = val & mask; + old_sel >>= ffs(mask) - 1; + delta_sel = sel - old_sel; + + /* + * If directly modify the register to change the voltage, we will face + * the risk of overshoot. Put it into a multi-step, can effectively + * avoid this problem, a step is 100mv here. + */ + while (delta_sel > MAX_STEPS_ONE_TIME) { + old_sel += MAX_STEPS_ONE_TIME; + val = old_sel << (ffs(mask) - 1); + val |= tmp; + + /* + * i2c is 400kHz (2.5us per bit) and we must transmit _at least_ + * 3 bytes (24 bits) plus start and stop so 26 bits. So we've + * got more than 65 us between each voltage change and thus + * won't ramp faster than ~1500 uV / us. + */ + ret = regmap_write(rdev->regmap, rdev->desc->vsel_reg, val); + delta_sel = sel - old_sel; + } + + sel <<= ffs(mask) - 1; + val = tmp | sel; + ret = regmap_write(rdev->regmap, rdev->desc->vsel_reg, val); + + /* + * When we change the voltage register directly, the ramp rate is about + * 100000uv/us, wait 1us to make sure the target voltage to be stable, + * so we needn't wait extra time after that. + */ + udelay(1); + + return ret; +} + +static int rk808_buck1_2_set_voltage_sel(struct regulator_dev *rdev, + unsigned sel) +{ + struct rk808_regulator_data *pdata = rdev_get_drvdata(rdev); + int id = rdev->desc->id - RK808_ID_DCDC1; + struct gpio_desc *gpio = pdata->dvs_gpio[id]; + unsigned int reg = rdev->desc->vsel_reg; + unsigned old_sel; + int ret, gpio_level; + + if (!gpio) + return rk808_buck1_2_i2c_set_voltage_sel(rdev, sel); + + gpio_level = gpiod_get_value(gpio); + if (gpio_level == 0) { + reg += RK808_DVS_REG_OFFSET; + ret = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &old_sel); + } else { + ret = regmap_read(rdev->regmap, + reg + RK808_DVS_REG_OFFSET, + &old_sel); + } + + if (ret != 0) + return ret; + + sel <<= ffs(rdev->desc->vsel_mask) - 1; + sel |= old_sel & ~rdev->desc->vsel_mask; + + ret = regmap_write(rdev->regmap, reg, sel); + if (ret) + return ret; + + gpiod_set_value(gpio, !gpio_level); + + return ret; +} + +static int rk808_buck1_2_set_voltage_time_sel(struct regulator_dev *rdev, + unsigned int old_selector, + unsigned int new_selector) +{ + struct rk808_regulator_data *pdata = rdev_get_drvdata(rdev); + int id = rdev->desc->id - RK808_ID_DCDC1; + struct gpio_desc *gpio = pdata->dvs_gpio[id]; + + /* if there is no dvs1/2 pin, we don't need wait extra time here. */ + if (!gpio) + return 0; + + return regulator_set_voltage_time_sel(rdev, old_selector, new_selector); +} + static int rk808_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) { unsigned int ramp_value = RK808_RAMP_RATE_10MV_PER_US; @@ -137,8 +279,9 @@ static int rk808_set_suspend_disable(struct regulator_dev *rdev) static struct regulator_ops rk808_buck1_2_ops = { .list_voltage = regulator_list_voltage_linear_range, .map_voltage = regulator_map_voltage_linear_range, - .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = rk808_buck1_2_get_voltage_sel_regmap, + .set_voltage_sel = rk808_buck1_2_set_voltage_sel, + .set_voltage_time_sel = rk808_buck1_2_set_voltage_time_sel, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, @@ -380,25 +523,69 @@ static struct of_regulator_match rk808_reg_matches[] = { [RK808_ID_SWITCH2] = { .name = "SWITCH_REG2" }, }; +static int rk808_regulator_dt_parse_pdata(struct device *dev, + struct device *client_dev, + struct regmap *map, + struct rk808_regulator_data *pdata) +{ + struct device_node *np; + int tmp, ret, i; + + np = of_get_child_by_name(client_dev->of_node, "regulators"); + if (!np) + return -ENXIO; + + ret = of_regulator_match(dev, np, rk808_reg_matches, + RK808_NUM_REGULATORS); + if (ret < 0) + goto dt_parse_end; + + for (i = 0; i < ARRAY_SIZE(pdata->dvs_gpio); i++) { + pdata->dvs_gpio[i] = + devm_gpiod_get_index_optional(client_dev, "dvs", i, + GPIOD_OUT_LOW); + if (IS_ERR(pdata->dvs_gpio[i])) { + ret = PTR_ERR(pdata->dvs_gpio[i]); + dev_err(dev, "failed to get dvs%d gpio (%d)\n", i, ret); + goto dt_parse_end; + } + + if (!pdata->dvs_gpio[i]) { + dev_warn(dev, "there is no dvs%d gpio\n", i); + continue; + } + + tmp = i ? RK808_DVS2_POL : RK808_DVS1_POL; + ret = regmap_update_bits(map, RK808_IO_POL_REG, tmp, + gpiod_is_active_low(pdata->dvs_gpio[i]) ? + 0 : tmp); + } + +dt_parse_end: + of_node_put(np); + return ret; +} + static int rk808_regulator_probe(struct platform_device *pdev) { struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent); struct i2c_client *client = rk808->i2c; - struct device_node *reg_np; struct regulator_config config = {}; struct regulator_dev *rk808_rdev; + struct rk808_regulator_data *pdata; int ret, i; - reg_np = of_get_child_by_name(client->dev.of_node, "regulators"); - if (!reg_np) - return -ENXIO; + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; - ret = of_regulator_match(&pdev->dev, reg_np, rk808_reg_matches, - RK808_NUM_REGULATORS); - of_node_put(reg_np); + ret = rk808_regulator_dt_parse_pdata(&pdev->dev, &client->dev, + rk808->regmap, pdata); if (ret < 0) return ret; + platform_set_drvdata(pdev, pdata); + /* Instantiate the regulators */ for (i = 0; i < RK808_NUM_REGULATORS; i++) { if (!rk808_reg_matches[i].init_data || @@ -406,7 +593,7 @@ static int rk808_regulator_probe(struct platform_device *pdev) continue; config.dev = &client->dev; - config.driver_data = rk808; + config.driver_data = pdata; config.regmap = rk808->regmap; config.of_node = rk808_reg_matches[i].of_node; config.init_data = rk808_reg_matches[i].init_data; @@ -427,6 +614,7 @@ static struct platform_driver rk808_regulator_driver = { .probe = rk808_regulator_probe, .driver = { .name = "rk808-regulator", + .owner = THIS_MODULE, }, }; diff --git a/drivers/regulator/tps51632-regulator.c b/drivers/regulator/tps51632-regulator.c index c213e37eb69e..572816e30095 100644 --- a/drivers/regulator/tps51632-regulator.c +++ b/drivers/regulator/tps51632-regulator.c @@ -362,7 +362,6 @@ MODULE_DEVICE_TABLE(i2c, tps51632_id); static struct i2c_driver tps51632_i2c_driver = { .driver = { .name = "tps51632", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(tps51632_of_match), }, .probe = tps51632_probe, diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c index a1fd626c6c96..f6a6d36a6533 100644 --- a/drivers/regulator/tps62360-regulator.c +++ b/drivers/regulator/tps62360-regulator.c @@ -515,7 +515,6 @@ MODULE_DEVICE_TABLE(i2c, tps62360_id); static struct i2c_driver tps62360_i2c_driver = { .driver = { .name = "tps62360", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(tps62360_of_match), }, .probe = tps62360_probe, diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c index b941e564b3f3..5cc19b44974a 100644 --- a/drivers/regulator/tps65023-regulator.c +++ b/drivers/regulator/tps65023-regulator.c @@ -410,7 +410,6 @@ MODULE_DEVICE_TABLE(i2c, tps_65023_id); static struct i2c_driver tps_65023_i2c_driver = { .driver = { .name = "tps65023", - .owner = THIS_MODULE, }, .probe = tps_65023_probe, .id_table = tps_65023_id, diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c index 2852de05d64d..9e9d22038017 100644 --- a/drivers/regulator/tps6586x-regulator.c +++ b/drivers/regulator/tps6586x-regulator.c @@ -422,12 +422,12 @@ static struct tps6586x_platform_data *tps6586x_parse_regulator_dt( return NULL; for (i = 0; i < num; i++) { - int id; + uintptr_t id; if (!tps6586x_matches[i].init_data) continue; pdata->reg_init_data[i] = tps6586x_matches[i].init_data; - id = (int)tps6586x_matches[i].driver_data; + id = (uintptr_t)tps6586x_matches[i].driver_data; if (id == TPS6586X_ID_SYS) sys_rail = pdata->reg_init_data[i]->constraints.name; |