mfd: fusb302: change to host when connect type-c to standard-a cable
[firefly-linux-kernel-4.4.55.git] / drivers / mfd / twl6030-power.c
1 /*
2  * Handling for Resource Mapping for TWL6030 Family of chips
3  *
4  * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
5  *      Nishanth Menon
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10
11  * This program is distributed "as is" WITHOUT ANY WARRANTY of any
12  * kind, whether express or implied; without even the implied warranty
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  */
16
17 #include <linux/module.h>
18 #include <linux/pm.h>
19 #include <linux/i2c/twl.h>
20 #include <linux/platform_device.h>
21 #include <linux/suspend.h>
22 #include <linux/string.h>
23
24 #include <asm/mach-types.h>
25
26 #define VREG_GRP                0
27 #define MSK_TRANSITION_APP_SHIFT        0x5
28
29 static u8 dev_on_group;
30
31 /**
32  * struct twl6030_resource_map - describe the resource mapping for TWL6030
33  * @name:       name of the resource
34  * @res_id:     resource ID
35  * @base_addr: base address for TWL6030
36  * @base_addr: type of the Resources Assignment register for TWL6032
37  * base_addr = 0 for PREQx_RES_ASS_A register
38  * base_addr = 1 for PREQx_RES_ASS_B register
39  * base_addr = 2 for PREQx_RES_ASS_C register
40  * @group: which device group can control this resource?
41  * @mask: unused for TWL6030
42  * @mask: bit mask of the resource in PREQx_RES_ASS_x registers for TWL6032
43  */
44 struct twl6030_resource_map {
45         char *name;
46         u8 res_id;
47         u8 base_addr;
48         u8 group;
49         u8 mask;
50 };
51
52 #define TWL6030_RES_DATA(ID, NAME, BASE_ADDR, GROUP) \
53         {.res_id = ID, .name = NAME, .base_addr = BASE_ADDR,\
54         .group = GROUP, .mask = 0,}
55
56 #define TWL6032_RES_DATA(ID, NAME, BASE_ADDR, GROUP, MASK) \
57         {.res_id = ID, .name = NAME, .base_addr = BASE_ADDR,\
58         .group = GROUP, .mask = MASK,}
59
60 /* list of all s/w modifiable resources in TWL6030 */
61 static __initdata struct twl6030_resource_map twl6030_res_map[] = {
62         TWL6030_RES_DATA(RES_V1V29, "V1V29", 0x40, DEV_GRP_P1),
63         TWL6030_RES_DATA(RES_V1V8, "V1V8", 0x46, DEV_GRP_P1),
64         TWL6030_RES_DATA(RES_V2V1, "V2V1", 0x4c, DEV_GRP_P1),
65         TWL6030_RES_DATA(RES_VDD1, "CORE1", 0x52, DEV_GRP_P1),
66         TWL6030_RES_DATA(RES_VDD2, "CORE2", 0x58, DEV_GRP_P1),
67         TWL6030_RES_DATA(RES_VDD3, "CORE3", 0x5e, DEV_GRP_P1),
68         TWL6030_RES_DATA(RES_VMEM, "VMEM", 0x64, DEV_GRP_P1),
69         /* VANA cannot be modified */
70         TWL6030_RES_DATA(RES_VUAX1, "VUAX1", 0x84, DEV_GRP_P1),
71         TWL6030_RES_DATA(RES_VAUX2, "VAUX2", 0x88, DEV_GRP_P1),
72         TWL6030_RES_DATA(RES_VAUX3, "VAUX3", 0x8c, DEV_GRP_P1),
73         TWL6030_RES_DATA(RES_VCXIO, "VCXIO", 0x90, DEV_GRP_P1),
74         TWL6030_RES_DATA(RES_VDAC, "VDAC", 0x94, DEV_GRP_P1),
75         TWL6030_RES_DATA(RES_VMMC1, "VMMC", 0x98, DEV_GRP_P1),
76         TWL6030_RES_DATA(RES_VPP, "VPP", 0x9c, DEV_GRP_P1),
77         /* VRTC cannot be modified */
78         TWL6030_RES_DATA(RES_VUSBCP, "VUSB", 0xa0, DEV_GRP_P1),
79         TWL6030_RES_DATA(RES_VSIM, "VSIM", 0xa4, DEV_GRP_P1),
80         TWL6030_RES_DATA(RES_REGEN, "REGEN1", 0xad, DEV_GRP_P1),
81         TWL6030_RES_DATA(RES_REGEN2, "REGEN2", 0xb0, DEV_GRP_P1),
82         TWL6030_RES_DATA(RES_SYSEN, "SYSEN", 0xb3, DEV_GRP_P1),
83         /* NRES_PWRON cannot be modified */
84         /* 32KCLKAO cannot be modified */
85         TWL6030_RES_DATA(RES_32KCLKG, "32KCLKG", 0xbc, DEV_GRP_P1),
86         TWL6030_RES_DATA(RES_32KCLKAUDIO, "32KCLKAUDIO", 0xbf, DEV_GRP_P1),
87         /* BIAS cannot be modified */
88         /* VBATMIN_HI cannot be modified */
89         /* RC6MHZ cannot be modified */
90         /* TEMP cannot be modified */
91 };
92
93 /* list of all s/w modifiable resources in TWL6032 */
94 static __initdata struct twl6030_resource_map twl6032_res_map[] = {
95         /* PREQx_RES_ASS_A register resources */
96         TWL6032_RES_DATA(RES_LDOUSB, "VUSB", 0, DEV_GRP_P1, BIT(5)),
97         TWL6032_RES_DATA(RES_SMPS5, "SMPS5", 0, DEV_GRP_P1, BIT(4)),
98         TWL6032_RES_DATA(RES_SMPS5, "SMPS4", 0, DEV_GRP_P1, BIT(3)),
99         TWL6032_RES_DATA(RES_SMPS5, "SMPS3", 0, DEV_GRP_P1, BIT(2)),
100         TWL6032_RES_DATA(RES_SMPS5, "SMPS2", 0, DEV_GRP_P1, BIT(1)),
101         TWL6032_RES_DATA(RES_SMPS5, "SMPS1", 0, DEV_GRP_P1, BIT(0)),
102         /* PREQx_RES_ASS_B register resources */
103         TWL6032_RES_DATA(RES_LDOLN, "LDOLN", 1, DEV_GRP_P1, BIT(7)),
104         TWL6032_RES_DATA(RES_LDO7, "LDO7", 1, DEV_GRP_P1, BIT(6)),
105         TWL6032_RES_DATA(RES_LDO6, "LDO6", 1, DEV_GRP_P1, BIT(5)),
106         TWL6032_RES_DATA(RES_LDO5, "LDO5", 1, DEV_GRP_P1, BIT(4)),
107         TWL6032_RES_DATA(RES_LDO4, "LDO4", 1, DEV_GRP_P1, BIT(3)),
108         TWL6032_RES_DATA(RES_LDO3, "LDO3", 1, DEV_GRP_P1, BIT(2)),
109         TWL6032_RES_DATA(RES_LDO2, "LDO2", 1, DEV_GRP_P1, BIT(1)),
110         TWL6032_RES_DATA(RES_LDO1, "LDO1", 1, DEV_GRP_P1, BIT(0)),
111         /* PREQx_RES_ASS_C register resources */
112         TWL6032_RES_DATA(RES_VSYSMIN_HI, "VSYSMIN_HI", 2, DEV_GRP_P1, BIT(5)),
113         TWL6032_RES_DATA(RES_32KCLKG, "32KCLKG", 2, DEV_GRP_P1, BIT(4)),
114         TWL6032_RES_DATA(RES_32KCLKAUDIO, "32KCLKAUDIO", 2, DEV_GRP_P1, BIT(3)),
115         TWL6032_RES_DATA(RES_SYSEN, "SYSEN", 2, DEV_GRP_P1, BIT(2)),
116         TWL6032_RES_DATA(RES_REGEN2, "REGEN2", 2, DEV_GRP_P1, BIT(1)),
117         TWL6032_RES_DATA(RES_REGEN, "REGEN1", 2, DEV_GRP_P1, BIT(0)),
118 };
119
120 static struct twl4030_system_config twl6030_sys_config[] = {
121         {.name = "DEV_ON", .group =  DEV_GRP_P1,},
122 };
123
124 /* Actual power groups that TWL understands */
125 #define P3_GRP_6030     BIT(2)          /* secondary processor, modem, etc */
126 #define P2_GRP_6030     BIT(1)          /* "peripherals" */
127 #define P1_GRP_6030     BIT(0)          /* CPU/Linux */
128
129 static __init void twl6030_process_system_config(void)
130 {
131         u8 grp;
132         int r;
133         bool i = false;
134
135         struct twl4030_system_config *sys_config;
136         sys_config = twl6030_sys_config;
137
138         while (sys_config && sys_config->name) {
139                 if (!strcmp(sys_config->name, "DEV_ON")) {
140                         dev_on_group = sys_config->group;
141                         i = true;
142                         break;
143                 }
144                 sys_config++;
145         }
146         if (!i)
147                 pr_err("%s: Couldn't find DEV_ON resource configuration!"
148                         " MOD & CON group would be kept active.\n", __func__);
149
150         if (dev_on_group) {
151                 r = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &grp,
152                                 TWL6030_PHOENIX_DEV_ON);
153                 if (r) {
154                         pr_err("%s: Error(%d) reading  {addr=0x%02x}",
155                                 __func__, r, TWL6030_PHOENIX_DEV_ON);
156                         /*
157                          * On error resetting to 0, so that all the process
158                          * groups are kept active.
159                          */
160                         dev_on_group = 0;
161                 } else {
162                         /*
163                          * Unmapped processor groups are disabled by writing
164                          * 1 to corresponding group in DEV_ON.
165                          */
166                         grp |= (dev_on_group & DEV_GRP_P1) ? 0 : P1_GRP_6030;
167                         grp |= (dev_on_group & DEV_GRP_P2) ? 0 : P2_GRP_6030;
168                         grp |= (dev_on_group & DEV_GRP_P3) ? 0 : P3_GRP_6030;
169                         dev_on_group = grp;
170                 }
171
172                 /*
173                  *  unmask PREQ transition Executes ACT2SLP and SLP2ACT sleep
174                  *   sequence
175                  */
176                 r = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &grp,
177                                 TWL6030_PM_MASTER_MSK_TRANSITION);
178                 if (r) {
179                         pr_err("%s: Error (%d) reading"
180                                 " TWL6030_MSK_TRANSITION\n", __func__, r);
181                         return;
182                 }
183
184                 grp &= (dev_on_group << MSK_TRANSITION_APP_SHIFT);
185
186                 r = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, grp,
187                                         TWL6030_PM_MASTER_MSK_TRANSITION);
188                 if (r)
189                         pr_err("%s: Error (%d) writing to"
190                                 " TWL6030_MSK_TRANSITION\n", __func__, r);
191         }
192 }
193
194 #define DEV_GRP_P1_OFFSET       1
195 #define DEV_GRP_P2_OFFSET       4
196 #define DEV_GRP_P3_OFFSET       7
197
198 static __init void twl6030_program_map(unsigned long features)
199 {
200         struct twl6030_resource_map *res;
201         int r, i;
202
203         if (features & TWL6032_SUBCLASS) {
204                 /**
205                  * mask[0] = 0 for twl_i2c_write
206                  * mask[1]-mask[3]: PREQ1_RES_ASS_A - PREQ1_RES_ASS_C
207                  * mask[4]-mask[6]: PREQ2_RES_ASS_A - PREQ2_RES_ASS_C
208                  * mask[7]-mask[9]: PREQ3_RES_ASS_A - PREQ3_RES_ASS_C
209                  */
210                 u8 mask[10];
211
212                 res = twl6032_res_map;
213                 memset(&mask[0], 0, 10);
214
215                 for (i = 0; i < ARRAY_SIZE(twl6032_res_map); i++) {
216                         /* map back from generic device id to TWL6032 mask */
217                         mask[DEV_GRP_P1_OFFSET + res->base_addr] |= \
218                                 (res->group & DEV_GRP_P1) ? res->mask : 0;
219                         mask[DEV_GRP_P2_OFFSET + res->base_addr] |= \
220                                 (res->group & DEV_GRP_P2) ? res->mask : 0;
221                         mask[DEV_GRP_P3_OFFSET + res->base_addr] |= \
222                                 (res->group & DEV_GRP_P3) ? res->mask : 0;
223                         res++;
224                 }
225
226                 r = twl_i2c_write(TWL6030_MODULE_ID0, &mask[0],
227                         TWL6032_PREQ1_RES_ASS_A, 9);
228
229                 if (r)
230                         pr_err("%s: Error(%d) programming TWL6032 PREQ "
231                                 "Assignment Registers {start addr=0xd7}\n",
232                                 __func__, r);
233         } else {
234                 res = twl6030_res_map;
235                 for (i = 0; i < ARRAY_SIZE(twl6030_res_map); i++) {
236                         u8 grp = 0;
237
238                         /* map back from generic device id to TWL6030 ID */
239                         grp |= (res->group & DEV_GRP_P1) ? P1_GRP_6030 : 0;
240                         grp |= (res->group & DEV_GRP_P2) ? P2_GRP_6030 : 0;
241                         grp |= (res->group & DEV_GRP_P3) ? P3_GRP_6030 : 0;
242
243                         r = twl_i2c_write_u8(TWL6030_MODULE_ID0, res->group,
244                                              res->base_addr);
245                         if (r)
246                                 pr_err("%s: Error(%d) programming map %s {"
247                                         "addr=0x%02x},grp=0x%02X\n", __func__,
248                                         r, res->name, res->base_addr,
249                                         res->group);
250                         res++;
251                 }
252         }
253 }
254
255 static __init void twl6030_update_system_map
256                         (struct twl4030_system_config *sys_list)
257 {
258         int i;
259         struct twl4030_system_config *sys_res;
260
261         while (sys_list && sys_list->name)  {
262                 sys_res = twl6030_sys_config;
263                 for (i = 0; i < ARRAY_SIZE(twl6030_sys_config); i++) {
264                         if (!strcmp(sys_res->name, sys_list->name))
265                                 sys_res->group = sys_list->group &
266                                         (DEV_GRP_P1 | DEV_GRP_P2 | DEV_GRP_P3);
267                         sys_res++;
268                 }
269                 sys_list++;
270         }
271 }
272
273 static __init void twl6030_update_map(struct twl4030_resconfig *res_list, \
274                                         unsigned long features)
275 {
276         int i, res_idx = 0;
277         struct twl6030_resource_map *res;
278         struct twl6030_resource_map *cur_twl6030_res = twl6030_res_map;
279         int twl6030_res_cnt = ARRAY_SIZE(twl6030_res_map);
280
281         if (features & TWL6032_SUBCLASS) {
282                 cur_twl6030_res = twl6032_res_map;
283                 twl6030_res_cnt = ARRAY_SIZE(twl6032_res_map);
284         }
285
286         while (res_list->resource != TWL4030_RESCONFIG_UNDEF) {
287                 res = cur_twl6030_res;
288                 for (i = 0; i < twl6030_res_cnt; i++) {
289                         if (res->res_id == res_list->resource) {
290                                 res->group = res_list->devgroup &
291                                     (DEV_GRP_P1 | DEV_GRP_P2 | DEV_GRP_P3);
292                                 break;
293                         }
294                         res++;
295                 }
296
297                 if (i == twl6030_res_cnt) {
298                         pr_err("%s: in platform_data resource index %d, cannot"
299                                " find match for resource 0x%02x. NO Update!\n",
300                                __func__, res_idx, res_list->resource);
301                 }
302                 res_list++;
303                 res_idx++;
304         }
305 }
306
307
308 static int twl6030_power_notifier_cb(struct notifier_block *notifier,
309                                         unsigned long pm_event,  void *unused)
310 {
311         int r = 0;
312
313         switch (pm_event) {
314         case PM_SUSPEND_PREPARE:
315                 r = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, dev_on_group,
316                                 TWL6030_PHOENIX_DEV_ON);
317                 if (r)
318                         pr_err("%s: Error(%d) programming {addr=0x%02x}",
319                                 __func__, r, TWL6030_PHOENIX_DEV_ON);
320                 break;
321         }
322
323         return notifier_from_errno(r);
324 }
325
326 static struct notifier_block twl6030_power_pm_notifier = {
327         .notifier_call = twl6030_power_notifier_cb,
328 };
329
330 /**
331  * twl6030_power_init() - Update the power map to reflect connectivity of board
332  * @power_data: power resource map to update (OPTIONAL) - use this if a resource
333  *              is used by other devices other than APP (DEV_GRP_P1)
334  */
335 void __init twl6030_power_init(struct twl4030_power_data *power_data, \
336                                         unsigned long features)
337 {
338         int r;
339
340         if (power_data && (!power_data->resource_config &&
341                                         !power_data->sys_config)) {
342                 pr_err("%s: power data from platform without configuration!\n",
343                        __func__);
344                 return;
345         }
346
347         if (power_data && power_data->resource_config)
348                 twl6030_update_map(power_data->resource_config, features);
349
350         if (power_data && power_data->sys_config)
351                 twl6030_update_system_map(power_data->sys_config);
352
353         twl6030_process_system_config();
354
355         twl6030_program_map(features);
356
357         r = register_pm_notifier(&twl6030_power_pm_notifier);
358         if (r)
359                 pr_err("%s: twl6030 power registration failed!\n", __func__);
360
361         return;
362 }