aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/smartreflex.c
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/mach-omap2/smartreflex.c
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/mach-omap2/smartreflex.c')
-rw-r--r--arch/arm/mach-omap2/smartreflex.c983
1 files changed, 983 insertions, 0 deletions
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");