| Yong Shen | 5e428d5 | 2010-12-14 14:00:55 +0800 | [diff] [blame] | 1 | /* | 
 | 2 |  * Regulator Driver for Freescale MC13892 PMIC | 
 | 3 |  * | 
 | 4 |  * Copyright 2010 Yong Shen <yong.shen@linaro.org> | 
 | 5 |  * | 
 | 6 |  * Based on draft driver from Arnaud Patard <arnaud.patard@rtp-net.org> | 
 | 7 |  * | 
 | 8 |  * This program is free software; you can redistribute it and/or modify | 
 | 9 |  * it under the terms of the GNU General Public License version 2 as | 
 | 10 |  * published by the Free Software Foundation. | 
 | 11 |  */ | 
 | 12 |  | 
 | 13 | #include <linux/mfd/mc13892.h> | 
 | 14 | #include <linux/regulator/machine.h> | 
 | 15 | #include <linux/regulator/driver.h> | 
 | 16 | #include <linux/platform_device.h> | 
 | 17 | #include <linux/kernel.h> | 
 | 18 | #include <linux/slab.h> | 
 | 19 | #include <linux/init.h> | 
 | 20 | #include <linux/err.h> | 
 | 21 | #include "mc13xxx.h" | 
 | 22 |  | 
 | 23 | #define MC13892_REVISION			7 | 
 | 24 |  | 
 | 25 | #define MC13892_POWERCTL0			13 | 
 | 26 | #define MC13892_POWERCTL0_USEROFFSPI		3 | 
 | 27 | #define MC13892_POWERCTL0_VCOINCELLVSEL		20 | 
 | 28 | #define MC13892_POWERCTL0_VCOINCELLVSEL_M	(7<<20) | 
 | 29 | #define MC13892_POWERCTL0_VCOINCELLEN		(1<<23) | 
 | 30 |  | 
 | 31 | #define MC13892_SWITCHERS0_SWxHI		(1<<23) | 
 | 32 |  | 
 | 33 | #define MC13892_SWITCHERS0			24 | 
 | 34 | #define MC13892_SWITCHERS0_SW1VSEL		0 | 
 | 35 | #define MC13892_SWITCHERS0_SW1VSEL_M		(0x1f<<0) | 
 | 36 | #define MC13892_SWITCHERS0_SW1HI		(1<<23) | 
 | 37 | #define MC13892_SWITCHERS0_SW1EN		0 | 
 | 38 |  | 
 | 39 | #define MC13892_SWITCHERS1			25 | 
 | 40 | #define MC13892_SWITCHERS1_SW2VSEL		0 | 
 | 41 | #define MC13892_SWITCHERS1_SW2VSEL_M		(0x1f<<0) | 
 | 42 | #define MC13892_SWITCHERS1_SW2HI		(1<<23) | 
 | 43 | #define MC13892_SWITCHERS1_SW2EN		0 | 
 | 44 |  | 
 | 45 | #define MC13892_SWITCHERS2			26 | 
 | 46 | #define MC13892_SWITCHERS2_SW3VSEL		0 | 
 | 47 | #define MC13892_SWITCHERS2_SW3VSEL_M		(0x1f<<0) | 
 | 48 | #define MC13892_SWITCHERS2_SW3HI		(1<<23) | 
 | 49 | #define MC13892_SWITCHERS2_SW3EN		0 | 
 | 50 |  | 
 | 51 | #define MC13892_SWITCHERS3			27 | 
 | 52 | #define MC13892_SWITCHERS3_SW4VSEL		0 | 
 | 53 | #define MC13892_SWITCHERS3_SW4VSEL_M		(0x1f<<0) | 
 | 54 | #define MC13892_SWITCHERS3_SW4HI		(1<<23) | 
 | 55 | #define MC13892_SWITCHERS3_SW4EN		0 | 
 | 56 |  | 
 | 57 | #define MC13892_SWITCHERS4			28 | 
 | 58 | #define MC13892_SWITCHERS4_SW1MODE		0 | 
 | 59 | #define MC13892_SWITCHERS4_SW1MODE_AUTO		(8<<0) | 
 | 60 | #define MC13892_SWITCHERS4_SW1MODE_M		(0xf<<0) | 
 | 61 | #define MC13892_SWITCHERS4_SW2MODE		10 | 
 | 62 | #define MC13892_SWITCHERS4_SW2MODE_AUTO		(8<<10) | 
 | 63 | #define MC13892_SWITCHERS4_SW2MODE_M		(0xf<<10) | 
 | 64 |  | 
 | 65 | #define MC13892_SWITCHERS5			29 | 
 | 66 | #define MC13892_SWITCHERS5_SW3MODE		0 | 
 | 67 | #define MC13892_SWITCHERS5_SW3MODE_AUTO		(8<<0) | 
 | 68 | #define MC13892_SWITCHERS5_SW3MODE_M		(0xf<<0) | 
 | 69 | #define MC13892_SWITCHERS5_SW4MODE		8 | 
 | 70 | #define MC13892_SWITCHERS5_SW4MODE_AUTO		(8<<8) | 
 | 71 | #define MC13892_SWITCHERS5_SW4MODE_M		(0xf<<8) | 
 | 72 | #define MC13892_SWITCHERS5_SWBSTEN		(1<<20) | 
 | 73 |  | 
 | 74 | #define MC13892_REGULATORSETTING0		30 | 
 | 75 | #define MC13892_REGULATORSETTING0_VGEN1VSEL	0 | 
 | 76 | #define MC13892_REGULATORSETTING0_VDIGVSEL	4 | 
 | 77 | #define MC13892_REGULATORSETTING0_VGEN2VSEL	6 | 
 | 78 | #define MC13892_REGULATORSETTING0_VPLLVSEL	9 | 
 | 79 | #define MC13892_REGULATORSETTING0_VUSB2VSEL	11 | 
 | 80 | #define MC13892_REGULATORSETTING0_VGEN3VSEL	14 | 
 | 81 | #define MC13892_REGULATORSETTING0_VCAMVSEL	16 | 
 | 82 |  | 
 | 83 | #define MC13892_REGULATORSETTING0_VGEN1VSEL_M	(3<<0) | 
 | 84 | #define MC13892_REGULATORSETTING0_VDIGVSEL_M	(3<<4) | 
 | 85 | #define MC13892_REGULATORSETTING0_VGEN2VSEL_M	(7<<6) | 
 | 86 | #define MC13892_REGULATORSETTING0_VPLLVSEL_M	(3<<9) | 
 | 87 | #define MC13892_REGULATORSETTING0_VUSB2VSEL_M	(3<<11) | 
 | 88 | #define MC13892_REGULATORSETTING0_VGEN3VSEL_M	(1<<14) | 
 | 89 | #define MC13892_REGULATORSETTING0_VCAMVSEL_M	(3<<16) | 
 | 90 |  | 
 | 91 | #define MC13892_REGULATORSETTING1		31 | 
 | 92 | #define MC13892_REGULATORSETTING1_VVIDEOVSEL	2 | 
 | 93 | #define MC13892_REGULATORSETTING1_VAUDIOVSEL	4 | 
 | 94 | #define MC13892_REGULATORSETTING1_VSDVSEL	6 | 
 | 95 |  | 
 | 96 | #define MC13892_REGULATORSETTING1_VVIDEOVSEL_M	(3<<2) | 
 | 97 | #define MC13892_REGULATORSETTING1_VAUDIOVSEL_M	(3<<4) | 
 | 98 | #define MC13892_REGULATORSETTING1_VSDVSEL_M	(7<<6) | 
 | 99 |  | 
 | 100 | #define MC13892_REGULATORMODE0			32 | 
 | 101 | #define MC13892_REGULATORMODE0_VGEN1EN		(1<<0) | 
 | 102 | #define MC13892_REGULATORMODE0_VGEN1STDBY	(1<<1) | 
 | 103 | #define MC13892_REGULATORMODE0_VGEN1MODE	(1<<2) | 
 | 104 | #define MC13892_REGULATORMODE0_VIOHIEN		(1<<3) | 
 | 105 | #define MC13892_REGULATORMODE0_VIOHISTDBY	(1<<4) | 
 | 106 | #define MC13892_REGULATORMODE0_VIOHIMODE	(1<<5) | 
 | 107 | #define MC13892_REGULATORMODE0_VDIGEN		(1<<9) | 
 | 108 | #define MC13892_REGULATORMODE0_VDIGSTDBY	(1<<10) | 
 | 109 | #define MC13892_REGULATORMODE0_VDIGMODE		(1<<11) | 
 | 110 | #define MC13892_REGULATORMODE0_VGEN2EN		(1<<12) | 
 | 111 | #define MC13892_REGULATORMODE0_VGEN2STDBY	(1<<13) | 
 | 112 | #define MC13892_REGULATORMODE0_VGEN2MODE	(1<<14) | 
 | 113 | #define MC13892_REGULATORMODE0_VPLLEN		(1<<15) | 
 | 114 | #define MC13892_REGULATORMODE0_VPLLSTDBY	(1<<16) | 
 | 115 | #define MC13892_REGULATORMODE0_VPLLMODE		(1<<17) | 
 | 116 | #define MC13892_REGULATORMODE0_VUSB2EN		(1<<18) | 
 | 117 | #define MC13892_REGULATORMODE0_VUSB2STDBY	(1<<19) | 
 | 118 | #define MC13892_REGULATORMODE0_VUSB2MODE	(1<<20) | 
 | 119 |  | 
 | 120 | #define MC13892_REGULATORMODE1			33 | 
 | 121 | #define MC13892_REGULATORMODE1_VGEN3EN		(1<<0) | 
 | 122 | #define MC13892_REGULATORMODE1_VGEN3STDBY	(1<<1) | 
 | 123 | #define MC13892_REGULATORMODE1_VGEN3MODE	(1<<2) | 
 | 124 | #define MC13892_REGULATORMODE1_VCAMEN		(1<<6) | 
 | 125 | #define MC13892_REGULATORMODE1_VCAMSTDBY	(1<<7) | 
 | 126 | #define MC13892_REGULATORMODE1_VCAMMODE		(1<<8) | 
 | 127 | #define MC13892_REGULATORMODE1_VCAMCONFIGEN	(1<<9) | 
 | 128 | #define MC13892_REGULATORMODE1_VVIDEOEN		(1<<12) | 
 | 129 | #define MC13892_REGULATORMODE1_VVIDEOSTDBY	(1<<13) | 
 | 130 | #define MC13892_REGULATORMODE1_VVIDEOMODE	(1<<14) | 
 | 131 | #define MC13892_REGULATORMODE1_VAUDIOEN		(1<<15) | 
 | 132 | #define MC13892_REGULATORMODE1_VAUDIOSTDBY	(1<<16) | 
 | 133 | #define MC13892_REGULATORMODE1_VAUDIOMODE	(1<<17) | 
 | 134 | #define MC13892_REGULATORMODE1_VSDEN		(1<<18) | 
 | 135 | #define MC13892_REGULATORMODE1_VSDSTDBY		(1<<19) | 
 | 136 | #define MC13892_REGULATORMODE1_VSDMODE		(1<<20) | 
 | 137 |  | 
 | 138 | #define MC13892_POWERMISC			34 | 
 | 139 | #define MC13892_POWERMISC_GPO1EN		(1<<6) | 
 | 140 | #define MC13892_POWERMISC_GPO2EN		(1<<8) | 
 | 141 | #define MC13892_POWERMISC_GPO3EN		(1<<10) | 
 | 142 | #define MC13892_POWERMISC_GPO4EN		(1<<12) | 
 | 143 | #define MC13892_POWERMISC_PWGT1SPIEN		(1<<15) | 
 | 144 | #define MC13892_POWERMISC_PWGT2SPIEN		(1<<16) | 
 | 145 | #define MC13892_POWERMISC_GPO4ADINEN		(1<<21) | 
 | 146 |  | 
 | 147 | #define MC13892_POWERMISC_PWGTSPI_M		(3 << 15) | 
 | 148 |  | 
 | 149 | #define MC13892_USB1				50 | 
 | 150 | #define MC13892_USB1_VUSBEN			(1<<3) | 
 | 151 |  | 
 | 152 | static const int mc13892_vcoincell[] = { | 
 | 153 | 	2500000, 2700000, 2800000, 2900000, 3000000, 3100000, | 
 | 154 | 	3200000, 3300000, | 
 | 155 | }; | 
 | 156 |  | 
 | 157 | static const int mc13892_sw1[] = { | 
 | 158 | 	600000,   625000,  650000,  675000,  700000,  725000, | 
 | 159 | 	750000,   775000,  800000,  825000,  850000,  875000, | 
 | 160 | 	900000,   925000,  950000,  975000, 1000000, 1025000, | 
 | 161 | 	1050000, 1075000, 1100000, 1125000, 1150000, 1175000, | 
 | 162 | 	1200000, 1225000, 1250000, 1275000, 1300000, 1325000, | 
 | 163 | 	1350000, 1375000 | 
 | 164 | }; | 
 | 165 |  | 
 | 166 | static const int mc13892_sw[] = { | 
 | 167 | 	600000,   625000,  650000,  675000,  700000,  725000, | 
 | 168 | 	750000,   775000,  800000,  825000,  850000,  875000, | 
 | 169 | 	900000,   925000,  950000,  975000, 1000000, 1025000, | 
 | 170 | 	1050000, 1075000, 1100000, 1125000, 1150000, 1175000, | 
 | 171 | 	1200000, 1225000, 1250000, 1275000, 1300000, 1325000, | 
 | 172 | 	1350000, 1375000, 1400000, 1425000, 1450000, 1475000, | 
 | 173 | 	1500000, 1525000, 1550000, 1575000, 1600000, 1625000, | 
 | 174 | 	1650000, 1675000, 1700000, 1725000, 1750000, 1775000, | 
 | 175 | 	1800000, 1825000, 1850000, 1875000 | 
 | 176 | }; | 
 | 177 |  | 
 | 178 | static const int mc13892_swbst[] = { | 
 | 179 | 	5000000, | 
 | 180 | }; | 
 | 181 |  | 
 | 182 | static const int mc13892_viohi[] = { | 
 | 183 | 	2775000, | 
 | 184 | }; | 
 | 185 |  | 
 | 186 | static const int mc13892_vpll[] = { | 
 | 187 | 	1050000, 1250000, 1650000, 1800000, | 
 | 188 | }; | 
 | 189 |  | 
 | 190 | static const int mc13892_vdig[] = { | 
 | 191 | 	1050000, 1250000, 1650000, 1800000, | 
 | 192 | }; | 
 | 193 |  | 
 | 194 | static const int mc13892_vsd[] = { | 
 | 195 | 	1800000, 2000000, 2600000, 2700000, | 
 | 196 | 	2800000, 2900000, 3000000, 3150000, | 
 | 197 | }; | 
 | 198 |  | 
 | 199 | static const int mc13892_vusb2[] = { | 
 | 200 | 	2400000, 2600000, 2700000, 2775000, | 
 | 201 | }; | 
 | 202 |  | 
 | 203 | static const int mc13892_vvideo[] = { | 
 | 204 | 	2700000, 2775000, 2500000, 2600000, | 
 | 205 | }; | 
 | 206 |  | 
 | 207 | static const int mc13892_vaudio[] = { | 
 | 208 | 	2300000, 2500000, 2775000, 3000000, | 
 | 209 | }; | 
 | 210 |  | 
 | 211 | static const int mc13892_vcam[] = { | 
 | 212 | 	2500000, 2600000, 2750000, 3000000, | 
 | 213 | }; | 
 | 214 |  | 
 | 215 | static const int mc13892_vgen1[] = { | 
 | 216 | 	1200000, 1500000, 2775000, 3150000, | 
 | 217 | }; | 
 | 218 |  | 
 | 219 | static const int mc13892_vgen2[] = { | 
 | 220 | 	1200000, 1500000, 1600000, 1800000, | 
 | 221 | 	2700000, 2800000, 3000000, 3150000, | 
 | 222 | }; | 
 | 223 |  | 
 | 224 | static const int mc13892_vgen3[] = { | 
 | 225 | 	1800000, 2900000, | 
 | 226 | }; | 
 | 227 |  | 
 | 228 | static const int mc13892_vusb[] = { | 
 | 229 | 	3300000, | 
 | 230 | }; | 
 | 231 |  | 
 | 232 | static const int mc13892_gpo[] = { | 
 | 233 | 	2750000, | 
 | 234 | }; | 
 | 235 |  | 
 | 236 | static const int mc13892_pwgtdrv[] = { | 
 | 237 | 	5000000, | 
 | 238 | }; | 
 | 239 |  | 
 | 240 | static struct regulator_ops mc13892_gpo_regulator_ops; | 
 | 241 | /* sw regulators need special care due to the "hi bit" */ | 
 | 242 | static struct regulator_ops mc13892_sw_regulator_ops; | 
 | 243 |  | 
 | 244 |  | 
 | 245 | #define MC13892_FIXED_DEFINE(name, reg, voltages)		\ | 
 | 246 | 	MC13xxx_FIXED_DEFINE(MC13892_, name, reg, voltages,	\ | 
 | 247 | 			mc13xxx_fixed_regulator_ops) | 
 | 248 |  | 
 | 249 | #define MC13892_GPO_DEFINE(name, reg, voltages)			\ | 
 | 250 | 	MC13xxx_GPO_DEFINE(MC13892_, name, reg, voltages,	\ | 
 | 251 | 			mc13892_gpo_regulator_ops) | 
 | 252 |  | 
 | 253 | #define MC13892_SW_DEFINE(name, reg, vsel_reg, voltages)	\ | 
 | 254 | 	MC13xxx_DEFINE(MC13892_, name, reg, vsel_reg, voltages, \ | 
 | 255 | 			mc13892_sw_regulator_ops) | 
 | 256 |  | 
 | 257 | #define MC13892_DEFINE_REGU(name, reg, vsel_reg, voltages)	\ | 
 | 258 | 	MC13xxx_DEFINE(MC13892_, name, reg, vsel_reg, voltages, \ | 
 | 259 | 			mc13xxx_regulator_ops) | 
 | 260 |  | 
 | 261 | static struct mc13xxx_regulator mc13892_regulators[] = { | 
| Axel Lin | 327e15a | 2011-05-10 19:10:36 +0800 | [diff] [blame] | 262 | 	MC13892_DEFINE_REGU(VCOINCELL, POWERCTL0, POWERCTL0, mc13892_vcoincell), | 
| Yong Shen | 5e428d5 | 2010-12-14 14:00:55 +0800 | [diff] [blame] | 263 | 	MC13892_SW_DEFINE(SW1, SWITCHERS0, SWITCHERS0, mc13892_sw1), | 
 | 264 | 	MC13892_SW_DEFINE(SW2, SWITCHERS1, SWITCHERS1, mc13892_sw), | 
 | 265 | 	MC13892_SW_DEFINE(SW3, SWITCHERS2, SWITCHERS2, mc13892_sw), | 
 | 266 | 	MC13892_SW_DEFINE(SW4, SWITCHERS3, SWITCHERS3, mc13892_sw), | 
 | 267 | 	MC13892_FIXED_DEFINE(SWBST, SWITCHERS5, mc13892_swbst), | 
 | 268 | 	MC13892_FIXED_DEFINE(VIOHI, REGULATORMODE0, mc13892_viohi), | 
 | 269 | 	MC13892_DEFINE_REGU(VPLL, REGULATORMODE0, REGULATORSETTING0,	\ | 
 | 270 | 		mc13892_vpll), | 
 | 271 | 	MC13892_DEFINE_REGU(VDIG, REGULATORMODE0, REGULATORSETTING0,	\ | 
 | 272 | 		mc13892_vdig), | 
 | 273 | 	MC13892_DEFINE_REGU(VSD, REGULATORMODE1, REGULATORSETTING1,	\ | 
 | 274 | 		mc13892_vsd), | 
 | 275 | 	MC13892_DEFINE_REGU(VUSB2, REGULATORMODE0, REGULATORSETTING0,	\ | 
 | 276 | 		mc13892_vusb2), | 
 | 277 | 	MC13892_DEFINE_REGU(VVIDEO, REGULATORMODE1, REGULATORSETTING1,	\ | 
 | 278 | 		mc13892_vvideo), | 
 | 279 | 	MC13892_DEFINE_REGU(VAUDIO, REGULATORMODE1, REGULATORSETTING1,	\ | 
 | 280 | 		mc13892_vaudio), | 
 | 281 | 	MC13892_DEFINE_REGU(VCAM, REGULATORMODE1, REGULATORSETTING0,	\ | 
 | 282 | 		mc13892_vcam), | 
 | 283 | 	MC13892_DEFINE_REGU(VGEN1, REGULATORMODE0, REGULATORSETTING0,	\ | 
 | 284 | 		mc13892_vgen1), | 
 | 285 | 	MC13892_DEFINE_REGU(VGEN2, REGULATORMODE0, REGULATORSETTING0,	\ | 
 | 286 | 		mc13892_vgen2), | 
 | 287 | 	MC13892_DEFINE_REGU(VGEN3, REGULATORMODE1, REGULATORSETTING0,	\ | 
 | 288 | 		mc13892_vgen3), | 
 | 289 | 	MC13892_FIXED_DEFINE(VUSB, USB1, mc13892_vusb), | 
 | 290 | 	MC13892_GPO_DEFINE(GPO1, POWERMISC, mc13892_gpo), | 
 | 291 | 	MC13892_GPO_DEFINE(GPO2, POWERMISC, mc13892_gpo), | 
 | 292 | 	MC13892_GPO_DEFINE(GPO3, POWERMISC, mc13892_gpo), | 
 | 293 | 	MC13892_GPO_DEFINE(GPO4, POWERMISC, mc13892_gpo), | 
 | 294 | 	MC13892_GPO_DEFINE(PWGT1SPI, POWERMISC, mc13892_pwgtdrv), | 
 | 295 | 	MC13892_GPO_DEFINE(PWGT2SPI, POWERMISC, mc13892_pwgtdrv), | 
 | 296 | }; | 
 | 297 |  | 
