blob: 98309d32ba9809f4af46aeaeea9b98d9469f6475 [file] [log] [blame]
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301/*
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
Tony Lindgrena1bcc1d2011-11-07 12:27:10 -080020#include <linux/module.h>
Thara Gopinath984aa6d2010-05-29 22:02:22 +053021#include <linux/interrupt.h>
22#include <linux/clk.h>
23#include <linux/io.h>
24#include <linux/debugfs.h>
25#include <linux/delay.h>
26#include <linux/slab.h>
27#include <linux/pm_runtime.h>
Jean Pihetb86aeaf2012-04-25 16:06:20 +053028#include <linux/power/smartreflex.h>
Thara Gopinath984aa6d2010-05-29 22:02:22 +053029
Tony Lindgren4e653312011-11-10 22:45:17 +010030#include "common.h"
Thara Gopinath984aa6d2010-05-29 22:02:22 +053031#include "pm.h"
32
33#define SMARTREFLEX_NAME_LEN 16
Thara Gopinath077fcec2010-10-27 20:29:37 +053034#define NVALUE_NAME_LEN 40
Thara Gopinath984aa6d2010-05-29 22:02:22 +053035#define SR_DISABLE_TIMEOUT 200
36
37struct omap_sr {
Felipe Balbi4018bfe2012-02-29 23:33:46 +010038 struct list_head node;
39 struct platform_device *pdev;
40 struct omap_sr_nvalue_table *nvalue_table;
41 struct voltagedomain *voltdm;
42 struct dentry *dbg_dir;
43 unsigned int irq;
Thara Gopinath984aa6d2010-05-29 22:02:22 +053044 int srid;
45 int ip_type;
46 int nvalue_count;
47 bool autocomp_active;
48 u32 clk_length;
49 u32 err_weight;
50 u32 err_minlimit;
51 u32 err_maxlimit;
52 u32 accum_data;
53 u32 senn_avgweight;
54 u32 senp_avgweight;
55 u32 senp_mod;
56 u32 senn_mod;
Thara Gopinath984aa6d2010-05-29 22:02:22 +053057 void __iomem *base;
Thara Gopinath984aa6d2010-05-29 22:02:22 +053058};
59
60/* sr_list contains all the instances of smartreflex module */
61static LIST_HEAD(sr_list);
62
63static struct omap_sr_class_data *sr_class;
64static struct omap_sr_pmic_data *sr_pmic_data;
Kevin Hilman633ef8b742011-04-05 14:39:11 -070065static struct dentry *sr_dbg_dir;
Thara Gopinath984aa6d2010-05-29 22:02:22 +053066
67static inline void sr_write_reg(struct omap_sr *sr, unsigned offset, u32 value)
68{
69 __raw_writel(value, (sr->base + offset));
70}
71
72static inline void sr_modify_reg(struct omap_sr *sr, unsigned offset, u32 mask,
73 u32 value)
74{
75 u32 reg_val;
Thara Gopinath984aa6d2010-05-29 22:02:22 +053076
77 /*
78 * Smartreflex error config register is special as it contains
79 * certain status bits which if written a 1 into means a clear
80 * of those bits. So in order to make sure no accidental write of
81 * 1 happens to those status bits, do a clear of them in the read
82 * value. This mean this API doesn't rewrite values in these bits
83 * if they are currently set, but does allow the caller to write
84 * those bits.
85 */
Nishanth Menonade6ec02012-02-29 23:33:41 +010086 if (sr->ip_type == SR_TYPE_V1 && offset == ERRCONFIG_V1)
87 mask |= ERRCONFIG_STATUS_V1_MASK;
88 else if (sr->ip_type == SR_TYPE_V2 && offset == ERRCONFIG_V2)
89 mask |= ERRCONFIG_VPBOUNDINTST_V2;
Thara Gopinath984aa6d2010-05-29 22:02:22 +053090
Nishanth Menonade6ec02012-02-29 23:33:41 +010091 reg_val = __raw_readl(sr->base + offset);
92 reg_val &= ~mask;
93
94 value &= mask;
Thara Gopinath984aa6d2010-05-29 22:02:22 +053095
96 reg_val |= value;
97
98 __raw_writel(reg_val, (sr->base + offset));
99}
100
101static inline u32 sr_read_reg(struct omap_sr *sr, unsigned offset)
102{
103 return __raw_readl(sr->base + offset);
104}
105
106static struct omap_sr *_sr_lookup(struct voltagedomain *voltdm)
107{
108 struct omap_sr *sr_info;
109
110 if (!voltdm) {
111 pr_err("%s: Null voltage domain passed!\n", __func__);
112 return ERR_PTR(-EINVAL);
113 }
114
115 list_for_each_entry(sr_info, &sr_list, node) {
116 if (voltdm == sr_info->voltdm)
117 return sr_info;
118 }
119
120 return ERR_PTR(-ENODATA);
121}
122
123static irqreturn_t sr_interrupt(int irq, void *data)
124{
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100125 struct omap_sr *sr_info = data;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530126 u32 status = 0;
127
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100128 switch (sr_info->ip_type) {
129 case SR_TYPE_V1:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530130 /* Read the status bits */
131 status = sr_read_reg(sr_info, ERRCONFIG_V1);
132
133 /* Clear them by writing back */
134 sr_write_reg(sr_info, ERRCONFIG_V1, status);
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100135 break;
136 case SR_TYPE_V2:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530137 /* Read the status bits */
Felipe Balbi5a4f1842011-11-23 14:43:37 -0800138 status = sr_read_reg(sr_info, IRQSTATUS);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530139
140 /* Clear them by writing back */
141 sr_write_reg(sr_info, IRQSTATUS, status);
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100142 break;
143 default:
144 dev_err(&sr_info->pdev->dev, "UNKNOWN IP type %d\n",
145 sr_info->ip_type);
146 return IRQ_NONE;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530147 }
148
Nishanth Menon7a89afa2011-02-14 12:16:36 +0530149 if (sr_class->notify)
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530150 sr_class->notify(sr_info->voltdm, status);
151
152 return IRQ_HANDLED;
153}
154
155static void sr_set_clk_length(struct omap_sr *sr)
156{
157 struct clk *sys_ck;
158 u32 sys_clk_speed;
159
Thara Gopinathb35cecf2010-08-18 12:23:12 +0530160 if (cpu_is_omap34xx())
161 sys_ck = clk_get(NULL, "sys_ck");
162 else
163 sys_ck = clk_get(NULL, "sys_clkin_ck");
164
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530165 if (IS_ERR(sys_ck)) {
166 dev_err(&sr->pdev->dev, "%s: unable to get sys clk\n",
167 __func__);
168 return;
169 }
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100170
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530171 sys_clk_speed = clk_get_rate(sys_ck);
172 clk_put(sys_ck);
173
174 switch (sys_clk_speed) {
175 case 12000000:
176 sr->clk_length = SRCLKLENGTH_12MHZ_SYSCLK;
177 break;
178 case 13000000:
179 sr->clk_length = SRCLKLENGTH_13MHZ_SYSCLK;
180 break;
181 case 19200000:
182 sr->clk_length = SRCLKLENGTH_19MHZ_SYSCLK;
183 break;
184 case 26000000:
185 sr->clk_length = SRCLKLENGTH_26MHZ_SYSCLK;
186 break;
187 case 38400000:
188 sr->clk_length = SRCLKLENGTH_38MHZ_SYSCLK;
189 break;
190 default:
191 dev_err(&sr->pdev->dev, "%s: Invalid sysclk value: %d\n",
192 __func__, sys_clk_speed);
193 break;
194 }
195}
196
197static void sr_set_regfields(struct omap_sr *sr)
198{
199 /*
200 * For time being these values are defined in smartreflex.h
201 * and populated during init. May be they can be moved to board
202 * file or pmic specific data structure. In that case these structure
203 * fields will have to be populated using the pdata or pmic structure.
204 */
Thara Gopinathb35cecf2010-08-18 12:23:12 +0530205 if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530206 sr->err_weight = OMAP3430_SR_ERRWEIGHT;
207 sr->err_maxlimit = OMAP3430_SR_ERRMAXLIMIT;
208 sr->accum_data = OMAP3430_SR_ACCUMDATA;
209 if (!(strcmp(sr->voltdm->name, "mpu"))) {
210 sr->senn_avgweight = OMAP3430_SR1_SENNAVGWEIGHT;
211 sr->senp_avgweight = OMAP3430_SR1_SENPAVGWEIGHT;
212 } else {
213 sr->senn_avgweight = OMAP3430_SR2_SENNAVGWEIGHT;
214 sr->senp_avgweight = OMAP3430_SR2_SENPAVGWEIGHT;
215 }
216 }
217}
218
219static void sr_start_vddautocomp(struct omap_sr *sr)
220{
221 if (!sr_class || !(sr_class->enable) || !(sr_class->configure)) {
222 dev_warn(&sr->pdev->dev,
223 "%s: smartreflex class driver not registered\n",
224 __func__);
225 return;
226 }
227
228 if (!sr_class->enable(sr->voltdm))
229 sr->autocomp_active = true;
230}
231
232static void sr_stop_vddautocomp(struct omap_sr *sr)
233{
234 if (!sr_class || !(sr_class->disable)) {
235 dev_warn(&sr->pdev->dev,
236 "%s: smartreflex class driver not registered\n",
237 __func__);
238 return;
239 }
240
241 if (sr->autocomp_active) {
242 sr_class->disable(sr->voltdm, 1);
243 sr->autocomp_active = false;
244 }
245}
246
247/*
248 * This function handles the intializations which have to be done
249 * only when both sr device and class driver regiter has
250 * completed. This will be attempted to be called from both sr class
251 * driver register and sr device intializtion API's. Only one call
252 * will ultimately succeed.
253 *
Vitaliy Ivanovfb914eb2011-06-23 20:01:55 +0300254 * Currently this function registers interrupt handler for a particular SR
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530255 * if smartreflex class driver is already registered and has
256 * requested for interrupts and the SR interrupt line in present.
257 */
258static int sr_late_init(struct omap_sr *sr_info)
259{
260 char *name;
261 struct omap_sr_data *pdata = sr_info->pdev->dev.platform_data;
262 struct resource *mem;
263 int ret = 0;
264
Nishanth Menon7a89afa2011-02-14 12:16:36 +0530265 if (sr_class->notify && sr_class->notify_flags && sr_info->irq) {
Vasiliy Kulikov5c56f322011-01-19 15:57:22 +0300266 name = kasprintf(GFP_KERNEL, "sr_%s", sr_info->voltdm->name);
267 if (name == NULL) {
268 ret = -ENOMEM;
269 goto error;
270 }
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530271 ret = request_irq(sr_info->irq, sr_interrupt,
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100272 0, name, sr_info);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530273 if (ret)
274 goto error;
Nishanth Menon1279ba52011-02-14 12:41:10 +0530275 disable_irq(sr_info->irq);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530276 }
277
278 if (pdata && pdata->enable_on_init)
279 sr_start_vddautocomp(sr_info);
280
281 return ret;
282
283error:
Nishanth Menon442155a2011-02-14 12:33:13 +0530284 iounmap(sr_info->base);
285 mem = platform_get_resource(sr_info->pdev, IORESOURCE_MEM, 0);
286 release_mem_region(mem->start, resource_size(mem));
287 list_del(&sr_info->node);
288 dev_err(&sr_info->pdev->dev, "%s: ERROR in registering"
289 "interrupt handler. Smartreflex will"
290 "not function as desired\n", __func__);
291 kfree(name);
292 kfree(sr_info);
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100293
Nishanth Menon442155a2011-02-14 12:33:13 +0530294 return ret;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530295}
296
297static void sr_v1_disable(struct omap_sr *sr)
298{
299 int timeout = 0;
Nishanth Menoncfec9c52012-02-29 23:33:42 +0100300 int errconf_val = ERRCONFIG_MCUACCUMINTST | ERRCONFIG_MCUVALIDINTST |
301 ERRCONFIG_MCUBOUNDINTST;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530302
303 /* Enable MCUDisableAcknowledge interrupt */
304 sr_modify_reg(sr, ERRCONFIG_V1,
305 ERRCONFIG_MCUDISACKINTEN, ERRCONFIG_MCUDISACKINTEN);
306
307 /* SRCONFIG - disable SR */
308 sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0x0);
309
Nishanth Menoncfec9c52012-02-29 23:33:42 +0100310 /* Disable all other SR interrupts and clear the status as needed */
311 if (sr_read_reg(sr, ERRCONFIG_V1) & ERRCONFIG_VPBOUNDINTST_V1)
312 errconf_val |= ERRCONFIG_VPBOUNDINTST_V1;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530313 sr_modify_reg(sr, ERRCONFIG_V1,
314 (ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUVALIDINTEN |
315 ERRCONFIG_MCUBOUNDINTEN | ERRCONFIG_VPBOUNDINTEN_V1),
Nishanth Menoncfec9c52012-02-29 23:33:42 +0100316 errconf_val);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530317
318 /*
319 * Wait for SR to be disabled.
320 * wait until ERRCONFIG.MCUDISACKINTST = 1. Typical latency is 1us.
321 */
322 omap_test_timeout((sr_read_reg(sr, ERRCONFIG_V1) &
323 ERRCONFIG_MCUDISACKINTST), SR_DISABLE_TIMEOUT,
324 timeout);
325
326 if (timeout >= SR_DISABLE_TIMEOUT)
327 dev_warn(&sr->pdev->dev, "%s: Smartreflex disable timedout\n",
328 __func__);
329
330 /* Disable MCUDisableAcknowledge interrupt & clear pending interrupt */
331 sr_modify_reg(sr, ERRCONFIG_V1, ERRCONFIG_MCUDISACKINTEN,
332 ERRCONFIG_MCUDISACKINTST);
333}
334
335static void sr_v2_disable(struct omap_sr *sr)
336{
337 int timeout = 0;
338
339 /* Enable MCUDisableAcknowledge interrupt */
340 sr_write_reg(sr, IRQENABLE_SET, IRQENABLE_MCUDISABLEACKINT);
341
342 /* SRCONFIG - disable SR */
343 sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0x0);
344
Nishanth Menoncfec9c52012-02-29 23:33:42 +0100345 /*
346 * Disable all other SR interrupts and clear the status
347 * write to status register ONLY on need basis - only if status
348 * is set.
349 */
350 if (sr_read_reg(sr, ERRCONFIG_V2) & ERRCONFIG_VPBOUNDINTST_V2)
351 sr_modify_reg(sr, ERRCONFIG_V2, ERRCONFIG_VPBOUNDINTEN_V2,
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530352 ERRCONFIG_VPBOUNDINTST_V2);
Nishanth Menoncfec9c52012-02-29 23:33:42 +0100353 else
354 sr_modify_reg(sr, ERRCONFIG_V2, ERRCONFIG_VPBOUNDINTEN_V2,
355 0x0);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530356 sr_write_reg(sr, IRQENABLE_CLR, (IRQENABLE_MCUACCUMINT |
357 IRQENABLE_MCUVALIDINT |
358 IRQENABLE_MCUBOUNDSINT));
359 sr_write_reg(sr, IRQSTATUS, (IRQSTATUS_MCUACCUMINT |
360 IRQSTATUS_MCVALIDINT |
361 IRQSTATUS_MCBOUNDSINT));
362
363 /*
364 * Wait for SR to be disabled.
365 * wait until IRQSTATUS.MCUDISACKINTST = 1. Typical latency is 1us.
366 */
367 omap_test_timeout((sr_read_reg(sr, IRQSTATUS) &
368 IRQSTATUS_MCUDISABLEACKINT), SR_DISABLE_TIMEOUT,
369 timeout);
370
371 if (timeout >= SR_DISABLE_TIMEOUT)
372 dev_warn(&sr->pdev->dev, "%s: Smartreflex disable timedout\n",
373 __func__);
374
375 /* Disable MCUDisableAcknowledge interrupt & clear pending interrupt */
376 sr_write_reg(sr, IRQENABLE_CLR, IRQENABLE_MCUDISABLEACKINT);
377 sr_write_reg(sr, IRQSTATUS, IRQSTATUS_MCUDISABLEACKINT);
378}
379
380static u32 sr_retrieve_nvalue(struct omap_sr *sr, u32 efuse_offs)
381{
382 int i;
383
384 if (!sr->nvalue_table) {
385 dev_warn(&sr->pdev->dev, "%s: Missing ntarget value table\n",
386 __func__);
387 return 0;
388 }
389
390 for (i = 0; i < sr->nvalue_count; i++) {
391 if (sr->nvalue_table[i].efuse_offs == efuse_offs)
392 return sr->nvalue_table[i].nvalue;
393 }
394
395 return 0;
396}
397
398/* Public Functions */
399
400/**
401 * sr_configure_errgen() - Configures the smrtreflex to perform AVS using the
402 * error generator module.
403 * @voltdm: VDD pointer to which the SR module to be configured belongs to.
404 *
405 * This API is to be called from the smartreflex class driver to
406 * configure the error generator module inside the smartreflex module.
407 * SR settings if using the ERROR module inside Smartreflex.
408 * SR CLASS 3 by default uses only the ERROR module where as
409 * SR CLASS 2 can choose between ERROR module and MINMAXAVG
410 * module. Returns 0 on success and error value in case of failure.
411 */
412int sr_configure_errgen(struct voltagedomain *voltdm)
413{
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100414 u32 sr_config, sr_errconfig, errconfig_offs;
415 u32 vpboundint_en, vpboundint_st;
416 u32 senp_en = 0, senn_en = 0;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530417 u8 senp_shift, senn_shift;
418 struct omap_sr *sr = _sr_lookup(voltdm);
419
420 if (IS_ERR(sr)) {
421 pr_warning("%s: omap_sr struct for sr_%s not found\n",
422 __func__, voltdm->name);
Jean Pihet63371fa2012-02-29 23:33:49 +0100423 return PTR_ERR(sr);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530424 }
425
426 if (!sr->clk_length)
427 sr_set_clk_length(sr);
428
429 senp_en = sr->senp_mod;
430 senn_en = sr->senn_mod;
431
432 sr_config = (sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
433 SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN;
434
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100435 switch (sr->ip_type) {
436 case SR_TYPE_V1:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530437 sr_config |= SRCONFIG_DELAYCTRL;
438 senn_shift = SRCONFIG_SENNENABLE_V1_SHIFT;
439 senp_shift = SRCONFIG_SENPENABLE_V1_SHIFT;
440 errconfig_offs = ERRCONFIG_V1;
441 vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V1;
442 vpboundint_st = ERRCONFIG_VPBOUNDINTST_V1;
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100443 break;
444 case SR_TYPE_V2:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530445 senn_shift = SRCONFIG_SENNENABLE_V2_SHIFT;
446 senp_shift = SRCONFIG_SENPENABLE_V2_SHIFT;
447 errconfig_offs = ERRCONFIG_V2;
448 vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V2;
449 vpboundint_st = ERRCONFIG_VPBOUNDINTST_V2;
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100450 break;
451 default:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530452 dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex"
453 "module without specifying the ip\n", __func__);
454 return -EINVAL;
455 }
456
457 sr_config |= ((senn_en << senn_shift) | (senp_en << senp_shift));
458 sr_write_reg(sr, SRCONFIG, sr_config);
459 sr_errconfig = (sr->err_weight << ERRCONFIG_ERRWEIGHT_SHIFT) |
460 (sr->err_maxlimit << ERRCONFIG_ERRMAXLIMIT_SHIFT) |
461 (sr->err_minlimit << ERRCONFIG_ERRMINLIMIT_SHIFT);
462 sr_modify_reg(sr, errconfig_offs, (SR_ERRWEIGHT_MASK |
463 SR_ERRMAXLIMIT_MASK | SR_ERRMINLIMIT_MASK),
464 sr_errconfig);
465
466 /* Enabling the interrupts if the ERROR module is used */
Nishanth Menon74754cc2012-02-29 23:33:38 +0100467 sr_modify_reg(sr, errconfig_offs, (vpboundint_en | vpboundint_st),
468 vpboundint_en);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530469
470 return 0;
471}
472
473/**
Nishanth Menonad54c3d2012-02-29 23:33:39 +0100474 * sr_disable_errgen() - Disables SmartReflex AVS module's errgen component
475 * @voltdm: VDD pointer to which the SR module to be configured belongs to.
476 *
477 * This API is to be called from the smartreflex class driver to
478 * disable the error generator module inside the smartreflex module.
479 *
480 * Returns 0 on success and error value in case of failure.
481 */
482int sr_disable_errgen(struct voltagedomain *voltdm)
483{
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100484 u32 errconfig_offs;
485 u32 vpboundint_en, vpboundint_st;
Nishanth Menonad54c3d2012-02-29 23:33:39 +0100486 struct omap_sr *sr = _sr_lookup(voltdm);
487
488 if (IS_ERR(sr)) {
489 pr_warning("%s: omap_sr struct for sr_%s not found\n",
490 __func__, voltdm->name);
Jean Pihet63371fa2012-02-29 23:33:49 +0100491 return PTR_ERR(sr);
Nishanth Menonad54c3d2012-02-29 23:33:39 +0100492 }
493
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100494 switch (sr->ip_type) {
495 case SR_TYPE_V1:
Nishanth Menonad54c3d2012-02-29 23:33:39 +0100496 errconfig_offs = ERRCONFIG_V1;
497 vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V1;
498 vpboundint_st = ERRCONFIG_VPBOUNDINTST_V1;
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100499 break;
500 case SR_TYPE_V2:
Nishanth Menonad54c3d2012-02-29 23:33:39 +0100501 errconfig_offs = ERRCONFIG_V2;
502 vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V2;
503 vpboundint_st = ERRCONFIG_VPBOUNDINTST_V2;
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100504 break;
505 default:
Nishanth Menonad54c3d2012-02-29 23:33:39 +0100506 dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex"
507 "module without specifying the ip\n", __func__);
508 return -EINVAL;
509 }
510
511 /* Disable the interrupts of ERROR module */
512 sr_modify_reg(sr, errconfig_offs, vpboundint_en | vpboundint_st, 0);
513
514 /* Disable the Sensor and errorgen */
515 sr_modify_reg(sr, SRCONFIG, SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN, 0);
516
517 return 0;
518}
519
520/**
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530521 * sr_configure_minmax() - Configures the smrtreflex to perform AVS using the
522 * minmaxavg module.
523 * @voltdm: VDD pointer to which the SR module to be configured belongs to.
524 *
525 * This API is to be called from the smartreflex class driver to
526 * configure the minmaxavg module inside the smartreflex module.
527 * SR settings if using the ERROR module inside Smartreflex.
528 * SR CLASS 3 by default uses only the ERROR module where as
529 * SR CLASS 2 can choose between ERROR module and MINMAXAVG
530 * module. Returns 0 on success and error value in case of failure.
531 */
532int sr_configure_minmax(struct voltagedomain *voltdm)
533{
534 u32 sr_config, sr_avgwt;
535 u32 senp_en = 0, senn_en = 0;
536 u8 senp_shift, senn_shift;
537 struct omap_sr *sr = _sr_lookup(voltdm);
538
539 if (IS_ERR(sr)) {
540 pr_warning("%s: omap_sr struct for sr_%s not found\n",
541 __func__, voltdm->name);
Jean Pihet63371fa2012-02-29 23:33:49 +0100542 return PTR_ERR(sr);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530543 }
544
545 if (!sr->clk_length)
546 sr_set_clk_length(sr);
547
548 senp_en = sr->senp_mod;
549 senn_en = sr->senn_mod;
550
551 sr_config = (sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
552 SRCONFIG_SENENABLE |
553 (sr->accum_data << SRCONFIG_ACCUMDATA_SHIFT);
554
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100555 switch (sr->ip_type) {
556 case SR_TYPE_V1:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530557 sr_config |= SRCONFIG_DELAYCTRL;
558 senn_shift = SRCONFIG_SENNENABLE_V1_SHIFT;
559 senp_shift = SRCONFIG_SENPENABLE_V1_SHIFT;
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100560 break;
561 case SR_TYPE_V2:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530562 senn_shift = SRCONFIG_SENNENABLE_V2_SHIFT;
563 senp_shift = SRCONFIG_SENPENABLE_V2_SHIFT;
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100564 break;
565 default:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530566 dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex"
567 "module without specifying the ip\n", __func__);
568 return -EINVAL;
569 }
570
571 sr_config |= ((senn_en << senn_shift) | (senp_en << senp_shift));
572 sr_write_reg(sr, SRCONFIG, sr_config);
573 sr_avgwt = (sr->senp_avgweight << AVGWEIGHT_SENPAVGWEIGHT_SHIFT) |
574 (sr->senn_avgweight << AVGWEIGHT_SENNAVGWEIGHT_SHIFT);
575 sr_write_reg(sr, AVGWEIGHT, sr_avgwt);
576
577 /*
578 * Enabling the interrupts if MINMAXAVG module is used.
579 * TODO: check if all the interrupts are mandatory
580 */
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100581 switch (sr->ip_type) {
582 case SR_TYPE_V1:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530583 sr_modify_reg(sr, ERRCONFIG_V1,
584 (ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUVALIDINTEN |
585 ERRCONFIG_MCUBOUNDINTEN),
586 (ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUACCUMINTST |
587 ERRCONFIG_MCUVALIDINTEN | ERRCONFIG_MCUVALIDINTST |
588 ERRCONFIG_MCUBOUNDINTEN | ERRCONFIG_MCUBOUNDINTST));
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100589 break;
590 case SR_TYPE_V2:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530591 sr_write_reg(sr, IRQSTATUS,
592 IRQSTATUS_MCUACCUMINT | IRQSTATUS_MCVALIDINT |
593 IRQSTATUS_MCBOUNDSINT | IRQSTATUS_MCUDISABLEACKINT);
594 sr_write_reg(sr, IRQENABLE_SET,
595 IRQENABLE_MCUACCUMINT | IRQENABLE_MCUVALIDINT |
596 IRQENABLE_MCUBOUNDSINT | IRQENABLE_MCUDISABLEACKINT);
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100597 break;
598 default:
599 dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex"
600 "module without specifying the ip\n", __func__);
601 return -EINVAL;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530602 }
603
604 return 0;
605}
606
607/**
608 * sr_enable() - Enables the smartreflex module.
609 * @voltdm: VDD pointer to which the SR module to be configured belongs to.
610 * @volt: The voltage at which the Voltage domain associated with
611 * the smartreflex module is operating at.
612 * This is required only to program the correct Ntarget value.
613 *
614 * This API is to be called from the smartreflex class driver to
615 * enable a smartreflex module. Returns 0 on success. Returns error
616 * value if the voltage passed is wrong or if ntarget value is wrong.
617 */
618int sr_enable(struct voltagedomain *voltdm, unsigned long volt)
619{
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530620 struct omap_volt_data *volt_data;
621 struct omap_sr *sr = _sr_lookup(voltdm);
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100622 u32 nvalue_reciprocal;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530623 int ret;
624
625 if (IS_ERR(sr)) {
626 pr_warning("%s: omap_sr struct for sr_%s not found\n",
627 __func__, voltdm->name);
Jean Pihet63371fa2012-02-29 23:33:49 +0100628 return PTR_ERR(sr);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530629 }
630
631 volt_data = omap_voltage_get_voltdata(sr->voltdm, volt);
632
633 if (IS_ERR(volt_data)) {
634 dev_warn(&sr->pdev->dev, "%s: Unable to get voltage table"
635 "for nominal voltage %ld\n", __func__, volt);
Jean Pihet63371fa2012-02-29 23:33:49 +0100636 return PTR_ERR(volt_data);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530637 }
638
639 nvalue_reciprocal = sr_retrieve_nvalue(sr, volt_data->sr_efuse_offs);
640
641 if (!nvalue_reciprocal) {
642 dev_warn(&sr->pdev->dev, "%s: NVALUE = 0 at voltage %ld\n",
643 __func__, volt);
644 return -ENODATA;
645 }
646
647 /* errminlimit is opp dependent and hence linked to voltage */
648 sr->err_minlimit = volt_data->sr_errminlimit;
649
650 pm_runtime_get_sync(&sr->pdev->dev);
651
652 /* Check if SR is already enabled. If yes do nothing */
653 if (sr_read_reg(sr, SRCONFIG) & SRCONFIG_SRENABLE)
654 return 0;
655
656 /* Configure SR */
657 ret = sr_class->configure(voltdm);
658 if (ret)
659 return ret;
660
661 sr_write_reg(sr, NVALUERECIPROCAL, nvalue_reciprocal);
662
663 /* SRCONFIG - enable SR */
664 sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, SRCONFIG_SRENABLE);
665 return 0;
666}
667
668/**
669 * sr_disable() - Disables the smartreflex module.
670 * @voltdm: VDD pointer to which the SR module to be configured belongs to.
671 *
672 * This API is to be called from the smartreflex class driver to
673 * disable a smartreflex module.
674 */
675void sr_disable(struct voltagedomain *voltdm)
676{
677 struct omap_sr *sr = _sr_lookup(voltdm);
678
679 if (IS_ERR(sr)) {
680 pr_warning("%s: omap_sr struct for sr_%s not found\n",
681 __func__, voltdm->name);
682 return;
683 }
684
685 /* Check if SR clocks are already disabled. If yes do nothing */
686 if (pm_runtime_suspended(&sr->pdev->dev))
687 return;
688
689 /*
690 * Disable SR if only it is indeed enabled. Else just
691 * disable the clocks.
692 */
693 if (sr_read_reg(sr, SRCONFIG) & SRCONFIG_SRENABLE) {
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100694 switch (sr->ip_type) {
695 case SR_TYPE_V1:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530696 sr_v1_disable(sr);
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100697 break;
698 case SR_TYPE_V2:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530699 sr_v2_disable(sr);
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100700 break;
701 default:
702 dev_err(&sr->pdev->dev, "UNKNOWN IP type %d\n",
703 sr->ip_type);
704 }
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530705 }
706
Colin Cross98333b32011-07-22 00:55:52 -0500707 pm_runtime_put_sync_suspend(&sr->pdev->dev);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530708}
709
710/**
711 * sr_register_class() - API to register a smartreflex class parameters.
712 * @class_data: The structure containing various sr class specific data.
713 *
714 * This API is to be called by the smartreflex class driver to register itself
715 * with the smartreflex driver during init. Returns 0 on success else the
716 * error value.
717 */
718int sr_register_class(struct omap_sr_class_data *class_data)
719{
720 struct omap_sr *sr_info;
721
722 if (!class_data) {
723 pr_warning("%s:, Smartreflex class data passed is NULL\n",
724 __func__);
725 return -EINVAL;
726 }
727
728 if (sr_class) {
729 pr_warning("%s: Smartreflex class driver already registered\n",
730 __func__);
731 return -EBUSY;
732 }
733
734 sr_class = class_data;
735
736 /*
737 * Call into late init to do intializations that require
738 * both sr driver and sr class driver to be initiallized.
739 */
740 list_for_each_entry(sr_info, &sr_list, node)
741 sr_late_init(sr_info);
742
743 return 0;
744}
745
746/**
747 * omap_sr_enable() - API to enable SR clocks and to call into the
748 * registered smartreflex class enable API.
749 * @voltdm: VDD pointer to which the SR module to be configured belongs to.
750 *
751 * This API is to be called from the kernel in order to enable
752 * a particular smartreflex module. This API will do the initial
753 * configurations to turn on the smartreflex module and in turn call
754 * into the registered smartreflex class enable API.
755 */
756void omap_sr_enable(struct voltagedomain *voltdm)
757{
758 struct omap_sr *sr = _sr_lookup(voltdm);
759
760 if (IS_ERR(sr)) {
761 pr_warning("%s: omap_sr struct for sr_%s not found\n",
762 __func__, voltdm->name);
763 return;
764 }
765
766 if (!sr->autocomp_active)
767 return;
768
769 if (!sr_class || !(sr_class->enable) || !(sr_class->configure)) {
770 dev_warn(&sr->pdev->dev, "%s: smartreflex class driver not"
771 "registered\n", __func__);
772 return;
773 }
774
775 sr_class->enable(voltdm);
776}
777
778/**
779 * omap_sr_disable() - API to disable SR without resetting the voltage
780 * processor voltage
781 * @voltdm: VDD pointer to which the SR module to be configured belongs to.
782 *
783 * This API is to be called from the kernel in order to disable
784 * a particular smartreflex module. This API will in turn call
785 * into the registered smartreflex class disable API. This API will tell
786 * the smartreflex class disable not to reset the VP voltage after
787 * disabling smartreflex.
788 */
789void omap_sr_disable(struct voltagedomain *voltdm)
790{
791 struct omap_sr *sr = _sr_lookup(voltdm);
792
793 if (IS_ERR(sr)) {
794 pr_warning("%s: omap_sr struct for sr_%s not found\n",
795 __func__, voltdm->name);
796 return;
797 }
798
799 if (!sr->autocomp_active)
800 return;
801
802 if (!sr_class || !(sr_class->disable)) {
803 dev_warn(&sr->pdev->dev, "%s: smartreflex class driver not"
804 "registered\n", __func__);
805 return;
806 }
807
808 sr_class->disable(voltdm, 0);
809}
810
811/**
812 * omap_sr_disable_reset_volt() - API to disable SR and reset the
813 * voltage processor voltage
814 * @voltdm: VDD pointer to which the SR module to be configured belongs to.
815 *
816 * This API is to be called from the kernel in order to disable
817 * a particular smartreflex module. This API will in turn call
818 * into the registered smartreflex class disable API. This API will tell
819 * the smartreflex class disable to reset the VP voltage after
820 * disabling smartreflex.
821 */
822void omap_sr_disable_reset_volt(struct voltagedomain *voltdm)
823{
824 struct omap_sr *sr = _sr_lookup(voltdm);
825
826 if (IS_ERR(sr)) {
827 pr_warning("%s: omap_sr struct for sr_%s not found\n",
828 __func__, voltdm->name);
829 return;
830 }
831
832 if (!sr->autocomp_active)
833 return;
834
835 if (!sr_class || !(sr_class->disable)) {
836 dev_warn(&sr->pdev->dev, "%s: smartreflex class driver not"
837 "registered\n", __func__);
838 return;
839 }
840
841 sr_class->disable(voltdm, 1);
842}
843
844/**
845 * omap_sr_register_pmic() - API to register pmic specific info.
846 * @pmic_data: The structure containing pmic specific data.
847 *
848 * This API is to be called from the PMIC specific code to register with
849 * smartreflex driver pmic specific info. Currently the only info required
850 * is the smartreflex init on the PMIC side.
851 */
852void omap_sr_register_pmic(struct omap_sr_pmic_data *pmic_data)
853{
854 if (!pmic_data) {
855 pr_warning("%s: Trying to register NULL PMIC data structure"
856 "with smartreflex\n", __func__);
857 return;
858 }
859
860 sr_pmic_data = pmic_data;
861}
862
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100863/* PM Debug FS entries to enable and disable smartreflex. */
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530864static int omap_sr_autocomp_show(void *data, u64 *val)
865{
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100866 struct omap_sr *sr_info = data;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530867
868 if (!sr_info) {
Stefan Weil83535842011-01-30 20:29:38 +0100869 pr_warning("%s: omap_sr struct not found\n", __func__);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530870 return -EINVAL;
871 }
872
873 *val = sr_info->autocomp_active;
874
875 return 0;
876}
877
878static int omap_sr_autocomp_store(void *data, u64 val)
879{
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100880 struct omap_sr *sr_info = data;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530881
882 if (!sr_info) {
Stefan Weil83535842011-01-30 20:29:38 +0100883 pr_warning("%s: omap_sr struct not found\n", __func__);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530884 return -EINVAL;
885 }
886
887 /* Sanity check */
Felipe Balbid6173692012-02-29 23:33:47 +0100888 if (val > 1) {
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530889 pr_warning("%s: Invalid argument %lld\n", __func__, val);
890 return -EINVAL;
891 }
892
Nishanth Menonac77a6f2011-02-14 21:14:17 +0530893 /* control enable/disable only if there is a delta in value */
894 if (sr_info->autocomp_active != val) {
895 if (!val)
896 sr_stop_vddautocomp(sr_info);
897 else
898 sr_start_vddautocomp(sr_info);
899 }
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530900
901 return 0;
902}
903
904DEFINE_SIMPLE_ATTRIBUTE(pm_sr_fops, omap_sr_autocomp_show,
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100905 omap_sr_autocomp_store, "%llu\n");
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530906
907static int __init omap_sr_probe(struct platform_device *pdev)
908{
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100909 struct omap_sr *sr_info;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530910 struct omap_sr_data *pdata = pdev->dev.platform_data;
911 struct resource *mem, *irq;
Kevin Hilman633ef8b742011-04-05 14:39:11 -0700912 struct dentry *nvalue_dir;
Thara Gopinath077fcec2010-10-27 20:29:37 +0530913 struct omap_volt_data *volt_data;
914 int i, ret = 0;
Kevin Hilman633ef8b742011-04-05 14:39:11 -0700915 char *name;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530916
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100917 sr_info = kzalloc(sizeof(struct omap_sr), GFP_KERNEL);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530918 if (!sr_info) {
919 dev_err(&pdev->dev, "%s: unable to allocate sr_info\n",
920 __func__);
921 return -ENOMEM;
922 }
923
Felipe Balbi1079a8b2012-02-29 23:33:44 +0100924 platform_set_drvdata(pdev, sr_info);
925
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530926 if (!pdata) {
927 dev_err(&pdev->dev, "%s: platform data missing\n", __func__);
Stefan Weil720bc782011-01-30 20:26:27 +0100928 ret = -EINVAL;
929 goto err_free_devinfo;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530930 }
931
932 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
933 if (!mem) {
934 dev_err(&pdev->dev, "%s: no mem resource\n", __func__);
935 ret = -ENODEV;
936 goto err_free_devinfo;
937 }
938
Aaro Koskinenda9e73922011-04-26 02:25:16 -0700939 mem = request_mem_region(mem->start, resource_size(mem),
940 dev_name(&pdev->dev));
941 if (!mem) {
942 dev_err(&pdev->dev, "%s: no mem region\n", __func__);
943 ret = -EBUSY;
944 goto err_free_devinfo;
945 }
946
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530947 irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
948
949 pm_runtime_enable(&pdev->dev);
Nishanth Menone13d8f32011-07-09 14:37:21 -0700950 pm_runtime_irq_safe(&pdev->dev);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530951
952 sr_info->pdev = pdev;
953 sr_info->srid = pdev->id;
954 sr_info->voltdm = pdata->voltdm;
955 sr_info->nvalue_table = pdata->nvalue_table;
956 sr_info->nvalue_count = pdata->nvalue_count;
957 sr_info->senn_mod = pdata->senn_mod;
958 sr_info->senp_mod = pdata->senp_mod;
959 sr_info->autocomp_active = false;
960 sr_info->ip_type = pdata->ip_type;
961 sr_info->base = ioremap(mem->start, resource_size(mem));
962 if (!sr_info->base) {
963 dev_err(&pdev->dev, "%s: ioremap fail\n", __func__);
964 ret = -ENOMEM;
965 goto err_release_region;
966 }
967
968 if (irq)
969 sr_info->irq = irq->start;
970
971 sr_set_clk_length(sr_info);
972 sr_set_regfields(sr_info);
973
974 list_add(&sr_info->node, &sr_list);
975
976 /*
977 * Call into late init to do intializations that require
978 * both sr driver and sr class driver to be initiallized.
979 */
980 if (sr_class) {
981 ret = sr_late_init(sr_info);
982 if (ret) {
983 pr_warning("%s: Error in SR late init\n", __func__);
Julia Lawall14ea9602012-01-12 10:55:17 +0100984 goto err_iounmap;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530985 }
986 }
987
988 dev_info(&pdev->dev, "%s: SmartReflex driver initialized\n", __func__);
Kevin Hilman633ef8b742011-04-05 14:39:11 -0700989 if (!sr_dbg_dir) {
990 sr_dbg_dir = debugfs_create_dir("smartreflex", NULL);
Jean Pihet54b28cd2012-02-29 23:33:48 +0100991 if (IS_ERR_OR_NULL(sr_dbg_dir)) {
Kevin Hilman633ef8b742011-04-05 14:39:11 -0700992 ret = PTR_ERR(sr_dbg_dir);
993 pr_err("%s:sr debugfs dir creation failed(%d)\n",
994 __func__, ret);
995 goto err_iounmap;
996 }
Shweta Gulatib3329a32011-02-15 13:40:30 +0530997 }
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530998
Kevin Hilman633ef8b742011-04-05 14:39:11 -0700999 name = kasprintf(GFP_KERNEL, "sr_%s", sr_info->voltdm->name);
1000 if (!name) {
1001 dev_err(&pdev->dev, "%s: Unable to alloc debugfs name\n",
1002 __func__);
1003 ret = -ENOMEM;
1004 goto err_iounmap;
1005 }
1006 sr_info->dbg_dir = debugfs_create_dir(name, sr_dbg_dir);
1007 kfree(name);
Jean Pihet54b28cd2012-02-29 23:33:48 +01001008 if (IS_ERR_OR_NULL(sr_info->dbg_dir)) {
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301009 dev_err(&pdev->dev, "%s: Unable to create debugfs directory\n",
1010 __func__);
Anand S Sawantb1ace382011-02-17 21:27:30 +05301011 ret = PTR_ERR(sr_info->dbg_dir);
Aaro Koskinen0c49cc12011-04-26 02:25:21 -07001012 goto err_iounmap;
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301013 }
1014
Anand S Sawantb1ace382011-02-17 21:27:30 +05301015 (void) debugfs_create_file("autocomp", S_IRUGO | S_IWUSR,
1016 sr_info->dbg_dir, (void *)sr_info, &pm_sr_fops);
1017 (void) debugfs_create_x32("errweight", S_IRUGO, sr_info->dbg_dir,
Thara Gopinath077fcec2010-10-27 20:29:37 +05301018 &sr_info->err_weight);
Anand S Sawantb1ace382011-02-17 21:27:30 +05301019 (void) debugfs_create_x32("errmaxlimit", S_IRUGO, sr_info->dbg_dir,
Thara Gopinath077fcec2010-10-27 20:29:37 +05301020 &sr_info->err_maxlimit);
Anand S Sawantb1ace382011-02-17 21:27:30 +05301021 (void) debugfs_create_x32("errminlimit", S_IRUGO, sr_info->dbg_dir,
Thara Gopinath077fcec2010-10-27 20:29:37 +05301022 &sr_info->err_minlimit);
1023
Anand S Sawantb1ace382011-02-17 21:27:30 +05301024 nvalue_dir = debugfs_create_dir("nvalue", sr_info->dbg_dir);
Jean Pihet54b28cd2012-02-29 23:33:48 +01001025 if (IS_ERR_OR_NULL(nvalue_dir)) {
Thara Gopinath077fcec2010-10-27 20:29:37 +05301026 dev_err(&pdev->dev, "%s: Unable to create debugfs directory"
1027 "for n-values\n", __func__);
Shweta Gulatib3329a32011-02-15 13:40:30 +05301028 ret = PTR_ERR(nvalue_dir);
Aaro Koskinen283a1c12011-04-26 02:25:32 -07001029 goto err_debugfs;
Thara Gopinath077fcec2010-10-27 20:29:37 +05301030 }
1031
1032 omap_voltage_get_volttable(sr_info->voltdm, &volt_data);
1033 if (!volt_data) {
1034 dev_warn(&pdev->dev, "%s: No Voltage table for the"
1035 " corresponding vdd vdd_%s. Cannot create debugfs"
1036 "entries for n-values\n",
1037 __func__, sr_info->voltdm->name);
Shweta Gulatib3329a32011-02-15 13:40:30 +05301038 ret = -ENODATA;
Aaro Koskinen283a1c12011-04-26 02:25:32 -07001039 goto err_debugfs;
Thara Gopinath077fcec2010-10-27 20:29:37 +05301040 }
1041
1042 for (i = 0; i < sr_info->nvalue_count; i++) {
Aaro Koskinen865212a2011-02-07 16:08:04 +02001043 char name[NVALUE_NAME_LEN + 1];
Thara Gopinath077fcec2010-10-27 20:29:37 +05301044
Aaro Koskinen865212a2011-02-07 16:08:04 +02001045 snprintf(name, sizeof(name), "volt_%d",
1046 volt_data[i].volt_nominal);
Vasiliy Kulikov1232a182011-02-04 12:23:20 +00001047 (void) debugfs_create_x32(name, S_IRUGO | S_IWUSR, nvalue_dir,
Thara Gopinath077fcec2010-10-27 20:29:37 +05301048 &(sr_info->nvalue_table[i].nvalue));
1049 }
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301050
1051 return ret;
1052
Aaro Koskinen283a1c12011-04-26 02:25:32 -07001053err_debugfs:
1054 debugfs_remove_recursive(sr_info->dbg_dir);
Aaro Koskinen0c49cc12011-04-26 02:25:21 -07001055err_iounmap:
Aaro Koskinen833d78f2011-04-26 02:25:27 -07001056 list_del(&sr_info->node);
Aaro Koskinen0c49cc12011-04-26 02:25:21 -07001057 iounmap(sr_info->base);
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301058err_release_region:
1059 release_mem_region(mem->start, resource_size(mem));
1060err_free_devinfo:
1061 kfree(sr_info);
1062
1063 return ret;
1064}
1065
1066static int __devexit omap_sr_remove(struct platform_device *pdev)
1067{
1068 struct omap_sr_data *pdata = pdev->dev.platform_data;
1069 struct omap_sr *sr_info;
1070 struct resource *mem;
1071
1072 if (!pdata) {
1073 dev_err(&pdev->dev, "%s: platform data missing\n", __func__);
1074 return -EINVAL;
1075 }
1076
1077 sr_info = _sr_lookup(pdata->voltdm);
Julia Lawall28693ec2011-01-24 20:55:22 +01001078 if (IS_ERR(sr_info)) {
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301079 dev_warn(&pdev->dev, "%s: omap_sr struct not found\n",
1080 __func__);
Jean Pihet63371fa2012-02-29 23:33:49 +01001081 return PTR_ERR(sr_info);
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301082 }
1083
1084 if (sr_info->autocomp_active)
1085 sr_stop_vddautocomp(sr_info);
Anand S Sawantb1ace382011-02-17 21:27:30 +05301086 if (sr_info->dbg_dir)
1087 debugfs_remove_recursive(sr_info->dbg_dir);
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301088
1089 list_del(&sr_info->node);
1090 iounmap(sr_info->base);
1091 kfree(sr_info);
1092 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1093 release_mem_region(mem->start, resource_size(mem));
1094
1095 return 0;
1096}
1097
Nishanth Menon1f55bc1852012-03-01 00:29:44 +01001098static void __devexit omap_sr_shutdown(struct platform_device *pdev)
1099{
1100 struct omap_sr_data *pdata = pdev->dev.platform_data;
1101 struct omap_sr *sr_info;
1102
1103 if (!pdata) {
1104 dev_err(&pdev->dev, "%s: platform data missing\n", __func__);
1105 return;
1106 }
1107
1108 sr_info = _sr_lookup(pdata->voltdm);
1109 if (IS_ERR(sr_info)) {
1110 dev_warn(&pdev->dev, "%s: omap_sr struct not found\n",
1111 __func__);
1112 return;
1113 }
1114
1115 if (sr_info->autocomp_active)
1116 sr_stop_vddautocomp(sr_info);
1117
1118 return;
1119}
1120
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301121static struct platform_driver smartreflex_driver = {
Tony Lindgren149f1d52012-02-23 14:55:40 -08001122 .remove = __devexit_p(omap_sr_remove),
Nishanth Menon1f55bc1852012-03-01 00:29:44 +01001123 .shutdown = __devexit_p(omap_sr_shutdown),
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301124 .driver = {
1125 .name = "smartreflex",
1126 },
1127};
1128
1129static int __init sr_init(void)
1130{
1131 int ret = 0;
1132
1133 /*
1134 * sr_init is a late init. If by then a pmic specific API is not
1135 * registered either there is no need for anything to be done on
1136 * the PMIC side or somebody has forgotten to register a PMIC
1137 * handler. Warn for the second condition.
1138 */
1139 if (sr_pmic_data && sr_pmic_data->sr_pmic_init)
1140 sr_pmic_data->sr_pmic_init();
1141 else
1142 pr_warning("%s: No PMIC hook to init smartreflex\n", __func__);
1143
1144 ret = platform_driver_probe(&smartreflex_driver, omap_sr_probe);
1145 if (ret) {
1146 pr_err("%s: platform driver register failed for SR\n",
1147 __func__);
1148 return ret;
1149 }
1150
1151 return 0;
1152}
Felipe Balbi1a21a682012-02-29 23:33:45 +01001153late_initcall(sr_init);
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301154
1155static void __exit sr_exit(void)
1156{
1157 platform_driver_unregister(&smartreflex_driver);
1158}
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301159module_exit(sr_exit);
1160
1161MODULE_DESCRIPTION("OMAP Smartreflex Driver");
1162MODULE_LICENSE("GPL");
1163MODULE_ALIAS("platform:" DRIVER_NAME);
1164MODULE_AUTHOR("Texas Instruments Inc");