blob: 08a8a299f1fd30e322a41d8329059b1578ba0de9 [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 *
Jean Pihet21ff63a2012-04-25 16:43:17 +05306 * Copyright (C) 2012 Texas Instruments, Inc.
Thara Gopinath984aa6d2010-05-29 22:02:22 +05307 * 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
Andrii Tseglytskyi33da2822013-05-30 13:08:36 +030030#define DRIVER_NAME "smartreflex"
Thara Gopinath984aa6d2010-05-29 22:02:22 +053031#define SMARTREFLEX_NAME_LEN 16
Thara Gopinath077fcec2010-10-27 20:29:37 +053032#define NVALUE_NAME_LEN 40
Thara Gopinath984aa6d2010-05-29 22:02:22 +053033#define SR_DISABLE_TIMEOUT 200
34
Thara Gopinath984aa6d2010-05-29 22:02:22 +053035/* sr_list contains all the instances of smartreflex module */
36static LIST_HEAD(sr_list);
37
38static struct omap_sr_class_data *sr_class;
39static struct omap_sr_pmic_data *sr_pmic_data;
Kevin Hilman633ef8b742011-04-05 14:39:11 -070040static struct dentry *sr_dbg_dir;
Thara Gopinath984aa6d2010-05-29 22:02:22 +053041
42static inline void sr_write_reg(struct omap_sr *sr, unsigned offset, u32 value)
43{
44 __raw_writel(value, (sr->base + offset));
45}
46
47static inline void sr_modify_reg(struct omap_sr *sr, unsigned offset, u32 mask,
48 u32 value)
49{
50 u32 reg_val;
Thara Gopinath984aa6d2010-05-29 22:02:22 +053051
52 /*
53 * Smartreflex error config register is special as it contains
54 * certain status bits which if written a 1 into means a clear
55 * of those bits. So in order to make sure no accidental write of
56 * 1 happens to those status bits, do a clear of them in the read
57 * value. This mean this API doesn't rewrite values in these bits
58 * if they are currently set, but does allow the caller to write
59 * those bits.
60 */
Nishanth Menonade6ec02012-02-29 23:33:41 +010061 if (sr->ip_type == SR_TYPE_V1 && offset == ERRCONFIG_V1)
62 mask |= ERRCONFIG_STATUS_V1_MASK;
63 else if (sr->ip_type == SR_TYPE_V2 && offset == ERRCONFIG_V2)
64 mask |= ERRCONFIG_VPBOUNDINTST_V2;
Thara Gopinath984aa6d2010-05-29 22:02:22 +053065
Nishanth Menonade6ec02012-02-29 23:33:41 +010066 reg_val = __raw_readl(sr->base + offset);
67 reg_val &= ~mask;
68
69 value &= mask;
Thara Gopinath984aa6d2010-05-29 22:02:22 +053070
71 reg_val |= value;
72
73 __raw_writel(reg_val, (sr->base + offset));
74}
75
76static inline u32 sr_read_reg(struct omap_sr *sr, unsigned offset)
77{
78 return __raw_readl(sr->base + offset);
79}
80
81static struct omap_sr *_sr_lookup(struct voltagedomain *voltdm)
82{
83 struct omap_sr *sr_info;
84
85 if (!voltdm) {
86 pr_err("%s: Null voltage domain passed!\n", __func__);
87 return ERR_PTR(-EINVAL);
88 }
89
90 list_for_each_entry(sr_info, &sr_list, node) {
91 if (voltdm == sr_info->voltdm)
92 return sr_info;
93 }
94
95 return ERR_PTR(-ENODATA);
96}
97
98static irqreturn_t sr_interrupt(int irq, void *data)
99{
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100100 struct omap_sr *sr_info = data;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530101 u32 status = 0;
102
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100103 switch (sr_info->ip_type) {
104 case SR_TYPE_V1:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530105 /* Read the status bits */
106 status = sr_read_reg(sr_info, ERRCONFIG_V1);
107
108 /* Clear them by writing back */
109 sr_write_reg(sr_info, ERRCONFIG_V1, status);
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100110 break;
111 case SR_TYPE_V2:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530112 /* Read the status bits */
Felipe Balbi5a4f1842011-11-23 14:43:37 -0800113 status = sr_read_reg(sr_info, IRQSTATUS);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530114
115 /* Clear them by writing back */
116 sr_write_reg(sr_info, IRQSTATUS, status);
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100117 break;
118 default:
119 dev_err(&sr_info->pdev->dev, "UNKNOWN IP type %d\n",
120 sr_info->ip_type);
121 return IRQ_NONE;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530122 }
123
Nishanth Menon7a89afa2011-02-14 12:16:36 +0530124 if (sr_class->notify)
Jean Pihet80821c92012-04-24 10:22:12 +0530125 sr_class->notify(sr_info, status);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530126
127 return IRQ_HANDLED;
128}
129
130static void sr_set_clk_length(struct omap_sr *sr)
131{
Jean Pihet98aed082012-10-04 18:47:11 +0200132 struct clk *fck;
133 u32 fclk_speed;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530134
Jean Pihet98aed082012-10-04 18:47:11 +0200135 fck = clk_get(&sr->pdev->dev, "fck");
Thara Gopinathb35cecf2010-08-18 12:23:12 +0530136
Jean Pihet98aed082012-10-04 18:47:11 +0200137 if (IS_ERR(fck)) {
138 dev_err(&sr->pdev->dev, "%s: unable to get fck for device %s\n",
139 __func__, dev_name(&sr->pdev->dev));
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530140 return;
141 }
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100142
Jean Pihet98aed082012-10-04 18:47:11 +0200143 fclk_speed = clk_get_rate(fck);
144 clk_put(fck);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530145
Jean Pihet98aed082012-10-04 18:47:11 +0200146 switch (fclk_speed) {
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530147 case 12000000:
148 sr->clk_length = SRCLKLENGTH_12MHZ_SYSCLK;
149 break;
150 case 13000000:
151 sr->clk_length = SRCLKLENGTH_13MHZ_SYSCLK;
152 break;
153 case 19200000:
154 sr->clk_length = SRCLKLENGTH_19MHZ_SYSCLK;
155 break;
156 case 26000000:
157 sr->clk_length = SRCLKLENGTH_26MHZ_SYSCLK;
158 break;
159 case 38400000:
160 sr->clk_length = SRCLKLENGTH_38MHZ_SYSCLK;
161 break;
162 default:
Jean Pihet98aed082012-10-04 18:47:11 +0200163 dev_err(&sr->pdev->dev, "%s: Invalid fclk rate: %d\n",
164 __func__, fclk_speed);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530165 break;
166 }
167}
168
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530169static void sr_start_vddautocomp(struct omap_sr *sr)
170{
171 if (!sr_class || !(sr_class->enable) || !(sr_class->configure)) {
172 dev_warn(&sr->pdev->dev,
173 "%s: smartreflex class driver not registered\n",
174 __func__);
175 return;
176 }
177
Jean Pihet80821c92012-04-24 10:22:12 +0530178 if (!sr_class->enable(sr))
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530179 sr->autocomp_active = true;
180}
181
182static void sr_stop_vddautocomp(struct omap_sr *sr)
183{
184 if (!sr_class || !(sr_class->disable)) {
185 dev_warn(&sr->pdev->dev,
186 "%s: smartreflex class driver not registered\n",
187 __func__);
188 return;
189 }
190
191 if (sr->autocomp_active) {
Jean Pihet80821c92012-04-24 10:22:12 +0530192 sr_class->disable(sr, 1);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530193 sr->autocomp_active = false;
194 }
195}
196
197/*
198 * This function handles the intializations which have to be done
199 * only when both sr device and class driver regiter has
200 * completed. This will be attempted to be called from both sr class
201 * driver register and sr device intializtion API's. Only one call
202 * will ultimately succeed.
203 *
Vitaliy Ivanovfb914eb2011-06-23 20:01:55 +0300204 * Currently this function registers interrupt handler for a particular SR
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530205 * if smartreflex class driver is already registered and has
206 * requested for interrupts and the SR interrupt line in present.
207 */
208static int sr_late_init(struct omap_sr *sr_info)
209{
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530210 struct omap_sr_data *pdata = sr_info->pdev->dev.platform_data;
211 struct resource *mem;
212 int ret = 0;
213
Nishanth Menon7a89afa2011-02-14 12:16:36 +0530214 if (sr_class->notify && sr_class->notify_flags && sr_info->irq) {
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530215 ret = request_irq(sr_info->irq, sr_interrupt,
Jean Pihet8b765d72012-04-24 10:41:27 +0530216 0, sr_info->name, sr_info);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530217 if (ret)
218 goto error;
Nishanth Menon1279ba52011-02-14 12:41:10 +0530219 disable_irq(sr_info->irq);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530220 }
221
222 if (pdata && pdata->enable_on_init)
223 sr_start_vddautocomp(sr_info);
224
225 return ret;
226
227error:
Nishanth Menon442155a2011-02-14 12:33:13 +0530228 iounmap(sr_info->base);
229 mem = platform_get_resource(sr_info->pdev, IORESOURCE_MEM, 0);
230 release_mem_region(mem->start, resource_size(mem));
231 list_del(&sr_info->node);
232 dev_err(&sr_info->pdev->dev, "%s: ERROR in registering"
233 "interrupt handler. Smartreflex will"
234 "not function as desired\n", __func__);
Nishanth Menon442155a2011-02-14 12:33:13 +0530235 kfree(sr_info);
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100236
Nishanth Menon442155a2011-02-14 12:33:13 +0530237 return ret;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530238}
239
240static void sr_v1_disable(struct omap_sr *sr)
241{
242 int timeout = 0;
Nishanth Menoncfec9c52012-02-29 23:33:42 +0100243 int errconf_val = ERRCONFIG_MCUACCUMINTST | ERRCONFIG_MCUVALIDINTST |
244 ERRCONFIG_MCUBOUNDINTST;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530245
246 /* Enable MCUDisableAcknowledge interrupt */
247 sr_modify_reg(sr, ERRCONFIG_V1,
248 ERRCONFIG_MCUDISACKINTEN, ERRCONFIG_MCUDISACKINTEN);
249
250 /* SRCONFIG - disable SR */
251 sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0x0);
252
Nishanth Menoncfec9c52012-02-29 23:33:42 +0100253 /* Disable all other SR interrupts and clear the status as needed */
254 if (sr_read_reg(sr, ERRCONFIG_V1) & ERRCONFIG_VPBOUNDINTST_V1)
255 errconf_val |= ERRCONFIG_VPBOUNDINTST_V1;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530256 sr_modify_reg(sr, ERRCONFIG_V1,
257 (ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUVALIDINTEN |
258 ERRCONFIG_MCUBOUNDINTEN | ERRCONFIG_VPBOUNDINTEN_V1),
Nishanth Menoncfec9c52012-02-29 23:33:42 +0100259 errconf_val);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530260
261 /*
262 * Wait for SR to be disabled.
263 * wait until ERRCONFIG.MCUDISACKINTST = 1. Typical latency is 1us.
264 */
Jean Pihet50e4a7d2012-04-24 10:56:40 +0530265 sr_test_cond_timeout((sr_read_reg(sr, ERRCONFIG_V1) &
266 ERRCONFIG_MCUDISACKINTST), SR_DISABLE_TIMEOUT,
267 timeout);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530268
269 if (timeout >= SR_DISABLE_TIMEOUT)
270 dev_warn(&sr->pdev->dev, "%s: Smartreflex disable timedout\n",
271 __func__);
272
273 /* Disable MCUDisableAcknowledge interrupt & clear pending interrupt */
274 sr_modify_reg(sr, ERRCONFIG_V1, ERRCONFIG_MCUDISACKINTEN,
275 ERRCONFIG_MCUDISACKINTST);
276}
277
278static void sr_v2_disable(struct omap_sr *sr)
279{
280 int timeout = 0;
281
282 /* Enable MCUDisableAcknowledge interrupt */
283 sr_write_reg(sr, IRQENABLE_SET, IRQENABLE_MCUDISABLEACKINT);
284
285 /* SRCONFIG - disable SR */
286 sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0x0);
287
Nishanth Menoncfec9c52012-02-29 23:33:42 +0100288 /*
289 * Disable all other SR interrupts and clear the status
290 * write to status register ONLY on need basis - only if status
291 * is set.
292 */
293 if (sr_read_reg(sr, ERRCONFIG_V2) & ERRCONFIG_VPBOUNDINTST_V2)
294 sr_modify_reg(sr, ERRCONFIG_V2, ERRCONFIG_VPBOUNDINTEN_V2,
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530295 ERRCONFIG_VPBOUNDINTST_V2);
Nishanth Menoncfec9c52012-02-29 23:33:42 +0100296 else
297 sr_modify_reg(sr, ERRCONFIG_V2, ERRCONFIG_VPBOUNDINTEN_V2,
298 0x0);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530299 sr_write_reg(sr, IRQENABLE_CLR, (IRQENABLE_MCUACCUMINT |
300 IRQENABLE_MCUVALIDINT |
301 IRQENABLE_MCUBOUNDSINT));
302 sr_write_reg(sr, IRQSTATUS, (IRQSTATUS_MCUACCUMINT |
303 IRQSTATUS_MCVALIDINT |
304 IRQSTATUS_MCBOUNDSINT));
305
306 /*
307 * Wait for SR to be disabled.
308 * wait until IRQSTATUS.MCUDISACKINTST = 1. Typical latency is 1us.
309 */
Jean Pihet50e4a7d2012-04-24 10:56:40 +0530310 sr_test_cond_timeout((sr_read_reg(sr, IRQSTATUS) &
311 IRQSTATUS_MCUDISABLEACKINT), SR_DISABLE_TIMEOUT,
312 timeout);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530313
314 if (timeout >= SR_DISABLE_TIMEOUT)
315 dev_warn(&sr->pdev->dev, "%s: Smartreflex disable timedout\n",
316 __func__);
317
318 /* Disable MCUDisableAcknowledge interrupt & clear pending interrupt */
319 sr_write_reg(sr, IRQENABLE_CLR, IRQENABLE_MCUDISABLEACKINT);
320 sr_write_reg(sr, IRQSTATUS, IRQSTATUS_MCUDISABLEACKINT);
321}
322
Jean Pihet5e7f2e12012-04-25 11:19:44 +0530323static struct omap_sr_nvalue_table *sr_retrieve_nvalue_row(
324 struct omap_sr *sr, u32 efuse_offs)
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530325{
326 int i;
327
328 if (!sr->nvalue_table) {
329 dev_warn(&sr->pdev->dev, "%s: Missing ntarget value table\n",
330 __func__);
Jean Pihet5e7f2e12012-04-25 11:19:44 +0530331 return NULL;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530332 }
333
334 for (i = 0; i < sr->nvalue_count; i++) {
335 if (sr->nvalue_table[i].efuse_offs == efuse_offs)
Jean Pihet5e7f2e12012-04-25 11:19:44 +0530336 return &sr->nvalue_table[i];
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530337 }
338
Jean Pihet5e7f2e12012-04-25 11:19:44 +0530339 return NULL;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530340}
341
342/* Public Functions */
343
344/**
Andrii Tseglytskyi3dfc35f2013-05-27 14:09:22 +0300345 * sr_configure_errgen() - Configures the SmartReflex to perform AVS using the
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530346 * error generator module.
Andrii Tseglytskyi3dfc35f2013-05-27 14:09:22 +0300347 * @sr: SR module to be configured.
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530348 *
349 * This API is to be called from the smartreflex class driver to
350 * configure the error generator module inside the smartreflex module.
351 * SR settings if using the ERROR module inside Smartreflex.
352 * SR CLASS 3 by default uses only the ERROR module where as
353 * SR CLASS 2 can choose between ERROR module and MINMAXAVG
354 * module. Returns 0 on success and error value in case of failure.
355 */
Andrii Tseglytskyi3dfc35f2013-05-27 14:09:22 +0300356int sr_configure_errgen(struct omap_sr *sr)
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530357{
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100358 u32 sr_config, sr_errconfig, errconfig_offs;
359 u32 vpboundint_en, vpboundint_st;
360 u32 senp_en = 0, senn_en = 0;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530361 u8 senp_shift, senn_shift;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530362
Andrii Tseglytskyi3dfc35f2013-05-27 14:09:22 +0300363 if (!sr) {
364 pr_warn("%s: NULL omap_sr from %pF\n", __func__,
365 (void *)_RET_IP_);
366 return -EINVAL;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530367 }
368
369 if (!sr->clk_length)
370 sr_set_clk_length(sr);
371
372 senp_en = sr->senp_mod;
373 senn_en = sr->senn_mod;
374
375 sr_config = (sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
376 SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN;
377
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100378 switch (sr->ip_type) {
379 case SR_TYPE_V1:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530380 sr_config |= SRCONFIG_DELAYCTRL;
381 senn_shift = SRCONFIG_SENNENABLE_V1_SHIFT;
382 senp_shift = SRCONFIG_SENPENABLE_V1_SHIFT;
383 errconfig_offs = ERRCONFIG_V1;
384 vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V1;
385 vpboundint_st = ERRCONFIG_VPBOUNDINTST_V1;
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100386 break;
387 case SR_TYPE_V2:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530388 senn_shift = SRCONFIG_SENNENABLE_V2_SHIFT;
389 senp_shift = SRCONFIG_SENPENABLE_V2_SHIFT;
390 errconfig_offs = ERRCONFIG_V2;
391 vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V2;
392 vpboundint_st = ERRCONFIG_VPBOUNDINTST_V2;
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100393 break;
394 default:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530395 dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex"
396 "module without specifying the ip\n", __func__);
397 return -EINVAL;
398 }
399
400 sr_config |= ((senn_en << senn_shift) | (senp_en << senp_shift));
401 sr_write_reg(sr, SRCONFIG, sr_config);
402 sr_errconfig = (sr->err_weight << ERRCONFIG_ERRWEIGHT_SHIFT) |
403 (sr->err_maxlimit << ERRCONFIG_ERRMAXLIMIT_SHIFT) |
404 (sr->err_minlimit << ERRCONFIG_ERRMINLIMIT_SHIFT);
405 sr_modify_reg(sr, errconfig_offs, (SR_ERRWEIGHT_MASK |
406 SR_ERRMAXLIMIT_MASK | SR_ERRMINLIMIT_MASK),
407 sr_errconfig);
408
409 /* Enabling the interrupts if the ERROR module is used */
Nishanth Menon74754cc2012-02-29 23:33:38 +0100410 sr_modify_reg(sr, errconfig_offs, (vpboundint_en | vpboundint_st),
411 vpboundint_en);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530412
413 return 0;
414}
415
416/**
Nishanth Menonad54c3d2012-02-29 23:33:39 +0100417 * sr_disable_errgen() - Disables SmartReflex AVS module's errgen component
Andrii Tseglytskyi3dfc35f2013-05-27 14:09:22 +0300418 * @sr: SR module to be configured.
Nishanth Menonad54c3d2012-02-29 23:33:39 +0100419 *
420 * This API is to be called from the smartreflex class driver to
421 * disable the error generator module inside the smartreflex module.
422 *
423 * Returns 0 on success and error value in case of failure.
424 */
Andrii Tseglytskyi3dfc35f2013-05-27 14:09:22 +0300425int sr_disable_errgen(struct omap_sr *sr)
Nishanth Menonad54c3d2012-02-29 23:33:39 +0100426{
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100427 u32 errconfig_offs;
428 u32 vpboundint_en, vpboundint_st;
Nishanth Menonad54c3d2012-02-29 23:33:39 +0100429
Andrii Tseglytskyi3dfc35f2013-05-27 14:09:22 +0300430 if (!sr) {
431 pr_warn("%s: NULL omap_sr from %pF\n", __func__,
432 (void *)_RET_IP_);
433 return -EINVAL;
Nishanth Menonad54c3d2012-02-29 23:33:39 +0100434 }
435
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100436 switch (sr->ip_type) {
437 case SR_TYPE_V1:
Nishanth Menonad54c3d2012-02-29 23:33:39 +0100438 errconfig_offs = ERRCONFIG_V1;
439 vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V1;
440 vpboundint_st = ERRCONFIG_VPBOUNDINTST_V1;
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100441 break;
442 case SR_TYPE_V2:
Nishanth Menonad54c3d2012-02-29 23:33:39 +0100443 errconfig_offs = ERRCONFIG_V2;
444 vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V2;
445 vpboundint_st = ERRCONFIG_VPBOUNDINTST_V2;
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100446 break;
447 default:
Nishanth Menonad54c3d2012-02-29 23:33:39 +0100448 dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex"
449 "module without specifying the ip\n", __func__);
450 return -EINVAL;
451 }
452
Nishanth Menonad54c3d2012-02-29 23:33:39 +0100453 /* Disable the Sensor and errorgen */
454 sr_modify_reg(sr, SRCONFIG, SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN, 0);
455
Nishanth Menonefe4e062013-05-30 13:08:34 +0300456 /*
457 * Disable the interrupts of ERROR module
458 * NOTE: modify is a read, modify,write - an implicit OCP barrier
459 * which is required is present here - sequencing is critical
460 * at this point (after errgen is disabled, vpboundint disable)
461 */
462 sr_modify_reg(sr, errconfig_offs, vpboundint_en | vpboundint_st, 0);
463
Nishanth Menonad54c3d2012-02-29 23:33:39 +0100464 return 0;
465}
466
467/**
Andrii Tseglytskyi6c805732013-05-27 14:09:23 +0300468 * sr_configure_minmax() - Configures the SmartReflex to perform AVS using the
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530469 * minmaxavg module.
Andrii Tseglytskyi6c805732013-05-27 14:09:23 +0300470 * @sr: SR module to be configured.
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530471 *
472 * This API is to be called from the smartreflex class driver to
473 * configure the minmaxavg module inside the smartreflex module.
474 * SR settings if using the ERROR module inside Smartreflex.
475 * SR CLASS 3 by default uses only the ERROR module where as
476 * SR CLASS 2 can choose between ERROR module and MINMAXAVG
477 * module. Returns 0 on success and error value in case of failure.
478 */
Andrii Tseglytskyi6c805732013-05-27 14:09:23 +0300479int sr_configure_minmax(struct omap_sr *sr)
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530480{
481 u32 sr_config, sr_avgwt;
482 u32 senp_en = 0, senn_en = 0;
483 u8 senp_shift, senn_shift;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530484
Andrii Tseglytskyi6c805732013-05-27 14:09:23 +0300485 if (!sr) {
486 pr_warn("%s: NULL omap_sr from %pF\n", __func__,
487 (void *)_RET_IP_);
488 return -EINVAL;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530489 }
490
491 if (!sr->clk_length)
492 sr_set_clk_length(sr);
493
494 senp_en = sr->senp_mod;
495 senn_en = sr->senn_mod;
496
497 sr_config = (sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
498 SRCONFIG_SENENABLE |
499 (sr->accum_data << SRCONFIG_ACCUMDATA_SHIFT);
500
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100501 switch (sr->ip_type) {
502 case SR_TYPE_V1:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530503 sr_config |= SRCONFIG_DELAYCTRL;
504 senn_shift = SRCONFIG_SENNENABLE_V1_SHIFT;
505 senp_shift = SRCONFIG_SENPENABLE_V1_SHIFT;
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100506 break;
507 case SR_TYPE_V2:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530508 senn_shift = SRCONFIG_SENNENABLE_V2_SHIFT;
509 senp_shift = SRCONFIG_SENPENABLE_V2_SHIFT;
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100510 break;
511 default:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530512 dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex"
513 "module without specifying the ip\n", __func__);
514 return -EINVAL;
515 }
516
517 sr_config |= ((senn_en << senn_shift) | (senp_en << senp_shift));
518 sr_write_reg(sr, SRCONFIG, sr_config);
519 sr_avgwt = (sr->senp_avgweight << AVGWEIGHT_SENPAVGWEIGHT_SHIFT) |
520 (sr->senn_avgweight << AVGWEIGHT_SENNAVGWEIGHT_SHIFT);
521 sr_write_reg(sr, AVGWEIGHT, sr_avgwt);
522
523 /*
524 * Enabling the interrupts if MINMAXAVG module is used.
525 * TODO: check if all the interrupts are mandatory
526 */
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100527 switch (sr->ip_type) {
528 case SR_TYPE_V1:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530529 sr_modify_reg(sr, ERRCONFIG_V1,
530 (ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUVALIDINTEN |
531 ERRCONFIG_MCUBOUNDINTEN),
532 (ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUACCUMINTST |
533 ERRCONFIG_MCUVALIDINTEN | ERRCONFIG_MCUVALIDINTST |
534 ERRCONFIG_MCUBOUNDINTEN | ERRCONFIG_MCUBOUNDINTST));
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100535 break;
536 case SR_TYPE_V2:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530537 sr_write_reg(sr, IRQSTATUS,
538 IRQSTATUS_MCUACCUMINT | IRQSTATUS_MCVALIDINT |
539 IRQSTATUS_MCBOUNDSINT | IRQSTATUS_MCUDISABLEACKINT);
540 sr_write_reg(sr, IRQENABLE_SET,
541 IRQENABLE_MCUACCUMINT | IRQENABLE_MCUVALIDINT |
542 IRQENABLE_MCUBOUNDSINT | IRQENABLE_MCUDISABLEACKINT);
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100543 break;
544 default:
545 dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex"
546 "module without specifying the ip\n", __func__);
547 return -EINVAL;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530548 }
549
550 return 0;
551}
552
553/**
554 * sr_enable() - Enables the smartreflex module.
555 * @voltdm: VDD pointer to which the SR module to be configured belongs to.
556 * @volt: The voltage at which the Voltage domain associated with
557 * the smartreflex module is operating at.
558 * This is required only to program the correct Ntarget value.
559 *
560 * This API is to be called from the smartreflex class driver to
561 * enable a smartreflex module. Returns 0 on success. Returns error
562 * value if the voltage passed is wrong or if ntarget value is wrong.
563 */
564int sr_enable(struct voltagedomain *voltdm, unsigned long volt)
565{
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530566 struct omap_volt_data *volt_data;
567 struct omap_sr *sr = _sr_lookup(voltdm);
Jean Pihet5e7f2e12012-04-25 11:19:44 +0530568 struct omap_sr_nvalue_table *nvalue_row;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530569 int ret;
570
571 if (IS_ERR(sr)) {
Jean Pihet8b765d72012-04-24 10:41:27 +0530572 pr_warning("%s: omap_sr struct for voltdm not found\n", __func__);
Jean Pihet63371fa2012-02-29 23:33:49 +0100573 return PTR_ERR(sr);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530574 }
575
576 volt_data = omap_voltage_get_voltdata(sr->voltdm, volt);
577
578 if (IS_ERR(volt_data)) {
579 dev_warn(&sr->pdev->dev, "%s: Unable to get voltage table"
580 "for nominal voltage %ld\n", __func__, volt);
Jean Pihet63371fa2012-02-29 23:33:49 +0100581 return PTR_ERR(volt_data);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530582 }
583
Jean Pihet5e7f2e12012-04-25 11:19:44 +0530584 nvalue_row = sr_retrieve_nvalue_row(sr, volt_data->sr_efuse_offs);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530585
Jean Pihet5e7f2e12012-04-25 11:19:44 +0530586 if (!nvalue_row) {
587 dev_warn(&sr->pdev->dev, "%s: failure getting SR data for this voltage %ld\n",
588 __func__, volt);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530589 return -ENODATA;
590 }
591
592 /* errminlimit is opp dependent and hence linked to voltage */
Jean Pihet5e7f2e12012-04-25 11:19:44 +0530593 sr->err_minlimit = nvalue_row->errminlimit;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530594
595 pm_runtime_get_sync(&sr->pdev->dev);
596
597 /* Check if SR is already enabled. If yes do nothing */
598 if (sr_read_reg(sr, SRCONFIG) & SRCONFIG_SRENABLE)
599 return 0;
600
601 /* Configure SR */
Jean Pihet80821c92012-04-24 10:22:12 +0530602 ret = sr_class->configure(sr);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530603 if (ret)
604 return ret;
605
Jean Pihet5e7f2e12012-04-25 11:19:44 +0530606 sr_write_reg(sr, NVALUERECIPROCAL, nvalue_row->nvalue);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530607
608 /* SRCONFIG - enable SR */
609 sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, SRCONFIG_SRENABLE);
610 return 0;
611}
612
613/**
614 * sr_disable() - Disables the smartreflex module.
615 * @voltdm: VDD pointer to which the SR module to be configured belongs to.
616 *
617 * This API is to be called from the smartreflex class driver to
618 * disable a smartreflex module.
619 */
620void sr_disable(struct voltagedomain *voltdm)
621{
622 struct omap_sr *sr = _sr_lookup(voltdm);
623
624 if (IS_ERR(sr)) {
Jean Pihet8b765d72012-04-24 10:41:27 +0530625 pr_warning("%s: omap_sr struct for voltdm not found\n", __func__);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530626 return;
627 }
628
629 /* Check if SR clocks are already disabled. If yes do nothing */
630 if (pm_runtime_suspended(&sr->pdev->dev))
631 return;
632
633 /*
634 * Disable SR if only it is indeed enabled. Else just
635 * disable the clocks.
636 */
637 if (sr_read_reg(sr, SRCONFIG) & SRCONFIG_SRENABLE) {
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100638 switch (sr->ip_type) {
639 case SR_TYPE_V1:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530640 sr_v1_disable(sr);
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100641 break;
642 case SR_TYPE_V2:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530643 sr_v2_disable(sr);
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100644 break;
645 default:
646 dev_err(&sr->pdev->dev, "UNKNOWN IP type %d\n",
647 sr->ip_type);
648 }
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530649 }
650
Colin Cross98333b32011-07-22 00:55:52 -0500651 pm_runtime_put_sync_suspend(&sr->pdev->dev);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530652}
653
654/**
655 * sr_register_class() - API to register a smartreflex class parameters.
656 * @class_data: The structure containing various sr class specific data.
657 *
658 * This API is to be called by the smartreflex class driver to register itself
659 * with the smartreflex driver during init. Returns 0 on success else the
660 * error value.
661 */
662int sr_register_class(struct omap_sr_class_data *class_data)
663{
664 struct omap_sr *sr_info;
665
666 if (!class_data) {
667 pr_warning("%s:, Smartreflex class data passed is NULL\n",
668 __func__);
669 return -EINVAL;
670 }
671
672 if (sr_class) {
673 pr_warning("%s: Smartreflex class driver already registered\n",
674 __func__);
675 return -EBUSY;
676 }
677
678 sr_class = class_data;
679
680 /*
681 * Call into late init to do intializations that require
682 * both sr driver and sr class driver to be initiallized.
683 */
684 list_for_each_entry(sr_info, &sr_list, node)
685 sr_late_init(sr_info);
686
687 return 0;
688}
689
690/**
691 * omap_sr_enable() - API to enable SR clocks and to call into the
692 * registered smartreflex class enable API.
693 * @voltdm: VDD pointer to which the SR module to be configured belongs to.
694 *
695 * This API is to be called from the kernel in order to enable
696 * a particular smartreflex module. This API will do the initial
697 * configurations to turn on the smartreflex module and in turn call
698 * into the registered smartreflex class enable API.
699 */
700void omap_sr_enable(struct voltagedomain *voltdm)
701{
702 struct omap_sr *sr = _sr_lookup(voltdm);
703
704 if (IS_ERR(sr)) {
Jean Pihet8b765d72012-04-24 10:41:27 +0530705 pr_warning("%s: omap_sr struct for voltdm not found\n", __func__);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530706 return;
707 }
708
709 if (!sr->autocomp_active)
710 return;
711
712 if (!sr_class || !(sr_class->enable) || !(sr_class->configure)) {
713 dev_warn(&sr->pdev->dev, "%s: smartreflex class driver not"
714 "registered\n", __func__);
715 return;
716 }
717
Jean Pihet80821c92012-04-24 10:22:12 +0530718 sr_class->enable(sr);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530719}
720
721/**
722 * omap_sr_disable() - API to disable SR without resetting the voltage
723 * processor voltage
724 * @voltdm: VDD pointer to which the SR module to be configured belongs to.
725 *
726 * This API is to be called from the kernel in order to disable
727 * a particular smartreflex module. This API will in turn call
728 * into the registered smartreflex class disable API. This API will tell
729 * the smartreflex class disable not to reset the VP voltage after
730 * disabling smartreflex.
731 */
732void omap_sr_disable(struct voltagedomain *voltdm)
733{
734 struct omap_sr *sr = _sr_lookup(voltdm);
735
736 if (IS_ERR(sr)) {
Jean Pihet8b765d72012-04-24 10:41:27 +0530737 pr_warning("%s: omap_sr struct for voltdm not found\n", __func__);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530738 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
Jean Pihet80821c92012-04-24 10:22:12 +0530750 sr_class->disable(sr, 0);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530751}
752
753/**
754 * omap_sr_disable_reset_volt() - API to disable SR and reset the
755 * voltage processor voltage
756 * @voltdm: VDD pointer to which the SR module to be configured belongs to.
757 *
758 * This API is to be called from the kernel in order to disable
759 * a particular smartreflex module. This API will in turn call
760 * into the registered smartreflex class disable API. This API will tell
761 * the smartreflex class disable to reset the VP voltage after
762 * disabling smartreflex.
763 */
764void omap_sr_disable_reset_volt(struct voltagedomain *voltdm)
765{
766 struct omap_sr *sr = _sr_lookup(voltdm);
767
768 if (IS_ERR(sr)) {
Jean Pihet8b765d72012-04-24 10:41:27 +0530769 pr_warning("%s: omap_sr struct for voltdm not found\n", __func__);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530770 return;
771 }
772
773 if (!sr->autocomp_active)
774 return;
775
776 if (!sr_class || !(sr_class->disable)) {
777 dev_warn(&sr->pdev->dev, "%s: smartreflex class driver not"
778 "registered\n", __func__);
779 return;
780 }
781
Jean Pihet80821c92012-04-24 10:22:12 +0530782 sr_class->disable(sr, 1);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530783}
784
785/**
786 * omap_sr_register_pmic() - API to register pmic specific info.
787 * @pmic_data: The structure containing pmic specific data.
788 *
789 * This API is to be called from the PMIC specific code to register with
790 * smartreflex driver pmic specific info. Currently the only info required
791 * is the smartreflex init on the PMIC side.
792 */
793void omap_sr_register_pmic(struct omap_sr_pmic_data *pmic_data)
794{
795 if (!pmic_data) {
796 pr_warning("%s: Trying to register NULL PMIC data structure"
797 "with smartreflex\n", __func__);
798 return;
799 }
800
801 sr_pmic_data = pmic_data;
802}
803
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100804/* PM Debug FS entries to enable and disable smartreflex. */
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530805static int omap_sr_autocomp_show(void *data, u64 *val)
806{
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100807 struct omap_sr *sr_info = data;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530808
809 if (!sr_info) {
Stefan Weil83535842011-01-30 20:29:38 +0100810 pr_warning("%s: omap_sr struct not found\n", __func__);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530811 return -EINVAL;
812 }
813
814 *val = sr_info->autocomp_active;
815
816 return 0;
817}
818
819static int omap_sr_autocomp_store(void *data, u64 val)
820{
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100821 struct omap_sr *sr_info = data;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530822
823 if (!sr_info) {
Stefan Weil83535842011-01-30 20:29:38 +0100824 pr_warning("%s: omap_sr struct not found\n", __func__);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530825 return -EINVAL;
826 }
827
828 /* Sanity check */
Felipe Balbid6173692012-02-29 23:33:47 +0100829 if (val > 1) {
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530830 pr_warning("%s: Invalid argument %lld\n", __func__, val);
831 return -EINVAL;
832 }
833
Nishanth Menonac77a6f2011-02-14 21:14:17 +0530834 /* control enable/disable only if there is a delta in value */
835 if (sr_info->autocomp_active != val) {
836 if (!val)
837 sr_stop_vddautocomp(sr_info);
838 else
839 sr_start_vddautocomp(sr_info);
840 }
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530841
842 return 0;
843}
844
845DEFINE_SIMPLE_ATTRIBUTE(pm_sr_fops, omap_sr_autocomp_show,
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100846 omap_sr_autocomp_store, "%llu\n");
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530847
848static int __init omap_sr_probe(struct platform_device *pdev)
849{
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100850 struct omap_sr *sr_info;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530851 struct omap_sr_data *pdata = pdev->dev.platform_data;
852 struct resource *mem, *irq;
Kevin Hilman633ef8b742011-04-05 14:39:11 -0700853 struct dentry *nvalue_dir;
Thara Gopinath077fcec2010-10-27 20:29:37 +0530854 int i, ret = 0;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530855
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100856 sr_info = kzalloc(sizeof(struct omap_sr), GFP_KERNEL);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530857 if (!sr_info) {
858 dev_err(&pdev->dev, "%s: unable to allocate sr_info\n",
859 __func__);
860 return -ENOMEM;
861 }
862
Felipe Balbi1079a8b2012-02-29 23:33:44 +0100863 platform_set_drvdata(pdev, sr_info);
864
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530865 if (!pdata) {
866 dev_err(&pdev->dev, "%s: platform data missing\n", __func__);
Stefan Weil720bc782011-01-30 20:26:27 +0100867 ret = -EINVAL;
868 goto err_free_devinfo;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530869 }
870
871 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
872 if (!mem) {
873 dev_err(&pdev->dev, "%s: no mem resource\n", __func__);
874 ret = -ENODEV;
875 goto err_free_devinfo;
876 }
877
Aaro Koskinenda9e73922011-04-26 02:25:16 -0700878 mem = request_mem_region(mem->start, resource_size(mem),
879 dev_name(&pdev->dev));
880 if (!mem) {
881 dev_err(&pdev->dev, "%s: no mem region\n", __func__);
882 ret = -EBUSY;
883 goto err_free_devinfo;
884 }
885
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530886 irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
887
888 pm_runtime_enable(&pdev->dev);
Nishanth Menone13d8f32011-07-09 14:37:21 -0700889 pm_runtime_irq_safe(&pdev->dev);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530890
Jean Pihet8b765d72012-04-24 10:41:27 +0530891 sr_info->name = kasprintf(GFP_KERNEL, "%s", pdata->name);
892 if (!sr_info->name) {
893 dev_err(&pdev->dev, "%s: Unable to alloc SR instance name\n",
894 __func__);
895 ret = -ENOMEM;
896 goto err_release_region;
897 }
898
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530899 sr_info->pdev = pdev;
900 sr_info->srid = pdev->id;
901 sr_info->voltdm = pdata->voltdm;
902 sr_info->nvalue_table = pdata->nvalue_table;
903 sr_info->nvalue_count = pdata->nvalue_count;
904 sr_info->senn_mod = pdata->senn_mod;
905 sr_info->senp_mod = pdata->senp_mod;
Jean Pihet98aed082012-10-04 18:47:11 +0200906 sr_info->err_weight = pdata->err_weight;
907 sr_info->err_maxlimit = pdata->err_maxlimit;
908 sr_info->accum_data = pdata->accum_data;
909 sr_info->senn_avgweight = pdata->senn_avgweight;
910 sr_info->senp_avgweight = pdata->senp_avgweight;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530911 sr_info->autocomp_active = false;
912 sr_info->ip_type = pdata->ip_type;
Jean Pihet98aed082012-10-04 18:47:11 +0200913
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530914 sr_info->base = ioremap(mem->start, resource_size(mem));
915 if (!sr_info->base) {
916 dev_err(&pdev->dev, "%s: ioremap fail\n", __func__);
917 ret = -ENOMEM;
Jean Pihetce3810c2012-09-24 16:16:40 +0200918 goto err_free_name;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530919 }
920
921 if (irq)
922 sr_info->irq = irq->start;
923
924 sr_set_clk_length(sr_info);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530925
926 list_add(&sr_info->node, &sr_list);
927
928 /*
929 * Call into late init to do intializations that require
930 * both sr driver and sr class driver to be initiallized.
931 */
932 if (sr_class) {
933 ret = sr_late_init(sr_info);
934 if (ret) {
935 pr_warning("%s: Error in SR late init\n", __func__);
Julia Lawall14ea9602012-01-12 10:55:17 +0100936 goto err_iounmap;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530937 }
938 }
939
940 dev_info(&pdev->dev, "%s: SmartReflex driver initialized\n", __func__);
Kevin Hilman633ef8b742011-04-05 14:39:11 -0700941 if (!sr_dbg_dir) {
942 sr_dbg_dir = debugfs_create_dir("smartreflex", NULL);
Jean Pihet54b28cd2012-02-29 23:33:48 +0100943 if (IS_ERR_OR_NULL(sr_dbg_dir)) {
Kevin Hilman633ef8b742011-04-05 14:39:11 -0700944 ret = PTR_ERR(sr_dbg_dir);
945 pr_err("%s:sr debugfs dir creation failed(%d)\n",
946 __func__, ret);
947 goto err_iounmap;
948 }
Shweta Gulatib3329a32011-02-15 13:40:30 +0530949 }
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530950
Jean Pihet8b765d72012-04-24 10:41:27 +0530951 sr_info->dbg_dir = debugfs_create_dir(sr_info->name, sr_dbg_dir);
Jean Pihet54b28cd2012-02-29 23:33:48 +0100952 if (IS_ERR_OR_NULL(sr_info->dbg_dir)) {
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530953 dev_err(&pdev->dev, "%s: Unable to create debugfs directory\n",
954 __func__);
Anand S Sawantb1ace382011-02-17 21:27:30 +0530955 ret = PTR_ERR(sr_info->dbg_dir);
Jean Pihetce3810c2012-09-24 16:16:40 +0200956 goto err_debugfs;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530957 }
958
Anand S Sawantb1ace382011-02-17 21:27:30 +0530959 (void) debugfs_create_file("autocomp", S_IRUGO | S_IWUSR,
960 sr_info->dbg_dir, (void *)sr_info, &pm_sr_fops);
961 (void) debugfs_create_x32("errweight", S_IRUGO, sr_info->dbg_dir,
Thara Gopinath077fcec2010-10-27 20:29:37 +0530962 &sr_info->err_weight);
Anand S Sawantb1ace382011-02-17 21:27:30 +0530963 (void) debugfs_create_x32("errmaxlimit", S_IRUGO, sr_info->dbg_dir,
Thara Gopinath077fcec2010-10-27 20:29:37 +0530964 &sr_info->err_maxlimit);
Thara Gopinath077fcec2010-10-27 20:29:37 +0530965
Anand S Sawantb1ace382011-02-17 21:27:30 +0530966 nvalue_dir = debugfs_create_dir("nvalue", sr_info->dbg_dir);
Jean Pihet54b28cd2012-02-29 23:33:48 +0100967 if (IS_ERR_OR_NULL(nvalue_dir)) {
Thara Gopinath077fcec2010-10-27 20:29:37 +0530968 dev_err(&pdev->dev, "%s: Unable to create debugfs directory"
969 "for n-values\n", __func__);
Shweta Gulatib3329a32011-02-15 13:40:30 +0530970 ret = PTR_ERR(nvalue_dir);
Aaro Koskinen283a1c12011-04-26 02:25:32 -0700971 goto err_debugfs;
Thara Gopinath077fcec2010-10-27 20:29:37 +0530972 }
973
Jean Pihet5e7f2e12012-04-25 11:19:44 +0530974 if (sr_info->nvalue_count == 0 || !sr_info->nvalue_table) {
975 dev_warn(&pdev->dev, "%s: %s: No Voltage table for the corresponding vdd. Cannot create debugfs entries for n-values\n",
976 __func__, sr_info->name);
977
Shweta Gulatib3329a32011-02-15 13:40:30 +0530978 ret = -ENODATA;
Aaro Koskinen283a1c12011-04-26 02:25:32 -0700979 goto err_debugfs;
Thara Gopinath077fcec2010-10-27 20:29:37 +0530980 }
981
982 for (i = 0; i < sr_info->nvalue_count; i++) {
Aaro Koskinen865212a2011-02-07 16:08:04 +0200983 char name[NVALUE_NAME_LEN + 1];
Thara Gopinath077fcec2010-10-27 20:29:37 +0530984
Jean Pihet5e7f2e12012-04-25 11:19:44 +0530985 snprintf(name, sizeof(name), "volt_%lu",
986 sr_info->nvalue_table[i].volt_nominal);
Vasiliy Kulikov1232a182011-02-04 12:23:20 +0000987 (void) debugfs_create_x32(name, S_IRUGO | S_IWUSR, nvalue_dir,
Thara Gopinath077fcec2010-10-27 20:29:37 +0530988 &(sr_info->nvalue_table[i].nvalue));
Jean Pihet308d1bd2012-04-24 23:41:54 +0530989 snprintf(name, sizeof(name), "errminlimit_%lu",
990 sr_info->nvalue_table[i].volt_nominal);
991 (void) debugfs_create_x32(name, S_IRUGO | S_IWUSR, nvalue_dir,
992 &(sr_info->nvalue_table[i].errminlimit));
993
Thara Gopinath077fcec2010-10-27 20:29:37 +0530994 }
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530995
996 return ret;
997
Aaro Koskinen283a1c12011-04-26 02:25:32 -0700998err_debugfs:
999 debugfs_remove_recursive(sr_info->dbg_dir);
Aaro Koskinen0c49cc12011-04-26 02:25:21 -07001000err_iounmap:
Aaro Koskinen833d78f2011-04-26 02:25:27 -07001001 list_del(&sr_info->node);
Aaro Koskinen0c49cc12011-04-26 02:25:21 -07001002 iounmap(sr_info->base);
Jean Pihetce3810c2012-09-24 16:16:40 +02001003err_free_name:
1004 kfree(sr_info->name);
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301005err_release_region:
1006 release_mem_region(mem->start, resource_size(mem));
1007err_free_devinfo:
1008 kfree(sr_info);
1009
1010 return ret;
1011}
1012
Bill Pemberton415ec692012-11-19 13:26:07 -05001013static int omap_sr_remove(struct platform_device *pdev)
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301014{
1015 struct omap_sr_data *pdata = pdev->dev.platform_data;
1016 struct omap_sr *sr_info;
1017 struct resource *mem;
1018
1019 if (!pdata) {
1020 dev_err(&pdev->dev, "%s: platform data missing\n", __func__);
1021 return -EINVAL;
1022 }
1023
1024 sr_info = _sr_lookup(pdata->voltdm);
Julia Lawall28693ec2011-01-24 20:55:22 +01001025 if (IS_ERR(sr_info)) {
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301026 dev_warn(&pdev->dev, "%s: omap_sr struct not found\n",
1027 __func__);
Jean Pihet63371fa2012-02-29 23:33:49 +01001028 return PTR_ERR(sr_info);
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301029 }
1030
1031 if (sr_info->autocomp_active)
1032 sr_stop_vddautocomp(sr_info);
Anand S Sawantb1ace382011-02-17 21:27:30 +05301033 if (sr_info->dbg_dir)
1034 debugfs_remove_recursive(sr_info->dbg_dir);
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301035
Andrii Tseglytskyibd4a36b2013-05-30 13:08:35 +03001036 pm_runtime_disable(&pdev->dev);
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301037 list_del(&sr_info->node);
1038 iounmap(sr_info->base);
Jean Pihet8b765d72012-04-24 10:41:27 +05301039 kfree(sr_info->name);
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301040 kfree(sr_info);
1041 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1042 release_mem_region(mem->start, resource_size(mem));
1043
1044 return 0;
1045}
1046
Bill Pemberton415ec692012-11-19 13:26:07 -05001047static void omap_sr_shutdown(struct platform_device *pdev)
Nishanth Menon1f55bc1852012-03-01 00:29:44 +01001048{
1049 struct omap_sr_data *pdata = pdev->dev.platform_data;
1050 struct omap_sr *sr_info;
1051
1052 if (!pdata) {
1053 dev_err(&pdev->dev, "%s: platform data missing\n", __func__);
1054 return;
1055 }
1056
1057 sr_info = _sr_lookup(pdata->voltdm);
1058 if (IS_ERR(sr_info)) {
1059 dev_warn(&pdev->dev, "%s: omap_sr struct not found\n",
1060 __func__);
1061 return;
1062 }
1063
1064 if (sr_info->autocomp_active)
1065 sr_stop_vddautocomp(sr_info);
1066
1067 return;
1068}
1069
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301070static struct platform_driver smartreflex_driver = {
Bill Pemberton28ea73f2012-11-19 13:20:40 -05001071 .remove = omap_sr_remove,
1072 .shutdown = omap_sr_shutdown,
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301073 .driver = {
Andrii Tseglytskyi33da2822013-05-30 13:08:36 +03001074 .name = DRIVER_NAME,
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301075 },
1076};
1077
1078static int __init sr_init(void)
1079{
1080 int ret = 0;
1081
1082 /*
1083 * sr_init is a late init. If by then a pmic specific API is not
1084 * registered either there is no need for anything to be done on
1085 * the PMIC side or somebody has forgotten to register a PMIC
1086 * handler. Warn for the second condition.
1087 */
1088 if (sr_pmic_data && sr_pmic_data->sr_pmic_init)
1089 sr_pmic_data->sr_pmic_init();
1090 else
1091 pr_warning("%s: No PMIC hook to init smartreflex\n", __func__);
1092
1093 ret = platform_driver_probe(&smartreflex_driver, omap_sr_probe);
1094 if (ret) {
1095 pr_err("%s: platform driver register failed for SR\n",
1096 __func__);
1097 return ret;
1098 }
1099
1100 return 0;
1101}
Felipe Balbi1a21a682012-02-29 23:33:45 +01001102late_initcall(sr_init);
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301103
1104static void __exit sr_exit(void)
1105{
1106 platform_driver_unregister(&smartreflex_driver);
1107}
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301108module_exit(sr_exit);
1109
1110MODULE_DESCRIPTION("OMAP Smartreflex Driver");
1111MODULE_LICENSE("GPL");
1112MODULE_ALIAS("platform:" DRIVER_NAME);
1113MODULE_AUTHOR("Texas Instruments Inc");