| Mark Brown | 27315cf | 2010-12-16 15:29:56 +0000 | [diff] [blame] | 298 | static int mc13892_powermisc_rmw(struct mc13xxx_regulator_priv *priv, u32 mask, | 
 | 299 | 				 u32 val) | 
| Yong Shen | 5e428d5 | 2010-12-14 14:00:55 +0800 | [diff] [blame] | 300 | { | 
 | 301 | 	struct mc13xxx *mc13892 = priv->mc13xxx; | 
 | 302 | 	int ret; | 
 | 303 | 	u32 valread; | 
 | 304 |  | 
 | 305 | 	BUG_ON(val & ~mask); | 
 | 306 |  | 
 | 307 | 	ret = mc13xxx_reg_read(mc13892, MC13892_POWERMISC, &valread); | 
 | 308 | 	if (ret) | 
 | 309 | 		return ret; | 
 | 310 |  | 
 | 311 | 	/* Update the stored state for Power Gates. */ | 
 | 312 | 	priv->powermisc_pwgt_state = | 
 | 313 | 		(priv->powermisc_pwgt_state & ~mask) | val; | 
 | 314 | 	priv->powermisc_pwgt_state &= MC13892_POWERMISC_PWGTSPI_M; | 
 | 315 |  | 
 | 316 | 	/* Construct the new register value */ | 
 | 317 | 	valread = (valread & ~mask) | val; | 
 | 318 | 	/* Overwrite the PWGTxEN with the stored version */ | 
 | 319 | 	valread = (valread & ~MC13892_POWERMISC_PWGTSPI_M) | | 
 | 320 | 		priv->powermisc_pwgt_state; | 
 | 321 |  | 
 | 322 | 	return mc13xxx_reg_write(mc13892, MC13892_POWERMISC, valread); | 
 | 323 | } | 
 | 324 |  | 
 | 325 | static int mc13892_gpo_regulator_enable(struct regulator_dev *rdev) | 
 | 326 | { | 
 | 327 | 	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); | 
 | 328 | 	int id = rdev_get_id(rdev); | 
 | 329 | 	int ret; | 
 | 330 | 	u32 en_val = mc13892_regulators[id].enable_bit; | 
 | 331 | 	u32 mask = mc13892_regulators[id].enable_bit; | 
 | 332 |  | 
 | 333 | 	dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); | 
 | 334 |  | 
 | 335 | 	/* Power Gate enable value is 0 */ | 
 | 336 | 	if (id == MC13892_PWGT1SPI || id == MC13892_PWGT2SPI) | 
 | 337 | 		en_val = 0; | 
 | 338 |  | 
 | 339 | 	if (id == MC13892_GPO4) | 
 | 340 | 		mask |= MC13892_POWERMISC_GPO4ADINEN; | 
 | 341 |  | 
 | 342 | 	mc13xxx_lock(priv->mc13xxx); | 
 | 343 | 	ret = mc13892_powermisc_rmw(priv, mask, en_val); | 
 | 344 | 	mc13xxx_unlock(priv->mc13xxx); | 
 | 345 |  | 
 | 346 | 	return ret; | 
 | 347 | } | 
 | 348 |  | 
 | 349 | static int mc13892_gpo_regulator_disable(struct regulator_dev *rdev) | 
 | 350 | { | 
 | 351 | 	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); | 
 | 352 | 	int id = rdev_get_id(rdev); | 
 | 353 | 	int ret; | 
 | 354 | 	u32 dis_val = 0; | 
 | 355 |  | 
 | 356 | 	dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); | 
 | 357 |  | 
 | 358 | 	/* Power Gate disable value is 1 */ | 
 | 359 | 	if (id == MC13892_PWGT1SPI || id == MC13892_PWGT2SPI) | 
 | 360 | 		dis_val = mc13892_regulators[id].enable_bit; | 
 | 361 |  | 
 | 362 | 	mc13xxx_lock(priv->mc13xxx); | 
 | 363 | 	ret = mc13892_powermisc_rmw(priv, mc13892_regulators[id].enable_bit, | 
 | 364 | 		dis_val); | 
 | 365 | 	mc13xxx_unlock(priv->mc13xxx); | 
 | 366 |  | 
 | 367 | 	return ret; | 
 | 368 | } | 
 | 369 |  | 
 | 370 | static int mc13892_gpo_regulator_is_enabled(struct regulator_dev *rdev) | 
 | 371 | { | 
 | 372 | 	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); | 
 | 373 | 	int ret, id = rdev_get_id(rdev); | 
 | 374 | 	unsigned int val; | 
 | 375 |  | 
 | 376 | 	mc13xxx_lock(priv->mc13xxx); | 
 | 377 | 	ret = mc13xxx_reg_read(priv->mc13xxx, mc13892_regulators[id].reg, &val); | 
 | 378 | 	mc13xxx_unlock(priv->mc13xxx); | 
 | 379 |  | 
 | 380 | 	if (ret) | 
 | 381 | 		return ret; | 
 | 382 |  | 
 | 383 | 	/* Power Gates state is stored in powermisc_pwgt_state | 
 | 384 | 	 * where the meaning of bits is negated */ | 
 | 385 | 	val = (val & ~MC13892_POWERMISC_PWGTSPI_M) | | 
 | 386 | 		(priv->powermisc_pwgt_state ^ MC13892_POWERMISC_PWGTSPI_M); | 
 | 387 |  | 
 | 388 | 	return (val & mc13892_regulators[id].enable_bit) != 0; | 
 | 389 | } | 
 | 390 |  | 
 | 391 |  | 
 | 392 | static struct regulator_ops mc13892_gpo_regulator_ops = { | 
 | 393 | 	.enable = mc13892_gpo_regulator_enable, | 
 | 394 | 	.disable = mc13892_gpo_regulator_disable, | 
 | 395 | 	.is_enabled = mc13892_gpo_regulator_is_enabled, | 
 | 396 | 	.list_voltage = mc13xxx_regulator_list_voltage, | 
 | 397 | 	.set_voltage = mc13xxx_fixed_regulator_set_voltage, | 
 | 398 | 	.get_voltage = mc13xxx_fixed_regulator_get_voltage, | 
 | 399 | }; | 
 | 400 |  | 
 | 401 | static int mc13892_sw_regulator_get_voltage(struct regulator_dev *rdev) | 
 | 402 | { | 
 | 403 | 	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); | 
 | 404 | 	int ret, id = rdev_get_id(rdev); | 
 | 405 | 	unsigned int val, hi; | 
 | 406 |  | 
 | 407 | 	dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); | 
 | 408 |  | 
 | 409 | 	mc13xxx_lock(priv->mc13xxx); | 
 | 410 | 	ret = mc13xxx_reg_read(priv->mc13xxx, | 
 | 411 | 		mc13892_regulators[id].vsel_reg, &val); | 
 | 412 | 	mc13xxx_unlock(priv->mc13xxx); | 
 | 413 | 	if (ret) | 
 | 414 | 		return ret; | 
 | 415 |  | 
 | 416 | 	hi  = val & MC13892_SWITCHERS0_SWxHI; | 
 | 417 | 	val = (val & mc13892_regulators[id].vsel_mask) | 
 | 418 | 		>> mc13892_regulators[id].vsel_shift; | 
 | 419 |  | 
 | 420 | 	dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val); | 
 | 421 |  | 
 | 422 | 	if (hi) | 
 | 423 | 		val = (25000 * val) + 1100000; | 
 | 424 | 	else | 
 | 425 | 		val = (25000 * val) + 600000; | 
 | 426 |  | 
 | 427 | 	return val; | 
 | 428 | } | 
 | 429 |  | 
 | 430 | static int mc13892_sw_regulator_set_voltage(struct regulator_dev *rdev, | 
 | 431 | 		int min_uV, int max_uV, unsigned *selector) | 
 | 432 | { | 
 | 433 | 	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); | 
