162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2014, Sony Mobile Communications AB. 462306a36Sopenharmony_ci * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/module.h> 862306a36Sopenharmony_ci#include <linux/platform_device.h> 962306a36Sopenharmony_ci#include <linux/of.h> 1062306a36Sopenharmony_ci#include <linux/of_device.h> 1162306a36Sopenharmony_ci#include <linux/regulator/driver.h> 1262306a36Sopenharmony_ci#include <linux/regulator/machine.h> 1362306a36Sopenharmony_ci#include <linux/regulator/of_regulator.h> 1462306a36Sopenharmony_ci#include <linux/mfd/qcom_rpm.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <dt-bindings/mfd/qcom-rpm.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#define MAX_REQUEST_LEN 2 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistruct request_member { 2162306a36Sopenharmony_ci int word; 2262306a36Sopenharmony_ci unsigned int mask; 2362306a36Sopenharmony_ci int shift; 2462306a36Sopenharmony_ci}; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistruct rpm_reg_parts { 2762306a36Sopenharmony_ci struct request_member mV; /* used if voltage is in mV */ 2862306a36Sopenharmony_ci struct request_member uV; /* used if voltage is in uV */ 2962306a36Sopenharmony_ci struct request_member ip; /* peak current in mA */ 3062306a36Sopenharmony_ci struct request_member pd; /* pull down enable */ 3162306a36Sopenharmony_ci struct request_member ia; /* average current in mA */ 3262306a36Sopenharmony_ci struct request_member fm; /* force mode */ 3362306a36Sopenharmony_ci struct request_member pm; /* power mode */ 3462306a36Sopenharmony_ci struct request_member pc; /* pin control */ 3562306a36Sopenharmony_ci struct request_member pf; /* pin function */ 3662306a36Sopenharmony_ci struct request_member enable_state; /* NCP and switch */ 3762306a36Sopenharmony_ci struct request_member comp_mode; /* NCP */ 3862306a36Sopenharmony_ci struct request_member freq; /* frequency: NCP and SMPS */ 3962306a36Sopenharmony_ci struct request_member freq_clk_src; /* clock source: SMPS */ 4062306a36Sopenharmony_ci struct request_member hpm; /* switch: control OCP and SS */ 4162306a36Sopenharmony_ci int request_len; 4262306a36Sopenharmony_ci}; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#define FORCE_MODE_IS_2_BITS(reg) \ 4562306a36Sopenharmony_ci (((reg)->parts->fm.mask >> (reg)->parts->fm.shift) == 3) 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistruct qcom_rpm_reg { 4862306a36Sopenharmony_ci struct qcom_rpm *rpm; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci struct mutex lock; 5162306a36Sopenharmony_ci struct device *dev; 5262306a36Sopenharmony_ci struct regulator_desc desc; 5362306a36Sopenharmony_ci const struct rpm_reg_parts *parts; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci int resource; 5662306a36Sopenharmony_ci u32 val[MAX_REQUEST_LEN]; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci int uV; 5962306a36Sopenharmony_ci int is_enabled; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci bool supports_force_mode_auto; 6262306a36Sopenharmony_ci bool supports_force_mode_bypass; 6362306a36Sopenharmony_ci}; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic const struct rpm_reg_parts rpm8660_ldo_parts = { 6662306a36Sopenharmony_ci .request_len = 2, 6762306a36Sopenharmony_ci .mV = { 0, 0x00000FFF, 0 }, 6862306a36Sopenharmony_ci .ip = { 0, 0x00FFF000, 12 }, 6962306a36Sopenharmony_ci .fm = { 0, 0x03000000, 24 }, 7062306a36Sopenharmony_ci .pc = { 0, 0x3C000000, 26 }, 7162306a36Sopenharmony_ci .pf = { 0, 0xC0000000, 30 }, 7262306a36Sopenharmony_ci .pd = { 1, 0x00000001, 0 }, 7362306a36Sopenharmony_ci .ia = { 1, 0x00001FFE, 1 }, 7462306a36Sopenharmony_ci}; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic const struct rpm_reg_parts rpm8660_smps_parts = { 7762306a36Sopenharmony_ci .request_len = 2, 7862306a36Sopenharmony_ci .mV = { 0, 0x00000FFF, 0 }, 7962306a36Sopenharmony_ci .ip = { 0, 0x00FFF000, 12 }, 8062306a36Sopenharmony_ci .fm = { 0, 0x03000000, 24 }, 8162306a36Sopenharmony_ci .pc = { 0, 0x3C000000, 26 }, 8262306a36Sopenharmony_ci .pf = { 0, 0xC0000000, 30 }, 8362306a36Sopenharmony_ci .pd = { 1, 0x00000001, 0 }, 8462306a36Sopenharmony_ci .ia = { 1, 0x00001FFE, 1 }, 8562306a36Sopenharmony_ci .freq = { 1, 0x001FE000, 13 }, 8662306a36Sopenharmony_ci .freq_clk_src = { 1, 0x00600000, 21 }, 8762306a36Sopenharmony_ci}; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic const struct rpm_reg_parts rpm8660_switch_parts = { 9062306a36Sopenharmony_ci .request_len = 1, 9162306a36Sopenharmony_ci .enable_state = { 0, 0x00000001, 0 }, 9262306a36Sopenharmony_ci .pd = { 0, 0x00000002, 1 }, 9362306a36Sopenharmony_ci .pc = { 0, 0x0000003C, 2 }, 9462306a36Sopenharmony_ci .pf = { 0, 0x000000C0, 6 }, 9562306a36Sopenharmony_ci .hpm = { 0, 0x00000300, 8 }, 9662306a36Sopenharmony_ci}; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic const struct rpm_reg_parts rpm8660_ncp_parts = { 9962306a36Sopenharmony_ci .request_len = 1, 10062306a36Sopenharmony_ci .mV = { 0, 0x00000FFF, 0 }, 10162306a36Sopenharmony_ci .enable_state = { 0, 0x00001000, 12 }, 10262306a36Sopenharmony_ci .comp_mode = { 0, 0x00002000, 13 }, 10362306a36Sopenharmony_ci .freq = { 0, 0x003FC000, 14 }, 10462306a36Sopenharmony_ci}; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic const struct rpm_reg_parts rpm8960_ldo_parts = { 10762306a36Sopenharmony_ci .request_len = 2, 10862306a36Sopenharmony_ci .uV = { 0, 0x007FFFFF, 0 }, 10962306a36Sopenharmony_ci .pd = { 0, 0x00800000, 23 }, 11062306a36Sopenharmony_ci .pc = { 0, 0x0F000000, 24 }, 11162306a36Sopenharmony_ci .pf = { 0, 0xF0000000, 28 }, 11262306a36Sopenharmony_ci .ip = { 1, 0x000003FF, 0 }, 11362306a36Sopenharmony_ci .ia = { 1, 0x000FFC00, 10 }, 11462306a36Sopenharmony_ci .fm = { 1, 0x00700000, 20 }, 11562306a36Sopenharmony_ci}; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic const struct rpm_reg_parts rpm8960_smps_parts = { 11862306a36Sopenharmony_ci .request_len = 2, 11962306a36Sopenharmony_ci .uV = { 0, 0x007FFFFF, 0 }, 12062306a36Sopenharmony_ci .pd = { 0, 0x00800000, 23 }, 12162306a36Sopenharmony_ci .pc = { 0, 0x0F000000, 24 }, 12262306a36Sopenharmony_ci .pf = { 0, 0xF0000000, 28 }, 12362306a36Sopenharmony_ci .ip = { 1, 0x000003FF, 0 }, 12462306a36Sopenharmony_ci .ia = { 1, 0x000FFC00, 10 }, 12562306a36Sopenharmony_ci .fm = { 1, 0x00700000, 20 }, 12662306a36Sopenharmony_ci .pm = { 1, 0x00800000, 23 }, 12762306a36Sopenharmony_ci .freq = { 1, 0x1F000000, 24 }, 12862306a36Sopenharmony_ci .freq_clk_src = { 1, 0x60000000, 29 }, 12962306a36Sopenharmony_ci}; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistatic const struct rpm_reg_parts rpm8960_switch_parts = { 13262306a36Sopenharmony_ci .request_len = 1, 13362306a36Sopenharmony_ci .enable_state = { 0, 0x00000001, 0 }, 13462306a36Sopenharmony_ci .pd = { 0, 0x00000002, 1 }, 13562306a36Sopenharmony_ci .pc = { 0, 0x0000003C, 2 }, 13662306a36Sopenharmony_ci .pf = { 0, 0x000003C0, 6 }, 13762306a36Sopenharmony_ci .hpm = { 0, 0x00000C00, 10 }, 13862306a36Sopenharmony_ci}; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic const struct rpm_reg_parts rpm8960_ncp_parts = { 14162306a36Sopenharmony_ci .request_len = 1, 14262306a36Sopenharmony_ci .uV = { 0, 0x007FFFFF, 0 }, 14362306a36Sopenharmony_ci .enable_state = { 0, 0x00800000, 23 }, 14462306a36Sopenharmony_ci .comp_mode = { 0, 0x01000000, 24 }, 14562306a36Sopenharmony_ci .freq = { 0, 0x3E000000, 25 }, 14662306a36Sopenharmony_ci}; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci/* 14962306a36Sopenharmony_ci * Physically available PMIC regulator voltage ranges 15062306a36Sopenharmony_ci */ 15162306a36Sopenharmony_cistatic const struct linear_range pldo_ranges[] = { 15262306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE( 750000, 0, 59, 12500), 15362306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(1500000, 60, 123, 25000), 15462306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(3100000, 124, 160, 50000), 15562306a36Sopenharmony_ci}; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic const struct linear_range nldo_ranges[] = { 15862306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE( 750000, 0, 63, 12500), 15962306a36Sopenharmony_ci}; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic const struct linear_range nldo1200_ranges[] = { 16262306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE( 375000, 0, 59, 6250), 16362306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE( 750000, 60, 123, 12500), 16462306a36Sopenharmony_ci}; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic const struct linear_range smps_ranges[] = { 16762306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE( 375000, 0, 29, 12500), 16862306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE( 750000, 30, 89, 12500), 16962306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(1500000, 90, 153, 25000), 17062306a36Sopenharmony_ci}; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic const struct linear_range ftsmps_ranges[] = { 17362306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE( 350000, 0, 6, 50000), 17462306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE( 700000, 7, 63, 12500), 17562306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(1500000, 64, 100, 50000), 17662306a36Sopenharmony_ci}; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cistatic const struct linear_range smb208_ranges[] = { 17962306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE( 375000, 0, 29, 12500), 18062306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE( 750000, 30, 89, 12500), 18162306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(1500000, 90, 153, 25000), 18262306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(3100000, 154, 234, 25000), 18362306a36Sopenharmony_ci}; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic const struct linear_range ncp_ranges[] = { 18662306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(1500000, 0, 31, 50000), 18762306a36Sopenharmony_ci}; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic int rpm_reg_write(struct qcom_rpm_reg *vreg, 19062306a36Sopenharmony_ci const struct request_member *req, 19162306a36Sopenharmony_ci const int value) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci if (WARN_ON((value << req->shift) & ~req->mask)) 19462306a36Sopenharmony_ci return -EINVAL; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci vreg->val[req->word] &= ~req->mask; 19762306a36Sopenharmony_ci vreg->val[req->word] |= value << req->shift; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci return qcom_rpm_write(vreg->rpm, 20062306a36Sopenharmony_ci QCOM_RPM_ACTIVE_STATE, 20162306a36Sopenharmony_ci vreg->resource, 20262306a36Sopenharmony_ci vreg->val, 20362306a36Sopenharmony_ci vreg->parts->request_len); 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic int rpm_reg_set_mV_sel(struct regulator_dev *rdev, 20762306a36Sopenharmony_ci unsigned selector) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev); 21062306a36Sopenharmony_ci const struct rpm_reg_parts *parts = vreg->parts; 21162306a36Sopenharmony_ci const struct request_member *req = &parts->mV; 21262306a36Sopenharmony_ci int ret = 0; 21362306a36Sopenharmony_ci int uV; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (req->mask == 0) 21662306a36Sopenharmony_ci return -EINVAL; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci uV = regulator_list_voltage_linear_range(rdev, selector); 21962306a36Sopenharmony_ci if (uV < 0) 22062306a36Sopenharmony_ci return uV; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci mutex_lock(&vreg->lock); 22362306a36Sopenharmony_ci if (vreg->is_enabled) 22462306a36Sopenharmony_ci ret = rpm_reg_write(vreg, req, uV / 1000); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci if (!ret) 22762306a36Sopenharmony_ci vreg->uV = uV; 22862306a36Sopenharmony_ci mutex_unlock(&vreg->lock); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci return ret; 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic int rpm_reg_set_uV_sel(struct regulator_dev *rdev, 23462306a36Sopenharmony_ci unsigned selector) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev); 23762306a36Sopenharmony_ci const struct rpm_reg_parts *parts = vreg->parts; 23862306a36Sopenharmony_ci const struct request_member *req = &parts->uV; 23962306a36Sopenharmony_ci int ret = 0; 24062306a36Sopenharmony_ci int uV; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci if (req->mask == 0) 24362306a36Sopenharmony_ci return -EINVAL; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci uV = regulator_list_voltage_linear_range(rdev, selector); 24662306a36Sopenharmony_ci if (uV < 0) 24762306a36Sopenharmony_ci return uV; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci mutex_lock(&vreg->lock); 25062306a36Sopenharmony_ci if (vreg->is_enabled) 25162306a36Sopenharmony_ci ret = rpm_reg_write(vreg, req, uV); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci if (!ret) 25462306a36Sopenharmony_ci vreg->uV = uV; 25562306a36Sopenharmony_ci mutex_unlock(&vreg->lock); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci return ret; 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cistatic int rpm_reg_get_voltage(struct regulator_dev *rdev) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci return vreg->uV; 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic int rpm_reg_mV_enable(struct regulator_dev *rdev) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev); 27062306a36Sopenharmony_ci const struct rpm_reg_parts *parts = vreg->parts; 27162306a36Sopenharmony_ci const struct request_member *req = &parts->mV; 27262306a36Sopenharmony_ci int ret; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci if (req->mask == 0) 27562306a36Sopenharmony_ci return -EINVAL; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci mutex_lock(&vreg->lock); 27862306a36Sopenharmony_ci ret = rpm_reg_write(vreg, req, vreg->uV / 1000); 27962306a36Sopenharmony_ci if (!ret) 28062306a36Sopenharmony_ci vreg->is_enabled = 1; 28162306a36Sopenharmony_ci mutex_unlock(&vreg->lock); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci return ret; 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic int rpm_reg_uV_enable(struct regulator_dev *rdev) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev); 28962306a36Sopenharmony_ci const struct rpm_reg_parts *parts = vreg->parts; 29062306a36Sopenharmony_ci const struct request_member *req = &parts->uV; 29162306a36Sopenharmony_ci int ret; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci if (req->mask == 0) 29462306a36Sopenharmony_ci return -EINVAL; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci mutex_lock(&vreg->lock); 29762306a36Sopenharmony_ci ret = rpm_reg_write(vreg, req, vreg->uV); 29862306a36Sopenharmony_ci if (!ret) 29962306a36Sopenharmony_ci vreg->is_enabled = 1; 30062306a36Sopenharmony_ci mutex_unlock(&vreg->lock); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci return ret; 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cistatic int rpm_reg_switch_enable(struct regulator_dev *rdev) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev); 30862306a36Sopenharmony_ci const struct rpm_reg_parts *parts = vreg->parts; 30962306a36Sopenharmony_ci const struct request_member *req = &parts->enable_state; 31062306a36Sopenharmony_ci int ret; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci if (req->mask == 0) 31362306a36Sopenharmony_ci return -EINVAL; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci mutex_lock(&vreg->lock); 31662306a36Sopenharmony_ci ret = rpm_reg_write(vreg, req, 1); 31762306a36Sopenharmony_ci if (!ret) 31862306a36Sopenharmony_ci vreg->is_enabled = 1; 31962306a36Sopenharmony_ci mutex_unlock(&vreg->lock); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci return ret; 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_cistatic int rpm_reg_mV_disable(struct regulator_dev *rdev) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev); 32762306a36Sopenharmony_ci const struct rpm_reg_parts *parts = vreg->parts; 32862306a36Sopenharmony_ci const struct request_member *req = &parts->mV; 32962306a36Sopenharmony_ci int ret; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci if (req->mask == 0) 33262306a36Sopenharmony_ci return -EINVAL; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci mutex_lock(&vreg->lock); 33562306a36Sopenharmony_ci ret = rpm_reg_write(vreg, req, 0); 33662306a36Sopenharmony_ci if (!ret) 33762306a36Sopenharmony_ci vreg->is_enabled = 0; 33862306a36Sopenharmony_ci mutex_unlock(&vreg->lock); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci return ret; 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistatic int rpm_reg_uV_disable(struct regulator_dev *rdev) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev); 34662306a36Sopenharmony_ci const struct rpm_reg_parts *parts = vreg->parts; 34762306a36Sopenharmony_ci const struct request_member *req = &parts->uV; 34862306a36Sopenharmony_ci int ret; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci if (req->mask == 0) 35162306a36Sopenharmony_ci return -EINVAL; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci mutex_lock(&vreg->lock); 35462306a36Sopenharmony_ci ret = rpm_reg_write(vreg, req, 0); 35562306a36Sopenharmony_ci if (!ret) 35662306a36Sopenharmony_ci vreg->is_enabled = 0; 35762306a36Sopenharmony_ci mutex_unlock(&vreg->lock); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci return ret; 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cistatic int rpm_reg_switch_disable(struct regulator_dev *rdev) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev); 36562306a36Sopenharmony_ci const struct rpm_reg_parts *parts = vreg->parts; 36662306a36Sopenharmony_ci const struct request_member *req = &parts->enable_state; 36762306a36Sopenharmony_ci int ret; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci if (req->mask == 0) 37062306a36Sopenharmony_ci return -EINVAL; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci mutex_lock(&vreg->lock); 37362306a36Sopenharmony_ci ret = rpm_reg_write(vreg, req, 0); 37462306a36Sopenharmony_ci if (!ret) 37562306a36Sopenharmony_ci vreg->is_enabled = 0; 37662306a36Sopenharmony_ci mutex_unlock(&vreg->lock); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci return ret; 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_cistatic int rpm_reg_is_enabled(struct regulator_dev *rdev) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci return vreg->is_enabled; 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_cistatic int rpm_reg_set_load(struct regulator_dev *rdev, int load_uA) 38962306a36Sopenharmony_ci{ 39062306a36Sopenharmony_ci struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev); 39162306a36Sopenharmony_ci const struct rpm_reg_parts *parts = vreg->parts; 39262306a36Sopenharmony_ci const struct request_member *req = &parts->ia; 39362306a36Sopenharmony_ci int load_mA = load_uA / 1000; 39462306a36Sopenharmony_ci int max_mA = req->mask >> req->shift; 39562306a36Sopenharmony_ci int ret; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci if (req->mask == 0) 39862306a36Sopenharmony_ci return -EINVAL; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci if (load_mA > max_mA) 40162306a36Sopenharmony_ci load_mA = max_mA; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci mutex_lock(&vreg->lock); 40462306a36Sopenharmony_ci ret = rpm_reg_write(vreg, req, load_mA); 40562306a36Sopenharmony_ci mutex_unlock(&vreg->lock); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci return ret; 40862306a36Sopenharmony_ci} 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_cistatic const struct regulator_ops uV_ops = { 41162306a36Sopenharmony_ci .list_voltage = regulator_list_voltage_linear_range, 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci .set_voltage_sel = rpm_reg_set_uV_sel, 41462306a36Sopenharmony_ci .get_voltage = rpm_reg_get_voltage, 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci .enable = rpm_reg_uV_enable, 41762306a36Sopenharmony_ci .disable = rpm_reg_uV_disable, 41862306a36Sopenharmony_ci .is_enabled = rpm_reg_is_enabled, 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci .set_load = rpm_reg_set_load, 42162306a36Sopenharmony_ci}; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic const struct regulator_ops mV_ops = { 42462306a36Sopenharmony_ci .list_voltage = regulator_list_voltage_linear_range, 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci .set_voltage_sel = rpm_reg_set_mV_sel, 42762306a36Sopenharmony_ci .get_voltage = rpm_reg_get_voltage, 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci .enable = rpm_reg_mV_enable, 43062306a36Sopenharmony_ci .disable = rpm_reg_mV_disable, 43162306a36Sopenharmony_ci .is_enabled = rpm_reg_is_enabled, 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci .set_load = rpm_reg_set_load, 43462306a36Sopenharmony_ci}; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_cistatic const struct regulator_ops switch_ops = { 43762306a36Sopenharmony_ci .enable = rpm_reg_switch_enable, 43862306a36Sopenharmony_ci .disable = rpm_reg_switch_disable, 43962306a36Sopenharmony_ci .is_enabled = rpm_reg_is_enabled, 44062306a36Sopenharmony_ci}; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci/* 44362306a36Sopenharmony_ci * PM8018 regulators 44462306a36Sopenharmony_ci */ 44562306a36Sopenharmony_cistatic const struct qcom_rpm_reg pm8018_pldo = { 44662306a36Sopenharmony_ci .desc.linear_ranges = pldo_ranges, 44762306a36Sopenharmony_ci .desc.n_linear_ranges = ARRAY_SIZE(pldo_ranges), 44862306a36Sopenharmony_ci .desc.n_voltages = 161, 44962306a36Sopenharmony_ci .desc.ops = &uV_ops, 45062306a36Sopenharmony_ci .parts = &rpm8960_ldo_parts, 45162306a36Sopenharmony_ci .supports_force_mode_auto = false, 45262306a36Sopenharmony_ci .supports_force_mode_bypass = false, 45362306a36Sopenharmony_ci}; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_cistatic const struct qcom_rpm_reg pm8018_nldo = { 45662306a36Sopenharmony_ci .desc.linear_ranges = nldo_ranges, 45762306a36Sopenharmony_ci .desc.n_linear_ranges = ARRAY_SIZE(nldo_ranges), 45862306a36Sopenharmony_ci .desc.n_voltages = 64, 45962306a36Sopenharmony_ci .desc.ops = &uV_ops, 46062306a36Sopenharmony_ci .parts = &rpm8960_ldo_parts, 46162306a36Sopenharmony_ci .supports_force_mode_auto = false, 46262306a36Sopenharmony_ci .supports_force_mode_bypass = false, 46362306a36Sopenharmony_ci}; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cistatic const struct qcom_rpm_reg pm8018_smps = { 46662306a36Sopenharmony_ci .desc.linear_ranges = smps_ranges, 46762306a36Sopenharmony_ci .desc.n_linear_ranges = ARRAY_SIZE(smps_ranges), 46862306a36Sopenharmony_ci .desc.n_voltages = 154, 46962306a36Sopenharmony_ci .desc.ops = &uV_ops, 47062306a36Sopenharmony_ci .parts = &rpm8960_smps_parts, 47162306a36Sopenharmony_ci .supports_force_mode_auto = false, 47262306a36Sopenharmony_ci .supports_force_mode_bypass = false, 47362306a36Sopenharmony_ci}; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_cistatic const struct qcom_rpm_reg pm8018_switch = { 47662306a36Sopenharmony_ci .desc.ops = &switch_ops, 47762306a36Sopenharmony_ci .parts = &rpm8960_switch_parts, 47862306a36Sopenharmony_ci}; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci/* 48162306a36Sopenharmony_ci * PM8058 regulators 48262306a36Sopenharmony_ci */ 48362306a36Sopenharmony_cistatic const struct qcom_rpm_reg pm8058_pldo = { 48462306a36Sopenharmony_ci .desc.linear_ranges = pldo_ranges, 48562306a36Sopenharmony_ci .desc.n_linear_ranges = ARRAY_SIZE(pldo_ranges), 48662306a36Sopenharmony_ci .desc.n_voltages = 161, 48762306a36Sopenharmony_ci .desc.ops = &mV_ops, 48862306a36Sopenharmony_ci .parts = &rpm8660_ldo_parts, 48962306a36Sopenharmony_ci .supports_force_mode_auto = false, 49062306a36Sopenharmony_ci .supports_force_mode_bypass = false, 49162306a36Sopenharmony_ci}; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_cistatic const struct qcom_rpm_reg pm8058_nldo = { 49462306a36Sopenharmony_ci .desc.linear_ranges = nldo_ranges, 49562306a36Sopenharmony_ci .desc.n_linear_ranges = ARRAY_SIZE(nldo_ranges), 49662306a36Sopenharmony_ci .desc.n_voltages = 64, 49762306a36Sopenharmony_ci .desc.ops = &mV_ops, 49862306a36Sopenharmony_ci .parts = &rpm8660_ldo_parts, 49962306a36Sopenharmony_ci .supports_force_mode_auto = false, 50062306a36Sopenharmony_ci .supports_force_mode_bypass = false, 50162306a36Sopenharmony_ci}; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_cistatic const struct qcom_rpm_reg pm8058_smps = { 50462306a36Sopenharmony_ci .desc.linear_ranges = smps_ranges, 50562306a36Sopenharmony_ci .desc.n_linear_ranges = ARRAY_SIZE(smps_ranges), 50662306a36Sopenharmony_ci .desc.n_voltages = 154, 50762306a36Sopenharmony_ci .desc.ops = &mV_ops, 50862306a36Sopenharmony_ci .parts = &rpm8660_smps_parts, 50962306a36Sopenharmony_ci .supports_force_mode_auto = false, 51062306a36Sopenharmony_ci .supports_force_mode_bypass = false, 51162306a36Sopenharmony_ci}; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_cistatic const struct qcom_rpm_reg pm8058_ncp = { 51462306a36Sopenharmony_ci .desc.linear_ranges = ncp_ranges, 51562306a36Sopenharmony_ci .desc.n_linear_ranges = ARRAY_SIZE(ncp_ranges), 51662306a36Sopenharmony_ci .desc.n_voltages = 32, 51762306a36Sopenharmony_ci .desc.ops = &mV_ops, 51862306a36Sopenharmony_ci .parts = &rpm8660_ncp_parts, 51962306a36Sopenharmony_ci}; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_cistatic const struct qcom_rpm_reg pm8058_switch = { 52262306a36Sopenharmony_ci .desc.ops = &switch_ops, 52362306a36Sopenharmony_ci .parts = &rpm8660_switch_parts, 52462306a36Sopenharmony_ci}; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci/* 52762306a36Sopenharmony_ci * PM8901 regulators 52862306a36Sopenharmony_ci */ 52962306a36Sopenharmony_cistatic const struct qcom_rpm_reg pm8901_pldo = { 53062306a36Sopenharmony_ci .desc.linear_ranges = pldo_ranges, 53162306a36Sopenharmony_ci .desc.n_linear_ranges = ARRAY_SIZE(pldo_ranges), 53262306a36Sopenharmony_ci .desc.n_voltages = 161, 53362306a36Sopenharmony_ci .desc.ops = &mV_ops, 53462306a36Sopenharmony_ci .parts = &rpm8660_ldo_parts, 53562306a36Sopenharmony_ci .supports_force_mode_auto = false, 53662306a36Sopenharmony_ci .supports_force_mode_bypass = true, 53762306a36Sopenharmony_ci}; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_cistatic const struct qcom_rpm_reg pm8901_nldo = { 54062306a36Sopenharmony_ci .desc.linear_ranges = nldo_ranges, 54162306a36Sopenharmony_ci .desc.n_linear_ranges = ARRAY_SIZE(nldo_ranges), 54262306a36Sopenharmony_ci .desc.n_voltages = 64, 54362306a36Sopenharmony_ci .desc.ops = &mV_ops, 54462306a36Sopenharmony_ci .parts = &rpm8660_ldo_parts, 54562306a36Sopenharmony_ci .supports_force_mode_auto = false, 54662306a36Sopenharmony_ci .supports_force_mode_bypass = true, 54762306a36Sopenharmony_ci}; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_cistatic const struct qcom_rpm_reg pm8901_ftsmps = { 55062306a36Sopenharmony_ci .desc.linear_ranges = ftsmps_ranges, 55162306a36Sopenharmony_ci .desc.n_linear_ranges = ARRAY_SIZE(ftsmps_ranges), 55262306a36Sopenharmony_ci .desc.n_voltages = 101, 55362306a36Sopenharmony_ci .desc.ops = &mV_ops, 55462306a36Sopenharmony_ci .parts = &rpm8660_smps_parts, 55562306a36Sopenharmony_ci .supports_force_mode_auto = true, 55662306a36Sopenharmony_ci .supports_force_mode_bypass = false, 55762306a36Sopenharmony_ci}; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_cistatic const struct qcom_rpm_reg pm8901_switch = { 56062306a36Sopenharmony_ci .desc.ops = &switch_ops, 56162306a36Sopenharmony_ci .parts = &rpm8660_switch_parts, 56262306a36Sopenharmony_ci}; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci/* 56562306a36Sopenharmony_ci * PM8921 regulators 56662306a36Sopenharmony_ci */ 56762306a36Sopenharmony_cistatic const struct qcom_rpm_reg pm8921_pldo = { 56862306a36Sopenharmony_ci .desc.linear_ranges = pldo_ranges, 56962306a36Sopenharmony_ci .desc.n_linear_ranges = ARRAY_SIZE(pldo_ranges), 57062306a36Sopenharmony_ci .desc.n_voltages = 161, 57162306a36Sopenharmony_ci .desc.ops = &uV_ops, 57262306a36Sopenharmony_ci .parts = &rpm8960_ldo_parts, 57362306a36Sopenharmony_ci .supports_force_mode_auto = false, 57462306a36Sopenharmony_ci .supports_force_mode_bypass = true, 57562306a36Sopenharmony_ci}; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_cistatic const struct qcom_rpm_reg pm8921_nldo = { 57862306a36Sopenharmony_ci .desc.linear_ranges = nldo_ranges, 57962306a36Sopenharmony_ci .desc.n_linear_ranges = ARRAY_SIZE(nldo_ranges), 58062306a36Sopenharmony_ci .desc.n_voltages = 64, 58162306a36Sopenharmony_ci .desc.ops = &uV_ops, 58262306a36Sopenharmony_ci .parts = &rpm8960_ldo_parts, 58362306a36Sopenharmony_ci .supports_force_mode_auto = false, 58462306a36Sopenharmony_ci .supports_force_mode_bypass = true, 58562306a36Sopenharmony_ci}; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_cistatic const struct qcom_rpm_reg pm8921_nldo1200 = { 58862306a36Sopenharmony_ci .desc.linear_ranges = nldo1200_ranges, 58962306a36Sopenharmony_ci .desc.n_linear_ranges = ARRAY_SIZE(nldo1200_ranges), 59062306a36Sopenharmony_ci .desc.n_voltages = 124, 59162306a36Sopenharmony_ci .desc.ops = &uV_ops, 59262306a36Sopenharmony_ci .parts = &rpm8960_ldo_parts, 59362306a36Sopenharmony_ci .supports_force_mode_auto = false, 59462306a36Sopenharmony_ci .supports_force_mode_bypass = true, 59562306a36Sopenharmony_ci}; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_cistatic const struct qcom_rpm_reg pm8921_smps = { 59862306a36Sopenharmony_ci .desc.linear_ranges = smps_ranges, 59962306a36Sopenharmony_ci .desc.n_linear_ranges = ARRAY_SIZE(smps_ranges), 60062306a36Sopenharmony_ci .desc.n_voltages = 154, 60162306a36Sopenharmony_ci .desc.ops = &uV_ops, 60262306a36Sopenharmony_ci .parts = &rpm8960_smps_parts, 60362306a36Sopenharmony_ci .supports_force_mode_auto = true, 60462306a36Sopenharmony_ci .supports_force_mode_bypass = false, 60562306a36Sopenharmony_ci}; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_cistatic const struct qcom_rpm_reg pm8921_ncp = { 60862306a36Sopenharmony_ci .desc.linear_ranges = ncp_ranges, 60962306a36Sopenharmony_ci .desc.n_linear_ranges = ARRAY_SIZE(ncp_ranges), 61062306a36Sopenharmony_ci .desc.n_voltages = 32, 61162306a36Sopenharmony_ci .desc.ops = &uV_ops, 61262306a36Sopenharmony_ci .parts = &rpm8960_ncp_parts, 61362306a36Sopenharmony_ci}; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_cistatic const struct qcom_rpm_reg pm8921_switch = { 61662306a36Sopenharmony_ci .desc.ops = &switch_ops, 61762306a36Sopenharmony_ci .parts = &rpm8960_switch_parts, 61862306a36Sopenharmony_ci}; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_cistatic const struct qcom_rpm_reg smb208_smps = { 62162306a36Sopenharmony_ci .desc.linear_ranges = smb208_ranges, 62262306a36Sopenharmony_ci .desc.n_linear_ranges = ARRAY_SIZE(smb208_ranges), 62362306a36Sopenharmony_ci .desc.n_voltages = 235, 62462306a36Sopenharmony_ci .desc.ops = &uV_ops, 62562306a36Sopenharmony_ci .parts = &rpm8960_smps_parts, 62662306a36Sopenharmony_ci .supports_force_mode_auto = false, 62762306a36Sopenharmony_ci .supports_force_mode_bypass = false, 62862306a36Sopenharmony_ci}; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_cistatic int rpm_reg_set(struct qcom_rpm_reg *vreg, 63162306a36Sopenharmony_ci const struct request_member *req, 63262306a36Sopenharmony_ci const int value) 63362306a36Sopenharmony_ci{ 63462306a36Sopenharmony_ci if (req->mask == 0 || (value << req->shift) & ~req->mask) 63562306a36Sopenharmony_ci return -EINVAL; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci vreg->val[req->word] &= ~req->mask; 63862306a36Sopenharmony_ci vreg->val[req->word] |= value << req->shift; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci return 0; 64162306a36Sopenharmony_ci} 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_cistatic int rpm_reg_of_parse_freq(struct device *dev, 64462306a36Sopenharmony_ci struct device_node *node, 64562306a36Sopenharmony_ci struct qcom_rpm_reg *vreg) 64662306a36Sopenharmony_ci{ 64762306a36Sopenharmony_ci static const int freq_table[] = { 64862306a36Sopenharmony_ci 19200000, 9600000, 6400000, 4800000, 3840000, 3200000, 2740000, 64962306a36Sopenharmony_ci 2400000, 2130000, 1920000, 1750000, 1600000, 1480000, 1370000, 65062306a36Sopenharmony_ci 1280000, 1200000, 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci }; 65362306a36Sopenharmony_ci const char *key; 65462306a36Sopenharmony_ci u32 freq; 65562306a36Sopenharmony_ci int ret; 65662306a36Sopenharmony_ci int i; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci key = "qcom,switch-mode-frequency"; 65962306a36Sopenharmony_ci ret = of_property_read_u32(node, key, &freq); 66062306a36Sopenharmony_ci if (ret) { 66162306a36Sopenharmony_ci dev_err(dev, "regulator requires %s property\n", key); 66262306a36Sopenharmony_ci return -EINVAL; 66362306a36Sopenharmony_ci } 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(freq_table); i++) { 66662306a36Sopenharmony_ci if (freq == freq_table[i]) { 66762306a36Sopenharmony_ci rpm_reg_set(vreg, &vreg->parts->freq, i + 1); 66862306a36Sopenharmony_ci return 0; 66962306a36Sopenharmony_ci } 67062306a36Sopenharmony_ci } 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci dev_err(dev, "invalid frequency %d\n", freq); 67362306a36Sopenharmony_ci return -EINVAL; 67462306a36Sopenharmony_ci} 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_cistatic int rpm_reg_of_parse(struct device_node *node, 67762306a36Sopenharmony_ci const struct regulator_desc *desc, 67862306a36Sopenharmony_ci struct regulator_config *config) 67962306a36Sopenharmony_ci{ 68062306a36Sopenharmony_ci struct qcom_rpm_reg *vreg = config->driver_data; 68162306a36Sopenharmony_ci struct device *dev = config->dev; 68262306a36Sopenharmony_ci const char *key; 68362306a36Sopenharmony_ci u32 force_mode; 68462306a36Sopenharmony_ci bool pwm; 68562306a36Sopenharmony_ci u32 val; 68662306a36Sopenharmony_ci int ret; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci key = "bias-pull-down"; 68962306a36Sopenharmony_ci if (of_property_read_bool(node, key)) { 69062306a36Sopenharmony_ci ret = rpm_reg_set(vreg, &vreg->parts->pd, 1); 69162306a36Sopenharmony_ci if (ret) { 69262306a36Sopenharmony_ci dev_err(dev, "%s is invalid", key); 69362306a36Sopenharmony_ci return ret; 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci } 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci if (vreg->parts->freq.mask) { 69862306a36Sopenharmony_ci ret = rpm_reg_of_parse_freq(dev, node, vreg); 69962306a36Sopenharmony_ci if (ret < 0) 70062306a36Sopenharmony_ci return ret; 70162306a36Sopenharmony_ci } 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci if (vreg->parts->pm.mask) { 70462306a36Sopenharmony_ci key = "qcom,power-mode-hysteretic"; 70562306a36Sopenharmony_ci pwm = !of_property_read_bool(node, key); 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci ret = rpm_reg_set(vreg, &vreg->parts->pm, pwm); 70862306a36Sopenharmony_ci if (ret) { 70962306a36Sopenharmony_ci dev_err(dev, "failed to set power mode\n"); 71062306a36Sopenharmony_ci return ret; 71162306a36Sopenharmony_ci } 71262306a36Sopenharmony_ci } 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci if (vreg->parts->fm.mask) { 71562306a36Sopenharmony_ci force_mode = -1; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci key = "qcom,force-mode"; 71862306a36Sopenharmony_ci ret = of_property_read_u32(node, key, &val); 71962306a36Sopenharmony_ci if (ret == -EINVAL) { 72062306a36Sopenharmony_ci val = QCOM_RPM_FORCE_MODE_NONE; 72162306a36Sopenharmony_ci } else if (ret < 0) { 72262306a36Sopenharmony_ci dev_err(dev, "failed to read %s\n", key); 72362306a36Sopenharmony_ci return ret; 72462306a36Sopenharmony_ci } 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci /* 72762306a36Sopenharmony_ci * If force-mode is encoded as 2 bits then the 72862306a36Sopenharmony_ci * possible register values are: 72962306a36Sopenharmony_ci * NONE, LPM, HPM 73062306a36Sopenharmony_ci * otherwise: 73162306a36Sopenharmony_ci * NONE, LPM, AUTO, HPM, BYPASS 73262306a36Sopenharmony_ci */ 73362306a36Sopenharmony_ci switch (val) { 73462306a36Sopenharmony_ci case QCOM_RPM_FORCE_MODE_NONE: 73562306a36Sopenharmony_ci force_mode = 0; 73662306a36Sopenharmony_ci break; 73762306a36Sopenharmony_ci case QCOM_RPM_FORCE_MODE_LPM: 73862306a36Sopenharmony_ci force_mode = 1; 73962306a36Sopenharmony_ci break; 74062306a36Sopenharmony_ci case QCOM_RPM_FORCE_MODE_HPM: 74162306a36Sopenharmony_ci if (FORCE_MODE_IS_2_BITS(vreg)) 74262306a36Sopenharmony_ci force_mode = 2; 74362306a36Sopenharmony_ci else 74462306a36Sopenharmony_ci force_mode = 3; 74562306a36Sopenharmony_ci break; 74662306a36Sopenharmony_ci case QCOM_RPM_FORCE_MODE_AUTO: 74762306a36Sopenharmony_ci if (vreg->supports_force_mode_auto) 74862306a36Sopenharmony_ci force_mode = 2; 74962306a36Sopenharmony_ci break; 75062306a36Sopenharmony_ci case QCOM_RPM_FORCE_MODE_BYPASS: 75162306a36Sopenharmony_ci if (vreg->supports_force_mode_bypass) 75262306a36Sopenharmony_ci force_mode = 4; 75362306a36Sopenharmony_ci break; 75462306a36Sopenharmony_ci } 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci if (force_mode == -1) { 75762306a36Sopenharmony_ci dev_err(dev, "invalid force mode\n"); 75862306a36Sopenharmony_ci return -EINVAL; 75962306a36Sopenharmony_ci } 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci ret = rpm_reg_set(vreg, &vreg->parts->fm, force_mode); 76262306a36Sopenharmony_ci if (ret) { 76362306a36Sopenharmony_ci dev_err(dev, "failed to set force mode\n"); 76462306a36Sopenharmony_ci return ret; 76562306a36Sopenharmony_ci } 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci return 0; 76962306a36Sopenharmony_ci} 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_cistruct rpm_regulator_data { 77262306a36Sopenharmony_ci const char *name; 77362306a36Sopenharmony_ci int resource; 77462306a36Sopenharmony_ci const struct qcom_rpm_reg *template; 77562306a36Sopenharmony_ci const char *supply; 77662306a36Sopenharmony_ci}; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_cistatic const struct rpm_regulator_data rpm_pm8018_regulators[] = { 77962306a36Sopenharmony_ci { "s1", QCOM_RPM_PM8018_SMPS1, &pm8018_smps, "vdd_s1" }, 78062306a36Sopenharmony_ci { "s2", QCOM_RPM_PM8018_SMPS2, &pm8018_smps, "vdd_s2" }, 78162306a36Sopenharmony_ci { "s3", QCOM_RPM_PM8018_SMPS3, &pm8018_smps, "vdd_s3" }, 78262306a36Sopenharmony_ci { "s4", QCOM_RPM_PM8018_SMPS4, &pm8018_smps, "vdd_s4" }, 78362306a36Sopenharmony_ci { "s5", QCOM_RPM_PM8018_SMPS5, &pm8018_smps, "vdd_s5" }, 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci { "l2", QCOM_RPM_PM8018_LDO2, &pm8018_pldo, "vdd_l2" }, 78662306a36Sopenharmony_ci { "l3", QCOM_RPM_PM8018_LDO3, &pm8018_pldo, "vdd_l3" }, 78762306a36Sopenharmony_ci { "l4", QCOM_RPM_PM8018_LDO4, &pm8018_pldo, "vdd_l4" }, 78862306a36Sopenharmony_ci { "l5", QCOM_RPM_PM8018_LDO5, &pm8018_pldo, "vdd_l5" }, 78962306a36Sopenharmony_ci { "l6", QCOM_RPM_PM8018_LDO6, &pm8018_pldo, "vdd_l7" }, 79062306a36Sopenharmony_ci { "l7", QCOM_RPM_PM8018_LDO7, &pm8018_pldo, "vdd_l7" }, 79162306a36Sopenharmony_ci { "l8", QCOM_RPM_PM8018_LDO8, &pm8018_nldo, "vdd_l8" }, 79262306a36Sopenharmony_ci { "l9", QCOM_RPM_PM8018_LDO9, &pm8921_nldo1200, 79362306a36Sopenharmony_ci "vdd_l9_l10_l11_l12" }, 79462306a36Sopenharmony_ci { "l10", QCOM_RPM_PM8018_LDO10, &pm8018_nldo, "vdd_l9_l10_l11_l12" }, 79562306a36Sopenharmony_ci { "l11", QCOM_RPM_PM8018_LDO11, &pm8018_nldo, "vdd_l9_l10_l11_l12" }, 79662306a36Sopenharmony_ci { "l12", QCOM_RPM_PM8018_LDO12, &pm8018_nldo, "vdd_l9_l10_l11_l12" }, 79762306a36Sopenharmony_ci { "l14", QCOM_RPM_PM8018_LDO14, &pm8018_pldo, "vdd_l14" }, 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci { "lvs1", QCOM_RPM_PM8018_LVS1, &pm8018_switch, "lvs1_in" }, 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci { } 80262306a36Sopenharmony_ci}; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_cistatic const struct rpm_regulator_data rpm_pm8058_regulators[] = { 80562306a36Sopenharmony_ci { "s0", QCOM_RPM_PM8058_SMPS0, &pm8058_smps, "vdd_s0" }, 80662306a36Sopenharmony_ci { "s1", QCOM_RPM_PM8058_SMPS1, &pm8058_smps, "vdd_s1" }, 80762306a36Sopenharmony_ci { "s2", QCOM_RPM_PM8058_SMPS2, &pm8058_smps, "vdd_s2" }, 80862306a36Sopenharmony_ci { "s3", QCOM_RPM_PM8058_SMPS3, &pm8058_smps, "vdd_s3" }, 80962306a36Sopenharmony_ci { "s4", QCOM_RPM_PM8058_SMPS4, &pm8058_smps, "vdd_s4" }, 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci { "l0", QCOM_RPM_PM8058_LDO0, &pm8058_nldo, "vdd_l0_l1_lvs" }, 81262306a36Sopenharmony_ci { "l1", QCOM_RPM_PM8058_LDO1, &pm8058_nldo, "vdd_l0_l1_lvs" }, 81362306a36Sopenharmony_ci { "l2", QCOM_RPM_PM8058_LDO2, &pm8058_pldo, "vdd_l2_l11_l12" }, 81462306a36Sopenharmony_ci { "l3", QCOM_RPM_PM8058_LDO3, &pm8058_pldo, "vdd_l3_l4_l5" }, 81562306a36Sopenharmony_ci { "l4", QCOM_RPM_PM8058_LDO4, &pm8058_pldo, "vdd_l3_l4_l5" }, 81662306a36Sopenharmony_ci { "l5", QCOM_RPM_PM8058_LDO5, &pm8058_pldo, "vdd_l3_l4_l5" }, 81762306a36Sopenharmony_ci { "l6", QCOM_RPM_PM8058_LDO6, &pm8058_pldo, "vdd_l6_l7" }, 81862306a36Sopenharmony_ci { "l7", QCOM_RPM_PM8058_LDO7, &pm8058_pldo, "vdd_l6_l7" }, 81962306a36Sopenharmony_ci { "l8", QCOM_RPM_PM8058_LDO8, &pm8058_pldo, "vdd_l8" }, 82062306a36Sopenharmony_ci { "l9", QCOM_RPM_PM8058_LDO9, &pm8058_pldo, "vdd_l9" }, 82162306a36Sopenharmony_ci { "l10", QCOM_RPM_PM8058_LDO10, &pm8058_pldo, "vdd_l10" }, 82262306a36Sopenharmony_ci { "l11", QCOM_RPM_PM8058_LDO11, &pm8058_pldo, "vdd_l2_l11_l12" }, 82362306a36Sopenharmony_ci { "l12", QCOM_RPM_PM8058_LDO12, &pm8058_pldo, "vdd_l2_l11_l12" }, 82462306a36Sopenharmony_ci { "l13", QCOM_RPM_PM8058_LDO13, &pm8058_pldo, "vdd_l13_l16" }, 82562306a36Sopenharmony_ci { "l14", QCOM_RPM_PM8058_LDO14, &pm8058_pldo, "vdd_l14_l15" }, 82662306a36Sopenharmony_ci { "l15", QCOM_RPM_PM8058_LDO15, &pm8058_pldo, "vdd_l14_l15" }, 82762306a36Sopenharmony_ci { "l16", QCOM_RPM_PM8058_LDO16, &pm8058_pldo, "vdd_l13_l16" }, 82862306a36Sopenharmony_ci { "l17", QCOM_RPM_PM8058_LDO17, &pm8058_pldo, "vdd_l17_l18" }, 82962306a36Sopenharmony_ci { "l18", QCOM_RPM_PM8058_LDO18, &pm8058_pldo, "vdd_l17_l18" }, 83062306a36Sopenharmony_ci { "l19", QCOM_RPM_PM8058_LDO19, &pm8058_pldo, "vdd_l19_l20" }, 83162306a36Sopenharmony_ci { "l20", QCOM_RPM_PM8058_LDO20, &pm8058_pldo, "vdd_l19_l20" }, 83262306a36Sopenharmony_ci { "l21", QCOM_RPM_PM8058_LDO21, &pm8058_nldo, "vdd_l21" }, 83362306a36Sopenharmony_ci { "l22", QCOM_RPM_PM8058_LDO22, &pm8058_nldo, "vdd_l22" }, 83462306a36Sopenharmony_ci { "l23", QCOM_RPM_PM8058_LDO23, &pm8058_nldo, "vdd_l23_l24_l25" }, 83562306a36Sopenharmony_ci { "l24", QCOM_RPM_PM8058_LDO24, &pm8058_nldo, "vdd_l23_l24_l25" }, 83662306a36Sopenharmony_ci { "l25", QCOM_RPM_PM8058_LDO25, &pm8058_nldo, "vdd_l23_l24_l25" }, 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci { "lvs0", QCOM_RPM_PM8058_LVS0, &pm8058_switch, "vdd_l0_l1_lvs" }, 83962306a36Sopenharmony_ci { "lvs1", QCOM_RPM_PM8058_LVS1, &pm8058_switch, "vdd_l0_l1_lvs" }, 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci { "ncp", QCOM_RPM_PM8058_NCP, &pm8058_ncp, "vdd_ncp" }, 84262306a36Sopenharmony_ci { } 84362306a36Sopenharmony_ci}; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_cistatic const struct rpm_regulator_data rpm_pm8901_regulators[] = { 84662306a36Sopenharmony_ci { "s0", QCOM_RPM_PM8901_SMPS0, &pm8901_ftsmps, "vdd_s0" }, 84762306a36Sopenharmony_ci { "s1", QCOM_RPM_PM8901_SMPS1, &pm8901_ftsmps, "vdd_s1" }, 84862306a36Sopenharmony_ci { "s2", QCOM_RPM_PM8901_SMPS2, &pm8901_ftsmps, "vdd_s2" }, 84962306a36Sopenharmony_ci { "s3", QCOM_RPM_PM8901_SMPS3, &pm8901_ftsmps, "vdd_s3" }, 85062306a36Sopenharmony_ci { "s4", QCOM_RPM_PM8901_SMPS4, &pm8901_ftsmps, "vdd_s4" }, 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci { "l0", QCOM_RPM_PM8901_LDO0, &pm8901_nldo, "vdd_l0" }, 85362306a36Sopenharmony_ci { "l1", QCOM_RPM_PM8901_LDO1, &pm8901_pldo, "vdd_l1" }, 85462306a36Sopenharmony_ci { "l2", QCOM_RPM_PM8901_LDO2, &pm8901_pldo, "vdd_l2" }, 85562306a36Sopenharmony_ci { "l3", QCOM_RPM_PM8901_LDO3, &pm8901_pldo, "vdd_l3" }, 85662306a36Sopenharmony_ci { "l4", QCOM_RPM_PM8901_LDO4, &pm8901_pldo, "vdd_l4" }, 85762306a36Sopenharmony_ci { "l5", QCOM_RPM_PM8901_LDO5, &pm8901_pldo, "vdd_l5" }, 85862306a36Sopenharmony_ci { "l6", QCOM_RPM_PM8901_LDO6, &pm8901_pldo, "vdd_l6" }, 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci { "lvs0", QCOM_RPM_PM8901_LVS0, &pm8901_switch, "lvs0_in" }, 86162306a36Sopenharmony_ci { "lvs1", QCOM_RPM_PM8901_LVS1, &pm8901_switch, "lvs1_in" }, 86262306a36Sopenharmony_ci { "lvs2", QCOM_RPM_PM8901_LVS2, &pm8901_switch, "lvs2_in" }, 86362306a36Sopenharmony_ci { "lvs3", QCOM_RPM_PM8901_LVS3, &pm8901_switch, "lvs3_in" }, 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci { "mvs", QCOM_RPM_PM8901_MVS, &pm8901_switch, "mvs_in" }, 86662306a36Sopenharmony_ci { } 86762306a36Sopenharmony_ci}; 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_cistatic const struct rpm_regulator_data rpm_pm8921_regulators[] = { 87062306a36Sopenharmony_ci { "s1", QCOM_RPM_PM8921_SMPS1, &pm8921_smps, "vdd_s1" }, 87162306a36Sopenharmony_ci { "s2", QCOM_RPM_PM8921_SMPS2, &pm8921_smps, "vdd_s2" }, 87262306a36Sopenharmony_ci { "s3", QCOM_RPM_PM8921_SMPS3, &pm8921_smps }, 87362306a36Sopenharmony_ci { "s4", QCOM_RPM_PM8921_SMPS4, &pm8921_smps, "vdd_s4" }, 87462306a36Sopenharmony_ci { "s7", QCOM_RPM_PM8921_SMPS7, &pm8921_smps, "vdd_s7" }, 87562306a36Sopenharmony_ci { "s8", QCOM_RPM_PM8921_SMPS8, &pm8921_smps, "vdd_s8" }, 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci { "l1", QCOM_RPM_PM8921_LDO1, &pm8921_nldo, "vdd_l1_l2_l12_l18" }, 87862306a36Sopenharmony_ci { "l2", QCOM_RPM_PM8921_LDO2, &pm8921_nldo, "vdd_l1_l2_l12_l18" }, 87962306a36Sopenharmony_ci { "l3", QCOM_RPM_PM8921_LDO3, &pm8921_pldo, "vdd_l3_l15_l17" }, 88062306a36Sopenharmony_ci { "l4", QCOM_RPM_PM8921_LDO4, &pm8921_pldo, "vdd_l4_l14" }, 88162306a36Sopenharmony_ci { "l5", QCOM_RPM_PM8921_LDO5, &pm8921_pldo, "vdd_l5_l8_l16" }, 88262306a36Sopenharmony_ci { "l6", QCOM_RPM_PM8921_LDO6, &pm8921_pldo, "vdd_l6_l7" }, 88362306a36Sopenharmony_ci { "l7", QCOM_RPM_PM8921_LDO7, &pm8921_pldo, "vdd_l6_l7" }, 88462306a36Sopenharmony_ci { "l8", QCOM_RPM_PM8921_LDO8, &pm8921_pldo, "vdd_l5_l8_l16" }, 88562306a36Sopenharmony_ci { "l9", QCOM_RPM_PM8921_LDO9, &pm8921_pldo, "vdd_l9_l11" }, 88662306a36Sopenharmony_ci { "l10", QCOM_RPM_PM8921_LDO10, &pm8921_pldo, "vdd_l10_l22" }, 88762306a36Sopenharmony_ci { "l11", QCOM_RPM_PM8921_LDO11, &pm8921_pldo, "vdd_l9_l11" }, 88862306a36Sopenharmony_ci { "l12", QCOM_RPM_PM8921_LDO12, &pm8921_nldo, "vdd_l1_l2_l12_l18" }, 88962306a36Sopenharmony_ci { "l14", QCOM_RPM_PM8921_LDO14, &pm8921_pldo, "vdd_l4_l14" }, 89062306a36Sopenharmony_ci { "l15", QCOM_RPM_PM8921_LDO15, &pm8921_pldo, "vdd_l3_l15_l17" }, 89162306a36Sopenharmony_ci { "l16", QCOM_RPM_PM8921_LDO16, &pm8921_pldo, "vdd_l5_l8_l16" }, 89262306a36Sopenharmony_ci { "l17", QCOM_RPM_PM8921_LDO17, &pm8921_pldo, "vdd_l3_l15_l17" }, 89362306a36Sopenharmony_ci { "l18", QCOM_RPM_PM8921_LDO18, &pm8921_nldo, "vdd_l1_l2_l12_l18" }, 89462306a36Sopenharmony_ci { "l21", QCOM_RPM_PM8921_LDO21, &pm8921_pldo, "vdd_l21_l23_l29" }, 89562306a36Sopenharmony_ci { "l22", QCOM_RPM_PM8921_LDO22, &pm8921_pldo, "vdd_l10_l22" }, 89662306a36Sopenharmony_ci { "l23", QCOM_RPM_PM8921_LDO23, &pm8921_pldo, "vdd_l21_l23_l29" }, 89762306a36Sopenharmony_ci { "l24", QCOM_RPM_PM8921_LDO24, &pm8921_nldo1200, "vdd_l24" }, 89862306a36Sopenharmony_ci { "l25", QCOM_RPM_PM8921_LDO25, &pm8921_nldo1200, "vdd_l25" }, 89962306a36Sopenharmony_ci { "l26", QCOM_RPM_PM8921_LDO26, &pm8921_nldo1200, "vdd_l26" }, 90062306a36Sopenharmony_ci { "l27", QCOM_RPM_PM8921_LDO27, &pm8921_nldo1200, "vdd_l27" }, 90162306a36Sopenharmony_ci { "l28", QCOM_RPM_PM8921_LDO28, &pm8921_nldo1200, "vdd_l28" }, 90262306a36Sopenharmony_ci { "l29", QCOM_RPM_PM8921_LDO29, &pm8921_pldo, "vdd_l21_l23_l29" }, 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci { "lvs1", QCOM_RPM_PM8921_LVS1, &pm8921_switch, "vin_lvs1_3_6" }, 90562306a36Sopenharmony_ci { "lvs2", QCOM_RPM_PM8921_LVS2, &pm8921_switch, "vin_lvs2" }, 90662306a36Sopenharmony_ci { "lvs3", QCOM_RPM_PM8921_LVS3, &pm8921_switch, "vin_lvs1_3_6" }, 90762306a36Sopenharmony_ci { "lvs4", QCOM_RPM_PM8921_LVS4, &pm8921_switch, "vin_lvs4_5_7" }, 90862306a36Sopenharmony_ci { "lvs5", QCOM_RPM_PM8921_LVS5, &pm8921_switch, "vin_lvs4_5_7" }, 90962306a36Sopenharmony_ci { "lvs6", QCOM_RPM_PM8921_LVS6, &pm8921_switch, "vin_lvs1_3_6" }, 91062306a36Sopenharmony_ci { "lvs7", QCOM_RPM_PM8921_LVS7, &pm8921_switch, "vin_lvs4_5_7" }, 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci { "usb-switch", QCOM_RPM_USB_OTG_SWITCH, &pm8921_switch, "vin_5vs" }, 91362306a36Sopenharmony_ci { "hdmi-switch", QCOM_RPM_HDMI_SWITCH, &pm8921_switch, "vin_5vs" }, 91462306a36Sopenharmony_ci { "ncp", QCOM_RPM_PM8921_NCP, &pm8921_ncp, "vdd_ncp" }, 91562306a36Sopenharmony_ci { } 91662306a36Sopenharmony_ci}; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_cistatic const struct rpm_regulator_data rpm_smb208_regulators[] = { 91962306a36Sopenharmony_ci { "s1a", QCOM_RPM_SMB208_S1a, &smb208_smps, "vin_s1a" }, 92062306a36Sopenharmony_ci { "s1b", QCOM_RPM_SMB208_S1b, &smb208_smps, "vin_s1b" }, 92162306a36Sopenharmony_ci { "s2a", QCOM_RPM_SMB208_S2a, &smb208_smps, "vin_s2a" }, 92262306a36Sopenharmony_ci { "s2b", QCOM_RPM_SMB208_S2b, &smb208_smps, "vin_s2b" }, 92362306a36Sopenharmony_ci { } 92462306a36Sopenharmony_ci}; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_cistatic const struct of_device_id rpm_of_match[] = { 92762306a36Sopenharmony_ci { .compatible = "qcom,rpm-pm8018-regulators", 92862306a36Sopenharmony_ci .data = &rpm_pm8018_regulators }, 92962306a36Sopenharmony_ci { .compatible = "qcom,rpm-pm8058-regulators", .data = &rpm_pm8058_regulators }, 93062306a36Sopenharmony_ci { .compatible = "qcom,rpm-pm8901-regulators", .data = &rpm_pm8901_regulators }, 93162306a36Sopenharmony_ci { .compatible = "qcom,rpm-pm8921-regulators", .data = &rpm_pm8921_regulators }, 93262306a36Sopenharmony_ci { .compatible = "qcom,rpm-smb208-regulators", .data = &rpm_smb208_regulators }, 93362306a36Sopenharmony_ci { } 93462306a36Sopenharmony_ci}; 93562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, rpm_of_match); 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_cistatic int rpm_reg_probe(struct platform_device *pdev) 93862306a36Sopenharmony_ci{ 93962306a36Sopenharmony_ci const struct rpm_regulator_data *reg; 94062306a36Sopenharmony_ci const struct of_device_id *match; 94162306a36Sopenharmony_ci struct regulator_config config = { }; 94262306a36Sopenharmony_ci struct regulator_dev *rdev; 94362306a36Sopenharmony_ci struct qcom_rpm_reg *vreg; 94462306a36Sopenharmony_ci struct qcom_rpm *rpm; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci rpm = dev_get_drvdata(pdev->dev.parent); 94762306a36Sopenharmony_ci if (!rpm) { 94862306a36Sopenharmony_ci dev_err(&pdev->dev, "unable to retrieve handle to rpm\n"); 94962306a36Sopenharmony_ci return -ENODEV; 95062306a36Sopenharmony_ci } 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci match = of_match_device(rpm_of_match, &pdev->dev); 95362306a36Sopenharmony_ci if (!match) { 95462306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to match device\n"); 95562306a36Sopenharmony_ci return -ENODEV; 95662306a36Sopenharmony_ci } 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci for (reg = match->data; reg->name; reg++) { 95962306a36Sopenharmony_ci vreg = devm_kmemdup(&pdev->dev, reg->template, sizeof(*vreg), GFP_KERNEL); 96062306a36Sopenharmony_ci if (!vreg) 96162306a36Sopenharmony_ci return -ENOMEM; 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci mutex_init(&vreg->lock); 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci vreg->dev = &pdev->dev; 96662306a36Sopenharmony_ci vreg->resource = reg->resource; 96762306a36Sopenharmony_ci vreg->rpm = rpm; 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci vreg->desc.id = -1; 97062306a36Sopenharmony_ci vreg->desc.owner = THIS_MODULE; 97162306a36Sopenharmony_ci vreg->desc.type = REGULATOR_VOLTAGE; 97262306a36Sopenharmony_ci vreg->desc.name = reg->name; 97362306a36Sopenharmony_ci vreg->desc.supply_name = reg->supply; 97462306a36Sopenharmony_ci vreg->desc.of_match = reg->name; 97562306a36Sopenharmony_ci vreg->desc.of_parse_cb = rpm_reg_of_parse; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci config.dev = &pdev->dev; 97862306a36Sopenharmony_ci config.driver_data = vreg; 97962306a36Sopenharmony_ci rdev = devm_regulator_register(&pdev->dev, &vreg->desc, &config); 98062306a36Sopenharmony_ci if (IS_ERR(rdev)) { 98162306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to register %s\n", reg->name); 98262306a36Sopenharmony_ci return PTR_ERR(rdev); 98362306a36Sopenharmony_ci } 98462306a36Sopenharmony_ci } 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci return 0; 98762306a36Sopenharmony_ci} 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_cistatic struct platform_driver rpm_reg_driver = { 99062306a36Sopenharmony_ci .probe = rpm_reg_probe, 99162306a36Sopenharmony_ci .driver = { 99262306a36Sopenharmony_ci .name = "qcom_rpm_reg", 99362306a36Sopenharmony_ci .probe_type = PROBE_PREFER_ASYNCHRONOUS, 99462306a36Sopenharmony_ci .of_match_table = of_match_ptr(rpm_of_match), 99562306a36Sopenharmony_ci }, 99662306a36Sopenharmony_ci}; 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_cistatic int __init rpm_reg_init(void) 99962306a36Sopenharmony_ci{ 100062306a36Sopenharmony_ci return platform_driver_register(&rpm_reg_driver); 100162306a36Sopenharmony_ci} 100262306a36Sopenharmony_cisubsys_initcall(rpm_reg_init); 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_cistatic void __exit rpm_reg_exit(void) 100562306a36Sopenharmony_ci{ 100662306a36Sopenharmony_ci platform_driver_unregister(&rpm_reg_driver); 100762306a36Sopenharmony_ci} 100862306a36Sopenharmony_cimodule_exit(rpm_reg_exit) 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ciMODULE_DESCRIPTION("Qualcomm RPM regulator driver"); 101162306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1012