tizen 2.4 release
[profile/mobile/platform/kernel/u-boot-tm1.git] / arch / arm / cpu / armv7 / sc8830 / dcdc_cal_x15.c
1 #include <common.h>
2 #include <asm/io.h>
3 #include <asm/arch/adc_drvapi.h>
4 #include <asm/arch/adi_hal_internal.h>
5 #include <asm/arch/sprd_reg.h>
6
7 int regulator_default_get(const char con_id[]);
8 void regulator_default_set(const char con_id[], int vol);
9 int regulator_default_set_all(void);
10 u32 regulator_get_calibration_mask(void);
11
12 #define REGU_CALI_DEBUG
13
14 #ifdef REGU_CALI_DEBUG
15 #define regu_debug(fmt, arg...)         printf(fmt, ## arg)
16 #else
17 #define regu_debug(fmt, arg...)
18 #endif
19
20 #undef debug
21 #define debug0(format, arg...)
22 #define debug(format, arg...)           regu_debug(format, ## arg)
23 #define debug1(format, arg...)          regu_debug("\t" format, ## arg)
24 #define debug2(format, arg...)          regu_debug("\t\t" format, ## arg)
25
26 /* abs() handles unsigned and signed longs, ints, shorts and chars.  For all input types abs()
27  * returns a signed long.
28  * abs() should not be used for 64-bit types (s64, u64, long long) - use abs64() for those.*/
29 #define abs(x) ({                                                                       \
30                                 long ret;                                                       \
31                                 if (sizeof(x) == sizeof(long)) {                \
32                                         long __x = (x);                         \
33                                         ret = (__x < 0) ? -__x : __x;           \
34                                 } else {                                                        \
35                                         int __x = (x);                                  \
36                                         ret = (__x < 0) ? -__x : __x;           \
37                                 }                                                               \
38                                 ret;                                                            \
39                         })
40
41
42 #undef ffs
43 #undef fls
44
45 /* On ARMv5 and above those functions can be implemented around the clz instruction for
46  * much better code efficiency.         */
47
48 static inline int fls(int x)
49 {
50         int ret;
51
52         asm("clz\t%0, %1": "=r"(ret):"r"(x));
53         ret = 32 - ret;
54         return ret;
55 }
56
57 #define __fls(x) (fls(x) - 1)
58 #define ffs(x) ({ unsigned long __t = (x); fls(__t & -__t); })
59 #define __ffs(x) (ffs(x) - 1)
60 #define ffz(x) __ffs( ~(x) )
61
62 #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
63
64 #define MEASURE_TIMES                           (15)
65
66 #define ADC_DROP_CNT    ( DIV_ROUND(MEASURE_TIMES, 5) )
67 static int __average(int a[], int N)
68 {
69         int i, sum = 0;
70         for (i = 0; i < N; i++)
71                 sum += a[i];
72         return DIV_ROUND(sum, N);
73 }
74
75 static void bubble_sort(int a[], int N)
76 {
77         int i, j, t;
78         for (i = 0; i < N - 1; i++) {
79                 for (j = i + 1; j < N; j++) {
80                         if (a[i] > a[j]) {
81                                 t = a[i];
82                                 a[i] = a[j];
83                                 a[j] = t;
84                         }
85                 }
86         }
87 }
88
89 static int sci_adc_request(int channel, int scale)
90 {
91         int results[MEASURE_TIMES];
92
93         if (-1 == ADC_GetValues(channel, scale, MEASURE_TIMES, results)) {
94                 return 0;
95         }
96
97         bubble_sort(results, MEASURE_TIMES);
98
99 #if 0
100 {
101         int i;
102
103         /* dump results */
104         for (i = 0; i < MEASURE_TIMES; i++) {
105                 printf("%d ", results[i]);
106         }
107         printf("\n");
108 }
109 #endif
110
111         return __average(&results[ADC_DROP_CNT], MEASURE_TIMES - ADC_DROP_CNT * 2);
112 }
113
114 #define RATIO(_n_, _d_) (_n_ << 16 | _d_)
115
116 static int sci_adc_ratio(int channel, int scale, int mux)
117 {
118         switch (channel) {
119         case 0x00:
120         case 0x01:
121         case 0x02:
122         case 0x03:
123                 return ((ADC_SCALE_3V == scale) ? RATIO(400, 1025) : RATIO(1, 1));
124         case 0x05:              //vbat
125                 return RATIO(7, 29);
126         case 0x0D:              //dcdccore
127         case 0x0E:              //dcdcarm
128                 return ((ADC_SCALE_3V == scale) ? RATIO(4, 5) : RATIO(1, 1));
129         case 0x0F:              //dcdcmem
130                 return ((ADC_SCALE_3V == scale) ? RATIO(3, 5) : RATIO(4, 5));
131         case 0x10:              //dcdcgen
132                 return RATIO(4, 9);
133         case 0x15:              //DCDC Supply LDO
134                 return RATIO(1, 2);
135         case 0x13:              //DCDCVBATBK
136         case 0x16:              //VBATD Domain LDO
137         case 0x17:              //VBATA Domain LDO
138         case 0x1E:              //DP from terminal
139         case 0x1F:              //DM from terminal
140                 return RATIO(1, 3);
141         case 0x14:              //DCDCHEADMIC
142                 return ((ADC_SCALE_3V == scale) ? RATIO(1, 3) : RATIO(1, 1));
143
144         default:
145                 return RATIO(1, 1);
146         }
147         return RATIO(1, 1);
148 }
149
150 static u32 bat_numerators, bat_denominators = 0;
151 extern uint16_t sprdbat_auxadc2vbatvol (uint16_t adcvalue);
152
153 static int sci_adc_vol_request(int channel, int scale, int mux, int* adc)
154 {
155         int chan_adc, chan_vol;
156
157         if(0 == bat_denominators) {
158                 u32 res;
159                 /* FIXME: Update CHGMNG_AdcvalueToVoltage table before setup vbat ratio. */
160                 /*ADC_CHANNEL_VBAT is 5*/
161                 res = (u32) sci_adc_ratio(5, ADC_SCALE_3V, 0);
162                 bat_numerators = res >> 16;
163                 bat_denominators = res & 0xffff;
164         }
165
166         chan_adc = sci_adc_request(channel, scale);
167         if (chan_adc) {
168                 if(adc)
169                         *adc = chan_adc;
170
171                 chan_vol = sprdbat_auxadc2vbatvol(chan_adc);
172                 if(ADC_SCALE_3V == scale) {
173                         u32 res, chan_numerators, chan_denominators;
174                         res = (u32) sci_adc_ratio(channel, scale, mux);
175                         chan_numerators = res >> 16;
176                         chan_denominators = res & 0xffff;
177
178                     chan_vol *= (bat_numerators * chan_denominators);
179                         chan_vol /= (bat_denominators * chan_numerators);
180                 }
181                 return chan_vol;
182         }
183         return 0;
184 }
185
186 /* Simple shorthand for a section definition */
187 #ifndef __section
188 # define __section(S) __attribute__ ((__section__(#S)))
189 #endif
190
191 #define __init0 __section(.rodata.regu.init0)
192 #define __init1 __section(.rodata.regu.init1)
193 #define __init2 __section(.rodata.regu.init2)
194
195 static const u32 __init0 __init_begin = 0xeeeebbbb;
196 static const u32 __init2 __init_end = 0xddddeeee;
197
198 struct regulator_regs {
199         int typ;
200         u32 pd_set, pd_set_bit;
201         /* at new feature, some LDOs had only set, no rst bits.
202          * and DCDCs voltage and trimming controller is the same register */
203         u32 pd_rst, pd_rst_bit;
204         u32 slp_ctl, slp_ctl_bit;
205         u32 vol_trm, vol_trm_bits;
206         u32 cal_ctl, cal_ctl_bits;
207         u32 vol_def;
208         u32 vol_ctl, vol_ctl_bits;
209         u32 vol_sel_cnt, vol_sel[];
210 };
211
212 struct regulator_desc {
213         int id;
214         const char *name;
215         struct regulator_regs *regs;
216 };
217
218 #define REGU_VERIFY_DLY (1000)  /*ms */
219 #define SCI_REGU_REG(VDD, TYP, PD_SET, SET_BIT, PD_RST, RST_BIT, SLP_CTL, SLP_CTL_BIT, \
220                      VOL_TRM, VOL_TRM_BITS, CAL_CTL, CAL_CTL_BITS, VOL_DEF,     \
221                      VOL_CTL, VOL_CTL_BITS, VOL_SEL_CNT, ...)                                   \
222         static struct regulator_regs REGS_##VDD = {                                             \
223                 .typ = TYP,                                                     \
224                 .pd_set = PD_SET,                                       \
225                 .pd_set_bit = SET_BIT,                                  \
226                 .pd_rst = PD_RST,                                               \
227                 .pd_rst_bit = RST_BIT,                                  \
228                 .slp_ctl = SLP_CTL,                                             \
229                 .slp_ctl_bit = SLP_CTL_BIT,                             \
230                 .vol_trm = VOL_TRM,                                     \
231                 .vol_trm_bits = VOL_TRM_BITS,                   \
232                 .cal_ctl = CAL_CTL,                                     \
233                 .cal_ctl_bits = CAL_CTL_BITS,                   \
234                 .vol_def = VOL_DEF,                                     \
235                 .vol_ctl = VOL_CTL,                                     \
236                 .vol_ctl_bits = VOL_CTL_BITS,                   \
237                 .vol_sel_cnt = VOL_SEL_CNT,                     \
238                 .vol_sel = {__VA_ARGS__},                               \
239         };                                                                              \
240         struct regulator_desc __init1 DESC_##VDD = {    \
241                 .id = -1,                                                               \
242                 .name = #VDD,                                           \
243                 .regs = &REGS_##VDD,                                    \
244         };                                                                              \
245
246 #include <asm/arch/__sc2711_regulator_map.h>
247
248
249 /* standard dcdc ops*/
250 static int adjust_ldo_vol_base(struct regulator_desc *desc)
251 {
252         struct regulator_regs *regs = desc->regs;
253
254         if (regs->vol_sel_cnt == 2) {
255                 if ((0 == strcmp(desc->name, "vdd18"))
256                         || (0 == strcmp(desc->name, "vddemmcio"))
257                         || (0 == strcmp(desc->name, "vddcamd"))
258                         || (0 == strcmp(desc->name, "vddcamio"))) {
259
260                         regs->vol_sel[0] = 1400;
261                 }
262         }
263         debug0("%s vol base %dmv\n", desc->name, regs->vol_sel[0]);
264         return regs->vol_sel[0];
265 }
266
267 static int __dcdc_is_up_down_adjust(struct regulator_desc *desc)
268 {
269         return ((0 == strcmp(desc->name, "vddmem")) ? 1 : 0);
270 }
271
272 static int dcdc_get_trimming_step(struct regulator_desc *desc, int to_vol)
273 {
274         /* FIXME: vddmem step 200/32mV */
275         return (!strcmp(desc->name, "vddmem") ) ? (1000 * 200 / 32) : (1000 * 100 / 32) /*uV */;
276 }
277
278 static int __match_dcdc_vol(struct regulator_desc *desc, u32 vol)
279 {
280         int i, j = -1;
281         int ds, min_ds = 100;   /* mV, the max range of small voltage */
282         const struct regulator_regs *regs = desc->regs;
283
284         for (i = 0; i < regs->vol_sel_cnt; i++) {
285                 ds = vol - regs->vol_sel[i];
286                 if (ds >= 0 && ds < min_ds) {
287                         min_ds = ds;
288                         j = i;
289                 }
290         }
291
292         if (j < 0) {
293                 for (i = 0; i < regs->vol_sel_cnt; i++) {
294                         ds = abs(vol - regs->vol_sel[i]);
295                         if (ds < min_ds) {
296                                 min_ds = ds;
297                                 j = i;
298                         }
299                 }
300         }
301
302         return j;
303 }
304
305 static int dcdc_get_voltage(struct regulator_desc *desc)
306 {
307         const struct regulator_regs *regs = desc->regs;
308         u32 mv;
309         int cal = 0;            /* uV */
310         int i, shft = __ffs(regs->vol_ctl_bits);
311
312         i = (ANA_REG_GET(regs->vol_ctl) & regs->vol_ctl_bits) >> shft;
313         mv = regs->vol_sel[i];
314
315         cal = (ANA_REG_GET(regs->vol_trm) & regs->vol_trm_bits) >> __ffs(regs->vol_trm_bits);
316         if (__dcdc_is_up_down_adjust(desc)) {
317                 cal -= 0x10;
318         }
319         cal *= dcdc_get_trimming_step(desc, 0); /*uV */
320
321         debug0("%s %d +%dmv\n", desc->name, mv, cal / 1000);
322         return mv + cal / 1000;
323 }
324
325 static int dcdc_set_voltage(struct regulator_desc *desc, int min_mV, int max_mV)
326 {
327         const struct regulator_regs *regs = desc->regs;
328         int i, mv = min_mV;
329
330         /* found the closely vol ctrl bits */
331         i = __match_dcdc_vol(desc, mv);
332         if (i < 0) {
333                 debug2("%s: %s failed to match voltage: %d\n",__func__,desc->name,mv);
334                 return -1;
335         }
336
337         /* dcdc calibration control bits (default 0) small adjust voltage: 100/32mv ~= 3.125mv */
338         {
339                 int shft_ctl = __ffs(regs->vol_ctl_bits);
340                 int shft_trm = __ffs(regs->vol_trm_bits);
341                 int step = dcdc_get_trimming_step(desc, mv);
342                 int j = (int)(mv - (int)regs->vol_sel[i]) * 1000 / step;
343
344                 if (__dcdc_is_up_down_adjust(desc))
345                         j += 0x10;
346
347                 debug2("regu_dcdc %d = %d %+dmv (trim=%d step=%duv);\n",
348                            mv, regs->vol_sel[i], mv - regs->vol_sel[i], j, step);
349
350                 if (j >= 0 && j <= (regs->vol_trm_bits >> shft_trm))
351                         ANA_REG_MSK_OR(regs->vol_ctl, (j << shft_trm) | (i << shft_ctl),
352                                 regs->vol_trm_bits | regs->vol_ctl_bits);
353         }
354         return 0;
355 }
356
357 static int dcdc_set_trimming(struct regulator_desc *desc, int def_vol, int to_vol, int adc_vol)
358 {
359         //int acc_vol = dcdc_get_trimming_step(desc, to_vol) / 1000;
360         int ctl_vol = (def_vol - (adc_vol - to_vol));
361
362         return dcdc_set_voltage(desc, ctl_vol, ctl_vol);
363 }
364
365 static int ldo_get_voltage(struct regulator_desc *desc)
366 {
367         const struct regulator_regs *regs = desc->regs;
368         u32 vol;
369
370         if (regs->vol_trm && regs->vol_sel_cnt == 2) {
371                 int shft = __ffs(regs->vol_trm_bits);
372                 u32 trim =
373                     (ANA_REG_GET(regs->vol_trm) & regs->vol_trm_bits) >> shft;
374                 vol = regs->vol_sel[0] * 1000 + trim * regs->vol_sel[1];
375                 vol /= 1000;
376                 debug0("%s voltage %dmv\n", desc->name, vol);
377                 return vol;
378         }
379
380         return -1;
381 }
382
383 static int ldo_set_trimming(struct regulator_desc *desc, int def_vol, int to_vol, int adc_vol)
384 {
385         const struct regulator_regs *regs = desc->regs;
386         int ret = -1;
387
388         if (!regs->vol_ctl && regs->vol_sel_cnt == 2) {
389                 /* ctl_vol = vol_base + reg[vol_trm] * vol_step  */
390                 int shft = __ffs(regs->vol_trm_bits);
391                 int ctl_vol = (def_vol - (adc_vol - to_vol));   //same as dcdc?
392                 u32 trim = 0;
393                 if(adc_vol > to_vol)
394                         trim = DIV_ROUND_UP((ctl_vol - regs->vol_sel[0]) * 1000, regs->vol_sel[1]);
395                 else
396                         trim = ((ctl_vol - regs->vol_sel[0]) * 1000 / regs->vol_sel[1]);
397
398                 debug2("regu_ldo %d = %d %+dmv (trim=%d step=%duv vol_base=%dmv)\n",
399                         ctl_vol, regs->vol_sel[0], ctl_vol - regs->vol_sel[0], trim, regs->vol_sel[1], regs->vol_sel[0]);
400
401                 if ((trim >= 0) && (trim <= (regs->vol_trm_bits >> shft))) {
402                         ANA_REG_MSK_OR(regs->vol_trm,
403                                         trim << shft,
404                                         regs->vol_trm_bits);
405                         ret = 0;
406                 }
407         }
408
409         return ret;
410 }
411
412 static int DCDC_Cal_One(struct regulator_desc *desc, int is_cal)
413 {
414         struct regulator_regs *regs = desc->regs;
415         int def_vol = 0, to_vol = 0;
416         int adc = 0, adc_vol = 0, cal_vol = 0;
417         int ret = -1, adc_chan = regs->cal_ctl_bits >> 16;
418         u16 ldo_cal_sel = regs->cal_ctl_bits & 0xFFFF;
419
420         if (!adc_chan || !regs->vol_def)
421                 return -1;
422
423         /* only verify dcdc calibration */
424         if (!is_cal && (2 != desc->regs->typ))
425                 return -2;
426
427         if (is_cal)
428                 debug("\nCalibrate %s ...\n", desc->name);
429         else
430                 debug("\nVerify %s ...\n", desc->name);
431
432
433         if(0x2711A000 == ANA_GET_CHIP_ID()) {
434                 if (desc->regs->typ == 0) {
435                         adjust_ldo_vol_base(desc);
436                 }
437         }
438
439         if (0 == strcmp(desc->name, "vddrf0")) {
440                 if ((ANA_REG_GET(ANA_REG_GLB_LDO_V_CTRL9) & BIT(15)) >> 15) { /* BONDOPT4 */
441                         regs->vol_def = 2800;
442                 } else {
443                         regs->vol_def = 1800;
444                 }
445         }
446
447         if (ldo_cal_sel)
448                 ANA_REG_OR(regs->cal_ctl, ldo_cal_sel);
449
450         /*
451          * FIXME: force get dcdc&ldo voltage from ana global regs
452          * and get ideal voltage from vol para.
453          */
454         if (desc->regs->typ == 2 /*DCDC*/) {
455                 def_vol = dcdc_get_voltage(desc);
456         }
457         else if (desc->regs->typ == 0 /*LDO*/) {
458                 def_vol = ldo_get_voltage(desc);
459         }
460
461         to_vol = regulator_default_get(desc->name);
462         if (!to_vol)
463                 to_vol = regs->vol_def;
464
465         adc_vol = sci_adc_vol_request(adc_chan, ADC_SCALE_3V, ldo_cal_sel, &adc);
466         if (adc_vol <= 0) {
467                 debug1("%s default %dmv, adc channel %d, maybe not enable\n", desc->name, def_vol, adc_chan);
468                 goto exit;
469         }
470
471         cal_vol = abs(adc_vol - to_vol);
472         debug1("%s chan[%d] adc %d, default %dmv, from %dmv to %dmv, bias %c%d.%03d%%\n",
473               desc->name, adc_chan, adc, def_vol, adc_vol, to_vol,
474               (adc_vol > to_vol) ? '+' : '-',
475               cal_vol * 100 / to_vol, cal_vol * 100 * 1000 / to_vol % 1000);
476
477         if (!def_vol || !to_vol || adc_vol <= 0)
478                 goto exit;
479         if (abs(adc_vol - def_vol) >= def_vol / 9)      /* adjust limit 9% */
480                 goto exit;
481         else if (cal_vol < to_vol / 100) {      /* bias 1% */
482                 goto exit;
483         }
484
485         if (is_cal) {
486                 if (regs->typ == 2/*VDD_TYP_DCDC*/)
487                         ret = dcdc_set_trimming(desc, def_vol, to_vol, adc_vol);
488                 else if (regs->typ == 0/*VDD_TYP_LDO*/)
489                         ret = ldo_set_trimming(desc, def_vol, to_vol, adc_vol);
490
491                 if(ret < 0)
492                         regulator_default_set(desc->name, 0);
493         }
494
495 exit:
496         if (ldo_cal_sel)
497                 ANA_REG_BIC(regs->cal_ctl, ldo_cal_sel);
498
499         return ret;
500 }
501
502 int DCDC_Cal_ArmCore(void)
503 {
504         u16 regval_dcdc_store, regval_ldo_store;
505         struct regulator_desc *desc = NULL;
506         struct regulator_desc *desc_end = NULL;
507         u32 cali_mask = regulator_get_calibration_mask();
508         u32 chip_id = ANA_GET_CHIP_ID();
509         int vbat_adc = 0;
510         int vbat_vol = sci_adc_vol_request(5, ADC_SCALE_3V, 0, &vbat_adc);
511
512         printf("%s; adie chip id: (0x%08x), cali_mask: (0x%08x), VBAT(vol %d, adc %d)\n",
513                 __FUNCTION__, chip_id, cali_mask, vbat_vol, vbat_adc);
514
515         cali_mask &= 0x01F00FFF;
516
517         regval_dcdc_store = ANA_REG_GET(ANA_REG_GLB_LDO_DCDC_PD) & 0xFFFF;
518         ANA_REG_MSK_OR(ANA_REG_GLB_PWR_WR_PROT_VALUE, BITS_PWR_WR_PROT_VALUE(0x6e7f), 0x7FFF);
519         ANA_REG_BIC(ANA_REG_GLB_LDO_DCDC_PD, (cali_mask >> 16));
520         ANA_REG_MSK_OR(ANA_REG_GLB_PWR_WR_PROT_VALUE, 0, 0x7FFF);
521
522         regval_ldo_store = ANA_REG_GET(ANA_REG_GLB_LDO_PD_CTRL) & 0xFFFF;
523         ANA_REG_BIC(ANA_REG_GLB_LDO_PD_CTRL, cali_mask & 0xFFFF);
524
525         if(0x2711A000 == chip_id) {
526                 //FIXME: vddcamio/vddcamd/vddemmcio/vdd18 real voltage value is greater than design value
527                 ANA_REG_MSK_OR(ANA_REG_GLB_LDO_V_CTRL9, BITS_LDO_VDD18_V(0x40),
528                                 BITS_LDO_VDD18_V(-1)); //0x68D2 -->0x40D2
529                 ANA_REG_MSK_OR(ANA_REG_GLB_LDO_V_CTRL2, BITS_LDO_EMMCIO_V(0x40),
530                                 BITS_LDO_EMMCIO_V(-1));  //0x3C68 -->0x3C40
531                 ANA_REG_MSK_OR(ANA_REG_GLB_LDO_V_CTRL1, BITS_LDO_CAMIO_V(0x40) | BITS_LDO_CAMD_V(0x10),
532                                 BITS_LDO_CAMIO_V(-1) | BITS_LDO_CAMD_V(-1)); //0x6838 -->0x4010
533                 udelay(10 * 1000); //wait 10ms
534         }
535
536         /* TODO: calibrate all DCDCs */
537         desc = (struct regulator_desc *)(&__init_begin + 1);
538
539         printf("%p (%x) -- %p -- %p (%x)\n", &__init_begin, __init_begin,
540                 desc, &__init_end, __init_end);
541
542         desc_end = (struct regulator_desc *)(&__init_end) - 1;
543         while (desc_end >= desc) { /* reverse order */
544                 DCDC_Cal_One(desc_end, 1);
545                 desc_end--;
546         }
547
548 #if defined(REGU_CALI_DEBUG)
549         /* wait a moment for LDOs ready */
550         udelay(10 * 1000); //wait 10ms
551
552         /* TODO: verify all DCDCs */
553         desc = (struct regulator_desc *)(&__init_begin + 1);
554         desc_end = (struct regulator_desc *)(&__init_end) - 1;
555         while (desc_end >= desc) { /* reverse order */
556                 DCDC_Cal_One(desc_end, 0);
557                 desc_end--;
558         }
559 #endif
560
561         /* restore adie dcdc/ldo PD bits */
562         ANA_REG_SET(ANA_REG_GLB_LDO_PD_CTRL, regval_ldo_store);
563         ANA_REG_MSK_OR(ANA_REG_GLB_PWR_WR_PROT_VALUE, BITS_PWR_WR_PROT_VALUE(0x6e7f), 0x7FFF);
564         ANA_REG_SET(ANA_REG_GLB_LDO_DCDC_PD, regval_dcdc_store);
565         ANA_REG_MSK_OR(ANA_REG_GLB_PWR_WR_PROT_VALUE, 0, 0x7FFF);
566
567         return 0;
568 }
569
570
571 int regulator_init(void)
572 {
573         /*
574          * FIXME: turn on all DCDC/LDOs if need
575          */
576         return 0;
577 }
578
579 struct regulator_desc *regulator_get(void/*struct device*/ *dev, const char *id)
580 {
581         struct regulator_desc *desc =
582                 (struct regulator_desc *)(&__init_begin + 1);
583         while (desc < (struct regulator_desc *)&__init_end) {
584                 if (0 == strcmp(desc->name, id))
585                         return desc;
586                 desc++;
587         }
588         return 0;
589 }
590
591 int regulator_disable_all(void)
592 {
593         ANA_REG_OR(ANA_REG_GLB_LDO_PD_CTRL, 0x7ff);
594         ANA_REG_OR(ANA_REG_GLB_LDO_DCDC_PD, 0x1fff);
595         return 0;
596 }
597
598 int regulator_enable_all(void)
599 {
600         ANA_REG_BIC(ANA_REG_GLB_LDO_DCDC_PD, 0x1fff);
601         ANA_REG_BIC(ANA_REG_GLB_LDO_PD_CTRL, 0x7ff);
602         return 0;
603 }
604
605 int regulator_disable(const char con_id[])
606 {
607         struct regulator_desc *desc = regulator_get(0, con_id);
608         if (desc) {
609                 struct regulator_regs *regs = desc->regs;
610                 ANA_REG_OR(regs->pd_set, regs->pd_set_bit);
611         }
612         return 0;
613 }
614
615 int regulator_enable(const char con_id[])
616 {
617         struct regulator_desc *desc = regulator_get(0, con_id);
618         if (desc) {
619                 struct regulator_regs *regs = desc->regs;
620                 ANA_REG_BIC(regs->pd_set, regs->pd_set_bit);
621         }
622         return 0;
623 }
624
625 int regulator_set_voltage(const char con_id[], int to_vol)
626 {
627         int ret = 0;
628         struct regulator_desc *desc = regulator_get(0, con_id);
629         if (desc) {
630                 struct regulator_regs *regs = desc->regs;
631                 if (regs->typ == 2/*VDD_TYP_DCDC*/)
632                         ret = dcdc_set_voltage(desc, to_vol, 0);
633                 else if (regs->typ == 0/*VDD_TYP_LDO*/)
634                         ret = ldo_set_trimming(desc, 0, to_vol, 0);
635         }
636         return ret;
637 }
638
639 typedef struct {
640         uint16 ideal_vol;
641         const char name[14];
642 }vol_para_t;
643
644 #if defined(CONFIG_FDL2_BUILD)
645 vol_para_t **ppvol_para = 0x50000020;
646 #else
647 vol_para_t **ppvol_para = 0x50005c20;
648 #endif
649
650 static int get_vol_para_num(void)
651 {
652         int i = 0;
653
654         if (!(ppvol_para && *ppvol_para))
655                 return 0;
656
657         if(strcmp((*ppvol_para)[0].name, "volpara_begin") || (0xfaed != (*ppvol_para)[0].ideal_vol))
658                 return 0;
659
660         while(0 != strcmp((*ppvol_para)[i++].name, "volpara_end"))
661                 ;
662
663         return (i+1);
664 }
665
666 static vol_para_t * match_vol_para(const char* vol_name)
667 {
668         int i = 0;
669
670         BUG_ON(NULL == vol_name);
671
672         if (!(ppvol_para && *ppvol_para))
673                 return NULL;
674
675         if(strcmp((*ppvol_para)[0].name, "volpara_begin") || (0xfaed != (*ppvol_para)[0].ideal_vol))
676                 return NULL;
677
678         while(0 != strcmp((*ppvol_para)[i++].name, "volpara_end")) {
679                 if (0 == strcmp((*ppvol_para)[i].name, vol_name)) {
680                         debug0("%s name %s, ideal_vol %d\n", __func__, (*ppvol_para)[i].name, (*ppvol_para)[i].ideal_vol);
681                         return (vol_para_t*)(&(*ppvol_para)[i]);
682                 }
683         }
684
685         return NULL;
686 }
687
688 int regulator_default_get(const char con_id[])
689 {
690         vol_para_t * pvol_para = match_vol_para(con_id);
691
692         return (int)(pvol_para ? pvol_para->ideal_vol : 0);
693 }
694
695 void regulator_default_set(const char con_id[], int vol)
696 {
697         vol_para_t * pvol_para = match_vol_para(con_id);
698
699         if(pvol_para) {
700                 pvol_para->ideal_vol = vol;
701         }
702 }
703
704 int regulator_default_set_all(void)
705 {
706         int i = 0, ret = 0;
707
708         //dump & check all vol para
709         if (!(ppvol_para && *ppvol_para))
710                 return -1;
711
712         if(strcmp((*ppvol_para)[0].name, "volpara_begin") || (0xfaed != (*ppvol_para)[0].ideal_vol))
713                 return 0;
714
715         while(0 != strcmp((*ppvol_para)[i++].name, "volpara_end")) {
716                 debug("regu: [%d] %s : %d\n", i, (*ppvol_para)[i].name, (*ppvol_para)[i].ideal_vol);
717
718                 ret |= regulator_set_voltage((*ppvol_para)[i].name, (*ppvol_para)[i].ideal_vol);
719         }
720
721         return ret;
722 }
723
724 /********************************************************************
725 *
726 * regulator_get_calibration_mask - get dcdc/ldo calibration flag
727 *
728 //
729 //High 16bit: dcdc ctrl calibration flag
730 //
731 * bit[13] ~ bit[15] : reserved
732 * bit[12] : dcdcgen
733 * bit[11] : dcdcmem
734 * bit[10] : dcdcarm
735 * bit[9]   : dcdccore
736 * bit[8]   : vddrf0
737 * bit[7]   : vddemmccore
738 * bit[6]   : vddemmcio
739 * bit[5]   : vdddcxo
740 * bit[4]   : vddcon
741 * bit[3]   : vdd25
742 * bit[2]   : vdd28
743 * bit[1]   : vdd18
744 * bit[0]   : vddbg
745
746 //
747 //Low 16bit: ldo ctrl calibration flag
748 //
749 * bit[12] ~ bit[15] : reserved
750 * bit[11] : vddlpref
751 * bit[10] : dcdcwpa
752 * bit[9]   : vddclsg
753 * bit[8]   : vddusb
754 * bit[7]   : vddcammot
755 * bit[6]   : vddcamio
756 * bit[5]   : vddcamd
757 * bit[4]   : vddcama
758 * bit[3]   : vddsim2
759 * bit[2]   : vddsim1
760 * bit[1]   : vddsim0
761 * bit[0]   : vddsd
762 ********************************************************************/
763 u32 regulator_get_calibration_mask(void)
764 {
765         int len = get_vol_para_num();
766         volatile vol_para_t *pvol_para = (volatile vol_para_t *)(*ppvol_para);
767         volatile u32* pdebug_flag = (u32*)(&pvol_para[len-1]);
768
769         if(len > 2) {
770                 printf("%s, vol_para_tbl_len %d, ldo_pd_mask 0x%08x; \n", __func__, len, *pdebug_flag);
771                 return (*pdebug_flag);
772         }
773
774         return 0;
775 }
776