| Axel Lin | 98ea5c2 | 2011-05-09 17:49:40 +0800 | [diff] [blame] | 434 | 	int hi, value, mask, id = rdev_get_id(rdev); | 
 | 435 | 	u32 valread; | 
| Yong Shen | 5e428d5 | 2010-12-14 14:00:55 +0800 | [diff] [blame] | 436 | 	int ret; | 
 | 437 |  | 
 | 438 | 	dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n", | 
 | 439 | 		__func__, id, min_uV, max_uV); | 
 | 440 |  | 
 | 441 | 	/* Find the best index */ | 
 | 442 | 	value = mc13xxx_get_best_voltage_index(rdev, min_uV, max_uV); | 
 | 443 | 	dev_dbg(rdev_get_dev(rdev), "%s best value: %d\n", __func__, value); | 
 | 444 | 	if (value < 0) | 
 | 445 | 		return value; | 
 | 446 |  | 
 | 447 | 	value = mc13892_regulators[id].voltages[value]; | 
 | 448 |  | 
 | 449 | 	mc13xxx_lock(priv->mc13xxx); | 
 | 450 | 	ret = mc13xxx_reg_read(priv->mc13xxx, | 
| Axel Lin | 98ea5c2 | 2011-05-09 17:49:40 +0800 | [diff] [blame] | 451 | 		mc13892_regulators[id].vsel_reg, &valread); | 
| Yong Shen | 5e428d5 | 2010-12-14 14:00:55 +0800 | [diff] [blame] | 452 | 	if (ret) | 
 | 453 | 		goto err; | 
 | 454 |  | 
