aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorThara Gopinath <thara@ti.com>2010-05-29 12:32:22 -0400
committerKevin Hilman <khilman@deeprootsystems.com>2010-12-22 17:31:35 -0500
commit984aa6dbf4ca5be806fee217311c9cc68e8f2e88 (patch)
tree43092ea19c597efdaff5f7f7e2a9cc9cd59527fc /arch/arm
parent3b92408c7dfeb918fdd2f9fadc73177a59ad621c (diff)
OMAP3: PM: Adding smartreflex driver support.
SmartReflex modules do adaptive voltage control for real-time voltage adjustments. With Smartreflex the power supply voltage can be adapted to the silicon performance(manufacturing process, temperature induced performance, age induced performance etc). There are differnet classes of smartreflex implementation. Class-0: Manufacturing Test Calibration Class-1: Boot-Time Software Calibration Class-2: Continuous Software Calibration Class-3: Continuous Hardware Calibration Class-4: Fully Integrated Power Management OMAP3 has two smartreflex modules one associated with VDD MPU and the other associated with VDD CORE. This patch adds support for smartreflex driver. The driver is designed for Class-1 , Class-2 and Class-3 support and is a platform driver. Smartreflex driver can be enabled through a Kconfig option "SmartReflex support" under "System type"->"TI OMAP implementations" menu. Smartreflex autocompensation feature can be enabled runtime through a debug fs option. To enable smartreflex autocompensation feature echo 1 > /debug/voltage/vdd_<X>/smartreflex/autocomp To disable smartreflex autocompensation feature echo 0 > /debug/voltage/vdd_<X>/smartreflex/autocomp where X can be mpu, core , iva etc. This patch contains code originally in linux omap pm branch. Major contributors to this driver are Lesly A M, Rajendra Nayak, Kalle Jokiniemi, Paul Walmsley, Nishant Menon, Kevin Hilman. Signed-off-by: Thara Gopinath <thara@ti.com> Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mach-omap2/Makefile1
-rw-r--r--arch/arm/mach-omap2/smartreflex.c983
-rw-r--r--arch/arm/plat-omap/Kconfig22
-rw-r--r--arch/arm/plat-omap/include/plat/smartreflex.h245
4 files changed, 1251 insertions, 0 deletions
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index da7d53690d9..98c6309c250 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -62,6 +62,7 @@ obj-$(CONFIG_ARCH_OMAP3) += pm34xx.o sleep34xx.o voltage.o \
62 cpuidle34xx.o pm_bus.o 62 cpuidle34xx.o pm_bus.o
63obj-$(CONFIG_ARCH_OMAP4) += pm44xx.o pm_bus.o 63obj-$(CONFIG_ARCH_OMAP4) += pm44xx.o pm_bus.o
64obj-$(CONFIG_PM_DEBUG) += pm-debug.o 64obj-$(CONFIG_PM_DEBUG) += pm-debug.o
65obj-$(CONFIG_OMAP_SMARTREFLEX) += smartreflex.o
65 66
66AFLAGS_sleep24xx.o :=-Wa,-march=armv6 67AFLAGS_sleep24xx.o :=-Wa,-march=armv6
67AFLAGS_sleep34xx.o :=-Wa,-march=armv7-a 68AFLAGS_sleep34xx.o :=-Wa,-march=armv7-a
diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
new file mode 100644
index 00000000000..eee23d0f50d
--- /dev/null
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -0,0 +1,983 @@
1/*
2 * OMAP SmartReflex Voltage Control
3 *
4 * Author: Thara Gopinath <thara@ti.com>
5 *
6 * Copyright (C) 2010 Texas Instruments, Inc.
7 * Thara Gopinath <thara@ti.com>
8 *
9 * Copyright (C) 2008 Nokia Corporation
10 * Kalle Jokiniemi
11 *
12 * Copyright (C) 2007 Texas Instruments, Inc.
13 * Lesly A M <x0080970@ti.com>
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License version 2 as
17 * published by the Free Software Foundation.
18 */
19
20#include <linux/interrupt.h>
21#include <linux/clk.h>
22#include <linux/io.h>
23#include <linux/debugfs.h>
24#include <linux/delay.h>
25#include <linux/slab.h>
26#include <linux/pm_runtime.h>
27
28#include <plat/common.h>
29#include <plat/smartreflex.h>
30
31#include "pm.h"
32
33#define SMARTREFLEX_NAME_LEN 16
34#define SR_DISABLE_TIMEOUT 200
35
36struct omap_sr {
37 int srid;
38 int ip_type;
39 int nvalue_count;
40 bool autocomp_active;
41 u32 clk_length;
42 u32 err_weight;
43 u32 err_minlimit;
44 u32 err_maxlimit;
45 u32 accum_data;
46 u32 senn_avgweight;
47 u32 senp_avgweight;
48 u32 senp_mod;
49 u32 senn_mod;
50 unsigned int irq;
51 void __iomem *base;
52 struct platform_device *pdev;
53 struct list_head node;
54 struct omap_sr_nvalue_table *nvalue_table;
55 struct voltagedomain *voltdm;
56};
57
58/* sr_list contains all the instances of smartreflex module */
59static LIST_HEAD(sr_list);
60
61static struct omap_sr_class_data *sr_class;
62static struct omap_sr_pmic_data *sr_pmic_data;
63
64static inline void sr_write_reg(struct omap_sr *sr, unsigned offset, u32 value)
65{
66 __raw_writel(value, (sr->base + offset));
67}
68
69static inline void sr_modify_reg(struct omap_sr *sr, unsigned offset, u32 mask,
70 u32 value)
71{
72 u32 reg_val;
73 u32 errconfig_offs = 0, errconfig_mask = 0;
74
75 reg_val = __raw_readl(sr->base + offset);
76 reg_val &= ~mask;
77
78 /*
79 * Smartreflex error config register is special as it contains
80 * certain status bits which if written a 1 into means a clear
81 * of those bits. So in order to make sure no accidental write of
82 * 1 happens to those status bits, do a clear of them in the read
83 * value. This mean this API doesn't rewrite values in these bits
84 * if they are currently set, but does allow the caller to write
85 * those bits.
86 */
87 if (sr->ip_type == SR_TYPE_V1) {
88 errconfig_offs = ERRCONFIG_V1;
89 errconfig_mask = ERRCONFIG_STATUS_V1_MASK;
90 } else if (sr->ip_type == SR_TYPE_V2) {
91 errconfig_offs = ERRCONFIG_V2;
92 errconfig_mask = ERRCONFIG_VPBOUNDINTST_V2;
93 }
94
95 if (offset == errconfig_offs)
96 reg_val &= ~errconfig_mask;
97
98 reg_val |= value;
99
100 __raw_writel(reg_val, (sr->base + offset));
101}
102
103static inline u32 sr_read_reg(struct omap_sr *sr, unsigned offset)
104{
105 return __raw_readl(sr->base + offset);
106}
107
108static struct omap_sr *_sr_lookup(struct voltagedomain *voltdm)
109{
110 struct omap_sr *sr_info;
111
112 if (!voltdm) {
113 pr_err("%s: Null voltage domain passed!\n", __func__);
114 return ERR_PTR(-EINVAL);
115 }
116
117 list_for_each_entry(sr_info, &sr_list, node) {
118 if (voltdm == sr_info->voltdm)
119 return sr_info;
120 }
121
122 return ERR_PTR(-ENODATA);
123}
124
125static irqreturn_t sr_interrupt(int irq, void *data)
126{
127 struct omap_sr *sr_info = (struct omap_sr *)data;
128 u32 status = 0;
129
130 if (sr_info->ip_type == SR_TYPE_V1) {
131 /* Read the status bits */
132 status = sr_read_reg(sr_info, ERRCONFIG_V1);
133
134 /* Clear them by writing back */
135 sr_write_reg(sr_info, ERRCONFIG_V1, status);
136 } else if (sr_info->ip_type == SR_TYPE_V2) {
137 /* Read the status bits */
138 sr_read_reg(sr_info, IRQSTATUS);
139
140 /* Clear them by writing back */
141 sr_write_reg(sr_info, IRQSTATUS, status);
142 }
143
144 if (sr_class->class_type == SR_CLASS2 && sr_class->notify)
145 sr_class->notify(sr_info->voltdm, status);
146
147 return IRQ_HANDLED;
148}
149
150static void sr_set_clk_length(struct omap_sr *sr)
151{
152 struct clk *sys_ck;
153 u32 sys_clk_speed;
154
155 sys_ck = clk_get(NULL, "sys_ck");
156 if (IS_ERR(sys_ck)) {
157 dev_err(&sr->pdev->dev, "%s: unable to get sys clk\n",
158 __func__);
159 return;
160 }
161 sys_clk_speed = clk_get_rate(sys_ck);
162 clk_put(sys_ck);
163
164 switch (sys_clk_speed) {
165 case 12000000:
166 sr->clk_length = SRCLKLENGTH_12MHZ_SYSCLK;
167 break;
168 case 13000000:
169 sr->clk_length = SRCLKLENGTH_13MHZ_SYSCLK;
170 break;
171 case 19200000:
172 sr->clk_length = SRCLKLENGTH_19MHZ_SYSCLK;
173 break;
174 case 26000000:
175 sr->clk_length = SRCLKLENGTH_26MHZ_SYSCLK;
176 break;
177 case 38400000:
178 sr->clk_length = SRCLKLENGTH_38MHZ_SYSCLK;
179 break;
180 default:
181 dev_err(&sr->pdev->dev, "%s: Invalid sysclk value: %d\n",
182 __func__, sys_clk_speed);
183 break;
184 }
185}
186
187static void sr_set_regfields(struct omap_sr *sr)
188{
189 /*
190 * For time being these values are defined in smartreflex.h
191 * and populated during init. May be they can be moved to board
192 * file or pmic specific data structure. In that case these structure
193 * fields will have to be populated using the pdata or pmic structure.
194 */
195 if (cpu_is_omap34xx()) {
196 sr->err_weight = OMAP3430_SR_ERRWEIGHT;
197 sr->err_maxlimit = OMAP3430_SR_ERRMAXLIMIT;
198 sr->accum_data = OMAP3430_SR_ACCUMDATA;
199 if (!(strcmp(sr->voltdm->name, "mpu"))) {
200 sr->senn_avgweight = OMAP3430_SR1_SENNAVGWEIGHT;
201 sr->senp_avgweight = OMAP3430_SR1_SENPAVGWEIGHT;
202 } else {
203 sr->senn_avgweight = OMAP3430_SR2_SENNAVGWEIGHT;
204 sr->senp_avgweight = OMAP3430_SR2_SENPAVGWEIGHT;
205 }
206 }
207}
208
209static void sr_start_vddautocomp(struct omap_sr *sr)
210{
211 if (!sr_class || !(sr_class->enable) || !(sr_class->configure)) {
212 dev_warn(&sr->pdev->dev,
213 "%s: smartreflex class driver not registered\n",
214 __func__);
215 return;
216 }
217
218 if (!sr_class->enable(sr->voltdm))
219 sr->autocomp_active = true;
220}
221
222static void sr_stop_vddautocomp(struct omap_sr *sr)
223{
224 if (!sr_class || !(sr_class->disable)) {
225 dev_warn(&sr->pdev->dev,
226 "%s: smartreflex class driver not registered\n",
227 __func__);
228 return;
229 }
230
231 if (sr->autocomp_active) {
232 sr_class->disable(sr->voltdm, 1);
233 sr->autocomp_active = false;
234 }
235}
236
237/*
238 * This function handles the intializations which have to be done
239 * only when both sr device and class driver regiter has
240 * completed. This will be attempted to be called from both sr class
241 * driver register and sr device intializtion API's. Only one call
242 * will ultimately succeed.
243 *
244 * Currenly this function registers interrrupt handler for a particular SR
245 * if smartreflex class driver is already registered and has
246 * requested for interrupts and the SR interrupt line in present.
247 */
248static int sr_late_init(struct omap_sr *sr_info)
249{
250 char *name;
251 struct omap_sr_data *pdata = sr_info->pdev->dev.platform_data;
252 struct resource *mem;
253 int ret = 0;
254
255 if (sr_class->class_type == SR_CLASS2 &&
256 sr_class->notify_flags && sr_info->irq) {
257
258 name = kzalloc(SMARTREFLEX_NAME_LEN + 1, GFP_KERNEL);
259 strcpy(name, "sr_");
260 strcat(name, sr_info->voltdm->name);
261 ret = request_irq(sr_info->irq, sr_interrupt,
262 0, name, (void *)sr_info);
263 if (ret)
264 goto error;
265 }
266
267 if (pdata && pdata->enable_on_init)
268 sr_start_vddautocomp(sr_info);
269
270 return ret;
271
272error:
273 iounmap(sr_info->base);
274 mem = platform_get_resource(sr_info->pdev, IORESOURCE_MEM, 0);
275 release_mem_region(mem->start, resource_size(mem));
276 list_del(&sr_info->node);
277 dev_err(&sr_info->pdev->dev, "%s: ERROR in registering"
278 "interrupt handler. Smartreflex will"
279 "not function as desired\n", __func__);
280 kfree(sr_info);
281 return ret;
282}
283
284static void sr_v1_disable(struct omap_sr *sr)
285{
286 int timeout = 0;
287
288 /* Enable MCUDisableAcknowledge interrupt */
289 sr_modify_reg(sr, ERRCONFIG_V1,
290 ERRCONFIG_MCUDISACKINTEN, ERRCONFIG_MCUDISACKINTEN);
291
292 /* SRCONFIG - disable SR */
293 sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0x0);
294
295 /* Disable all other SR interrupts and clear the status */
296 sr_modify_reg(sr, ERRCONFIG_V1,
297 (ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUVALIDINTEN |
298 ERRCONFIG_MCUBOUNDINTEN | ERRCONFIG_VPBOUNDINTEN_V1),
299 (ERRCONFIG_MCUACCUMINTST | ERRCONFIG_MCUVALIDINTST |
300 ERRCONFIG_MCUBOUNDINTST |
301 ERRCONFIG_VPBOUNDINTST_V1));
302
303 /*
304 * Wait for SR to be disabled.
305 * wait until ERRCONFIG.MCUDISACKINTST = 1. Typical latency is 1us.
306 */
307 omap_test_timeout((sr_read_reg(sr, ERRCONFIG_V1) &
308 ERRCONFIG_MCUDISACKINTST), SR_DISABLE_TIMEOUT,
309 timeout);
310
311 if (timeout >= SR_DISABLE_TIMEOUT)
312 dev_warn(&sr->pdev->dev, "%s: Smartreflex disable timedout\n",
313 __func__);
314
315 /* Disable MCUDisableAcknowledge interrupt & clear pending interrupt */
316 sr_modify_reg(sr, ERRCONFIG_V1, ERRCONFIG_MCUDISACKINTEN,
317 ERRCONFIG_MCUDISACKINTST);
318}
319
320static void sr_v2_disable(struct omap_sr *sr)
321{
322 int timeout = 0;
323
324 /* Enable MCUDisableAcknowledge interrupt */
325 sr_write_reg(sr, IRQENABLE_SET, IRQENABLE_MCUDISABLEACKINT);
326
327 /* SRCONFIG - disable SR */
328 sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0x0);
329
330 /* Disable all other SR interrupts and clear the status */
331 sr_modify_reg(sr, ERRCONFIG_V2, ERRCONFIG_VPBOUNDINTEN_V2,
332 ERRCONFIG_VPBOUNDINTST_V2);
333 sr_write_reg(sr, IRQENABLE_CLR, (IRQENABLE_MCUACCUMINT |
334 IRQENABLE_MCUVALIDINT |
335 IRQENABLE_MCUBOUNDSINT));
336 sr_write_reg(sr, IRQSTATUS, (IRQSTATUS_MCUACCUMINT |
337 IRQSTATUS_MCVALIDINT |
338 IRQSTATUS_MCBOUNDSINT));
339
340 /*
341 * Wait for SR to be disabled.
342 * wait until IRQSTATUS.MCUDISACKINTST = 1. Typical latency is 1us.
343 */
344 omap_test_timeout((sr_read_reg(sr, IRQSTATUS) &
345 IRQSTATUS_MCUDISABLEACKINT), SR_DISABLE_TIMEOUT,
346 timeout);
347
348 if (timeout >= SR_DISABLE_TIMEOUT)
349 dev_warn(&sr->pdev->dev, "%s: Smartreflex disable timedout\n",
350 __func__);
351
352 /* Disable MCUDisableAcknowledge interrupt & clear pending interrupt */
353 sr_write_reg(sr, IRQENABLE_CLR, IRQENABLE_MCUDISABLEACKINT);
354 sr_write_reg(sr, IRQSTATUS, IRQSTATUS_MCUDISABLEACKINT);
355}
356
357static u32 sr_retrieve_nvalue(struct omap_sr *sr, u32 efuse_offs)
358{
359 int i;
360
361 if (!sr->nvalue_table) {
362 dev_warn(&sr->pdev->dev, "%s: Missing ntarget value table\n",
363 __func__);
364 return 0;
365 }
366
367 for (i = 0; i < sr->nvalue_count; i++) {
368 if (sr->nvalue_table[i].efuse_offs == efuse_offs)
369 return sr->nvalue_table[i].nvalue;
370 }
371
372 return 0;
373}
374
375/* Public Functions */
376
377/**
378 * sr_configure_errgen() - Configures the smrtreflex to perform AVS using the
379 * error generator module.
380 * @voltdm: VDD pointer to which the SR module to be configured belongs to.
381 *
382 * This API is to be called from the smartreflex class driver to
383 * configure the error generator module inside the smartreflex module.
384 * SR settings if using the ERROR module inside Smartreflex.
385 * SR CLASS 3 by default uses only the ERROR module where as
386 * SR CLASS 2 can choose between ERROR module and MINMAXAVG
387 * module. Returns 0 on success and error value in case of failure.
388 */
389int sr_configure_errgen(struct voltagedomain *voltdm)
390{
391 u32 sr_config, sr_errconfig, errconfig_offs, vpboundint_en;
392 u32 vpboundint_st, senp_en = 0, senn_en = 0;
393 u8 senp_shift, senn_shift;
394 struct omap_sr *sr = _sr_lookup(voltdm);
395
396 if (IS_ERR(sr)) {
397 pr_warning("%s: omap_sr struct for sr_%s not found\n",
398 __func__, voltdm->name);
399 return -EINVAL;
400 }
401
402 if (!sr->clk_length)
403 sr_set_clk_length(sr);
404
405 senp_en = sr->senp_mod;
406 senn_en = sr->senn_mod;
407
408 sr_config = (sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
409 SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN;
410
411 if (sr->ip_type == SR_TYPE_V1) {
412 sr_config |= SRCONFIG_DELAYCTRL;
413 senn_shift = SRCONFIG_SENNENABLE_V1_SHIFT;
414 senp_shift = SRCONFIG_SENPENABLE_V1_SHIFT;
415 errconfig_offs = ERRCONFIG_V1;
416 vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V1;
417 vpboundint_st = ERRCONFIG_VPBOUNDINTST_V1;
418 } else if (sr->ip_type == SR_TYPE_V2) {
419 senn_shift = SRCONFIG_SENNENABLE_V2_SHIFT;
420 senp_shift = SRCONFIG_SENPENABLE_V2_SHIFT;
421 errconfig_offs = ERRCONFIG_V2;
422 vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V2;
423 vpboundint_st = ERRCONFIG_VPBOUNDINTST_V2;
424 } else {
425 dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex"
426 "module without specifying the ip\n", __func__);
427 return -EINVAL;
428 }
429
430 sr_config |= ((senn_en << senn_shift) | (senp_en << senp_shift));
431 sr_write_reg(sr, SRCONFIG, sr_config);
432 sr_errconfig = (sr->err_weight << ERRCONFIG_ERRWEIGHT_SHIFT) |
433 (sr->err_maxlimit << ERRCONFIG_ERRMAXLIMIT_SHIFT) |
434 (sr->err_minlimit << ERRCONFIG_ERRMINLIMIT_SHIFT);
435 sr_modify_reg(sr, errconfig_offs, (SR_ERRWEIGHT_MASK |
436 SR_ERRMAXLIMIT_MASK | SR_ERRMINLIMIT_MASK),
437 sr_errconfig);
438
439 /* Enabling the interrupts if the ERROR module is used */
440 sr_modify_reg(sr, errconfig_offs,
441 vpboundint_en, (vpboundint_en | vpboundint_st));
442
443 return 0;
444}
445
446/**
447 * sr_configure_minmax() - Configures the smrtreflex to perform AVS using the
448 * minmaxavg module.
449 * @voltdm: VDD pointer to which the SR module to be configured belongs to.
450 *
451 * This API is to be called from the smartreflex class driver to
452 * configure the minmaxavg module inside the smartreflex module.
453 * SR settings if using the ERROR module inside Smartreflex.
454 * SR CLASS 3 by default uses only the ERROR module where as
455 * SR CLASS 2 can choose between ERROR module and MINMAXAVG
456 * module. Returns 0 on success and error value in case of failure.
457 */
458int sr_configure_minmax(struct voltagedomain *voltdm)
459{
460 u32 sr_config, sr_avgwt;
461 u32 senp_en = 0, senn_en = 0;
462 u8 senp_shift, senn_shift;
463 struct omap_sr *sr = _sr_lookup(voltdm);
464
465 if (IS_ERR(sr)) {
466 pr_warning("%s: omap_sr struct for sr_%s not found\n",
467 __func__, voltdm->name);
468 return -EINVAL;
469 }
470
471 if (!sr->clk_length)
472 sr_set_clk_length(sr);
473
474 senp_en = sr->senp_mod;
475 senn_en = sr->senn_mod;
476
477 sr_config = (sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
478 SRCONFIG_SENENABLE |
479 (sr->accum_data << SRCONFIG_ACCUMDATA_SHIFT);
480
481 if (sr->ip_type == SR_TYPE_V1) {
482 sr_config |= SRCONFIG_DELAYCTRL;
483 senn_shift = SRCONFIG_SENNENABLE_V1_SHIFT;
484 senp_shift = SRCONFIG_SENPENABLE_V1_SHIFT;
485 } else if (sr->ip_type == SR_TYPE_V2) {
486 senn_shift = SRCONFIG_SENNENABLE_V2_SHIFT;
487 senp_shift = SRCONFIG_SENPENABLE_V2_SHIFT;
488 } else {
489 dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex"
490 "module without specifying the ip\n", __func__);
491 return -EINVAL;
492 }
493
494 sr_config |= ((senn_en << senn_shift) | (senp_en << senp_shift));
495 sr_write_reg(sr, SRCONFIG, sr_config);
496 sr_avgwt = (sr->senp_avgweight << AVGWEIGHT_SENPAVGWEIGHT_SHIFT) |
497 (sr->senn_avgweight << AVGWEIGHT_SENNAVGWEIGHT_SHIFT);
498 sr_write_reg(sr, AVGWEIGHT, sr_avgwt);
499
500 /*
501 * Enabling the interrupts if MINMAXAVG module is used.
502 * TODO: check if all the interrupts are mandatory
503 */
504 if (sr->ip_type == SR_TYPE_V1) {
505 sr_modify_reg(sr, ERRCONFIG_V1,
506 (ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUVALIDINTEN |
507 ERRCONFIG_MCUBOUNDINTEN),
508 (ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUACCUMINTST |
509 ERRCONFIG_MCUVALIDINTEN | ERRCONFIG_MCUVALIDINTST |
510 ERRCONFIG_MCUBOUNDINTEN | ERRCONFIG_MCUBOUNDINTST));
511 } else if (sr->ip_type == SR_TYPE_V2) {
512 sr_write_reg(sr, IRQSTATUS,
513 IRQSTATUS_MCUACCUMINT | IRQSTATUS_MCVALIDINT |
514 IRQSTATUS_MCBOUNDSINT | IRQSTATUS_MCUDISABLEACKINT);
515 sr_write_reg(sr, IRQENABLE_SET,
516 IRQENABLE_MCUACCUMINT | IRQENABLE_MCUVALIDINT |
517 IRQENABLE_MCUBOUNDSINT | IRQENABLE_MCUDISABLEACKINT);
518 }
519
520 return 0;
521}
522
523/**
524 * sr_enable() - Enables the smartreflex module.
525 * @voltdm: VDD pointer to which the SR module to be configured belongs to.
526 * @volt: The voltage at which the Voltage domain associated with
527 * the smartreflex module is operating at.
528 * This is required only to program the correct Ntarget value.
529 *
530 * This API is to be called from the smartreflex class driver to
531 * enable a smartreflex module. Returns 0 on success. Returns error
532 * value if the voltage passed is wrong or if ntarget value is wrong.
533 */
534int sr_enable(struct voltagedomain *voltdm, unsigned long volt)
535{
536 u32 nvalue_reciprocal;
537 struct omap_volt_data *volt_data;
538 struct omap_sr *sr = _sr_lookup(voltdm);
539 int ret;
540
541 if (IS_ERR(sr)) {
542 pr_warning("%s: omap_sr struct for sr_%s not found\n",
543 __func__, voltdm->name);
544 return -EINVAL;
545 }
546
547 volt_data = omap_voltage_get_voltdata(sr->voltdm, volt);
548
549 if (IS_ERR(volt_data)) {
550 dev_warn(&sr->pdev->dev, "%s: Unable to get voltage table"
551 "for nominal voltage %ld\n", __func__, volt);
552 return -ENODATA;
553 }
554
555 nvalue_reciprocal = sr_retrieve_nvalue(sr, volt_data->sr_efuse_offs);
556
557 if (!nvalue_reciprocal) {
558 dev_warn(&sr->pdev->dev, "%s: NVALUE = 0 at voltage %ld\n",
559 __func__, volt);
560 return -ENODATA;
561 }
562
563 /* errminlimit is opp dependent and hence linked to voltage */
564 sr->err_minlimit = volt_data->sr_errminlimit;
565
566 pm_runtime_get_sync(&sr->pdev->dev);
567
568 /* Check if SR is already enabled. If yes do nothing */
569 if (sr_read_reg(sr, SRCONFIG) & SRCONFIG_SRENABLE)
570 return 0;
571
572 /* Configure SR */
573 ret = sr_class->configure(voltdm);
574 if (ret)
575 return ret;
576
577 sr_write_reg(sr, NVALUERECIPROCAL, nvalue_reciprocal);
578
579 /* SRCONFIG - enable SR */
580 sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, SRCONFIG_SRENABLE);
581 return 0;
582}
583
584/**
585 * sr_disable() - Disables the smartreflex module.
586 * @voltdm: VDD pointer to which the SR module to be configured belongs to.
587 *
588 * This API is to be called from the smartreflex class driver to
589 * disable a smartreflex module.
590 */
591void sr_disable(struct voltagedomain *voltdm)
592{
593 struct omap_sr *sr = _sr_lookup(voltdm);
594
595 if (IS_ERR(sr)) {
596 pr_warning("%s: omap_sr struct for sr_%s not found\n",
597 __func__, voltdm->name);
598 return;
599 }
600
601 /* Check if SR clocks are already disabled. If yes do nothing */
602 if (pm_runtime_suspended(&sr->pdev->dev))
603 return;
604
605 /*
606 * Disable SR if only it is indeed enabled. Else just
607 * disable the clocks.
608 */
609 if (sr_read_reg(sr, SRCONFIG) & SRCONFIG_SRENABLE) {
610 if (sr->ip_type == SR_TYPE_V1)
611 sr_v1_disable(sr);
612 else if (sr->ip_type == SR_TYPE_V2)
613 sr_v2_disable(sr);
614 }
615
616 pm_runtime_put_sync(&sr->pdev->dev);
617}
618
619/**
620 * sr_register_class() - API to register a smartreflex class parameters.
621 * @class_data: The structure containing various sr class specific data.
622 *
623 * This API is to be called by the smartreflex class driver to register itself
624 * with the smartreflex driver during init. Returns 0 on success else the
625 * error value.
626 */
627int sr_register_class(struct omap_sr_class_data *class_data)
628{
629 struct omap_sr *sr_info;
630
631 if (!class_data) {
632 pr_warning("%s:, Smartreflex class data passed is NULL\n",
633 __func__);
634 return -EINVAL;
635 }
636
637 if (sr_class) {
638 pr_warning("%s: Smartreflex class driver already registered\n",
639 __func__);
640 return -EBUSY;
641 }
642
643 sr_class = class_data;
644
645 /*
646 * Call into late init to do intializations that require
647 * both sr driver and sr class driver to be initiallized.
648 */
649 list_for_each_entry(sr_info, &sr_list, node)
650 sr_late_init(sr_info);
651
652 return 0;
653}
654
655/**
656 * omap_sr_enable() - API to enable SR clocks and to call into the
657 * registered smartreflex class enable API.
658 * @voltdm: VDD pointer to which the SR module to be configured belongs to.
659 *
660 * This API is to be called from the kernel in order to enable
661 * a particular smartreflex module. This API will do the initial
662 * configurations to turn on the smartreflex module and in turn call
663 * into the registered smartreflex class enable API.
664 */
665void omap_sr_enable(struct voltagedomain *voltdm)
666{
667 struct omap_sr *sr = _sr_lookup(voltdm);
668
669 if (IS_ERR(sr)) {
670 pr_warning("%s: omap_sr struct for sr_%s not found\n",
671 __func__, voltdm->name);
672 return;
673 }
674
675 if (!sr->autocomp_active)
676 return;
677
678 if (!sr_class || !(sr_class->enable) || !(sr_class->configure)) {
679 dev_warn(&sr->pdev->dev, "%s: smartreflex class driver not"
680 "registered\n", __func__);
681 return;
682 }
683
684 sr_class->enable(voltdm);
685}
686
687/**
688 * omap_sr_disable() - API to disable SR without resetting the voltage
689 * processor voltage
690 * @voltdm: VDD pointer to which the SR module to be configured belongs to.
691 *
692 * This API is to be called from the kernel in order to disable
693 * a particular smartreflex module. This API will in turn call
694 * into the registered smartreflex class disable API. This API will tell
695 * the smartreflex class disable not to reset the VP voltage after
696 * disabling smartreflex.
697 */
698void omap_sr_disable(struct voltagedomain *voltdm)
699{
700 struct omap_sr *sr = _sr_lookup(voltdm);
701
702 if (IS_ERR(sr)) {
703 pr_warning("%s: omap_sr struct for sr_%s not found\n",
704 __func__, voltdm->name);
705 return;
706 }
707
708 if (!sr->autocomp_active)
709 return;
710
711 if (!sr_class || !(sr_class->disable)) {
712 dev_warn(&sr->pdev->dev, "%s: smartreflex class driver not"
713 "registered\n", __func__);
714 return;
715 }
716
717 sr_class->disable(voltdm, 0);
718}
719
720/**
721 * omap_sr_disable_reset_volt() - API to disable SR and reset the
722 * voltage processor voltage
723 * @voltdm: VDD pointer to which the SR module to be configured belongs to.
724 *
725 * This API is to be called from the kernel in order to disable
726 * a particular smartreflex module. This API will in turn call
727 * into the registered smartreflex class disable API. This API will tell
728 * the smartreflex class disable to reset the VP voltage after
729 * disabling smartreflex.
730 */
731void omap_sr_disable_reset_volt(struct voltagedomain *voltdm)
732{
733 struct omap_sr *sr = _sr_lookup(voltdm);
734
735 if (IS_ERR(sr)) {
736 pr_warning("%s: omap_sr struct for sr_%s not found\n",
737 __func__, voltdm->name);
738 return;
739 }
740
741 if (!sr->autocomp_active)
742 return;
743
744 if (!sr_class || !(sr_class->disable)) {
745 dev_warn(&sr->pdev->dev, "%s: smartreflex class driver not"
746 "registered\n", __func__);
747 return;
748 }
749
750 sr_class->disable(voltdm, 1);
751}
752
753/**
754 * omap_sr_register_pmic() - API to register pmic specific info.
755 * @pmic_data: The structure containing pmic specific data.
756 *
757 * This API is to be called from the PMIC specific code to register with
758 * smartreflex driver pmic specific info. Currently the only info required
759 * is the smartreflex init on the PMIC side.
760 */
761void omap_sr_register_pmic(struct omap_sr_pmic_data *pmic_data)
762{
763 if (!pmic_data) {
764 pr_warning("%s: Trying to register NULL PMIC data structure"
765 "with smartreflex\n", __func__);
766 return;
767 }
768
769 sr_pmic_data = pmic_data;
770}
771
772/* PM Debug Fs enteries to enable disable smartreflex. */
773static int omap_sr_autocomp_show(void *data, u64 *val)
774{
775 struct omap_sr *sr_info = (struct omap_sr *) data;
776
777 if (!sr_info) {
778 pr_warning("%s: omap_sr struct for sr_%s not found\n",
779 __func__, sr_info->voltdm->name);
780 return -EINVAL;
781 }
782
783 *val = sr_info->autocomp_active;
784
785 return 0;
786}
787
788static int omap_sr_autocomp_store(void *data, u64 val)
789{
790 struct omap_sr *sr_info = (struct omap_sr *) data;
791
792 if (!sr_info) {
793 pr_warning("%s: omap_sr struct for sr_%s not found\n",
794 __func__, sr_info->voltdm->name);
795 return -EINVAL;
796 }
797
798 /* Sanity check */
799 if (val && (val != 1)) {
800 pr_warning("%s: Invalid argument %lld\n", __func__, val);
801 return -EINVAL;
802 }
803
804 if (!val)
805 sr_stop_vddautocomp(sr_info);
806 else
807 sr_start_vddautocomp(sr_info);
808
809 return 0;
810}
811
812DEFINE_SIMPLE_ATTRIBUTE(pm_sr_fops, omap_sr_autocomp_show,
813 omap_sr_autocomp_store, "%llu\n");
814
815static int __init omap_sr_probe(struct platform_device *pdev)
816{
817 struct omap_sr *sr_info = kzalloc(sizeof(struct omap_sr), GFP_KERNEL);
818 struct omap_sr_data *pdata = pdev->dev.platform_data;
819 struct resource *mem, *irq;
820 struct dentry *vdd_dbg_dir, *dbg_dir;
821 int ret = 0;
822
823 if (!sr_info) {
824 dev_err(&pdev->dev, "%s: unable to allocate sr_info\n",
825 __func__);
826 return -ENOMEM;
827 }
828
829 if (!pdata) {
830 dev_err(&pdev->dev, "%s: platform data missing\n", __func__);
831 return -EINVAL;
832 }
833
834 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
835 if (!mem) {
836 dev_err(&pdev->dev, "%s: no mem resource\n", __func__);
837 ret = -ENODEV;
838 goto err_free_devinfo;
839 }
840
841 irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
842
843 pm_runtime_enable(&pdev->dev);
844
845 sr_info->pdev = pdev;
846 sr_info->srid = pdev->id;
847 sr_info->voltdm = pdata->voltdm;
848 sr_info->nvalue_table = pdata->nvalue_table;
849 sr_info->nvalue_count = pdata->nvalue_count;
850 sr_info->senn_mod = pdata->senn_mod;
851 sr_info->senp_mod = pdata->senp_mod;
852 sr_info->autocomp_active = false;
853 sr_info->ip_type = pdata->ip_type;
854 sr_info->base = ioremap(mem->start, resource_size(mem));
855 if (!sr_info->base) {
856 dev_err(&pdev->dev, "%s: ioremap fail\n", __func__);
857 ret = -ENOMEM;
858 goto err_release_region;
859 }
860
861 if (irq)
862 sr_info->irq = irq->start;
863
864 sr_set_clk_length(sr_info);
865 sr_set_regfields(sr_info);
866
867 list_add(&sr_info->node, &sr_list);
868
869 /*
870 * Call into late init to do intializations that require
871 * both sr driver and sr class driver to be initiallized.
872 */
873 if (sr_class) {
874 ret = sr_late_init(sr_info);
875 if (ret) {
876 pr_warning("%s: Error in SR late init\n", __func__);
877 return ret;
878 }
879 }
880
881 dev_info(&pdev->dev, "%s: SmartReflex driver initialized\n", __func__);
882
883 /*
884 * If the voltage domain debugfs directory is not created, do
885 * not try to create rest of the debugfs entries.
886 */
887 vdd_dbg_dir = omap_voltage_get_dbgdir(sr_info->voltdm);
888 if (!vdd_dbg_dir)
889 return -EINVAL;
890
891 dbg_dir = debugfs_create_dir("smartreflex", vdd_dbg_dir);
892 if (IS_ERR(dbg_dir)) {
893 dev_err(&pdev->dev, "%s: Unable to create debugfs directory\n",
894 __func__);
895 return PTR_ERR(dbg_dir);
896 }
897
898 (void) debugfs_create_file("autocomp", S_IRUGO | S_IWUGO, dbg_dir,
899 (void *)sr_info, &pm_sr_fops);
900
901 return ret;
902
903err_release_region:
904 release_mem_region(mem->start, resource_size(mem));
905err_free_devinfo:
906 kfree(sr_info);
907
908 return ret;
909}
910
911static int __devexit omap_sr_remove(struct platform_device *pdev)
912{
913 struct omap_sr_data *pdata = pdev->dev.platform_data;
914 struct omap_sr *sr_info;
915 struct resource *mem;
916
917 if (!pdata) {
918 dev_err(&pdev->dev, "%s: platform data missing\n", __func__);
919 return -EINVAL;
920 }
921
922 sr_info = _sr_lookup(pdata->voltdm);
923 if (!sr_info) {
924 dev_warn(&pdev->dev, "%s: omap_sr struct not found\n",
925 __func__);
926 return -EINVAL;
927 }
928
929 if (sr_info->autocomp_active)
930 sr_stop_vddautocomp(sr_info);
931
932 list_del(&sr_info->node);
933 iounmap(sr_info->base);
934 kfree(sr_info);
935 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
936 release_mem_region(mem->start, resource_size(mem));
937
938 return 0;
939}
940
941static struct platform_driver smartreflex_driver = {
942 .remove = omap_sr_remove,
943 .driver = {
944 .name = "smartreflex",
945 },
946};
947
948static int __init sr_init(void)
949{
950 int ret = 0;
951
952 /*
953 * sr_init is a late init. If by then a pmic specific API is not
954 * registered either there is no need for anything to be done on
955 * the PMIC side or somebody has forgotten to register a PMIC
956 * handler. Warn for the second condition.
957 */
958 if (sr_pmic_data && sr_pmic_data->sr_pmic_init)
959 sr_pmic_data->sr_pmic_init();
960 else
961 pr_warning("%s: No PMIC hook to init smartreflex\n", __func__);
962
963 ret = platform_driver_probe(&smartreflex_driver, omap_sr_probe);
964 if (ret) {
965 pr_err("%s: platform driver register failed for SR\n",
966 __func__);
967 return ret;
968 }
969
970 return 0;
971}
972
973static void __exit sr_exit(void)
974{
975 platform_driver_unregister(&smartreflex_driver);
976}
977late_initcall(sr_init);
978module_exit(sr_exit);
979
980MODULE_DESCRIPTION("OMAP Smartreflex Driver");
981MODULE_LICENSE("GPL");
982MODULE_ALIAS("platform:" DRIVER_NAME);
983MODULE_AUTHOR("Texas Instruments Inc");
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index 5e63e5069e0..f1673fb96fe 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -35,6 +35,28 @@ config OMAP_DEBUG_LEDS
35 depends on OMAP_DEBUG_DEVICES 35 depends on OMAP_DEBUG_DEVICES
36 default y if LEDS_CLASS 36 default y if LEDS_CLASS
37 37
38config OMAP_SMARTREFLEX
39 bool "SmartReflex support"
40 depends on ARCH_OMAP3 && PM
41 help
42 Say Y if you want to enable SmartReflex.
43
44 SmartReflex can perform continuous dynamic voltage
45 scaling around the nominal operating point voltage
46 according to silicon characteristics and operating
47 conditions. Enabling SmartReflex reduces power
48 consumption.
49
50 Please note, that by default SmartReflex is only
51 initialized. To enable the automatic voltage
52 compensation for vdd mpu and vdd core from user space,
53 user must write 1 to
54 /debug/voltage/vdd_<X>/smartreflex/autocomp,
55 where X is mpu or core for OMAP3.
56 Optionallly autocompensation can be enabled in the kernel
57 by default during system init via the enable_on_init flag
58 which an be passed as platform data to the smartreflex driver.
59
38config OMAP_RESET_CLOCKS 60config OMAP_RESET_CLOCKS
39 bool "Reset unused clocks during boot" 61 bool "Reset unused clocks during boot"
40 depends on ARCH_OMAP 62 depends on ARCH_OMAP
diff --git a/arch/arm/plat-omap/include/plat/smartreflex.h b/arch/arm/plat-omap/include/plat/smartreflex.h
new file mode 100644
index 00000000000..6568c885f37
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/smartreflex.h
@@ -0,0 +1,245 @@
1/*
2 * OMAP Smartreflex Defines and Routines
3 *
4 * Author: Thara Gopinath <thara@ti.com>
5 *
6 * Copyright (C) 2010 Texas Instruments, Inc.
7 * Thara Gopinath <thara@ti.com>
8 *
9 * Copyright (C) 2008 Nokia Corporation
10 * Kalle Jokiniemi
11 *
12 * Copyright (C) 2007 Texas Instruments, Inc.
13 * Lesly A M <x0080970@ti.com>
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License version 2 as
17 * published by the Free Software Foundation.
18 */
19
20#ifndef __ASM_ARM_OMAP_SMARTREFLEX_H
21#define __ASM_ARM_OMAP_SMARTREFLEX_H
22
23#include <linux/platform_device.h>
24#include <plat/voltage.h>
25
26/*
27 * Different Smartreflex IPs version. The v1 is the 65nm version used in
28 * OMAP3430. The v2 is the update for the 45nm version of the IP
29 * used in OMAP3630 and OMAP4430
30 */
31#define SR_TYPE_V1 1
32#define SR_TYPE_V2 2
33
34/* SMART REFLEX REG ADDRESS OFFSET */
35#define SRCONFIG 0x00
36#define SRSTATUS 0x04
37#define SENVAL 0x08
38#define SENMIN 0x0C
39#define SENMAX 0x10
40#define SENAVG 0x14
41#define AVGWEIGHT 0x18
42#define NVALUERECIPROCAL 0x1c
43#define SENERROR_V1 0x20
44#define ERRCONFIG_V1 0x24
45#define IRQ_EOI 0x20
46#define IRQSTATUS_RAW 0x24
47#define IRQSTATUS 0x28
48#define IRQENABLE_SET 0x2C
49#define IRQENABLE_CLR 0x30
50#define SENERROR_V2 0x34
51#define ERRCONFIG_V2 0x38
52
53/* Bit/Shift Positions */
54
55/* SRCONFIG */
56#define SRCONFIG_ACCUMDATA_SHIFT 22
57#define SRCONFIG_SRCLKLENGTH_SHIFT 12
58#define SRCONFIG_SENNENABLE_V1_SHIFT 5
59#define SRCONFIG_SENPENABLE_V1_SHIFT 3
60#define SRCONFIG_SENNENABLE_V2_SHIFT 1
61#define SRCONFIG_SENPENABLE_V2_SHIFT 0
62#define SRCONFIG_CLKCTRL_SHIFT 0
63
64#define SRCONFIG_ACCUMDATA_MASK (0x3ff << 22)
65
66#define SRCONFIG_SRENABLE BIT(11)
67#define SRCONFIG_SENENABLE BIT(10)
68#define SRCONFIG_ERRGEN_EN BIT(9)
69#define SRCONFIG_MINMAXAVG_EN BIT(8)
70#define SRCONFIG_DELAYCTRL BIT(2)
71
72/* AVGWEIGHT */
73#define AVGWEIGHT_SENPAVGWEIGHT_SHIFT 2
74#define AVGWEIGHT_SENNAVGWEIGHT_SHIFT 0
75
76/* NVALUERECIPROCAL */
77#define NVALUERECIPROCAL_SENPGAIN_SHIFT 20
78#define NVALUERECIPROCAL_SENNGAIN_SHIFT 16
79#define NVALUERECIPROCAL_RNSENP_SHIFT 8
80#define NVALUERECIPROCAL_RNSENN_SHIFT 0
81
82/* ERRCONFIG */
83#define ERRCONFIG_ERRWEIGHT_SHIFT 16
84#define ERRCONFIG_ERRMAXLIMIT_SHIFT 8
85#define ERRCONFIG_ERRMINLIMIT_SHIFT 0
86
87#define SR_ERRWEIGHT_MASK (0x07 << 16)
88#define SR_ERRMAXLIMIT_MASK (0xff << 8)
89#define SR_ERRMINLIMIT_MASK (0xff << 0)
90
91#define ERRCONFIG_VPBOUNDINTEN_V1 BIT(31)
92#define ERRCONFIG_VPBOUNDINTST_V1 BIT(30)
93#define ERRCONFIG_MCUACCUMINTEN BIT(29)
94#define ERRCONFIG_MCUACCUMINTST BIT(28)
95#define ERRCONFIG_MCUVALIDINTEN BIT(27)
96#define ERRCONFIG_MCUVALIDINTST BIT(26)
97#define ERRCONFIG_MCUBOUNDINTEN BIT(25)
98#define ERRCONFIG_MCUBOUNDINTST BIT(24)
99#define ERRCONFIG_MCUDISACKINTEN BIT(23)
100#define ERRCONFIG_VPBOUNDINTST_V2 BIT(23)
101#define ERRCONFIG_MCUDISACKINTST BIT(22)
102#define ERRCONFIG_VPBOUNDINTEN_V2 BIT(22)
103
104#define ERRCONFIG_STATUS_V1_MASK (ERRCONFIG_VPBOUNDINTST_V1 | \
105 ERRCONFIG_MCUACCUMINTST | \
106 ERRCONFIG_MCUVALIDINTST | \
107 ERRCONFIG_MCUBOUNDINTST | \
108 ERRCONFIG_MCUDISACKINTST)
109/* IRQSTATUS */
110#define IRQSTATUS_MCUACCUMINT BIT(3)
111#define IRQSTATUS_MCVALIDINT BIT(2)
112#define IRQSTATUS_MCBOUNDSINT BIT(1)
113#define IRQSTATUS_MCUDISABLEACKINT BIT(0)
114
115/* IRQENABLE_SET and IRQENABLE_CLEAR */
116#define IRQENABLE_MCUACCUMINT BIT(3)
117#define IRQENABLE_MCUVALIDINT BIT(2)
118#define IRQENABLE_MCUBOUNDSINT BIT(1)
119#define IRQENABLE_MCUDISABLEACKINT BIT(0)
120
121/* Common Bit values */
122
123#define SRCLKLENGTH_12MHZ_SYSCLK 0x3c
124#define SRCLKLENGTH_13MHZ_SYSCLK 0x41
125#define SRCLKLENGTH_19MHZ_SYSCLK 0x60
126#define SRCLKLENGTH_26MHZ_SYSCLK 0x82
127#define SRCLKLENGTH_38MHZ_SYSCLK 0xC0
128
129/*
130 * 3430 specific values. Maybe these should be passed from board file or
131 * pmic structures.
132 */
133#define OMAP3430_SR_ACCUMDATA 0x1f4
134
135#define OMAP3430_SR1_SENPAVGWEIGHT 0x03
136#define OMAP3430_SR1_SENNAVGWEIGHT 0x03
137
138#define OMAP3430_SR2_SENPAVGWEIGHT 0x01
139#define OMAP3430_SR2_SENNAVGWEIGHT 0x01
140
141#define OMAP3430_SR_ERRWEIGHT 0x04
142#define OMAP3430_SR_ERRMAXLIMIT 0x02
143
144/**
145 * struct omap_sr_pmic_data - Strucutre to be populated by pmic code to pass
146 * pmic specific info to smartreflex driver
147 *
148 * @sr_pmic_init: API to initialize smartreflex on the PMIC side.
149 */
150struct omap_sr_pmic_data {
151 void (*sr_pmic_init) (void);
152};
153
154#ifdef CONFIG_OMAP_SMARTREFLEX
155/*
156 * The smart reflex driver supports CLASS1 CLASS2 and CLASS3 SR.
157 * The smartreflex class driver should pass the class type.
158 * Should be used to populate the class_type field of the
159 * omap_smartreflex_class_data structure.
160 */
161#define SR_CLASS1 0x1
162#define SR_CLASS2 0x2
163#define SR_CLASS3 0x3
164
165/**
166 * struct omap_sr_class_data - Smartreflex class driver info
167 *
168 * @enable: API to enable a particular class smaartreflex.
169 * @disable: API to disable a particular class smartreflex.
170 * @configure: API to configure a particular class smartreflex.
171 * @notify: API to notify the class driver about an event in SR.
172 * Not needed for class3.
173 * @notify_flags: specify the events to be notified to the class driver
174 * @class_type: specify which smartreflex class.
175 * Can be used by the SR driver to take any class
176 * based decisions.
177 */
178struct omap_sr_class_data {
179 int (*enable)(struct voltagedomain *voltdm);
180 int (*disable)(struct voltagedomain *voltdm, int is_volt_reset);
181 int (*configure)(struct voltagedomain *voltdm);
182 int (*notify)(struct voltagedomain *voltdm, u32 status);
183 u8 notify_flags;
184 u8 class_type;
185};
186
187/**
188 * struct omap_sr_nvalue_table - Smartreflex n-target value info
189 *
190 * @efuse_offs: The offset of the efuse where n-target values are stored.
191 * @nvalue: The n-target value.
192 */
193struct omap_sr_nvalue_table {
194 u32 efuse_offs;
195 u32 nvalue;
196};
197
198/**
199 * struct omap_sr_data - Smartreflex platform data.
200 *
201 * @ip_type: Smartreflex IP type.
202 * @senp_mod: SENPENABLE value for the sr
203 * @senn_mod: SENNENABLE value for sr
204 * @nvalue_count: Number of distinct nvalues in the nvalue table
205 * @enable_on_init: whether this sr module needs to enabled at
206 * boot up or not.
207 * @nvalue_table: table containing the efuse offsets and nvalues
208 * corresponding to them.
209 * @voltdm: Pointer to the voltage domain associated with the SR
210 */
211struct omap_sr_data {
212 int ip_type;
213 u32 senp_mod;
214 u32 senn_mod;
215 int nvalue_count;
216 bool enable_on_init;
217 struct omap_sr_nvalue_table *nvalue_table;
218 struct voltagedomain *voltdm;
219};
220
221/* Smartreflex module enable/disable interface */
222void omap_sr_enable(struct voltagedomain *voltdm);
223void omap_sr_disable(struct voltagedomain *voltdm);
224void omap_sr_disable_reset_volt(struct voltagedomain *voltdm);
225
226/* API to register the pmic specific data with the smartreflex driver. */
227void omap_sr_register_pmic(struct omap_sr_pmic_data *pmic_data);
228
229/* Smartreflex driver hooks to be called from Smartreflex class driver */
230int sr_enable(struct voltagedomain *voltdm, unsigned long volt);
231void sr_disable(struct voltagedomain *voltdm);
232int sr_configure_errgen(struct voltagedomain *voltdm);
233int sr_configure_minmax(struct voltagedomain *voltdm);
234
235/* API to register the smartreflex class driver with the smartreflex driver */
236int sr_register_class(struct omap_sr_class_data *class_data);
237#else
238static inline void omap_sr_enable(struct voltagedomain *voltdm) {}
239static inline void omap_sr_disable(struct voltagedomain *voltdm) {}
240static inline void omap_sr_disable_reset_volt(
241 struct voltagedomain *voltdm) {}
242static inline void omap_sr_register_pmic(
243 struct omap_sr_pmic_data *pmic_data) {}
244#endif
245#endif