2 * Handling for Resource Mapping for TWL6030 Family of chips
4 * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
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.
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.
17 #include <linux/module.h>
19 #include <linux/i2c/twl.h>
20 #include <linux/platform_device.h>
21 #include <linux/suspend.h>
22 #include <linux/string.h>
24 #include <asm/mach-types.h>
27 #define MSK_TRANSITION_APP_SHIFT 0x5
29 static u8 dev_on_group;
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
44 struct twl6030_resource_map {
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,}
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,}
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 */
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)),
120 static struct twl4030_system_config twl6030_sys_config[] = {
121 {.name = "DEV_ON", .group = DEV_GRP_P1,},
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 */
129 static __init void twl6030_process_system_config(void)
135 struct twl4030_system_config *sys_config;
136 sys_config = twl6030_sys_config;
138 while (sys_config && sys_config->name) {
139 if (!strcmp(sys_config->name, "DEV_ON")) {
140 dev_on_group = sys_config->group;
147 pr_err("%s: Couldn't find DEV_ON resource configuration!"
148 " MOD & CON group would be kept active.\n", __func__);
151 r = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &grp,
152 TWL6030_PHOENIX_DEV_ON);
154 pr_err("%s: Error(%d) reading {addr=0x%02x}",
155 __func__, r, TWL6030_PHOENIX_DEV_ON);
157 * On error resetting to 0, so that all the process
158 * groups are kept active.
163 * Unmapped processor groups are disabled by writing
164 * 1 to corresponding group in DEV_ON.
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;
173 * unmask PREQ transition Executes ACT2SLP and SLP2ACT sleep
176 r = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &grp,
177 TWL6030_PM_MASTER_MSK_TRANSITION);
179 pr_err("%s: Error (%d) reading"
180 " TWL6030_MSK_TRANSITION\n", __func__, r);
184 grp &= (dev_on_group << MSK_TRANSITION_APP_SHIFT);
186 r = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, grp,
187 TWL6030_PM_MASTER_MSK_TRANSITION);
189 pr_err("%s: Error (%d) writing to"
190 " TWL6030_MSK_TRANSITION\n", __func__, r);
194 #define DEV_GRP_P1_OFFSET 1
195 #define DEV_GRP_P2_OFFSET 4
196 #define DEV_GRP_P3_OFFSET 7
198 static __init void twl6030_program_map(unsigned long features)
200 struct twl6030_resource_map *res;
203 if (features & TWL6032_SUBCLASS) {
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
212 res = twl6032_res_map;
213 memset(&mask[0], 0, 10);
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;
226 r = twl_i2c_write(TWL6030_MODULE_ID0, &mask[0],
227 TWL6032_PREQ1_RES_ASS_A, 9);
230 pr_err("%s: Error(%d) programming TWL6032 PREQ "
231 "Assignment Registers {start addr=0xd7}\n",
234 res = twl6030_res_map;
235 for (i = 0; i < ARRAY_SIZE(twl6030_res_map); i++) {
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;
243 r = twl_i2c_write_u8(TWL6030_MODULE_ID0, res->group,
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,
255 static __init void twl6030_update_system_map
256 (struct twl4030_system_config *sys_list)
259 struct twl4030_system_config *sys_res;
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);
273 static __init void twl6030_update_map(struct twl4030_resconfig *res_list, \
274 unsigned long features)
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);
281 if (features & TWL6032_SUBCLASS) {
282 cur_twl6030_res = twl6032_res_map;
283 twl6030_res_cnt = ARRAY_SIZE(twl6032_res_map);
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);
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);
308 static int twl6030_power_notifier_cb(struct notifier_block *notifier,
309 unsigned long pm_event, void *unused)
314 case PM_SUSPEND_PREPARE:
315 r = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, dev_on_group,
316 TWL6030_PHOENIX_DEV_ON);
318 pr_err("%s: Error(%d) programming {addr=0x%02x}",
319 __func__, r, TWL6030_PHOENIX_DEV_ON);
323 return notifier_from_errno(r);
326 static struct notifier_block twl6030_power_pm_notifier = {
327 .notifier_call = twl6030_power_notifier_cb,
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)
335 void __init twl6030_power_init(struct twl4030_power_data *power_data, \
336 unsigned long features)
340 if (power_data && (!power_data->resource_config &&
341 !power_data->sys_config)) {
342 pr_err("%s: power data from platform without configuration!\n",
347 if (power_data && power_data->resource_config)
348 twl6030_update_map(power_data->resource_config, features);
350 if (power_data && power_data->sys_config)
351 twl6030_update_system_map(power_data->sys_config);
353 twl6030_process_system_config();
355 twl6030_program_map(features);
357 r = register_pm_notifier(&twl6030_power_pm_notifier);
359 pr_err("%s: twl6030 power registration failed!\n", __func__);