| Fabio Estevam | 6dc4efc | 2011-05-16 10:54:27 -0300 | [diff] [blame] | 455 | 	if (value > 1375000) | 
| Yong Shen | 5e428d5 | 2010-12-14 14:00:55 +0800 | [diff] [blame] | 456 | 		hi = 1; | 
| Fabio Estevam | 6dc4efc | 2011-05-16 10:54:27 -0300 | [diff] [blame] | 457 | 	else if (value < 1100000) | 
| Yong Shen | 5e428d5 | 2010-12-14 14:00:55 +0800 | [diff] [blame] | 458 | 		hi = 0; | 
| Axel Lin | 98ea5c2 | 2011-05-09 17:49:40 +0800 | [diff] [blame] | 459 | 	else | 
 | 460 | 		hi = valread & MC13892_SWITCHERS0_SWxHI; | 
| Yong Shen | 5e428d5 | 2010-12-14 14:00:55 +0800 | [diff] [blame] | 461 |  | 
 | 462 | 	if (hi) { | 
 | 463 | 		value = (value - 1100000) / 25000; | 
 | 464 | 		value |= MC13892_SWITCHERS0_SWxHI; | 
 | 465 | 	} else | 
 | 466 | 		value = (value - 600000) / 25000; | 
 | 467 |  | 
 | 468 | 	mask = mc13892_regulators[id].vsel_mask | MC13892_SWITCHERS0_SWxHI; | 
