blob: 82bdd2838a1777edf6ad1546e63e46d7df7c5abe [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
Thara Gopinath984aa6d2010-05-29 22:02:22 +053037/* sr_list contains all the instances of smartreflex module */
38static LIST_HEAD(sr_list);
39
40static struct omap_sr_class_data *sr_class;
41static struct omap_sr_pmic_data *sr_pmic_data;
Kevin Hilman633ef8b742011-04-05 14:39:11 -070042static struct dentry *sr_dbg_dir;
Thara Gopinath984aa6d2010-05-29 22:02:22 +053043
44static inline void sr_write_reg(struct omap_sr *sr, unsigned offset, u32 value)
45{
46 __raw_writel(value, (sr->base + offset));
47}
48
49static inline void sr_modify_reg(struct omap_sr *sr, unsigned offset, u32 mask,
50 u32 value)
51{
52 u32 reg_val;
Thara Gopinath984aa6d2010-05-29 22:02:22 +053053
54 /*
55 * Smartreflex error config register is special as it contains
56 * certain status bits which if written a 1 into means a clear
57 * of those bits. So in order to make sure no accidental write of
58 * 1 happens to those status bits, do a clear of them in the read
59 * value. This mean this API doesn't rewrite values in these bits
60 * if they are currently set, but does allow the caller to write
61 * those bits.
62 */
Nishanth Menonade6ec02012-02-29 23:33:41 +010063 if (sr->ip_type == SR_TYPE_V1 && offset == ERRCONFIG_V1)
64 mask |= ERRCONFIG_STATUS_V1_MASK;
65 else if (sr->ip_type == SR_TYPE_V2 && offset == ERRCONFIG_V2)
66 mask |= ERRCONFIG_VPBOUNDINTST_V2;
Thara Gopinath984aa6d2010-05-29 22:02:22 +053067
Nishanth Menonade6ec02012-02-29 23:33:41 +010068 reg_val = __raw_readl(sr->base + offset);
69 reg_val &= ~mask;
70
71 value &= mask;
Thara Gopinath984aa6d2010-05-29 22:02:22 +053072
73 reg_val |= value;
74
75 __raw_writel(reg_val, (sr->base + offset));
76}
77
78static inline u32 sr_read_reg(struct omap_sr *sr, unsigned offset)
79{
80 return __raw_readl(sr->base + offset);
81}
82
83static struct omap_sr *_sr_lookup(struct voltagedomain *voltdm)
84{
85 struct omap_sr *sr_info;
86
87 if (!voltdm) {
88 pr_err("%s: Null voltage domain passed!\n", __func__);
89 return ERR_PTR(-EINVAL);
90 }
91
92 list_for_each_entry(sr_info, &sr_list, node) {
93 if (voltdm == sr_info->voltdm)
94 return sr_info;
95 }
96
97 return ERR_PTR(-ENODATA);
98}
99
100static irqreturn_t sr_interrupt(int irq, void *data)
101{
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100102 struct omap_sr *sr_info = data;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530103 u32 status = 0;
104
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100105 switch (sr_info->ip_type) {
106 case SR_TYPE_V1:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530107 /* Read the status bits */
108 status = sr_read_reg(sr_info, ERRCONFIG_V1);
109
110 /* Clear them by writing back */
111 sr_write_reg(sr_info, ERRCONFIG_V1, status);
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100112 break;
113 case SR_TYPE_V2:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530114 /* Read the status bits */
Felipe Balbi5a4f1842011-11-23 14:43:37 -0800115 status = sr_read_reg(sr_info, IRQSTATUS);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530116
117 /* Clear them by writing back */
118 sr_write_reg(sr_info, IRQSTATUS, status);
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100119 break;
120 default:
121 dev_err(&sr_info->pdev->dev, "UNKNOWN IP type %d\n",
122 sr_info->ip_type);
123 return IRQ_NONE;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530124 }
125
Nishanth Menon7a89afa2011-02-14 12:16:36 +0530126 if (sr_class->notify)
Jean Pihet80821c92012-04-24 10:22:12 +0530127 sr_class->notify(sr_info, status);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530128
129 return IRQ_HANDLED;
130}
131
132static void sr_set_clk_length(struct omap_sr *sr)
133{
134 struct clk *sys_ck;
135 u32 sys_clk_speed;
136
Thara Gopinathb35cecf2010-08-18 12:23:12 +0530137 if (cpu_is_omap34xx())
138 sys_ck = clk_get(NULL, "sys_ck");
139 else
140 sys_ck = clk_get(NULL, "sys_clkin_ck");
141
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530142 if (IS_ERR(sys_ck)) {
143 dev_err(&sr->pdev->dev, "%s: unable to get sys clk\n",
144 __func__);
145 return;
146 }
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100147
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530148 sys_clk_speed = clk_get_rate(sys_ck);
149 clk_put(sys_ck);
150
151 switch (sys_clk_speed) {
152 case 12000000:
153 sr->clk_length = SRCLKLENGTH_12MHZ_SYSCLK;
154 break;
155 case 13000000:
156 sr->clk_length = SRCLKLENGTH_13MHZ_SYSCLK;
157 break;
158 case 19200000:
159 sr->clk_length = SRCLKLENGTH_19MHZ_SYSCLK;
160 break;
161 case 26000000:
162 sr->clk_length = SRCLKLENGTH_26MHZ_SYSCLK;
163 break;
164 case 38400000:
165 sr->clk_length = SRCLKLENGTH_38MHZ_SYSCLK;
166 break;
167 default:
168 dev_err(&sr->pdev->dev, "%s: Invalid sysclk value: %d\n",
169 __func__, sys_clk_speed);
170 break;
171 }
172}
173
174static void sr_set_regfields(struct omap_sr *sr)
175{
176 /*
177 * For time being these values are defined in smartreflex.h
178 * and populated during init. May be they can be moved to board
179 * file or pmic specific data structure. In that case these structure
180 * fields will have to be populated using the pdata or pmic structure.
181 */
Thara Gopinathb35cecf2010-08-18 12:23:12 +0530182 if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530183 sr->err_weight = OMAP3430_SR_ERRWEIGHT;
184 sr->err_maxlimit = OMAP3430_SR_ERRMAXLIMIT;
185 sr->accum_data = OMAP3430_SR_ACCUMDATA;
186 if (!(strcmp(sr->voltdm->name, "mpu"))) {
187 sr->senn_avgweight = OMAP3430_SR1_SENNAVGWEIGHT;
188 sr->senp_avgweight = OMAP3430_SR1_SENPAVGWEIGHT;
189 } else {
190 sr->senn_avgweight = OMAP3430_SR2_SENNAVGWEIGHT;
191 sr->senp_avgweight = OMAP3430_SR2_SENPAVGWEIGHT;
192 }
193 }
194}
195
196static void sr_start_vddautocomp(struct omap_sr *sr)
197{
198 if (!sr_class || !(sr_class->enable) || !(sr_class->configure)) {
199 dev_warn(&sr->pdev->dev,
200 "%s: smartreflex class driver not registered\n",
201 __func__);
202 return;
203 }
204
Jean Pihet80821c92012-04-24 10:22:12 +0530205 if (!sr_class->enable(sr))
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530206 sr->autocomp_active = true;
207}
208
209static void sr_stop_vddautocomp(struct omap_sr *sr)
210{
211 if (!sr_class || !(sr_class->disable)) {
212 dev_warn(&sr->pdev->dev,
213 "%s: smartreflex class driver not registered\n",
214 __func__);
215 return;
216 }
217
218 if (sr->autocomp_active) {
Jean Pihet80821c92012-04-24 10:22:12 +0530219 sr_class->disable(sr, 1);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530220 sr->autocomp_active = false;
221 }
222}
223
224/*
225 * This function handles the intializations which have to be done
226 * only when both sr device and class driver regiter has
227 * completed. This will be attempted to be called from both sr class
228 * driver register and sr device intializtion API's. Only one call
229 * will ultimately succeed.
230 *
Vitaliy Ivanovfb914eb2011-06-23 20:01:55 +0300231 * Currently this function registers interrupt handler for a particular SR
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530232 * if smartreflex class driver is already registered and has
233 * requested for interrupts and the SR interrupt line in present.
234 */
235static int sr_late_init(struct omap_sr *sr_info)
236{
237 char *name;
238 struct omap_sr_data *pdata = sr_info->pdev->dev.platform_data;
239 struct resource *mem;
240 int ret = 0;
241
Nishanth Menon7a89afa2011-02-14 12:16:36 +0530242 if (sr_class->notify && sr_class->notify_flags && sr_info->irq) {
Vasiliy Kulikov5c56f322011-01-19 15:57:22 +0300243 name = kasprintf(GFP_KERNEL, "sr_%s", sr_info->voltdm->name);
244 if (name == NULL) {
245 ret = -ENOMEM;
246 goto error;
247 }
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530248 ret = request_irq(sr_info->irq, sr_interrupt,
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100249 0, name, sr_info);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530250 if (ret)
251 goto error;
Nishanth Menon1279ba52011-02-14 12:41:10 +0530252 disable_irq(sr_info->irq);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530253 }
254
255 if (pdata && pdata->enable_on_init)
256 sr_start_vddautocomp(sr_info);
257
258 return ret;
259
260error:
Nishanth Menon442155a2011-02-14 12:33:13 +0530261 iounmap(sr_info->base);
262 mem = platform_get_resource(sr_info->pdev, IORESOURCE_MEM, 0);
263 release_mem_region(mem->start, resource_size(mem));
264 list_del(&sr_info->node);
265 dev_err(&sr_info->pdev->dev, "%s: ERROR in registering"
266 "interrupt handler. Smartreflex will"
267 "not function as desired\n", __func__);
268 kfree(name);
269 kfree(sr_info);
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100270
Nishanth Menon442155a2011-02-14 12:33:13 +0530271 return ret;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530272}
273
274static void sr_v1_disable(struct omap_sr *sr)
275{
276 int timeout = 0;
Nishanth Menoncfec9c52012-02-29 23:33:42 +0100277 int errconf_val = ERRCONFIG_MCUACCUMINTST | ERRCONFIG_MCUVALIDINTST |
278 ERRCONFIG_MCUBOUNDINTST;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530279
280 /* Enable MCUDisableAcknowledge interrupt */
281 sr_modify_reg(sr, ERRCONFIG_V1,
282 ERRCONFIG_MCUDISACKINTEN, ERRCONFIG_MCUDISACKINTEN);
283
284 /* SRCONFIG - disable SR */
285 sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0x0);
286
Nishanth Menoncfec9c52012-02-29 23:33:42 +0100287 /* Disable all other SR interrupts and clear the status as needed */
288 if (sr_read_reg(sr, ERRCONFIG_V1) & ERRCONFIG_VPBOUNDINTST_V1)
289 errconf_val |= ERRCONFIG_VPBOUNDINTST_V1;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530290 sr_modify_reg(sr, ERRCONFIG_V1,
291 (ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUVALIDINTEN |
292 ERRCONFIG_MCUBOUNDINTEN | ERRCONFIG_VPBOUNDINTEN_V1),
Nishanth Menoncfec9c52012-02-29 23:33:42 +0100293 errconf_val);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530294
295 /*
296 * Wait for SR to be disabled.
297 * wait until ERRCONFIG.MCUDISACKINTST = 1. Typical latency is 1us.
298 */
299 omap_test_timeout((sr_read_reg(sr, ERRCONFIG_V1) &
300 ERRCONFIG_MCUDISACKINTST), SR_DISABLE_TIMEOUT,
301 timeout);
302
303 if (timeout >= SR_DISABLE_TIMEOUT)
304 dev_warn(&sr->pdev->dev, "%s: Smartreflex disable timedout\n",
305 __func__);
306
307 /* Disable MCUDisableAcknowledge interrupt & clear pending interrupt */
308 sr_modify_reg(sr, ERRCONFIG_V1, ERRCONFIG_MCUDISACKINTEN,
309 ERRCONFIG_MCUDISACKINTST);
310}
311
312static void sr_v2_disable(struct omap_sr *sr)
313{
314 int timeout = 0;
315
316 /* Enable MCUDisableAcknowledge interrupt */
317 sr_write_reg(sr, IRQENABLE_SET, IRQENABLE_MCUDISABLEACKINT);
318
319 /* SRCONFIG - disable SR */
320 sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0x0);
321
Nishanth Menoncfec9c52012-02-29 23:33:42 +0100322 /*
323 * Disable all other SR interrupts and clear the status
324 * write to status register ONLY on need basis - only if status
325 * is set.
326 */
327 if (sr_read_reg(sr, ERRCONFIG_V2) & ERRCONFIG_VPBOUNDINTST_V2)
328 sr_modify_reg(sr, ERRCONFIG_V2, ERRCONFIG_VPBOUNDINTEN_V2,
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530329 ERRCONFIG_VPBOUNDINTST_V2);
Nishanth Menoncfec9c52012-02-29 23:33:42 +0100330 else
331 sr_modify_reg(sr, ERRCONFIG_V2, ERRCONFIG_VPBOUNDINTEN_V2,
332 0x0);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530333 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{
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100391 u32 sr_config, sr_errconfig, errconfig_offs;
392 u32 vpboundint_en, vpboundint_st;
393 u32 senp_en = 0, senn_en = 0;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530394 u8 senp_shift, senn_shift;
395 struct omap_sr *sr = _sr_lookup(voltdm);
396
397 if (IS_ERR(sr)) {
398 pr_warning("%s: omap_sr struct for sr_%s not found\n",
399 __func__, voltdm->name);
Jean Pihet63371fa2012-02-29 23:33:49 +0100400 return PTR_ERR(sr);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530401 }
402
403 if (!sr->clk_length)
404 sr_set_clk_length(sr);
405
406 senp_en = sr->senp_mod;
407 senn_en = sr->senn_mod;
408
409 sr_config = (sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
410 SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN;
411
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100412 switch (sr->ip_type) {
413 case SR_TYPE_V1:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530414 sr_config |= SRCONFIG_DELAYCTRL;
415 senn_shift = SRCONFIG_SENNENABLE_V1_SHIFT;
416 senp_shift = SRCONFIG_SENPENABLE_V1_SHIFT;
417 errconfig_offs = ERRCONFIG_V1;
418 vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V1;
419 vpboundint_st = ERRCONFIG_VPBOUNDINTST_V1;
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100420 break;
421 case SR_TYPE_V2:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530422 senn_shift = SRCONFIG_SENNENABLE_V2_SHIFT;
423 senp_shift = SRCONFIG_SENPENABLE_V2_SHIFT;
424 errconfig_offs = ERRCONFIG_V2;
425 vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V2;
426 vpboundint_st = ERRCONFIG_VPBOUNDINTST_V2;
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100427 break;
428 default:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530429 dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex"
430 "module without specifying the ip\n", __func__);
431 return -EINVAL;
432 }
433
434 sr_config |= ((senn_en << senn_shift) | (senp_en << senp_shift));
435 sr_write_reg(sr, SRCONFIG, sr_config);
436 sr_errconfig = (sr->err_weight << ERRCONFIG_ERRWEIGHT_SHIFT) |
437 (sr->err_maxlimit << ERRCONFIG_ERRMAXLIMIT_SHIFT) |
438 (sr->err_minlimit << ERRCONFIG_ERRMINLIMIT_SHIFT);
439 sr_modify_reg(sr, errconfig_offs, (SR_ERRWEIGHT_MASK |
440 SR_ERRMAXLIMIT_MASK | SR_ERRMINLIMIT_MASK),
441 sr_errconfig);
442
443 /* Enabling the interrupts if the ERROR module is used */
Nishanth Menon74754cc2012-02-29 23:33:38 +0100444 sr_modify_reg(sr, errconfig_offs, (vpboundint_en | vpboundint_st),
445 vpboundint_en);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530446
447 return 0;
448}
449
450/**
Nishanth Menonad54c3d2012-02-29 23:33:39 +0100451 * sr_disable_errgen() - Disables SmartReflex AVS module's errgen component
452 * @voltdm: VDD pointer to which the SR module to be configured belongs to.
453 *
454 * This API is to be called from the smartreflex class driver to
455 * disable the error generator module inside the smartreflex module.
456 *
457 * Returns 0 on success and error value in case of failure.
458 */
459int sr_disable_errgen(struct voltagedomain *voltdm)
460{
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100461 u32 errconfig_offs;
462 u32 vpboundint_en, vpboundint_st;
Nishanth Menonad54c3d2012-02-29 23:33:39 +0100463 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);
Jean Pihet63371fa2012-02-29 23:33:49 +0100468 return PTR_ERR(sr);
Nishanth Menonad54c3d2012-02-29 23:33:39 +0100469 }
470
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100471 switch (sr->ip_type) {
472 case SR_TYPE_V1:
Nishanth Menonad54c3d2012-02-29 23:33:39 +0100473 errconfig_offs = ERRCONFIG_V1;
474 vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V1;
475 vpboundint_st = ERRCONFIG_VPBOUNDINTST_V1;
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100476 break;
477 case SR_TYPE_V2:
Nishanth Menonad54c3d2012-02-29 23:33:39 +0100478 errconfig_offs = ERRCONFIG_V2;
479 vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V2;
480 vpboundint_st = ERRCONFIG_VPBOUNDINTST_V2;
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100481 break;
482 default:
Nishanth Menonad54c3d2012-02-29 23:33:39 +0100483 dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex"
484 "module without specifying the ip\n", __func__);
485 return -EINVAL;
486 }
487
488 /* Disable the interrupts of ERROR module */
489 sr_modify_reg(sr, errconfig_offs, vpboundint_en | vpboundint_st, 0);
490
491 /* Disable the Sensor and errorgen */
492 sr_modify_reg(sr, SRCONFIG, SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN, 0);
493
494 return 0;
495}
496
497/**
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530498 * sr_configure_minmax() - Configures the smrtreflex to perform AVS using the
499 * minmaxavg module.
500 * @voltdm: VDD pointer to which the SR module to be configured belongs to.
501 *
502 * This API is to be called from the smartreflex class driver to
503 * configure the minmaxavg module inside the smartreflex module.
504 * SR settings if using the ERROR module inside Smartreflex.
505 * SR CLASS 3 by default uses only the ERROR module where as
506 * SR CLASS 2 can choose between ERROR module and MINMAXAVG
507 * module. Returns 0 on success and error value in case of failure.
508 */
509int sr_configure_minmax(struct voltagedomain *voltdm)
510{
511 u32 sr_config, sr_avgwt;
512 u32 senp_en = 0, senn_en = 0;
513 u8 senp_shift, senn_shift;
514 struct omap_sr *sr = _sr_lookup(voltdm);
515
516 if (IS_ERR(sr)) {
517 pr_warning("%s: omap_sr struct for sr_%s not found\n",
518 __func__, voltdm->name);
Jean Pihet63371fa2012-02-29 23:33:49 +0100519 return PTR_ERR(sr);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530520 }
521
522 if (!sr->clk_length)
523 sr_set_clk_length(sr);
524
525 senp_en = sr->senp_mod;
526 senn_en = sr->senn_mod;
527
528 sr_config = (sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
529 SRCONFIG_SENENABLE |
530 (sr->accum_data << SRCONFIG_ACCUMDATA_SHIFT);
531
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100532 switch (sr->ip_type) {
533 case SR_TYPE_V1:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530534 sr_config |= SRCONFIG_DELAYCTRL;
535 senn_shift = SRCONFIG_SENNENABLE_V1_SHIFT;
536 senp_shift = SRCONFIG_SENPENABLE_V1_SHIFT;
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100537 break;
538 case SR_TYPE_V2:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530539 senn_shift = SRCONFIG_SENNENABLE_V2_SHIFT;
540 senp_shift = SRCONFIG_SENPENABLE_V2_SHIFT;
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100541 break;
542 default:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530543 dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex"
544 "module without specifying the ip\n", __func__);
545 return -EINVAL;
546 }
547
548 sr_config |= ((senn_en << senn_shift) | (senp_en << senp_shift));
549 sr_write_reg(sr, SRCONFIG, sr_config);
550 sr_avgwt = (sr->senp_avgweight << AVGWEIGHT_SENPAVGWEIGHT_SHIFT) |
551 (sr->senn_avgweight << AVGWEIGHT_SENNAVGWEIGHT_SHIFT);
552 sr_write_reg(sr, AVGWEIGHT, sr_avgwt);
553
554 /*
555 * Enabling the interrupts if MINMAXAVG module is used.
556 * TODO: check if all the interrupts are mandatory
557 */
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100558 switch (sr->ip_type) {
559 case SR_TYPE_V1:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530560 sr_modify_reg(sr, ERRCONFIG_V1,
561 (ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUVALIDINTEN |
562 ERRCONFIG_MCUBOUNDINTEN),
563 (ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUACCUMINTST |
564 ERRCONFIG_MCUVALIDINTEN | ERRCONFIG_MCUVALIDINTST |
565 ERRCONFIG_MCUBOUNDINTEN | ERRCONFIG_MCUBOUNDINTST));
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100566 break;
567 case SR_TYPE_V2:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530568 sr_write_reg(sr, IRQSTATUS,
569 IRQSTATUS_MCUACCUMINT | IRQSTATUS_MCVALIDINT |
570 IRQSTATUS_MCBOUNDSINT | IRQSTATUS_MCUDISABLEACKINT);
571 sr_write_reg(sr, IRQENABLE_SET,
572 IRQENABLE_MCUACCUMINT | IRQENABLE_MCUVALIDINT |
573 IRQENABLE_MCUBOUNDSINT | IRQENABLE_MCUDISABLEACKINT);
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100574 break;
575 default:
576 dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex"
577 "module without specifying the ip\n", __func__);
578 return -EINVAL;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530579 }
580
581 return 0;
582}
583
584/**
585 * sr_enable() - Enables the smartreflex module.
586 * @voltdm: VDD pointer to which the SR module to be configured belongs to.
587 * @volt: The voltage at which the Voltage domain associated with
588 * the smartreflex module is operating at.
589 * This is required only to program the correct Ntarget value.
590 *
591 * This API is to be called from the smartreflex class driver to
592 * enable a smartreflex module. Returns 0 on success. Returns error
593 * value if the voltage passed is wrong or if ntarget value is wrong.
594 */
595int sr_enable(struct voltagedomain *voltdm, unsigned long volt)
596{
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530597 struct omap_volt_data *volt_data;
598 struct omap_sr *sr = _sr_lookup(voltdm);
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100599 u32 nvalue_reciprocal;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530600 int ret;
601
602 if (IS_ERR(sr)) {
603 pr_warning("%s: omap_sr struct for sr_%s not found\n",
604 __func__, voltdm->name);
Jean Pihet63371fa2012-02-29 23:33:49 +0100605 return PTR_ERR(sr);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530606 }
607
608 volt_data = omap_voltage_get_voltdata(sr->voltdm, volt);
609
610 if (IS_ERR(volt_data)) {
611 dev_warn(&sr->pdev->dev, "%s: Unable to get voltage table"
612 "for nominal voltage %ld\n", __func__, volt);
Jean Pihet63371fa2012-02-29 23:33:49 +0100613 return PTR_ERR(volt_data);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530614 }
615
616 nvalue_reciprocal = sr_retrieve_nvalue(sr, volt_data->sr_efuse_offs);
617
618 if (!nvalue_reciprocal) {
619 dev_warn(&sr->pdev->dev, "%s: NVALUE = 0 at voltage %ld\n",
620 __func__, volt);
621 return -ENODATA;
622 }
623
624 /* errminlimit is opp dependent and hence linked to voltage */
625 sr->err_minlimit = volt_data->sr_errminlimit;
626
627 pm_runtime_get_sync(&sr->pdev->dev);
628
629 /* Check if SR is already enabled. If yes do nothing */
630 if (sr_read_reg(sr, SRCONFIG) & SRCONFIG_SRENABLE)
631 return 0;
632
633 /* Configure SR */
Jean Pihet80821c92012-04-24 10:22:12 +0530634 ret = sr_class->configure(sr);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530635 if (ret)
636 return ret;
637
638 sr_write_reg(sr, NVALUERECIPROCAL, nvalue_reciprocal);
639
640 /* SRCONFIG - enable SR */
641 sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, SRCONFIG_SRENABLE);
642 return 0;
643}
644
645/**
646 * sr_disable() - Disables the smartreflex module.
647 * @voltdm: VDD pointer to which the SR module to be configured belongs to.
648 *
649 * This API is to be called from the smartreflex class driver to
650 * disable a smartreflex module.
651 */
652void sr_disable(struct voltagedomain *voltdm)
653{
654 struct omap_sr *sr = _sr_lookup(voltdm);
655
656 if (IS_ERR(sr)) {
657 pr_warning("%s: omap_sr struct for sr_%s not found\n",
658 __func__, voltdm->name);
659 return;
660 }
661
662 /* Check if SR clocks are already disabled. If yes do nothing */
663 if (pm_runtime_suspended(&sr->pdev->dev))
664 return;
665
666 /*
667 * Disable SR if only it is indeed enabled. Else just
668 * disable the clocks.
669 */
670 if (sr_read_reg(sr, SRCONFIG) & SRCONFIG_SRENABLE) {
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100671 switch (sr->ip_type) {
672 case SR_TYPE_V1:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530673 sr_v1_disable(sr);
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100674 break;
675 case SR_TYPE_V2:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530676 sr_v2_disable(sr);
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100677 break;
678 default:
679 dev_err(&sr->pdev->dev, "UNKNOWN IP type %d\n",
680 sr->ip_type);
681 }
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530682 }
683
Colin Cross98333b32011-07-22 00:55:52 -0500684 pm_runtime_put_sync_suspend(&sr->pdev->dev);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530685}
686
687/**
688 * sr_register_class() - API to register a smartreflex class parameters.
689 * @class_data: The structure containing various sr class specific data.
690 *
691 * This API is to be called by the smartreflex class driver to register itself
692 * with the smartreflex driver during init. Returns 0 on success else the
693 * error value.
694 */
695int sr_register_class(struct omap_sr_class_data *class_data)
696{
697 struct omap_sr *sr_info;
698
699 if (!class_data) {
700 pr_warning("%s:, Smartreflex class data passed is NULL\n",
701 __func__);
702 return -EINVAL;
703 }
704
705 if (sr_class) {
706 pr_warning("%s: Smartreflex class driver already registered\n",
707 __func__);
708 return -EBUSY;
709 }
710
711 sr_class = class_data;
712
713 /*
714 * Call into late init to do intializations that require
715 * both sr driver and sr class driver to be initiallized.
716 */
717 list_for_each_entry(sr_info, &sr_list, node)
718 sr_late_init(sr_info);
719
720 return 0;
721}
722
723/**
724 * omap_sr_enable() - API to enable SR clocks and to call into the
725 * registered smartreflex class enable API.
726 * @voltdm: VDD pointer to which the SR module to be configured belongs to.
727 *
728 * This API is to be called from the kernel in order to enable
729 * a particular smartreflex module. This API will do the initial
730 * configurations to turn on the smartreflex module and in turn call
731 * into the registered smartreflex class enable API.
732 */
733void omap_sr_enable(struct voltagedomain *voltdm)
734{
735 struct omap_sr *sr = _sr_lookup(voltdm);
736
737 if (IS_ERR(sr)) {
738 pr_warning("%s: omap_sr struct for sr_%s not found\n",
739 __func__, voltdm->name);
740 return;
741 }
742
743 if (!sr->autocomp_active)
744 return;
745
746 if (!sr_class || !(sr_class->enable) || !(sr_class->configure)) {
747 dev_warn(&sr->pdev->dev, "%s: smartreflex class driver not"
748 "registered\n", __func__);
749 return;
750 }
751
Jean Pihet80821c92012-04-24 10:22:12 +0530752 sr_class->enable(sr);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530753}
754
755/**
756 * omap_sr_disable() - API to disable SR without resetting the voltage
757 * processor voltage
758 * @voltdm: VDD pointer to which the SR module to be configured belongs to.
759 *
760 * This API is to be called from the kernel in order to disable
761 * a particular smartreflex module. This API will in turn call
762 * into the registered smartreflex class disable API. This API will tell
763 * the smartreflex class disable not to reset the VP voltage after
764 * disabling smartreflex.
765 */
766void omap_sr_disable(struct voltagedomain *voltdm)
767{
768 struct omap_sr *sr = _sr_lookup(voltdm);
769
770 if (IS_ERR(sr)) {
771 pr_warning("%s: omap_sr struct for sr_%s not found\n",
772 __func__, voltdm->name);
773 return;
774 }
775
776 if (!sr->autocomp_active)
777 return;
778
779 if (!sr_class || !(sr_class->disable)) {
780 dev_warn(&sr->pdev->dev, "%s: smartreflex class driver not"
781 "registered\n", __func__);
782 return;
783 }
784
Jean Pihet80821c92012-04-24 10:22:12 +0530785 sr_class->disable(sr, 0);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530786}
787
788/**
789 * omap_sr_disable_reset_volt() - API to disable SR and reset the
790 * voltage processor voltage
791 * @voltdm: VDD pointer to which the SR module to be configured belongs to.
792 *
793 * This API is to be called from the kernel in order to disable
794 * a particular smartreflex module. This API will in turn call
795 * into the registered smartreflex class disable API. This API will tell
796 * the smartreflex class disable to reset the VP voltage after
797 * disabling smartreflex.
798 */
799void omap_sr_disable_reset_volt(struct voltagedomain *voltdm)
800{
801 struct omap_sr *sr = _sr_lookup(voltdm);
802
803 if (IS_ERR(sr)) {
804 pr_warning("%s: omap_sr struct for sr_%s not found\n",
805 __func__, voltdm->name);
806 return;
807 }
808
809 if (!sr->autocomp_active)
810 return;
811
812 if (!sr_class || !(sr_class->disable)) {
813 dev_warn(&sr->pdev->dev, "%s: smartreflex class driver not"
814 "registered\n", __func__);
815 return;
816 }
817
Jean Pihet80821c92012-04-24 10:22:12 +0530818 sr_class->disable(sr, 1);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530819}
820
821/**
822 * omap_sr_register_pmic() - API to register pmic specific info.
823 * @pmic_data: The structure containing pmic specific data.
824 *
825 * This API is to be called from the PMIC specific code to register with
826 * smartreflex driver pmic specific info. Currently the only info required
827 * is the smartreflex init on the PMIC side.
828 */
829void omap_sr_register_pmic(struct omap_sr_pmic_data *pmic_data)
830{
831 if (!pmic_data) {
832 pr_warning("%s: Trying to register NULL PMIC data structure"
833 "with smartreflex\n", __func__);
834 return;
835 }
836
837 sr_pmic_data = pmic_data;
838}
839
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100840/* PM Debug FS entries to enable and disable smartreflex. */
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530841static int omap_sr_autocomp_show(void *data, u64 *val)
842{
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100843 struct omap_sr *sr_info = data;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530844
845 if (!sr_info) {
Stefan Weil83535842011-01-30 20:29:38 +0100846 pr_warning("%s: omap_sr struct not found\n", __func__);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530847 return -EINVAL;
848 }
849
850 *val = sr_info->autocomp_active;
851
852 return 0;
853}
854
855static int omap_sr_autocomp_store(void *data, u64 val)
856{
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100857 struct omap_sr *sr_info = data;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530858
859 if (!sr_info) {
Stefan Weil83535842011-01-30 20:29:38 +0100860 pr_warning("%s: omap_sr struct not found\n", __func__);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530861 return -EINVAL;
862 }
863
864 /* Sanity check */
Felipe Balbid6173692012-02-29 23:33:47 +0100865 if (val > 1) {
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530866 pr_warning("%s: Invalid argument %lld\n", __func__, val);
867 return -EINVAL;
868 }
869
Nishanth Menonac77a6f2011-02-14 21:14:17 +0530870 /* control enable/disable only if there is a delta in value */
871 if (sr_info->autocomp_active != val) {
872 if (!val)
873 sr_stop_vddautocomp(sr_info);
874 else
875 sr_start_vddautocomp(sr_info);
876 }
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530877
878 return 0;
879}
880
881DEFINE_SIMPLE_ATTRIBUTE(pm_sr_fops, omap_sr_autocomp_show,
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100882 omap_sr_autocomp_store, "%llu\n");
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530883
884static int __init omap_sr_probe(struct platform_device *pdev)
885{
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100886 struct omap_sr *sr_info;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530887 struct omap_sr_data *pdata = pdev->dev.platform_data;
888 struct resource *mem, *irq;
Kevin Hilman633ef8b742011-04-05 14:39:11 -0700889 struct dentry *nvalue_dir;
Thara Gopinath077fcec2010-10-27 20:29:37 +0530890 struct omap_volt_data *volt_data;
891 int i, ret = 0;
Kevin Hilman633ef8b742011-04-05 14:39:11 -0700892 char *name;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530893
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100894 sr_info = kzalloc(sizeof(struct omap_sr), GFP_KERNEL);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530895 if (!sr_info) {
896 dev_err(&pdev->dev, "%s: unable to allocate sr_info\n",
897 __func__);
898 return -ENOMEM;
899 }
900
Felipe Balbi1079a8b2012-02-29 23:33:44 +0100901 platform_set_drvdata(pdev, sr_info);
902
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530903 if (!pdata) {
904 dev_err(&pdev->dev, "%s: platform data missing\n", __func__);
Stefan Weil720bc782011-01-30 20:26:27 +0100905 ret = -EINVAL;
906 goto err_free_devinfo;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530907 }
908
909 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
910 if (!mem) {
911 dev_err(&pdev->dev, "%s: no mem resource\n", __func__);
912 ret = -ENODEV;
913 goto err_free_devinfo;
914 }
915
Aaro Koskinenda9e73922011-04-26 02:25:16 -0700916 mem = request_mem_region(mem->start, resource_size(mem),
917 dev_name(&pdev->dev));
918 if (!mem) {
919 dev_err(&pdev->dev, "%s: no mem region\n", __func__);
920 ret = -EBUSY;
921 goto err_free_devinfo;
922 }
923
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530924 irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
925
926 pm_runtime_enable(&pdev->dev);
Nishanth Menone13d8f32011-07-09 14:37:21 -0700927 pm_runtime_irq_safe(&pdev->dev);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530928
929 sr_info->pdev = pdev;
930 sr_info->srid = pdev->id;
931 sr_info->voltdm = pdata->voltdm;
932 sr_info->nvalue_table = pdata->nvalue_table;
933 sr_info->nvalue_count = pdata->nvalue_count;
934 sr_info->senn_mod = pdata->senn_mod;
935 sr_info->senp_mod = pdata->senp_mod;
936 sr_info->autocomp_active = false;
937 sr_info->ip_type = pdata->ip_type;
938 sr_info->base = ioremap(mem->start, resource_size(mem));
939 if (!sr_info->base) {
940 dev_err(&pdev->dev, "%s: ioremap fail\n", __func__);
941 ret = -ENOMEM;
942 goto err_release_region;
943 }
944
945 if (irq)
946 sr_info->irq = irq->start;
947
948 sr_set_clk_length(sr_info);
949 sr_set_regfields(sr_info);
950
951 list_add(&sr_info->node, &sr_list);
952
953 /*
954 * Call into late init to do intializations that require
955 * both sr driver and sr class driver to be initiallized.
956 */
957 if (sr_class) {
958 ret = sr_late_init(sr_info);
959 if (ret) {
960 pr_warning("%s: Error in SR late init\n", __func__);
Julia Lawall14ea9602012-01-12 10:55:17 +0100961 goto err_iounmap;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530962 }
963 }
964
965 dev_info(&pdev->dev, "%s: SmartReflex driver initialized\n", __func__);
Kevin Hilman633ef8b742011-04-05 14:39:11 -0700966 if (!sr_dbg_dir) {
967 sr_dbg_dir = debugfs_create_dir("smartreflex", NULL);
Jean Pihet54b28cd2012-02-29 23:33:48 +0100968 if (IS_ERR_OR_NULL(sr_dbg_dir)) {
Kevin Hilman633ef8b742011-04-05 14:39:11 -0700969 ret = PTR_ERR(sr_dbg_dir);
970 pr_err("%s:sr debugfs dir creation failed(%d)\n",
971 __func__, ret);
972 goto err_iounmap;
973 }
Shweta Gulatib3329a32011-02-15 13:40:30 +0530974 }
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530975
Kevin Hilman633ef8b742011-04-05 14:39:11 -0700976 name = kasprintf(GFP_KERNEL, "sr_%s", sr_info->voltdm->name);
977 if (!name) {
978 dev_err(&pdev->dev, "%s: Unable to alloc debugfs name\n",
979 __func__);
980 ret = -ENOMEM;
981 goto err_iounmap;
982 }
983 sr_info->dbg_dir = debugfs_create_dir(name, sr_dbg_dir);
984 kfree(name);
Jean Pihet54b28cd2012-02-29 23:33:48 +0100985 if (IS_ERR_OR_NULL(sr_info->dbg_dir)) {
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530986 dev_err(&pdev->dev, "%s: Unable to create debugfs directory\n",
987 __func__);
Anand S Sawantb1ace382011-02-17 21:27:30 +0530988 ret = PTR_ERR(sr_info->dbg_dir);
Aaro Koskinen0c49cc12011-04-26 02:25:21 -0700989 goto err_iounmap;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530990 }
991
Anand S Sawantb1ace382011-02-17 21:27:30 +0530992 (void) debugfs_create_file("autocomp", S_IRUGO | S_IWUSR,
993 sr_info->dbg_dir, (void *)sr_info, &pm_sr_fops);
994 (void) debugfs_create_x32("errweight", S_IRUGO, sr_info->dbg_dir,
Thara Gopinath077fcec2010-10-27 20:29:37 +0530995 &sr_info->err_weight);
Anand S Sawantb1ace382011-02-17 21:27:30 +0530996 (void) debugfs_create_x32("errmaxlimit", S_IRUGO, sr_info->dbg_dir,
Thara Gopinath077fcec2010-10-27 20:29:37 +0530997 &sr_info->err_maxlimit);
Anand S Sawantb1ace382011-02-17 21:27:30 +0530998 (void) debugfs_create_x32("errminlimit", S_IRUGO, sr_info->dbg_dir,
Thara Gopinath077fcec2010-10-27 20:29:37 +0530999 &sr_info->err_minlimit);
1000
Anand S Sawantb1ace382011-02-17 21:27:30 +05301001 nvalue_dir = debugfs_create_dir("nvalue", sr_info->dbg_dir);
Jean Pihet54b28cd2012-02-29 23:33:48 +01001002 if (IS_ERR_OR_NULL(nvalue_dir)) {
Thara Gopinath077fcec2010-10-27 20:29:37 +05301003 dev_err(&pdev->dev, "%s: Unable to create debugfs directory"
1004 "for n-values\n", __func__);
Shweta Gulatib3329a32011-02-15 13:40:30 +05301005 ret = PTR_ERR(nvalue_dir);
Aaro Koskinen283a1c12011-04-26 02:25:32 -07001006 goto err_debugfs;
Thara Gopinath077fcec2010-10-27 20:29:37 +05301007 }
1008
1009 omap_voltage_get_volttable(sr_info->voltdm, &volt_data);
1010 if (!volt_data) {
1011 dev_warn(&pdev->dev, "%s: No Voltage table for the"
1012 " corresponding vdd vdd_%s. Cannot create debugfs"
1013 "entries for n-values\n",
1014 __func__, sr_info->voltdm->name);
Shweta Gulatib3329a32011-02-15 13:40:30 +05301015 ret = -ENODATA;
Aaro Koskinen283a1c12011-04-26 02:25:32 -07001016 goto err_debugfs;
Thara Gopinath077fcec2010-10-27 20:29:37 +05301017 }
1018
1019 for (i = 0; i < sr_info->nvalue_count; i++) {
Aaro Koskinen865212a2011-02-07 16:08:04 +02001020 char name[NVALUE_NAME_LEN + 1];
Thara Gopinath077fcec2010-10-27 20:29:37 +05301021
Aaro Koskinen865212a2011-02-07 16:08:04 +02001022 snprintf(name, sizeof(name), "volt_%d",
1023 volt_data[i].volt_nominal);
Vasiliy Kulikov1232a182011-02-04 12:23:20 +00001024 (void) debugfs_create_x32(name, S_IRUGO | S_IWUSR, nvalue_dir,
Thara Gopinath077fcec2010-10-27 20:29:37 +05301025 &(sr_info->nvalue_table[i].nvalue));
1026 }
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301027
1028 return ret;
1029
Aaro Koskinen283a1c12011-04-26 02:25:32 -07001030err_debugfs:
1031 debugfs_remove_recursive(sr_info->dbg_dir);
Aaro Koskinen0c49cc12011-04-26 02:25:21 -07001032err_iounmap:
Aaro Koskinen833d78f2011-04-26 02:25:27 -07001033 list_del(&sr_info->node);
Aaro Koskinen0c49cc12011-04-26 02:25:21 -07001034 iounmap(sr_info->base);
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301035err_release_region:
1036 release_mem_region(mem->start, resource_size(mem));
1037err_free_devinfo:
1038 kfree(sr_info);
1039
1040 return ret;
1041}
1042
1043static int __devexit omap_sr_remove(struct platform_device *pdev)
1044{
1045 struct omap_sr_data *pdata = pdev->dev.platform_data;
1046 struct omap_sr *sr_info;
1047 struct resource *mem;
1048
1049 if (!pdata) {
1050 dev_err(&pdev->dev, "%s: platform data missing\n", __func__);
1051 return -EINVAL;
1052 }
1053
1054 sr_info = _sr_lookup(pdata->voltdm);
Julia Lawall28693ec2011-01-24 20:55:22 +01001055 if (IS_ERR(sr_info)) {
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301056 dev_warn(&pdev->dev, "%s: omap_sr struct not found\n",
1057 __func__);
Jean Pihet63371fa2012-02-29 23:33:49 +01001058 return PTR_ERR(sr_info);
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301059 }
1060
1061 if (sr_info->autocomp_active)
1062 sr_stop_vddautocomp(sr_info);
Anand S Sawantb1ace382011-02-17 21:27:30 +05301063 if (sr_info->dbg_dir)
1064 debugfs_remove_recursive(sr_info->dbg_dir);
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301065
1066 list_del(&sr_info->node);
1067 iounmap(sr_info->base);
1068 kfree(sr_info);
1069 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1070 release_mem_region(mem->start, resource_size(mem));
1071
1072 return 0;
1073}
1074
Nishanth Menon1f55bc1852012-03-01 00:29:44 +01001075static void __devexit omap_sr_shutdown(struct platform_device *pdev)
1076{
1077 struct omap_sr_data *pdata = pdev->dev.platform_data;
1078 struct omap_sr *sr_info;
1079
1080 if (!pdata) {
1081 dev_err(&pdev->dev, "%s: platform data missing\n", __func__);
1082 return;
1083 }
1084
1085 sr_info = _sr_lookup(pdata->voltdm);
1086 if (IS_ERR(sr_info)) {
1087 dev_warn(&pdev->dev, "%s: omap_sr struct not found\n",
1088 __func__);
1089 return;
1090 }
1091
1092 if (sr_info->autocomp_active)
1093 sr_stop_vddautocomp(sr_info);
1094
1095 return;
1096}
1097
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301098static struct platform_driver smartreflex_driver = {
Tony Lindgren149f1d52012-02-23 14:55:40 -08001099 .remove = __devexit_p(omap_sr_remove),
Nishanth Menon1f55bc1852012-03-01 00:29:44 +01001100 .shutdown = __devexit_p(omap_sr_shutdown),
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301101 .driver = {
1102 .name = "smartreflex",
1103 },
1104};
1105
1106static int __init sr_init(void)
1107{
1108 int ret = 0;
1109
1110 /*
1111 * sr_init is a late init. If by then a pmic specific API is not
1112 * registered either there is no need for anything to be done on
1113 * the PMIC side or somebody has forgotten to register a PMIC
1114 * handler. Warn for the second condition.
1115 */
1116 if (sr_pmic_data && sr_pmic_data->sr_pmic_init)
1117 sr_pmic_data->sr_pmic_init();
1118 else
1119 pr_warning("%s: No PMIC hook to init smartreflex\n", __func__);
1120
1121 ret = platform_driver_probe(&smartreflex_driver, omap_sr_probe);
1122 if (ret) {
1123 pr_err("%s: platform driver register failed for SR\n",
1124 __func__);
1125 return ret;
1126 }
1127
1128 return 0;
1129}
Felipe Balbi1a21a682012-02-29 23:33:45 +01001130late_initcall(sr_init);
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301131
1132static void __exit sr_exit(void)
1133{
1134 platform_driver_unregister(&smartreflex_driver);
1135}
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301136module_exit(sr_exit);
1137
1138MODULE_DESCRIPTION("OMAP Smartreflex Driver");
1139MODULE_LICENSE("GPL");
1140MODULE_ALIAS("platform:" DRIVER_NAME);
1141MODULE_AUTHOR("Texas Instruments Inc");