197fb5e8dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
22720386eSBjorn Andersson /*
32720386eSBjorn Andersson  * Copyright (c) 2014, Sony Mobile Communications AB.
42720386eSBjorn Andersson  * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
52720386eSBjorn Andersson  */
62720386eSBjorn Andersson 
72720386eSBjorn Andersson #include <linux/module.h>
82720386eSBjorn Andersson #include <linux/platform_device.h>
92720386eSBjorn Andersson #include <linux/of.h>
102720386eSBjorn Andersson #include <linux/of_device.h>
112720386eSBjorn Andersson #include <linux/regulator/driver.h>
122720386eSBjorn Andersson #include <linux/regulator/machine.h>
132720386eSBjorn Andersson #include <linux/regulator/of_regulator.h>
142720386eSBjorn Andersson #include <linux/mfd/qcom_rpm.h>
152720386eSBjorn Andersson 
162720386eSBjorn Andersson #include <dt-bindings/mfd/qcom-rpm.h>
172720386eSBjorn Andersson 
182720386eSBjorn Andersson #define MAX_REQUEST_LEN 2
192720386eSBjorn Andersson 
202720386eSBjorn Andersson struct request_member {
212720386eSBjorn Andersson 	int		word;
222720386eSBjorn Andersson 	unsigned int	mask;
232720386eSBjorn Andersson 	int		shift;
242720386eSBjorn Andersson };
252720386eSBjorn Andersson 
262720386eSBjorn Andersson struct rpm_reg_parts {
272720386eSBjorn Andersson 	struct request_member mV;		/* used if voltage is in mV */
282720386eSBjorn Andersson 	struct request_member uV;		/* used if voltage is in uV */
292720386eSBjorn Andersson 	struct request_member ip;		/* peak current in mA */
302720386eSBjorn Andersson 	struct request_member pd;		/* pull down enable */
312720386eSBjorn Andersson 	struct request_member ia;		/* average current in mA */
322720386eSBjorn Andersson 	struct request_member fm;		/* force mode */
332720386eSBjorn Andersson 	struct request_member pm;		/* power mode */
342720386eSBjorn Andersson 	struct request_member pc;		/* pin control */
352720386eSBjorn Andersson 	struct request_member pf;		/* pin function */
362720386eSBjorn Andersson 	struct request_member enable_state;	/* NCP and switch */
372720386eSBjorn Andersson 	struct request_member comp_mode;	/* NCP */
382720386eSBjorn Andersson 	struct request_member freq;		/* frequency: NCP and SMPS */
392720386eSBjorn Andersson 	struct request_member freq_clk_src;	/* clock source: SMPS */
402720386eSBjorn Andersson 	struct request_member hpm;		/* switch: control OCP and SS */
412720386eSBjorn Andersson 	int request_len;
422720386eSBjorn Andersson };
432720386eSBjorn Andersson 
442720386eSBjorn Andersson #define FORCE_MODE_IS_2_BITS(reg) \
456a642509SAxel Lin 	(((reg)->parts->fm.mask >> (reg)->parts->fm.shift) == 3)
462720386eSBjorn Andersson 
472720386eSBjorn Andersson struct qcom_rpm_reg {
482720386eSBjorn Andersson 	struct qcom_rpm *rpm;
492720386eSBjorn Andersson 
502720386eSBjorn Andersson 	struct mutex lock;
512720386eSBjorn Andersson 	struct device *dev;
522720386eSBjorn Andersson 	struct regulator_desc desc;
532720386eSBjorn Andersson 	const struct rpm_reg_parts *parts;
542720386eSBjorn Andersson 
552720386eSBjorn Andersson 	int resource;
562720386eSBjorn Andersson 	u32 val[MAX_REQUEST_LEN];
572720386eSBjorn Andersson 
582720386eSBjorn Andersson 	int uV;
592720386eSBjorn Andersson 	int is_enabled;
602720386eSBjorn Andersson 
612720386eSBjorn Andersson 	bool supports_force_mode_auto;
622720386eSBjorn Andersson 	bool supports_force_mode_bypass;
632720386eSBjorn Andersson };
642720386eSBjorn Andersson 
652720386eSBjorn Andersson static const struct rpm_reg_parts rpm8660_ldo_parts = {
662720386eSBjorn Andersson 	.request_len    = 2,
672720386eSBjorn Andersson 	.mV             = { 0, 0x00000FFF,  0 },
682720386eSBjorn Andersson 	.ip             = { 0, 0x00FFF000, 12 },
692720386eSBjorn Andersson 	.fm             = { 0, 0x03000000, 24 },
702720386eSBjorn Andersson 	.pc             = { 0, 0x3C000000, 26 },
712720386eSBjorn Andersson 	.pf             = { 0, 0xC0000000, 30 },
722720386eSBjorn Andersson 	.pd             = { 1, 0x00000001,  0 },
732720386eSBjorn Andersson 	.ia             = { 1, 0x00001FFE,  1 },
742720386eSBjorn Andersson };
752720386eSBjorn Andersson 
762720386eSBjorn Andersson static const struct rpm_reg_parts rpm8660_smps_parts = {
772720386eSBjorn Andersson 	.request_len    = 2,
782720386eSBjorn Andersson 	.mV             = { 0, 0x00000FFF,  0 },
792720386eSBjorn Andersson 	.ip             = { 0, 0x00FFF000, 12 },
802720386eSBjorn Andersson 	.fm             = { 0, 0x03000000, 24 },
812720386eSBjorn Andersson 	.pc             = { 0, 0x3C000000, 26 },
822720386eSBjorn Andersson 	.pf             = { 0, 0xC0000000, 30 },
832720386eSBjorn Andersson 	.pd             = { 1, 0x00000001,  0 },
842720386eSBjorn Andersson 	.ia             = { 1, 0x00001FFE,  1 },
852720386eSBjorn Andersson 	.freq           = { 1, 0x001FE000, 13 },
862720386eSBjorn Andersson 	.freq_clk_src   = { 1, 0x00600000, 21 },
872720386eSBjorn Andersson };
882720386eSBjorn Andersson 
892720386eSBjorn Andersson static const struct rpm_reg_parts rpm8660_switch_parts = {
902720386eSBjorn Andersson 	.request_len    = 1,
912720386eSBjorn Andersson 	.enable_state   = { 0, 0x00000001,  0 },
922720386eSBjorn Andersson 	.pd             = { 0, 0x00000002,  1 },
932720386eSBjorn Andersson 	.pc             = { 0, 0x0000003C,  2 },
942720386eSBjorn Andersson 	.pf             = { 0, 0x000000C0,  6 },
952720386eSBjorn Andersson 	.hpm            = { 0, 0x00000300,  8 },
962720386eSBjorn Andersson };
972720386eSBjorn Andersson 
982720386eSBjorn Andersson static const struct rpm_reg_parts rpm8660_ncp_parts = {
992720386eSBjorn Andersson 	.request_len    = 1,
1002720386eSBjorn Andersson 	.mV             = { 0, 0x00000FFF,  0 },
1012720386eSBjorn Andersson 	.enable_state   = { 0, 0x00001000, 12 },
1022720386eSBjorn Andersson 	.comp_mode      = { 0, 0x00002000, 13 },
1032720386eSBjorn Andersson 	.freq           = { 0, 0x003FC000, 14 },
1042720386eSBjorn Andersson };
1052720386eSBjorn Andersson 
1062720386eSBjorn Andersson static const struct rpm_reg_parts rpm8960_ldo_parts = {
1072720386eSBjorn Andersson 	.request_len    = 2,
1082720386eSBjorn Andersson 	.uV             = { 0, 0x007FFFFF,  0 },
1092720386eSBjorn Andersson 	.pd             = { 0, 0x00800000, 23 },
1102720386eSBjorn Andersson 	.pc             = { 0, 0x0F000000, 24 },
1112720386eSBjorn Andersson 	.pf             = { 0, 0xF0000000, 28 },
1122720386eSBjorn Andersson 	.ip             = { 1, 0x000003FF,  0 },
1132720386eSBjorn Andersson 	.ia             = { 1, 0x000FFC00, 10 },
1142720386eSBjorn Andersson 	.fm             = { 1, 0x00700000, 20 },
1152720386eSBjorn Andersson };
1162720386eSBjorn Andersson 
1172720386eSBjorn Andersson static const struct rpm_reg_parts rpm8960_smps_parts = {
1182720386eSBjorn Andersson 	.request_len    = 2,
1192720386eSBjorn Andersson 	.uV             = { 0, 0x007FFFFF,  0 },
1202720386eSBjorn Andersson 	.pd             = { 0, 0x00800000, 23 },
1212720386eSBjorn Andersson 	.pc             = { 0, 0x0F000000, 24 },
1222720386eSBjorn Andersson 	.pf             = { 0, 0xF0000000, 28 },
1232720386eSBjorn Andersson 	.ip             = { 1, 0x000003FF,  0 },
1242720386eSBjorn Andersson 	.ia             = { 1, 0x000FFC00, 10 },
1252720386eSBjorn Andersson 	.fm             = { 1, 0x00700000, 20 },
1262720386eSBjorn Andersson 	.pm             = { 1, 0x00800000, 23 },
1272720386eSBjorn Andersson 	.freq           = { 1, 0x1F000000, 24 },
1282720386eSBjorn Andersson 	.freq_clk_src   = { 1, 0x60000000, 29 },
1292720386eSBjorn Andersson };
1302720386eSBjorn Andersson 
1312720386eSBjorn Andersson static const struct rpm_reg_parts rpm8960_switch_parts = {
1322720386eSBjorn Andersson 	.request_len    = 1,
1332720386eSBjorn Andersson 	.enable_state   = { 0, 0x00000001,  0 },
1342720386eSBjorn Andersson 	.pd             = { 0, 0x00000002,  1 },
1352720386eSBjorn Andersson 	.pc             = { 0, 0x0000003C,  2 },
1362720386eSBjorn Andersson 	.pf             = { 0, 0x000003C0,  6 },
1372720386eSBjorn Andersson 	.hpm            = { 0, 0x00000C00, 10 },
1382720386eSBjorn Andersson };
1392720386eSBjorn Andersson 
1402720386eSBjorn Andersson static const struct rpm_reg_parts rpm8960_ncp_parts = {
1412720386eSBjorn Andersson 	.request_len    = 1,
1422720386eSBjorn Andersson 	.uV             = { 0, 0x007FFFFF,  0 },
1432720386eSBjorn Andersson 	.enable_state   = { 0, 0x00800000, 23 },
1442720386eSBjorn Andersson 	.comp_mode      = { 0, 0x01000000, 24 },
1452720386eSBjorn Andersson 	.freq           = { 0, 0x3E000000, 25 },
1462720386eSBjorn Andersson };
1472720386eSBjorn Andersson 
1482720386eSBjorn Andersson /*
1492720386eSBjorn Andersson  * Physically available PMIC regulator voltage ranges
1502720386eSBjorn Andersson  */
15160ab7f41SMatti Vaittinen static const struct linear_range pldo_ranges[] = {
1522720386eSBjorn Andersson 	REGULATOR_LINEAR_RANGE( 750000,   0,  59, 12500),
1532720386eSBjorn Andersson 	REGULATOR_LINEAR_RANGE(1500000,  60, 123, 25000),
1542720386eSBjorn Andersson 	REGULATOR_LINEAR_RANGE(3100000, 124, 160, 50000),
1552720386eSBjorn Andersson };
1562720386eSBjorn Andersson 
15760ab7f41SMatti Vaittinen static const struct linear_range nldo_ranges[] = {
1582720386eSBjorn Andersson 	REGULATOR_LINEAR_RANGE( 750000,   0,  63, 12500),
1592720386eSBjorn Andersson };
1602720386eSBjorn Andersson 
16160ab7f41SMatti Vaittinen static const struct linear_range nldo1200_ranges[] = {
1622720386eSBjorn Andersson 	REGULATOR_LINEAR_RANGE( 375000,   0,  59,  6250),
1632720386eSBjorn Andersson 	REGULATOR_LINEAR_RANGE( 750000,  60, 123, 12500),
1642720386eSBjorn Andersson };
1652720386eSBjorn Andersson 
16660ab7f41SMatti Vaittinen static const struct linear_range smps_ranges[] = {
1672720386eSBjorn Andersson 	REGULATOR_LINEAR_RANGE( 375000,   0,  29, 12500),
1682720386eSBjorn Andersson 	REGULATOR_LINEAR_RANGE( 750000,  30,  89, 12500),
1692720386eSBjorn Andersson 	REGULATOR_LINEAR_RANGE(1500000,  90, 153, 25000),
1702720386eSBjorn Andersson };
1712720386eSBjorn Andersson 
17260ab7f41SMatti Vaittinen static const struct linear_range ftsmps_ranges[] = {
1732720386eSBjorn Andersson 	REGULATOR_LINEAR_RANGE( 350000,   0,   6, 50000),
1742720386eSBjorn Andersson 	REGULATOR_LINEAR_RANGE( 700000,   7,  63, 12500),
1752720386eSBjorn Andersson 	REGULATOR_LINEAR_RANGE(1500000,  64, 100, 50000),
1762720386eSBjorn Andersson };
1772720386eSBjorn Andersson 
17860ab7f41SMatti Vaittinen static const struct linear_range smb208_ranges[] = {
1790f5bb5b5SJosh Cartwright 	REGULATOR_LINEAR_RANGE( 375000,   0,  29, 12500),
1800f5bb5b5SJosh Cartwright 	REGULATOR_LINEAR_RANGE( 750000,  30,  89, 12500),
1810f5bb5b5SJosh Cartwright 	REGULATOR_LINEAR_RANGE(1500000,  90, 153, 25000),
1820f5bb5b5SJosh Cartwright 	REGULATOR_LINEAR_RANGE(3100000, 154, 234, 25000),
1830f5bb5b5SJosh Cartwright };
1840f5bb5b5SJosh Cartwright 
18560ab7f41SMatti Vaittinen static const struct linear_range ncp_ranges[] = {
1862720386eSBjorn Andersson 	REGULATOR_LINEAR_RANGE(1500000,   0,  31, 50000),
1872720386eSBjorn Andersson };
1882720386eSBjorn Andersson 
rpm_reg_write(struct qcom_rpm_reg * vreg,const struct request_member * req,const int value)1892720386eSBjorn Andersson static int rpm_reg_write(struct qcom_rpm_reg *vreg,
1902720386eSBjorn Andersson 			 const struct request_member *req,
1912720386eSBjorn Andersson 			 const int value)
1922720386eSBjorn Andersson {
1932720386eSBjorn Andersson 	if (WARN_ON((value << req->shift) & ~req->mask))
1942720386eSBjorn Andersson 		return -EINVAL;
1952720386eSBjorn Andersson 
1962720386eSBjorn Andersson 	vreg->val[req->word] &= ~req->mask;
1972720386eSBjorn Andersson 	vreg->val[req->word] |= value << req->shift;
1982720386eSBjorn Andersson 
1992720386eSBjorn Andersson 	return qcom_rpm_write(vreg->rpm,
20080392682SBjorn Andersson 			      QCOM_RPM_ACTIVE_STATE,
2012720386eSBjorn Andersson 			      vreg->resource,
2022720386eSBjorn Andersson 			      vreg->val,
2032720386eSBjorn Andersson 			      vreg->parts->request_len);
2042720386eSBjorn Andersson }
2052720386eSBjorn Andersson 
rpm_reg_set_mV_sel(struct regulator_dev * rdev,unsigned selector)2062720386eSBjorn Andersson static int rpm_reg_set_mV_sel(struct regulator_dev *rdev,
2072720386eSBjorn Andersson 			      unsigned selector)
2082720386eSBjorn Andersson {
2092720386eSBjorn Andersson 	struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
2102720386eSBjorn Andersson 	const struct rpm_reg_parts *parts = vreg->parts;
2112720386eSBjorn Andersson 	const struct request_member *req = &parts->mV;
2122720386eSBjorn Andersson 	int ret = 0;
2132720386eSBjorn Andersson 	int uV;
2142720386eSBjorn Andersson 
2152720386eSBjorn Andersson 	if (req->mask == 0)
2162720386eSBjorn Andersson 		return -EINVAL;
2172720386eSBjorn Andersson 
2182720386eSBjorn Andersson 	uV = regulator_list_voltage_linear_range(rdev, selector);
2192720386eSBjorn Andersson 	if (uV < 0)
2202720386eSBjorn Andersson 		return uV;
2212720386eSBjorn Andersson 
2222720386eSBjorn Andersson 	mutex_lock(&vreg->lock);
2232720386eSBjorn Andersson 	if (vreg->is_enabled)
224c6515d2fSAxel Lin 		ret = rpm_reg_write(vreg, req, uV / 1000);
225c6515d2fSAxel Lin 
226c6515d2fSAxel Lin 	if (!ret)
227c6515d2fSAxel Lin 		vreg->uV = uV;
2282720386eSBjorn Andersson 	mutex_unlock(&vreg->lock);
2292720386eSBjorn Andersson 
2302720386eSBjorn Andersson 	return ret;
2312720386eSBjorn Andersson }
2322720386eSBjorn Andersson 
rpm_reg_set_uV_sel(struct regulator_dev * rdev,unsigned selector)2332720386eSBjorn Andersson static int rpm_reg_set_uV_sel(struct regulator_dev *rdev,
2342720386eSBjorn Andersson 			      unsigned selector)
2352720386eSBjorn Andersson {
2362720386eSBjorn Andersson 	struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
2372720386eSBjorn Andersson 	const struct rpm_reg_parts *parts = vreg->parts;
2382720386eSBjorn Andersson 	const struct request_member *req = &parts->uV;
2392720386eSBjorn Andersson 	int ret = 0;
2402720386eSBjorn Andersson 	int uV;
2412720386eSBjorn Andersson 
2422720386eSBjorn Andersson 	if (req->mask == 0)
2432720386eSBjorn Andersson 		return -EINVAL;
2442720386eSBjorn Andersson 
2452720386eSBjorn Andersson 	uV = regulator_list_voltage_linear_range(rdev, selector);
2462720386eSBjorn Andersson 	if (uV < 0)
2472720386eSBjorn Andersson 		return uV;
2482720386eSBjorn Andersson 
2492720386eSBjorn Andersson 	mutex_lock(&vreg->lock);
2502720386eSBjorn Andersson 	if (vreg->is_enabled)
251c6515d2fSAxel Lin 		ret = rpm_reg_write(vreg, req, uV);
252c6515d2fSAxel Lin 
253c6515d2fSAxel Lin 	if (!ret)
254c6515d2fSAxel Lin 		vreg->uV = uV;
2552720386eSBjorn Andersson 	mutex_unlock(&vreg->lock);
2562720386eSBjorn Andersson 
2572720386eSBjorn Andersson 	return ret;
2582720386eSBjorn Andersson }
2592720386eSBjorn Andersson 
rpm_reg_get_voltage(struct regulator_dev * rdev)2602720386eSBjorn Andersson static int rpm_reg_get_voltage(struct regulator_dev *rdev)
2612720386eSBjorn Andersson {
2622720386eSBjorn Andersson 	struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
2632720386eSBjorn Andersson 
2642720386eSBjorn Andersson 	return vreg->uV;
2652720386eSBjorn Andersson }
2662720386eSBjorn Andersson 
rpm_reg_mV_enable(struct regulator_dev * rdev)2672720386eSBjorn Andersson static int rpm_reg_mV_enable(struct regulator_dev *rdev)
2682720386eSBjorn Andersson {
2692720386eSBjorn Andersson 	struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
2702720386eSBjorn Andersson 	const struct rpm_reg_parts *parts = vreg->parts;
2712720386eSBjorn Andersson 	const struct request_member *req = &parts->mV;
2722720386eSBjorn Andersson 	int ret;
2732720386eSBjorn Andersson 
2742720386eSBjorn Andersson 	if (req->mask == 0)
2752720386eSBjorn Andersson 		return -EINVAL;
2762720386eSBjorn Andersson 
2772720386eSBjorn Andersson 	mutex_lock(&vreg->lock);
2782720386eSBjorn Andersson 	ret = rpm_reg_write(vreg, req, vreg->uV / 1000);
2792720386eSBjorn Andersson 	if (!ret)
2802720386eSBjorn Andersson 		vreg->is_enabled = 1;
2812720386eSBjorn Andersson 	mutex_unlock(&vreg->lock);
2822720386eSBjorn Andersson 
2832720386eSBjorn Andersson 	return ret;
2842720386eSBjorn Andersson }
2852720386eSBjorn Andersson 
rpm_reg_uV_enable(struct regulator_dev * rdev)2862720386eSBjorn Andersson static int rpm_reg_uV_enable(struct regulator_dev *rdev)
2872720386eSBjorn Andersson {
2882720386eSBjorn Andersson 	struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
2892720386eSBjorn Andersson 	const struct rpm_reg_parts *parts = vreg->parts;
2902720386eSBjorn Andersson 	const struct request_member *req = &parts->uV;
2912720386eSBjorn Andersson 	int ret;
2922720386eSBjorn Andersson 
2932720386eSBjorn Andersson 	if (req->mask == 0)
2942720386eSBjorn Andersson 		return -EINVAL;
2952720386eSBjorn Andersson 
2962720386eSBjorn Andersson 	mutex_lock(&vreg->lock);
2972720386eSBjorn Andersson 	ret = rpm_reg_write(vreg, req, vreg->uV);
2982720386eSBjorn Andersson 	if (!ret)
2992720386eSBjorn Andersson 		vreg->is_enabled = 1;
3002720386eSBjorn Andersson 	mutex_unlock(&vreg->lock);
3012720386eSBjorn Andersson 
3022720386eSBjorn Andersson 	return ret;
3032720386eSBjorn Andersson }
3042720386eSBjorn Andersson 
rpm_reg_switch_enable(struct regulator_dev * rdev)3052720386eSBjorn Andersson static int rpm_reg_switch_enable(struct regulator_dev *rdev)
3062720386eSBjorn Andersson {
3072720386eSBjorn Andersson 	struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
3082720386eSBjorn Andersson 	const struct rpm_reg_parts *parts = vreg->parts;
3092720386eSBjorn Andersson 	const struct request_member *req = &parts->enable_state;
3102720386eSBjorn Andersson 	int ret;
3112720386eSBjorn Andersson 
3122720386eSBjorn Andersson 	if (req->mask == 0)
3132720386eSBjorn Andersson 		return -EINVAL;
3142720386eSBjorn Andersson 
3152720386eSBjorn Andersson 	mutex_lock(&vreg->lock);
3162720386eSBjorn Andersson 	ret = rpm_reg_write(vreg, req, 1);
3172720386eSBjorn Andersson 	if (!ret)
3182720386eSBjorn Andersson 		vreg->is_enabled = 1;
3192720386eSBjorn Andersson 	mutex_unlock(&vreg->lock);
3202720386eSBjorn Andersson 
3212720386eSBjorn Andersson 	return ret;
3222720386eSBjorn Andersson }
3232720386eSBjorn Andersson 
rpm_reg_mV_disable(struct regulator_dev * rdev)3242720386eSBjorn Andersson static int rpm_reg_mV_disable(struct regulator_dev *rdev)
3252720386eSBjorn Andersson {
3262720386eSBjorn Andersson 	struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
3272720386eSBjorn Andersson 	const struct rpm_reg_parts *parts = vreg->parts;
3282720386eSBjorn Andersson 	const struct request_member *req = &parts->mV;
3292720386eSBjorn Andersson 	int ret;
3302720386eSBjorn Andersson 
3312720386eSBjorn Andersson 	if (req->mask == 0)
3322720386eSBjorn Andersson 		return -EINVAL;
3332720386eSBjorn Andersson 
3342720386eSBjorn Andersson 	mutex_lock(&vreg->lock);
3352720386eSBjorn Andersson 	ret = rpm_reg_write(vreg, req, 0);
3362720386eSBjorn Andersson 	if (!ret)
3372720386eSBjorn Andersson 		vreg->is_enabled = 0;
3382720386eSBjorn Andersson 	mutex_unlock(&vreg->lock);
3392720386eSBjorn Andersson 
3402720386eSBjorn Andersson 	return ret;
3412720386eSBjorn Andersson }
3422720386eSBjorn Andersson 
rpm_reg_uV_disable(struct regulator_dev * rdev)3432720386eSBjorn Andersson static int rpm_reg_uV_disable(struct regulator_dev *rdev)
3442720386eSBjorn Andersson {
3452720386eSBjorn Andersson 	struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
3462720386eSBjorn Andersson 	const struct rpm_reg_parts *parts = vreg->parts;
3472720386eSBjorn Andersson 	const struct request_member *req = &parts->uV;
3482720386eSBjorn Andersson 	int ret;
3492720386eSBjorn Andersson 
3502720386eSBjorn Andersson 	if (req->mask == 0)
3512720386eSBjorn Andersson 		return -EINVAL;
3522720386eSBjorn Andersson 
3532720386eSBjorn Andersson 	mutex_lock(&vreg->lock);
3542720386eSBjorn Andersson 	ret = rpm_reg_write(vreg, req, 0);
3552720386eSBjorn Andersson 	if (!ret)
3562720386eSBjorn Andersson 		vreg->is_enabled = 0;
3572720386eSBjorn Andersson 	mutex_unlock(&vreg->lock);
3582720386eSBjorn Andersson 
3592720386eSBjorn Andersson 	return ret;
3602720386eSBjorn Andersson }
3612720386eSBjorn Andersson 
rpm_reg_switch_disable(struct regulator_dev * rdev)3622720386eSBjorn Andersson static int rpm_reg_switch_disable(struct regulator_dev *rdev)
3632720386eSBjorn Andersson {
3642720386eSBjorn Andersson 	struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
3652720386eSBjorn Andersson 	const struct rpm_reg_parts *parts = vreg->parts;
3662720386eSBjorn Andersson 	const struct request_member *req = &parts->enable_state;
3672720386eSBjorn Andersson 	int ret;
3682720386eSBjorn Andersson 
3692720386eSBjorn Andersson 	if (req->mask == 0)
3702720386eSBjorn Andersson 		return -EINVAL;
3712720386eSBjorn Andersson 
3722720386eSBjorn Andersson 	mutex_lock(&vreg->lock);
3732720386eSBjorn Andersson 	ret = rpm_reg_write(vreg, req, 0);
3742720386eSBjorn Andersson 	if (!ret)
3752720386eSBjorn Andersson 		vreg->is_enabled = 0;
3762720386eSBjorn Andersson 	mutex_unlock(&vreg->lock);
3772720386eSBjorn Andersson 
3782720386eSBjorn Andersson 	return ret;
3792720386eSBjorn Andersson }
3802720386eSBjorn Andersson 
rpm_reg_is_enabled(struct regulator_dev * rdev)3812720386eSBjorn Andersson static int rpm_reg_is_enabled(struct regulator_dev *rdev)
3822720386eSBjorn Andersson {
3832720386eSBjorn Andersson 	struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
3842720386eSBjorn Andersson 
3852720386eSBjorn Andersson 	return vreg->is_enabled;
3862720386eSBjorn Andersson }
3872720386eSBjorn Andersson 
rpm_reg_set_load(struct regulator_dev * rdev,int load_uA)3882b85c28aSBjorn Andersson static int rpm_reg_set_load(struct regulator_dev *rdev, int load_uA)
3892b85c28aSBjorn Andersson {
3902b85c28aSBjorn Andersson 	struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
3912b85c28aSBjorn Andersson 	const struct rpm_reg_parts *parts = vreg->parts;
3922b85c28aSBjorn Andersson 	const struct request_member *req = &parts->ia;
3932b85c28aSBjorn Andersson 	int load_mA = load_uA / 1000;
3942b85c28aSBjorn Andersson 	int max_mA = req->mask >> req->shift;
3952b85c28aSBjorn Andersson 	int ret;
3962b85c28aSBjorn Andersson 
3972b85c28aSBjorn Andersson 	if (req->mask == 0)
3982b85c28aSBjorn Andersson 		return -EINVAL;
3992b85c28aSBjorn Andersson 
4002b85c28aSBjorn Andersson 	if (load_mA > max_mA)
4012b85c28aSBjorn Andersson 		load_mA = max_mA;
4022b85c28aSBjorn Andersson 
4032b85c28aSBjorn Andersson 	mutex_lock(&vreg->lock);
4042b85c28aSBjorn Andersson 	ret = rpm_reg_write(vreg, req, load_mA);
4052b85c28aSBjorn Andersson 	mutex_unlock(&vreg->lock);
4062b85c28aSBjorn Andersson 
4072b85c28aSBjorn Andersson 	return ret;
4082b85c28aSBjorn Andersson }
4092b85c28aSBjorn Andersson 
4108d41df64SRikard Falkeborn static const struct regulator_ops uV_ops = {
4112720386eSBjorn Andersson 	.list_voltage = regulator_list_voltage_linear_range,
4122720386eSBjorn Andersson 
4132720386eSBjorn Andersson 	.set_voltage_sel = rpm_reg_set_uV_sel,
4142720386eSBjorn Andersson 	.get_voltage = rpm_reg_get_voltage,
4152720386eSBjorn Andersson 
4162720386eSBjorn Andersson 	.enable = rpm_reg_uV_enable,
4172720386eSBjorn Andersson 	.disable = rpm_reg_uV_disable,
4182720386eSBjorn Andersson 	.is_enabled = rpm_reg_is_enabled,
4192b85c28aSBjorn Andersson 
4202b85c28aSBjorn Andersson 	.set_load = rpm_reg_set_load,
4212720386eSBjorn Andersson };
4222720386eSBjorn Andersson 
4238d41df64SRikard Falkeborn static const struct regulator_ops mV_ops = {
4242720386eSBjorn Andersson 	.list_voltage = regulator_list_voltage_linear_range,
4252720386eSBjorn Andersson 
4262720386eSBjorn Andersson 	.set_voltage_sel = rpm_reg_set_mV_sel,
4272720386eSBjorn Andersson 	.get_voltage = rpm_reg_get_voltage,
4282720386eSBjorn Andersson 
4292720386eSBjorn Andersson 	.enable = rpm_reg_mV_enable,
4302720386eSBjorn Andersson 	.disable = rpm_reg_mV_disable,
4312720386eSBjorn Andersson 	.is_enabled = rpm_reg_is_enabled,
4322b85c28aSBjorn Andersson 
4332b85c28aSBjorn Andersson 	.set_load = rpm_reg_set_load,
4342720386eSBjorn Andersson };
4352720386eSBjorn Andersson 
4368d41df64SRikard Falkeborn static const struct regulator_ops switch_ops = {
4372720386eSBjorn Andersson 	.enable = rpm_reg_switch_enable,
4382720386eSBjorn Andersson 	.disable = rpm_reg_switch_disable,
4392720386eSBjorn Andersson 	.is_enabled = rpm_reg_is_enabled,
4402720386eSBjorn Andersson };
4412720386eSBjorn Andersson 
4422720386eSBjorn Andersson /*
443ddc085d4SNeil Armstrong  * PM8018 regulators
444ddc085d4SNeil Armstrong  */
445ddc085d4SNeil Armstrong static const struct qcom_rpm_reg pm8018_pldo = {
446ddc085d4SNeil Armstrong 	.desc.linear_ranges = pldo_ranges,
447ddc085d4SNeil Armstrong 	.desc.n_linear_ranges = ARRAY_SIZE(pldo_ranges),
448ddc085d4SNeil Armstrong 	.desc.n_voltages = 161,
449ddc085d4SNeil Armstrong 	.desc.ops = &uV_ops,
450ddc085d4SNeil Armstrong 	.parts = &rpm8960_ldo_parts,
451ddc085d4SNeil Armstrong 	.supports_force_mode_auto = false,
452ddc085d4SNeil Armstrong 	.supports_force_mode_bypass = false,
453ddc085d4SNeil Armstrong };
454ddc085d4SNeil Armstrong 
455ddc085d4SNeil Armstrong static const struct qcom_rpm_reg pm8018_nldo = {
456ddc085d4SNeil Armstrong 	.desc.linear_ranges = nldo_ranges,
457ddc085d4SNeil Armstrong 	.desc.n_linear_ranges = ARRAY_SIZE(nldo_ranges),
458ddc085d4SNeil Armstrong 	.desc.n_voltages = 64,
459ddc085d4SNeil Armstrong 	.desc.ops = &uV_ops,
460ddc085d4SNeil Armstrong 	.parts = &rpm8960_ldo_parts,
461ddc085d4SNeil Armstrong 	.supports_force_mode_auto = false,
462ddc085d4SNeil Armstrong 	.supports_force_mode_bypass = false,
463ddc085d4SNeil Armstrong };
464ddc085d4SNeil Armstrong 
465ddc085d4SNeil Armstrong static const struct qcom_rpm_reg pm8018_smps = {
466ddc085d4SNeil Armstrong 	.desc.linear_ranges = smps_ranges,
467ddc085d4SNeil Armstrong 	.desc.n_linear_ranges = ARRAY_SIZE(smps_ranges),
468ddc085d4SNeil Armstrong 	.desc.n_voltages = 154,
469ddc085d4SNeil Armstrong 	.desc.ops = &uV_ops,
470ddc085d4SNeil Armstrong 	.parts = &rpm8960_smps_parts,
471ddc085d4SNeil Armstrong 	.supports_force_mode_auto = false,
472ddc085d4SNeil Armstrong 	.supports_force_mode_bypass = false,
473ddc085d4SNeil Armstrong };
474ddc085d4SNeil Armstrong 
475ddc085d4SNeil Armstrong static const struct qcom_rpm_reg pm8018_switch = {
476ddc085d4SNeil Armstrong 	.desc.ops = &switch_ops,
477ddc085d4SNeil Armstrong 	.parts = &rpm8960_switch_parts,
478ddc085d4SNeil Armstrong };
479ddc085d4SNeil Armstrong 
480ddc085d4SNeil Armstrong /*
4812720386eSBjorn Andersson  * PM8058 regulators
4822720386eSBjorn Andersson  */
4832720386eSBjorn Andersson static const struct qcom_rpm_reg pm8058_pldo = {
4842720386eSBjorn Andersson 	.desc.linear_ranges = pldo_ranges,
4852720386eSBjorn Andersson 	.desc.n_linear_ranges = ARRAY_SIZE(pldo_ranges),
4862720386eSBjorn Andersson 	.desc.n_voltages = 161,
4872720386eSBjorn Andersson 	.desc.ops = &mV_ops,
4882720386eSBjorn Andersson 	.parts = &rpm8660_ldo_parts,
4892720386eSBjorn Andersson 	.supports_force_mode_auto = false,
4902720386eSBjorn Andersson 	.supports_force_mode_bypass = false,
4912720386eSBjorn Andersson };
4922720386eSBjorn Andersson 
4932720386eSBjorn Andersson static const struct qcom_rpm_reg pm8058_nldo = {
4942720386eSBjorn Andersson 	.desc.linear_ranges = nldo_ranges,
4952720386eSBjorn Andersson 	.desc.n_linear_ranges = ARRAY_SIZE(nldo_ranges),
4962720386eSBjorn Andersson 	.desc.n_voltages = 64,
4972720386eSBjorn Andersson 	.desc.ops = &mV_ops,
4982720386eSBjorn Andersson 	.parts = &rpm8660_ldo_parts,
4992720386eSBjorn Andersson 	.supports_force_mode_auto = false,
5002720386eSBjorn Andersson 	.supports_force_mode_bypass = false,
5012720386eSBjorn Andersson };
5022720386eSBjorn Andersson 
5032720386eSBjorn Andersson static const struct qcom_rpm_reg pm8058_smps = {
5042720386eSBjorn Andersson 	.desc.linear_ranges = smps_ranges,
5052720386eSBjorn Andersson 	.desc.n_linear_ranges = ARRAY_SIZE(smps_ranges),
5062720386eSBjorn Andersson 	.desc.n_voltages = 154,
5072720386eSBjorn Andersson 	.desc.ops = &mV_ops,
5082720386eSBjorn Andersson 	.parts = &rpm8660_smps_parts,
5092720386eSBjorn Andersson 	.supports_force_mode_auto = false,
5102720386eSBjorn Andersson 	.supports_force_mode_bypass = false,
5112720386eSBjorn Andersson };
5122720386eSBjorn Andersson 
5132720386eSBjorn Andersson static const struct qcom_rpm_reg pm8058_ncp = {
5142720386eSBjorn Andersson 	.desc.linear_ranges = ncp_ranges,
5152720386eSBjorn Andersson 	.desc.n_linear_ranges = ARRAY_SIZE(ncp_ranges),
5162720386eSBjorn Andersson 	.desc.n_voltages = 32,
5172720386eSBjorn Andersson 	.desc.ops = &mV_ops,
5182720386eSBjorn Andersson 	.parts = &rpm8660_ncp_parts,
5192720386eSBjorn Andersson };
5202720386eSBjorn Andersson 
5212720386eSBjorn Andersson static const struct qcom_rpm_reg pm8058_switch = {
5222720386eSBjorn Andersson 	.desc.ops = &switch_ops,
5232720386eSBjorn Andersson 	.parts = &rpm8660_switch_parts,
5242720386eSBjorn Andersson };
5252720386eSBjorn Andersson 
5262720386eSBjorn Andersson /*
5272720386eSBjorn Andersson  * PM8901 regulators
5282720386eSBjorn Andersson  */
5292720386eSBjorn Andersson static const struct qcom_rpm_reg pm8901_pldo = {
5302720386eSBjorn Andersson 	.desc.linear_ranges = pldo_ranges,
5312720386eSBjorn Andersson 	.desc.n_linear_ranges = ARRAY_SIZE(pldo_ranges),
5322720386eSBjorn Andersson 	.desc.n_voltages = 161,
5332720386eSBjorn Andersson 	.desc.ops = &mV_ops,
5342720386eSBjorn Andersson 	.parts = &rpm8660_ldo_parts,
5352720386eSBjorn Andersson 	.supports_force_mode_auto = false,
5362720386eSBjorn Andersson 	.supports_force_mode_bypass = true,
5372720386eSBjorn Andersson };
5382720386eSBjorn Andersson 
5392720386eSBjorn Andersson static const struct qcom_rpm_reg pm8901_nldo = {
5402720386eSBjorn Andersson 	.desc.linear_ranges = nldo_ranges,
5412720386eSBjorn Andersson 	.desc.n_linear_ranges = ARRAY_SIZE(nldo_ranges),
5422720386eSBjorn Andersson 	.desc.n_voltages = 64,
5432720386eSBjorn Andersson 	.desc.ops = &mV_ops,
5442720386eSBjorn Andersson 	.parts = &rpm8660_ldo_parts,
5452720386eSBjorn Andersson 	.supports_force_mode_auto = false,
5462720386eSBjorn Andersson 	.supports_force_mode_bypass = true,
5472720386eSBjorn Andersson };
5482720386eSBjorn Andersson 
5492720386eSBjorn Andersson static const struct qcom_rpm_reg pm8901_ftsmps = {
5502720386eSBjorn Andersson 	.desc.linear_ranges = ftsmps_ranges,
5512720386eSBjorn Andersson 	.desc.n_linear_ranges = ARRAY_SIZE(ftsmps_ranges),
5522720386eSBjorn Andersson 	.desc.n_voltages = 101,
5532720386eSBjorn Andersson 	.desc.ops = &mV_ops,
5542720386eSBjorn Andersson 	.parts = &rpm8660_smps_parts,
5552720386eSBjorn Andersson 	.supports_force_mode_auto = true,
5562720386eSBjorn Andersson 	.supports_force_mode_bypass = false,
5572720386eSBjorn Andersson };
5582720386eSBjorn Andersson 
5592720386eSBjorn Andersson static const struct qcom_rpm_reg pm8901_switch = {
5602720386eSBjorn Andersson 	.desc.ops = &switch_ops,
5612720386eSBjorn Andersson 	.parts = &rpm8660_switch_parts,
5622720386eSBjorn Andersson };
5632720386eSBjorn Andersson 
5642720386eSBjorn Andersson /*
5652720386eSBjorn Andersson  * PM8921 regulators
5662720386eSBjorn Andersson  */
5672720386eSBjorn Andersson static const struct qcom_rpm_reg pm8921_pldo = {
5682720386eSBjorn Andersson 	.desc.linear_ranges = pldo_ranges,
5692720386eSBjorn Andersson 	.desc.n_linear_ranges = ARRAY_SIZE(pldo_ranges),
5702720386eSBjorn Andersson 	.desc.n_voltages = 161,
5712720386eSBjorn Andersson 	.desc.ops = &uV_ops,
5722720386eSBjorn Andersson 	.parts = &rpm8960_ldo_parts,
5732720386eSBjorn Andersson 	.supports_force_mode_auto = false,
5742720386eSBjorn Andersson 	.supports_force_mode_bypass = true,
5752720386eSBjorn Andersson };
5762720386eSBjorn Andersson 
5772720386eSBjorn Andersson static const struct qcom_rpm_reg pm8921_nldo = {
5782720386eSBjorn Andersson 	.desc.linear_ranges = nldo_ranges,
5792720386eSBjorn Andersson 	.desc.n_linear_ranges = ARRAY_SIZE(nldo_ranges),
5802720386eSBjorn Andersson 	.desc.n_voltages = 64,
5812720386eSBjorn Andersson 	.desc.ops = &uV_ops,
5822720386eSBjorn Andersson 	.parts = &rpm8960_ldo_parts,
5832720386eSBjorn Andersson 	.supports_force_mode_auto = false,
5842720386eSBjorn Andersson 	.supports_force_mode_bypass = true,
5852720386eSBjorn Andersson };
5862720386eSBjorn Andersson 
5872720386eSBjorn Andersson static const struct qcom_rpm_reg pm8921_nldo1200 = {
5882720386eSBjorn Andersson 	.desc.linear_ranges = nldo1200_ranges,
5892720386eSBjorn Andersson 	.desc.n_linear_ranges = ARRAY_SIZE(nldo1200_ranges),
5902720386eSBjorn Andersson 	.desc.n_voltages = 124,
5912720386eSBjorn Andersson 	.desc.ops = &uV_ops,
5922720386eSBjorn Andersson 	.parts = &rpm8960_ldo_parts,
5932720386eSBjorn Andersson 	.supports_force_mode_auto = false,
5942720386eSBjorn Andersson 	.supports_force_mode_bypass = true,
5952720386eSBjorn Andersson };
5962720386eSBjorn Andersson 
5972720386eSBjorn Andersson static const struct qcom_rpm_reg pm8921_smps = {
5982720386eSBjorn Andersson 	.desc.linear_ranges = smps_ranges,
5992720386eSBjorn Andersson 	.desc.n_linear_ranges = ARRAY_SIZE(smps_ranges),
6002720386eSBjorn Andersson 	.desc.n_voltages = 154,
6012720386eSBjorn Andersson 	.desc.ops = &uV_ops,
6022720386eSBjorn Andersson 	.parts = &rpm8960_smps_parts,
6032720386eSBjorn Andersson 	.supports_force_mode_auto = true,
6042720386eSBjorn Andersson 	.supports_force_mode_bypass = false,
6052720386eSBjorn Andersson };
6062720386eSBjorn Andersson 
6072720386eSBjorn Andersson static const struct qcom_rpm_reg pm8921_ncp = {
6082720386eSBjorn Andersson 	.desc.linear_ranges = ncp_ranges,
6092720386eSBjorn Andersson 	.desc.n_linear_ranges = ARRAY_SIZE(ncp_ranges),
6102720386eSBjorn Andersson 	.desc.n_voltages = 32,
6112720386eSBjorn Andersson 	.desc.ops = &uV_ops,
6122720386eSBjorn Andersson 	.parts = &rpm8960_ncp_parts,
6132720386eSBjorn Andersson };
6142720386eSBjorn Andersson 
6152720386eSBjorn Andersson static const struct qcom_rpm_reg pm8921_switch = {
6162720386eSBjorn Andersson 	.desc.ops = &switch_ops,
6172720386eSBjorn Andersson 	.parts = &rpm8960_switch_parts,
6182720386eSBjorn Andersson };
6192720386eSBjorn Andersson 
6200f5bb5b5SJosh Cartwright static const struct qcom_rpm_reg smb208_smps = {
6210f5bb5b5SJosh Cartwright 	.desc.linear_ranges = smb208_ranges,
6220f5bb5b5SJosh Cartwright 	.desc.n_linear_ranges = ARRAY_SIZE(smb208_ranges),
6230f5bb5b5SJosh Cartwright 	.desc.n_voltages = 235,
6240f5bb5b5SJosh Cartwright 	.desc.ops = &uV_ops,
6250f5bb5b5SJosh Cartwright 	.parts = &rpm8960_smps_parts,
6260f5bb5b5SJosh Cartwright 	.supports_force_mode_auto = false,
6270f5bb5b5SJosh Cartwright 	.supports_force_mode_bypass = false,
6280f5bb5b5SJosh Cartwright };
6290f5bb5b5SJosh Cartwright 
rpm_reg_set(struct qcom_rpm_reg * vreg,const struct request_member * req,const int value)6302720386eSBjorn Andersson static int rpm_reg_set(struct qcom_rpm_reg *vreg,
6312720386eSBjorn Andersson 		       const struct request_member *req,
6322720386eSBjorn Andersson 		       const int value)
6332720386eSBjorn Andersson {
6342720386eSBjorn Andersson 	if (req->mask == 0 || (value << req->shift) & ~req->mask)
6352720386eSBjorn Andersson 		return -EINVAL;
6362720386eSBjorn Andersson 
6372720386eSBjorn Andersson 	vreg->val[req->word] &= ~req->mask;
6382720386eSBjorn Andersson 	vreg->val[req->word] |= value << req->shift;
6392720386eSBjorn Andersson 
6402720386eSBjorn Andersson 	return 0;
6412720386eSBjorn Andersson }
6422720386eSBjorn Andersson 
rpm_reg_of_parse_freq(struct device * dev,struct device_node * node,struct qcom_rpm_reg * vreg)643469a9514SBjorn Andersson static int rpm_reg_of_parse_freq(struct device *dev,
644469a9514SBjorn Andersson 				 struct device_node *node,
645469a9514SBjorn Andersson 				 struct qcom_rpm_reg *vreg)
6462720386eSBjorn Andersson {
6472720386eSBjorn Andersson 	static const int freq_table[] = {
6482720386eSBjorn Andersson 		19200000, 9600000, 6400000, 4800000, 3840000, 3200000, 2740000,
6492720386eSBjorn Andersson 		2400000, 2130000, 1920000, 1750000, 1600000, 1480000, 1370000,
6502720386eSBjorn Andersson 		1280000, 1200000,
6512720386eSBjorn Andersson 
6522720386eSBjorn Andersson 	};
6532720386eSBjorn Andersson 	const char *key;
6542720386eSBjorn Andersson 	u32 freq;
6552720386eSBjorn Andersson 	int ret;
6562720386eSBjorn Andersson 	int i;
6572720386eSBjorn Andersson 
6582720386eSBjorn Andersson 	key = "qcom,switch-mode-frequency";
659469a9514SBjorn Andersson 	ret = of_property_read_u32(node, key, &freq);
6602720386eSBjorn Andersson 	if (ret) {
6612720386eSBjorn Andersson 		dev_err(dev, "regulator requires %s property\n", key);
6622720386eSBjorn Andersson 		return -EINVAL;
6632720386eSBjorn Andersson 	}
6642720386eSBjorn Andersson 
6652720386eSBjorn Andersson 	for (i = 0; i < ARRAY_SIZE(freq_table); i++) {
6662720386eSBjorn Andersson 		if (freq == freq_table[i]) {
6672720386eSBjorn Andersson 			rpm_reg_set(vreg, &vreg->parts->freq, i + 1);
6682720386eSBjorn Andersson 			return 0;
6692720386eSBjorn Andersson 		}
6702720386eSBjorn Andersson 	}
6712720386eSBjorn Andersson 
6722720386eSBjorn Andersson 	dev_err(dev, "invalid frequency %d\n", freq);
6732720386eSBjorn Andersson 	return -EINVAL;
6742720386eSBjorn Andersson }
6752720386eSBjorn Andersson 
rpm_reg_of_parse(struct device_node * node,const struct regulator_desc * desc,struct regulator_config * config)676469a9514SBjorn Andersson static int rpm_reg_of_parse(struct device_node *node,
677469a9514SBjorn Andersson 			    const struct regulator_desc *desc,
678469a9514SBjorn Andersson 			    struct regulator_config *config)
679469a9514SBjorn Andersson {
680469a9514SBjorn Andersson 	struct qcom_rpm_reg *vreg = config->driver_data;
681469a9514SBjorn Andersson 	struct device *dev = config->dev;
682469a9514SBjorn Andersson 	const char *key;
683469a9514SBjorn Andersson 	u32 force_mode;
684469a9514SBjorn Andersson 	bool pwm;
685469a9514SBjorn Andersson 	u32 val;
686469a9514SBjorn Andersson 	int ret;
687469a9514SBjorn Andersson 
688469a9514SBjorn Andersson 	key = "bias-pull-down";
689469a9514SBjorn Andersson 	if (of_property_read_bool(node, key)) {
690469a9514SBjorn Andersson 		ret = rpm_reg_set(vreg, &vreg->parts->pd, 1);
691469a9514SBjorn Andersson 		if (ret) {
692469a9514SBjorn Andersson 			dev_err(dev, "%s is invalid", key);
693469a9514SBjorn Andersson 			return ret;
694469a9514SBjorn Andersson 		}
695469a9514SBjorn Andersson 	}
696469a9514SBjorn Andersson 
697469a9514SBjorn Andersson 	if (vreg->parts->freq.mask) {
698469a9514SBjorn Andersson 		ret = rpm_reg_of_parse_freq(dev, node, vreg);
699469a9514SBjorn Andersson 		if (ret < 0)
700469a9514SBjorn Andersson 			return ret;
701469a9514SBjorn Andersson 	}
702469a9514SBjorn Andersson 
703469a9514SBjorn Andersson 	if (vreg->parts->pm.mask) {
704469a9514SBjorn Andersson 		key = "qcom,power-mode-hysteretic";
705469a9514SBjorn Andersson 		pwm = !of_property_read_bool(node, key);
706469a9514SBjorn Andersson 
707469a9514SBjorn Andersson 		ret = rpm_reg_set(vreg, &vreg->parts->pm, pwm);
708469a9514SBjorn Andersson 		if (ret) {
709469a9514SBjorn Andersson 			dev_err(dev, "failed to set power mode\n");
710469a9514SBjorn Andersson 			return ret;
711469a9514SBjorn Andersson 		}
712469a9514SBjorn Andersson 	}
713469a9514SBjorn Andersson 
714469a9514SBjorn Andersson 	if (vreg->parts->fm.mask) {
715469a9514SBjorn Andersson 		force_mode = -1;
716469a9514SBjorn Andersson 
717469a9514SBjorn Andersson 		key = "qcom,force-mode";
718469a9514SBjorn Andersson 		ret = of_property_read_u32(node, key, &val);
719469a9514SBjorn Andersson 		if (ret == -EINVAL) {
720469a9514SBjorn Andersson 			val = QCOM_RPM_FORCE_MODE_NONE;
721469a9514SBjorn Andersson 		} else if (ret < 0) {
722469a9514SBjorn Andersson 			dev_err(dev, "failed to read %s\n", key);
723469a9514SBjorn Andersson 			return ret;
724469a9514SBjorn Andersson 		}
725469a9514SBjorn Andersson 
726469a9514SBjorn Andersson 		/*
727469a9514SBjorn Andersson 		 * If force-mode is encoded as 2 bits then the
728469a9514SBjorn Andersson 		 * possible register values are:
729469a9514SBjorn Andersson 		 * NONE, LPM, HPM
730469a9514SBjorn Andersson 		 * otherwise:
731469a9514SBjorn Andersson 		 * NONE, LPM, AUTO, HPM, BYPASS
732469a9514SBjorn Andersson 		 */
733469a9514SBjorn Andersson 		switch (val) {
734469a9514SBjorn Andersson 		case QCOM_RPM_FORCE_MODE_NONE:
735469a9514SBjorn Andersson 			force_mode = 0;
736469a9514SBjorn Andersson 			break;
737469a9514SBjorn Andersson 		case QCOM_RPM_FORCE_MODE_LPM:
738469a9514SBjorn Andersson 			force_mode = 1;
739469a9514SBjorn Andersson 			break;
740469a9514SBjorn Andersson 		case QCOM_RPM_FORCE_MODE_HPM:
741469a9514SBjorn Andersson 			if (FORCE_MODE_IS_2_BITS(vreg))
742469a9514SBjorn Andersson 				force_mode = 2;
743469a9514SBjorn Andersson 			else
744469a9514SBjorn Andersson 				force_mode = 3;
745469a9514SBjorn Andersson 			break;
746469a9514SBjorn Andersson 		case QCOM_RPM_FORCE_MODE_AUTO:
747469a9514SBjorn Andersson 			if (vreg->supports_force_mode_auto)
748469a9514SBjorn Andersson 				force_mode = 2;
749469a9514SBjorn Andersson 			break;
750469a9514SBjorn Andersson 		case QCOM_RPM_FORCE_MODE_BYPASS:
751469a9514SBjorn Andersson 			if (vreg->supports_force_mode_bypass)
752469a9514SBjorn Andersson 				force_mode = 4;
753469a9514SBjorn Andersson 			break;
754469a9514SBjorn Andersson 		}
755469a9514SBjorn Andersson 
756469a9514SBjorn Andersson 		if (force_mode == -1) {
757469a9514SBjorn Andersson 			dev_err(dev, "invalid force mode\n");
758469a9514SBjorn Andersson 			return -EINVAL;
759469a9514SBjorn Andersson 		}
760469a9514SBjorn Andersson 
761469a9514SBjorn Andersson 		ret = rpm_reg_set(vreg, &vreg->parts->fm, force_mode);
762469a9514SBjorn Andersson 		if (ret) {
763469a9514SBjorn Andersson 			dev_err(dev, "failed to set force mode\n");
764469a9514SBjorn Andersson 			return ret;
765469a9514SBjorn Andersson 		}
766469a9514SBjorn Andersson 	}
767469a9514SBjorn Andersson 
768469a9514SBjorn Andersson 	return 0;
769469a9514SBjorn Andersson }
770469a9514SBjorn Andersson 
771087a1b5cSBjorn Andersson struct rpm_regulator_data {
772087a1b5cSBjorn Andersson 	const char *name;
773087a1b5cSBjorn Andersson 	int resource;
774087a1b5cSBjorn Andersson 	const struct qcom_rpm_reg *template;
775087a1b5cSBjorn Andersson 	const char *supply;
776087a1b5cSBjorn Andersson };
777087a1b5cSBjorn Andersson 
778ddc085d4SNeil Armstrong static const struct rpm_regulator_data rpm_pm8018_regulators[] = {
779ddc085d4SNeil Armstrong 	{ "s1",  QCOM_RPM_PM8018_SMPS1, &pm8018_smps, "vdd_s1" },
780ddc085d4SNeil Armstrong 	{ "s2",  QCOM_RPM_PM8018_SMPS2, &pm8018_smps, "vdd_s2" },
781ddc085d4SNeil Armstrong 	{ "s3",  QCOM_RPM_PM8018_SMPS3, &pm8018_smps, "vdd_s3" },
782ddc085d4SNeil Armstrong 	{ "s4",  QCOM_RPM_PM8018_SMPS4, &pm8018_smps, "vdd_s4" },
783ddc085d4SNeil Armstrong 	{ "s5",  QCOM_RPM_PM8018_SMPS5, &pm8018_smps, "vdd_s5" },
784ddc085d4SNeil Armstrong 
785ddc085d4SNeil Armstrong 	{ "l2",  QCOM_RPM_PM8018_LDO2,  &pm8018_pldo, "vdd_l2" },
786ddc085d4SNeil Armstrong 	{ "l3",  QCOM_RPM_PM8018_LDO3,  &pm8018_pldo, "vdd_l3" },
787ddc085d4SNeil Armstrong 	{ "l4",  QCOM_RPM_PM8018_LDO4,  &pm8018_pldo, "vdd_l4" },
788ddc085d4SNeil Armstrong 	{ "l5",  QCOM_RPM_PM8018_LDO5,  &pm8018_pldo, "vdd_l5" },
789ddc085d4SNeil Armstrong 	{ "l6",  QCOM_RPM_PM8018_LDO6,  &pm8018_pldo, "vdd_l7" },
790ddc085d4SNeil Armstrong 	{ "l7",  QCOM_RPM_PM8018_LDO7,  &pm8018_pldo, "vdd_l7" },
791ddc085d4SNeil Armstrong 	{ "l8",  QCOM_RPM_PM8018_LDO8,  &pm8018_nldo, "vdd_l8" },
792ddc085d4SNeil Armstrong 	{ "l9",  QCOM_RPM_PM8018_LDO9,  &pm8921_nldo1200,
793ddc085d4SNeil Armstrong 						      "vdd_l9_l10_l11_l12" },
794ddc085d4SNeil Armstrong 	{ "l10", QCOM_RPM_PM8018_LDO10, &pm8018_nldo, "vdd_l9_l10_l11_l12" },
795ddc085d4SNeil Armstrong 	{ "l11", QCOM_RPM_PM8018_LDO11, &pm8018_nldo, "vdd_l9_l10_l11_l12" },
796ddc085d4SNeil Armstrong 	{ "l12", QCOM_RPM_PM8018_LDO12, &pm8018_nldo, "vdd_l9_l10_l11_l12" },
797ddc085d4SNeil Armstrong 	{ "l14", QCOM_RPM_PM8018_LDO14, &pm8018_pldo, "vdd_l14" },
798ddc085d4SNeil Armstrong 
799ddc085d4SNeil Armstrong 	{ "lvs1", QCOM_RPM_PM8018_LVS1, &pm8018_switch, "lvs1_in" },
800ddc085d4SNeil Armstrong 
801ddc085d4SNeil Armstrong 	{ }
802ddc085d4SNeil Armstrong };
803ddc085d4SNeil Armstrong 
804087a1b5cSBjorn Andersson static const struct rpm_regulator_data rpm_pm8058_regulators[] = {
8058478ed58SLinus Walleij 	{ "s0",   QCOM_RPM_PM8058_SMPS0,  &pm8058_smps, "vdd_s0" },
8068478ed58SLinus Walleij 	{ "s1",   QCOM_RPM_PM8058_SMPS1,  &pm8058_smps, "vdd_s1" },
8078478ed58SLinus Walleij 	{ "s2",   QCOM_RPM_PM8058_SMPS2,  &pm8058_smps, "vdd_s2" },
8088478ed58SLinus Walleij 	{ "s3",   QCOM_RPM_PM8058_SMPS3,  &pm8058_smps, "vdd_s3" },
8098478ed58SLinus Walleij 	{ "s4",   QCOM_RPM_PM8058_SMPS4,  &pm8058_smps, "vdd_s4" },
8108478ed58SLinus Walleij 
811087a1b5cSBjorn Andersson 	{ "l0",   QCOM_RPM_PM8058_LDO0,   &pm8058_nldo, "vdd_l0_l1_lvs"	},
812087a1b5cSBjorn Andersson 	{ "l1",   QCOM_RPM_PM8058_LDO1,   &pm8058_nldo, "vdd_l0_l1_lvs" },
813087a1b5cSBjorn Andersson 	{ "l2",   QCOM_RPM_PM8058_LDO2,   &pm8058_pldo, "vdd_l2_l11_l12" },
814087a1b5cSBjorn Andersson 	{ "l3",   QCOM_RPM_PM8058_LDO3,   &pm8058_pldo, "vdd_l3_l4_l5" },
815087a1b5cSBjorn Andersson 	{ "l4",   QCOM_RPM_PM8058_LDO4,   &pm8058_pldo, "vdd_l3_l4_l5" },
816087a1b5cSBjorn Andersson 	{ "l5",   QCOM_RPM_PM8058_LDO5,   &pm8058_pldo, "vdd_l3_l4_l5" },
817087a1b5cSBjorn Andersson 	{ "l6",   QCOM_RPM_PM8058_LDO6,   &pm8058_pldo, "vdd_l6_l7" },
818087a1b5cSBjorn Andersson 	{ "l7",   QCOM_RPM_PM8058_LDO7,   &pm8058_pldo, "vdd_l6_l7" },
819087a1b5cSBjorn Andersson 	{ "l8",   QCOM_RPM_PM8058_LDO8,   &pm8058_pldo, "vdd_l8" },
820087a1b5cSBjorn Andersson 	{ "l9",   QCOM_RPM_PM8058_LDO9,   &pm8058_pldo, "vdd_l9" },
821087a1b5cSBjorn Andersson 	{ "l10",  QCOM_RPM_PM8058_LDO10,  &pm8058_pldo, "vdd_l10" },
822087a1b5cSBjorn Andersson 	{ "l11",  QCOM_RPM_PM8058_LDO11,  &pm8058_pldo, "vdd_l2_l11_l12" },
823087a1b5cSBjorn Andersson 	{ "l12",  QCOM_RPM_PM8058_LDO12,  &pm8058_pldo, "vdd_l2_l11_l12" },
824087a1b5cSBjorn Andersson 	{ "l13",  QCOM_RPM_PM8058_LDO13,  &pm8058_pldo, "vdd_l13_l16" },
825087a1b5cSBjorn Andersson 	{ "l14",  QCOM_RPM_PM8058_LDO14,  &pm8058_pldo, "vdd_l14_l15" },
826087a1b5cSBjorn Andersson 	{ "l15",  QCOM_RPM_PM8058_LDO15,  &pm8058_pldo, "vdd_l14_l15" },
827087a1b5cSBjorn Andersson 	{ "l16",  QCOM_RPM_PM8058_LDO16,  &pm8058_pldo, "vdd_l13_l16" },
828087a1b5cSBjorn Andersson 	{ "l17",  QCOM_RPM_PM8058_LDO17,  &pm8058_pldo, "vdd_l17_l18" },
829087a1b5cSBjorn Andersson 	{ "l18",  QCOM_RPM_PM8058_LDO18,  &pm8058_pldo, "vdd_l17_l18" },
830087a1b5cSBjorn Andersson 	{ "l19",  QCOM_RPM_PM8058_LDO19,  &pm8058_pldo, "vdd_l19_l20" },
831087a1b5cSBjorn Andersson 	{ "l20",  QCOM_RPM_PM8058_LDO20,  &pm8058_pldo, "vdd_l19_l20" },
832087a1b5cSBjorn Andersson 	{ "l21",  QCOM_RPM_PM8058_LDO21,  &pm8058_nldo, "vdd_l21" },
833087a1b5cSBjorn Andersson 	{ "l22",  QCOM_RPM_PM8058_LDO22,  &pm8058_nldo, "vdd_l22" },
834087a1b5cSBjorn Andersson 	{ "l23",  QCOM_RPM_PM8058_LDO23,  &pm8058_nldo, "vdd_l23_l24_l25" },
835087a1b5cSBjorn Andersson 	{ "l24",  QCOM_RPM_PM8058_LDO24,  &pm8058_nldo, "vdd_l23_l24_l25" },
836087a1b5cSBjorn Andersson 	{ "l25",  QCOM_RPM_PM8058_LDO25,  &pm8058_nldo, "vdd_l23_l24_l25" },
837087a1b5cSBjorn Andersson 
838087a1b5cSBjorn Andersson 	{ "lvs0", QCOM_RPM_PM8058_LVS0, &pm8058_switch, "vdd_l0_l1_lvs" },
839087a1b5cSBjorn Andersson 	{ "lvs1", QCOM_RPM_PM8058_LVS1, &pm8058_switch, "vdd_l0_l1_lvs" },
840087a1b5cSBjorn Andersson 
841087a1b5cSBjorn Andersson 	{ "ncp",  QCOM_RPM_PM8058_NCP, &pm8058_ncp, "vdd_ncp" },
842087a1b5cSBjorn Andersson 	{ }
843087a1b5cSBjorn Andersson };
844087a1b5cSBjorn Andersson 
845087a1b5cSBjorn Andersson static const struct rpm_regulator_data rpm_pm8901_regulators[] = {
8468478ed58SLinus Walleij 	{ "s0",   QCOM_RPM_PM8901_SMPS0, &pm8901_ftsmps, "vdd_s0" },
8478478ed58SLinus Walleij 	{ "s1",   QCOM_RPM_PM8901_SMPS1, &pm8901_ftsmps, "vdd_s1" },
8488478ed58SLinus Walleij 	{ "s2",   QCOM_RPM_PM8901_SMPS2, &pm8901_ftsmps, "vdd_s2" },
8498478ed58SLinus Walleij 	{ "s3",   QCOM_RPM_PM8901_SMPS3, &pm8901_ftsmps, "vdd_s3" },
8508478ed58SLinus Walleij 	{ "s4",   QCOM_RPM_PM8901_SMPS4, &pm8901_ftsmps, "vdd_s4" },
8518478ed58SLinus Walleij 
852087a1b5cSBjorn Andersson 	{ "l0",   QCOM_RPM_PM8901_LDO0, &pm8901_nldo, "vdd_l0" },
853087a1b5cSBjorn Andersson 	{ "l1",   QCOM_RPM_PM8901_LDO1, &pm8901_pldo, "vdd_l1" },
854087a1b5cSBjorn Andersson 	{ "l2",   QCOM_RPM_PM8901_LDO2, &pm8901_pldo, "vdd_l2" },
855087a1b5cSBjorn Andersson 	{ "l3",   QCOM_RPM_PM8901_LDO3, &pm8901_pldo, "vdd_l3" },
856087a1b5cSBjorn Andersson 	{ "l4",   QCOM_RPM_PM8901_LDO4, &pm8901_pldo, "vdd_l4" },
857087a1b5cSBjorn Andersson 	{ "l5",   QCOM_RPM_PM8901_LDO5, &pm8901_pldo, "vdd_l5" },
858087a1b5cSBjorn Andersson 	{ "l6",   QCOM_RPM_PM8901_LDO6, &pm8901_pldo, "vdd_l6" },
859087a1b5cSBjorn Andersson 
860087a1b5cSBjorn Andersson 	{ "lvs0", QCOM_RPM_PM8901_LVS0, &pm8901_switch, "lvs0_in" },
861087a1b5cSBjorn Andersson 	{ "lvs1", QCOM_RPM_PM8901_LVS1, &pm8901_switch, "lvs1_in" },
862087a1b5cSBjorn Andersson 	{ "lvs2", QCOM_RPM_PM8901_LVS2, &pm8901_switch, "lvs2_in" },
863087a1b5cSBjorn Andersson 	{ "lvs3", QCOM_RPM_PM8901_LVS3, &pm8901_switch, "lvs3_in" },
864087a1b5cSBjorn Andersson 
865087a1b5cSBjorn Andersson 	{ "mvs", QCOM_RPM_PM8901_MVS, &pm8901_switch, "mvs_in" },
866087a1b5cSBjorn Andersson 	{ }
867087a1b5cSBjorn Andersson };
868087a1b5cSBjorn Andersson 
869087a1b5cSBjorn Andersson static const struct rpm_regulator_data rpm_pm8921_regulators[] = {
870087a1b5cSBjorn Andersson 	{ "s1",  QCOM_RPM_PM8921_SMPS1, &pm8921_smps, "vdd_s1" },
871087a1b5cSBjorn Andersson 	{ "s2",  QCOM_RPM_PM8921_SMPS2, &pm8921_smps, "vdd_s2" },
872087a1b5cSBjorn Andersson 	{ "s3",  QCOM_RPM_PM8921_SMPS3, &pm8921_smps },
873087a1b5cSBjorn Andersson 	{ "s4",  QCOM_RPM_PM8921_SMPS4, &pm8921_smps, "vdd_s4" },
874087a1b5cSBjorn Andersson 	{ "s7",  QCOM_RPM_PM8921_SMPS7, &pm8921_smps, "vdd_s7" },
875087a1b5cSBjorn Andersson 	{ "s8",  QCOM_RPM_PM8921_SMPS8, &pm8921_smps, "vdd_s8"  },
876087a1b5cSBjorn Andersson 
877087a1b5cSBjorn Andersson 	{ "l1",  QCOM_RPM_PM8921_LDO1, &pm8921_nldo, "vdd_l1_l2_l12_l18" },
878087a1b5cSBjorn Andersson 	{ "l2",  QCOM_RPM_PM8921_LDO2, &pm8921_nldo, "vdd_l1_l2_l12_l18" },
879087a1b5cSBjorn Andersson 	{ "l3",  QCOM_RPM_PM8921_LDO3, &pm8921_pldo, "vdd_l3_l15_l17" },
880087a1b5cSBjorn Andersson 	{ "l4",  QCOM_RPM_PM8921_LDO4, &pm8921_pldo, "vdd_l4_l14" },
881087a1b5cSBjorn Andersson 	{ "l5",  QCOM_RPM_PM8921_LDO5, &pm8921_pldo, "vdd_l5_l8_l16" },
882087a1b5cSBjorn Andersson 	{ "l6",  QCOM_RPM_PM8921_LDO6, &pm8921_pldo, "vdd_l6_l7" },
883087a1b5cSBjorn Andersson 	{ "l7",  QCOM_RPM_PM8921_LDO7, &pm8921_pldo, "vdd_l6_l7" },
884087a1b5cSBjorn Andersson 	{ "l8",  QCOM_RPM_PM8921_LDO8, &pm8921_pldo, "vdd_l5_l8_l16" },
885087a1b5cSBjorn Andersson 	{ "l9",  QCOM_RPM_PM8921_LDO9, &pm8921_pldo, "vdd_l9_l11" },
886087a1b5cSBjorn Andersson 	{ "l10", QCOM_RPM_PM8921_LDO10, &pm8921_pldo, "vdd_l10_l22" },
887087a1b5cSBjorn Andersson 	{ "l11", QCOM_RPM_PM8921_LDO11, &pm8921_pldo, "vdd_l9_l11" },
888087a1b5cSBjorn Andersson 	{ "l12", QCOM_RPM_PM8921_LDO12, &pm8921_nldo, "vdd_l1_l2_l12_l18" },
889087a1b5cSBjorn Andersson 	{ "l14", QCOM_RPM_PM8921_LDO14, &pm8921_pldo, "vdd_l4_l14" },
890087a1b5cSBjorn Andersson 	{ "l15", QCOM_RPM_PM8921_LDO15, &pm8921_pldo, "vdd_l3_l15_l17" },
891087a1b5cSBjorn Andersson 	{ "l16", QCOM_RPM_PM8921_LDO16, &pm8921_pldo, "vdd_l5_l8_l16" },
892087a1b5cSBjorn Andersson 	{ "l17", QCOM_RPM_PM8921_LDO17, &pm8921_pldo, "vdd_l3_l15_l17" },
893087a1b5cSBjorn Andersson 	{ "l18", QCOM_RPM_PM8921_LDO18, &pm8921_nldo, "vdd_l1_l2_l12_l18" },
894087a1b5cSBjorn Andersson 	{ "l21", QCOM_RPM_PM8921_LDO21, &pm8921_pldo, "vdd_l21_l23_l29" },
895087a1b5cSBjorn Andersson 	{ "l22", QCOM_RPM_PM8921_LDO22, &pm8921_pldo, "vdd_l10_l22" },
896087a1b5cSBjorn Andersson 	{ "l23", QCOM_RPM_PM8921_LDO23, &pm8921_pldo, "vdd_l21_l23_l29" },
897087a1b5cSBjorn Andersson 	{ "l24", QCOM_RPM_PM8921_LDO24, &pm8921_nldo1200, "vdd_l24" },
898087a1b5cSBjorn Andersson 	{ "l25", QCOM_RPM_PM8921_LDO25, &pm8921_nldo1200, "vdd_l25" },
899087a1b5cSBjorn Andersson 	{ "l26", QCOM_RPM_PM8921_LDO26, &pm8921_nldo1200, "vdd_l26" },
900087a1b5cSBjorn Andersson 	{ "l27", QCOM_RPM_PM8921_LDO27, &pm8921_nldo1200, "vdd_l27" },
901087a1b5cSBjorn Andersson 	{ "l28", QCOM_RPM_PM8921_LDO28, &pm8921_nldo1200, "vdd_l28" },
902087a1b5cSBjorn Andersson 	{ "l29", QCOM_RPM_PM8921_LDO29, &pm8921_pldo, "vdd_l21_l23_l29" },
903087a1b5cSBjorn Andersson 
904087a1b5cSBjorn Andersson 	{ "lvs1", QCOM_RPM_PM8921_LVS1, &pm8921_switch, "vin_lvs1_3_6" },
905087a1b5cSBjorn Andersson 	{ "lvs2", QCOM_RPM_PM8921_LVS2, &pm8921_switch, "vin_lvs2" },
906087a1b5cSBjorn Andersson 	{ "lvs3", QCOM_RPM_PM8921_LVS3, &pm8921_switch, "vin_lvs1_3_6" },
907087a1b5cSBjorn Andersson 	{ "lvs4", QCOM_RPM_PM8921_LVS4, &pm8921_switch, "vin_lvs4_5_7" },
908087a1b5cSBjorn Andersson 	{ "lvs5", QCOM_RPM_PM8921_LVS5, &pm8921_switch, "vin_lvs4_5_7" },
909087a1b5cSBjorn Andersson 	{ "lvs6", QCOM_RPM_PM8921_LVS6, &pm8921_switch, "vin_lvs1_3_6" },
910087a1b5cSBjorn Andersson 	{ "lvs7", QCOM_RPM_PM8921_LVS7, &pm8921_switch, "vin_lvs4_5_7" },
911087a1b5cSBjorn Andersson 
912087a1b5cSBjorn Andersson 	{ "usb-switch", QCOM_RPM_USB_OTG_SWITCH, &pm8921_switch, "vin_5vs" },
913087a1b5cSBjorn Andersson 	{ "hdmi-switch", QCOM_RPM_HDMI_SWITCH, &pm8921_switch, "vin_5vs" },
914087a1b5cSBjorn Andersson 	{ "ncp", QCOM_RPM_PM8921_NCP, &pm8921_ncp, "vdd_ncp" },
915087a1b5cSBjorn Andersson 	{ }
916087a1b5cSBjorn Andersson };
917087a1b5cSBjorn Andersson 
918b5f25304SAnsuel Smith static const struct rpm_regulator_data rpm_smb208_regulators[] = {
919b5f25304SAnsuel Smith 	{ "s1a",  QCOM_RPM_SMB208_S1a, &smb208_smps, "vin_s1a" },
920b5f25304SAnsuel Smith 	{ "s1b",  QCOM_RPM_SMB208_S1b, &smb208_smps, "vin_s1b" },
921b5f25304SAnsuel Smith 	{ "s2a",  QCOM_RPM_SMB208_S2a, &smb208_smps, "vin_s2a" },
922b5f25304SAnsuel Smith 	{ "s2b",  QCOM_RPM_SMB208_S2b, &smb208_smps, "vin_s2b" },
923b5f25304SAnsuel Smith 	{ }
924b5f25304SAnsuel Smith };
925b5f25304SAnsuel Smith 
926087a1b5cSBjorn Andersson static const struct of_device_id rpm_of_match[] = {
927ddc085d4SNeil Armstrong 	{ .compatible = "qcom,rpm-pm8018-regulators",
928ddc085d4SNeil Armstrong 		.data = &rpm_pm8018_regulators },
929087a1b5cSBjorn Andersson 	{ .compatible = "qcom,rpm-pm8058-regulators", .data = &rpm_pm8058_regulators },
930087a1b5cSBjorn Andersson 	{ .compatible = "qcom,rpm-pm8901-regulators", .data = &rpm_pm8901_regulators },
931087a1b5cSBjorn Andersson 	{ .compatible = "qcom,rpm-pm8921-regulators", .data = &rpm_pm8921_regulators },
932b5f25304SAnsuel Smith 	{ .compatible = "qcom,rpm-smb208-regulators", .data = &rpm_smb208_regulators },
933087a1b5cSBjorn Andersson 	{ }
934087a1b5cSBjorn Andersson };
935087a1b5cSBjorn Andersson MODULE_DEVICE_TABLE(of, rpm_of_match);
936087a1b5cSBjorn Andersson 
rpm_reg_probe(struct platform_device * pdev)9372720386eSBjorn Andersson static int rpm_reg_probe(struct platform_device *pdev)
9382720386eSBjorn Andersson {
939087a1b5cSBjorn Andersson 	const struct rpm_regulator_data *reg;
9402720386eSBjorn Andersson 	const struct of_device_id *match;
941aad615c6SAxel Lin 	struct regulator_config config = { };
9422720386eSBjorn Andersson 	struct regulator_dev *rdev;
9432720386eSBjorn Andersson 	struct qcom_rpm_reg *vreg;
944ce8ae17cSBjorn Andersson 	struct qcom_rpm *rpm;
945ce8ae17cSBjorn Andersson 
946ce8ae17cSBjorn Andersson 	rpm = dev_get_drvdata(pdev->dev.parent);
947ce8ae17cSBjorn Andersson 	if (!rpm) {
948ce8ae17cSBjorn Andersson 		dev_err(&pdev->dev, "unable to retrieve handle to rpm\n");
949ce8ae17cSBjorn Andersson 		return -ENODEV;
950ce8ae17cSBjorn Andersson 	}
9512720386eSBjorn Andersson 
9522720386eSBjorn Andersson 	match = of_match_device(rpm_of_match, &pdev->dev);
9532f2472baSGustavo A. R. Silva 	if (!match) {
9542f2472baSGustavo A. R. Silva 		dev_err(&pdev->dev, "failed to match device\n");
9552f2472baSGustavo A. R. Silva 		return -ENODEV;
9562f2472baSGustavo A. R. Silva 	}
9572f2472baSGustavo A. R. Silva 
958087a1b5cSBjorn Andersson 	for (reg = match->data; reg->name; reg++) {
959*55975401SLi Zetao 		vreg = devm_kmemdup(&pdev->dev, reg->template, sizeof(*vreg), GFP_KERNEL);
960ce8ae17cSBjorn Andersson 		if (!vreg)
9612720386eSBjorn Andersson 			return -ENOMEM;
962ce8ae17cSBjorn Andersson 
9632720386eSBjorn Andersson 		mutex_init(&vreg->lock);
964087a1b5cSBjorn Andersson 
9652720386eSBjorn Andersson 		vreg->dev = &pdev->dev;
966087a1b5cSBjorn Andersson 		vreg->resource = reg->resource;
967ce8ae17cSBjorn Andersson 		vreg->rpm = rpm;
968087a1b5cSBjorn Andersson 
9692720386eSBjorn Andersson 		vreg->desc.id = -1;
9702720386eSBjorn Andersson 		vreg->desc.owner = THIS_MODULE;
9712720386eSBjorn Andersson 		vreg->desc.type = REGULATOR_VOLTAGE;
972087a1b5cSBjorn Andersson 		vreg->desc.name = reg->name;
973087a1b5cSBjorn Andersson 		vreg->desc.supply_name = reg->supply;
974087a1b5cSBjorn Andersson 		vreg->desc.of_match = reg->name;
975087a1b5cSBjorn Andersson 		vreg->desc.of_parse_cb = rpm_reg_of_parse;
9762720386eSBjorn Andersson 
9772720386eSBjorn Andersson 		config.dev = &pdev->dev;
9782720386eSBjorn Andersson 		config.driver_data = vreg;
9792720386eSBjorn Andersson 		rdev = devm_regulator_register(&pdev->dev, &vreg->desc, &config);
9802720386eSBjorn Andersson 		if (IS_ERR(rdev)) {
981ce8ae17cSBjorn Andersson 			dev_err(&pdev->dev, "failed to register %s\n", reg->name);
9822720386eSBjorn Andersson 			return PTR_ERR(rdev);
9832720386eSBjorn Andersson 		}
984087a1b5cSBjorn Andersson 	}
9852720386eSBjorn Andersson 
9862720386eSBjorn Andersson 	return 0;
9872720386eSBjorn Andersson }
9882720386eSBjorn Andersson 
9892720386eSBjorn Andersson static struct platform_driver rpm_reg_driver = {
9902720386eSBjorn Andersson 	.probe          = rpm_reg_probe,
9912720386eSBjorn Andersson 	.driver  = {
9922720386eSBjorn Andersson 		.name  = "qcom_rpm_reg",
993259b93b2SDouglas Anderson 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
9942720386eSBjorn Andersson 		.of_match_table = of_match_ptr(rpm_of_match),
9952720386eSBjorn Andersson 	},
9962720386eSBjorn Andersson };
9972720386eSBjorn Andersson 
rpm_reg_init(void)9982720386eSBjorn Andersson static int __init rpm_reg_init(void)
9992720386eSBjorn Andersson {
10002720386eSBjorn Andersson 	return platform_driver_register(&rpm_reg_driver);
10012720386eSBjorn Andersson }
10022720386eSBjorn Andersson subsys_initcall(rpm_reg_init);
10032720386eSBjorn Andersson 
rpm_reg_exit(void)10042720386eSBjorn Andersson static void __exit rpm_reg_exit(void)
10052720386eSBjorn Andersson {
10062720386eSBjorn Andersson 	platform_driver_unregister(&rpm_reg_driver);
10072720386eSBjorn Andersson }
10082720386eSBjorn Andersson module_exit(rpm_reg_exit)
10092720386eSBjorn Andersson 
10102720386eSBjorn Andersson MODULE_DESCRIPTION("Qualcomm RPM regulator driver");
10112720386eSBjorn Andersson MODULE_LICENSE("GPL v2");
1012