| Axel Lin | 98ea5c2 | 2011-05-09 17:49:40 +0800 | [diff] [blame] | 469 | 	valread = (valread & ~mask) | | 
 | 470 | 			(value << mc13892_regulators[id].vsel_shift); | 
 | 471 | 	ret = mc13xxx_reg_write(priv->mc13xxx, mc13892_regulators[id].vsel_reg, | 
 | 472 | 			valread); | 
| Yong Shen | 5e428d5 | 2010-12-14 14:00:55 +0800 | [diff] [blame] | 473 | err: | 
 | 474 | 	mc13xxx_unlock(priv->mc13xxx); | 
 | 475 |  | 
 | 476 | 	return ret; | 
 | 477 | } | 
 | 478 |  | 
 | 479 | static struct regulator_ops mc13892_sw_regulator_ops = { | 
 | 480 | 	.is_enabled = mc13xxx_sw_regulator_is_enabled, | 
 | 481 | 	.list_voltage = mc13xxx_regulator_list_voltage, | 
 | 482 | 	.set_voltage = mc13892_sw_regulator_set_voltage, | 
 | 483 | 	.get_voltage = mc13892_sw_regulator_get_voltage, | 
 | 484 | }; | 
 | 485 |  | 
 | 486 | static int mc13892_vcam_set_mode(struct regulator_dev *rdev, unsigned int mode) | 
 | 487 | { | 
 | 488 | 	unsigned int en_val = 0; | 
 | 489 | 	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); | 
 | 490 | 	int ret, id = rdev_get_id(rdev); | 
 | 491 |  | 
 | 492 | 	if (mode == REGULATOR_MODE_FAST) | 
 | 493 | 		en_val = MC13892_REGULATORMODE1_VCAMCONFIGEN; | 
 | 494 |  | 
 | 495 | 	mc13xxx_lock(priv->mc13xxx); | 
 | 496 | 	ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13892_regulators[id].reg, | 
 | 497 | 		MC13892_REGULATORMODE1_VCAMCONFIGEN, en_val); | 
 | 498 | 	mc13xxx_unlock(priv->mc13xxx); | 
 | 499 |  | 
 | 500 | 	return ret; | 
 | 501 | } | 
 | 502 |  | 
| Mark Brown | 27315cf | 2010-12-16 15:29:56 +0000 | [diff] [blame] | 503 | static unsigned int mc13892_vcam_get_mode(struct regulator_dev *rdev) | 
| Yong Shen | 5e428d5 | 2010-12-14 14:00:55 +0800 | [diff] [blame] | 504 | { | 
 | 505 | 	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); | 
 | 506 | 	int ret, id = rdev_get_id(rdev); | 
 | 507 | 	unsigned int val; | 
 | 508 |  | 
 | 509 | 	mc13xxx_lock(priv->mc13xxx); | 
 | 510 | 	ret = mc13xxx_reg_read(priv->mc13xxx, mc13892_regulators[id].reg, &val); | 
 | 511 | 	mc13xxx_unlock(priv->mc13xxx); | 
 | 512 |  | 
 | 513 | 	if (ret) | 
 | 514 | 		return ret; | 
 | 515 |  | 
 | 516 | 	if (val & MC13892_REGULATORMODE1_VCAMCONFIGEN) | 
 | 517 | 		return REGULATOR_MODE_FAST; | 
 | 518 |  | 
 | 519 | 	return REGULATOR_MODE_NORMAL; | 
 | 520 | } | 
 | 521 |  | 
 | 522 |  | 
 | 523 | static int __devinit mc13892_regulator_probe(struct platform_device *pdev) | 
 | 524 | { | 
 | 525 | 	struct mc13xxx_regulator_priv *priv; | 
 | 526 | 	struct mc13xxx *mc13892 = dev_get_drvdata(pdev->dev.parent); | 
| Samuel Ortiz | c8a03c9 | 2011-04-08 01:55:01 +0200 | [diff] [blame] | 527 | 	struct mc13xxx_regulator_platform_data *pdata = | 
 | 528 | 		dev_get_platdata(&pdev->dev); | 
| Yong Shen | 5e428d5 | 2010-12-14 14:00:55 +0800 | [diff] [blame] | 529 | 	struct mc13xxx_regulator_init_data *init_data; | 
 | 530 | 	int i, ret; | 
 | 531 | 	u32 val; | 
 | 532 |  | 
 | 533 | 	priv = kzalloc(sizeof(*priv) + | 
 | 534 | 		pdata->num_regulators * sizeof(priv->regulators[0]), | 
 | 535 | 		GFP_KERNEL); | 
 | 536 | 	if (!priv) | 
 | 537 | 		return -ENOMEM; | 
 | 538 |  | 
 | 539 | 	priv->mc13xxx_regulators = mc13892_regulators; | 
 | 540 | 	priv->mc13xxx = mc13892; | 
 | 541 |  | 
 | 542 | 	mc13xxx_lock(mc13892); | 
 | 543 | 	ret = mc13xxx_reg_read(mc13892, MC13892_REVISION, &val); | 
 | 544 | 	if (ret) | 
 | 545 | 		goto err_free; | 
 | 546 |  | 
 | 547 | 	/* enable switch auto mode */ | 
 | 548 | 	if ((val & 0x0000FFFF) == 0x45d0) { | 
 | 549 | 		ret = mc13xxx_reg_rmw(mc13892, MC13892_SWITCHERS4, | 
 | 550 | 			MC13892_SWITCHERS4_SW1MODE_M | | 
 | 551 | 			MC13892_SWITCHERS4_SW2MODE_M, | 
 | 552 | 			MC13892_SWITCHERS4_SW1MODE_AUTO | | 
 | 553 | 			MC13892_SWITCHERS4_SW2MODE_AUTO); | 
 | 554 | 		if (ret) | 
 | 555 | 			goto err_free; | 
 | 556 |  | 
| Axel Lin | 923430c | 2011-01-03 23:57:38 +0800 | [diff] [blame] | 557 | 		ret = mc13xxx_reg_rmw(mc13892, MC13892_SWITCHERS5, | 
| Yong Shen | 5e428d5 | 2010-12-14 14:00:55 +0800 | [diff] [blame] | 558 | 			MC13892_SWITCHERS5_SW3MODE_M | | 
 | 559 | 			MC13892_SWITCHERS5_SW4MODE_M, | 
 | 560 | 			MC13892_SWITCHERS5_SW3MODE_AUTO | | 
 | 561 | 			MC13892_SWITCHERS5_SW4MODE_AUTO); | 
 | 562 | 		if (ret) | 
 | 563 | 			goto err_free; | 
 | 564 | 	} | 
 | 565 | 	mc13xxx_unlock(mc13892); | 
 | 566 |  | 
 | 567 | 	mc13892_regulators[MC13892_VCAM].desc.ops->set_mode | 
 | 568 | 		= mc13892_vcam_set_mode; | 
 | 569 | 	mc13892_regulators[MC13892_VCAM].desc.ops->get_mode | 
 | 570 | 		= mc13892_vcam_get_mode; | 
 | 571 | 	for (i = 0; i < pdata->num_regulators; i++) { | 
 | 572 | 		init_data = &pdata->regulators[i]; | 
 | 573 | 		priv->regulators[i] = regulator_register( | 
 | 574 | 			&mc13892_regulators[init_data->id].desc, | 
 | 575 | 			&pdev->dev, init_data->init_data, priv); | 
 | 576 |  | 
 | 577 | 		if (IS_ERR(priv->regulators[i])) { | 
 | 578 | 			dev_err(&pdev->dev, "failed to register regulator %s\n", | 
 | 579 | 				mc13892_regulators[i].desc.name); | 
 | 580 | 			ret = PTR_ERR(priv->regulators[i]); | 
 | 581 | 			goto err; | 
 | 582 | 		} | 
 | 583 | 	} | 
 | 584 |  | 
 | 585 | 	platform_set_drvdata(pdev, priv); | 
 | 586 |  | 
 | 587 | 	return 0; | 
 | 588 | err: | 
 | 589 | 	while (--i >= 0) | 
 | 590 | 		regulator_unregister(priv->regulators[i]); | 
 | 591 |  | 
 | 592 | err_free: | 
 | 593 | 	mc13xxx_unlock(mc13892); | 
 | 594 | 	kfree(priv); | 
 | 595 |  | 
 | 596 | 	return ret; | 
 | 597 | } | 
 | 598 |  | 
 | 599 | static int __devexit mc13892_regulator_remove(struct platform_device *pdev) | 
 | 600 | { | 
 | 601 | 	struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev); | 
| Samuel Ortiz | c8a03c9 | 2011-04-08 01:55:01 +0200 | [diff] [blame] | 602 | 	struct mc13xxx_regulator_platform_data *pdata = | 
 | 603 | 		dev_get_platdata(&pdev->dev); | 
| Yong Shen | 5e428d5 | 2010-12-14 14:00:55 +0800 | [diff] [blame] | 604 | 	int i; | 
 | 605 |  | 
 | 606 | 	platform_set_drvdata(pdev, NULL); | 
 | 607 |  | 
 | 608 | 	for (i = 0; i < pdata->num_regulators; i++) | 
 | 609 | 		regulator_unregister(priv->regulators[i]); | 
 | 610 |  | 
 | 611 | 	kfree(priv); | 
 | 612 | 	return 0; | 
 | 613 | } | 
 | 614 |  | 
 | 615 | static struct platform_driver mc13892_regulator_driver = { | 
 | 616 | 	.driver	= { | 
 | 617 | 		.name	= "mc13892-regulator", | 
 | 618 | 		.owner	= THIS_MODULE, | 
 | 619 | 	}, | 
 | 620 | 	.remove	= __devexit_p(mc13892_regulator_remove), | 
 | 621 | 	.probe	= mc13892_regulator_probe, | 
 | 622 | }; | 
 | 623 |  | 
 | 624 | static int __init mc13892_regulator_init(void) | 
 | 625 | { | 
 | 626 | 	return platform_driver_register(&mc13892_regulator_driver); | 
 | 627 | } | 
 | 628 | subsys_initcall(mc13892_regulator_init); | 
 | 629 |  | 
 | 630 | static void __exit mc13892_regulator_exit(void) | 
 | 631 | { | 
 | 632 | 	platform_driver_unregister(&mc13892_regulator_driver); | 
 | 633 | } | 
 | 634 | module_exit(mc13892_regulator_exit); | 
 | 635 |  | 
 | 636 | MODULE_LICENSE("GPL v2"); | 
 | 637 | MODULE_AUTHOR("Yong Shen <yong.shen@linaro.org>"); | 
 | 638 | MODULE_DESCRIPTION("Regulator Driver for Freescale MC13892 PMIC"); | 
 | 639 | MODULE_ALIAS("platform:mc13892-regulator"); |