blob: 14cce7addbb9e6af5fb88bb78aebccf359372c2f [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.
Andrii Tseglytskyi299066b2013-05-27 14:09:24 +0300555 * @sr: pointer to which the SR module to be configured belongs to.
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530556 * @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 */
Andrii Tseglytskyi299066b2013-05-27 14:09:24 +0300564int sr_enable(struct omap_sr *sr, unsigned long volt)
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530565{
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530566 struct omap_volt_data *volt_data;
Jean Pihet5e7f2e12012-04-25 11:19:44 +0530567 struct omap_sr_nvalue_table *nvalue_row;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530568 int ret;
569
Andrii Tseglytskyi299066b2013-05-27 14:09:24 +0300570 if (!sr) {
571 pr_warn("%s: NULL omap_sr from %pF\n", __func__,
572 (void *)_RET_IP_);
573 return -EINVAL;
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.
Andrii Tseglytskyi299066b2013-05-27 14:09:24 +0300615 * @sr: pointer to which the SR module to be configured belongs to.
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530616 *
617 * This API is to be called from the smartreflex class driver to
618 * disable a smartreflex module.
619 */
Andrii Tseglytskyi299066b2013-05-27 14:09:24 +0300620void sr_disable(struct omap_sr *sr)
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530621{
Andrii Tseglytskyi299066b2013-05-27 14:09:24 +0300622 if (!sr) {
623 pr_warn("%s: NULL omap_sr from %pF\n", __func__,
624 (void *)_RET_IP_);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530625 return;
626 }
627
628 /* Check if SR clocks are already disabled. If yes do nothing */
629 if (pm_runtime_suspended(&sr->pdev->dev))
630 return;
631
632 /*
633 * Disable SR if only it is indeed enabled. Else just
634 * disable the clocks.
635 */
636 if (sr_read_reg(sr, SRCONFIG) & SRCONFIG_SRENABLE) {
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100637 switch (sr->ip_type) {
638 case SR_TYPE_V1:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530639 sr_v1_disable(sr);
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100640 break;
641 case SR_TYPE_V2:
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530642 sr_v2_disable(sr);
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100643 break;
644 default:
645 dev_err(&sr->pdev->dev, "UNKNOWN IP type %d\n",
646 sr->ip_type);
647 }
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530648 }
649
Colin Cross98333b32011-07-22 00:55:52 -0500650 pm_runtime_put_sync_suspend(&sr->pdev->dev);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530651}
652
653/**
654 * sr_register_class() - API to register a smartreflex class parameters.
655 * @class_data: The structure containing various sr class specific data.
656 *
657 * This API is to be called by the smartreflex class driver to register itself
658 * with the smartreflex driver during init. Returns 0 on success else the
659 * error value.
660 */
661int sr_register_class(struct omap_sr_class_data *class_data)
662{
663 struct omap_sr *sr_info;
664
665 if (!class_data) {
666 pr_warning("%s:, Smartreflex class data passed is NULL\n",
667 __func__);
668 return -EINVAL;
669 }
670
671 if (sr_class) {
672 pr_warning("%s: Smartreflex class driver already registered\n",
673 __func__);
674 return -EBUSY;
675 }
676
677 sr_class = class_data;
678
679 /*
680 * Call into late init to do intializations that require
681 * both sr driver and sr class driver to be initiallized.
682 */
683 list_for_each_entry(sr_info, &sr_list, node)
684 sr_late_init(sr_info);
685
686 return 0;
687}
688
689/**
690 * omap_sr_enable() - API to enable SR clocks and to call into the
691 * registered smartreflex class enable API.
692 * @voltdm: VDD pointer to which the SR module to be configured belongs to.
693 *
694 * This API is to be called from the kernel in order to enable
695 * a particular smartreflex module. This API will do the initial
696 * configurations to turn on the smartreflex module and in turn call
697 * into the registered smartreflex class enable API.
698 */
699void omap_sr_enable(struct voltagedomain *voltdm)
700{
701 struct omap_sr *sr = _sr_lookup(voltdm);
702
703 if (IS_ERR(sr)) {
Jean Pihet8b765d72012-04-24 10:41:27 +0530704 pr_warning("%s: omap_sr struct for voltdm not found\n", __func__);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530705 return;
706 }
707
708 if (!sr->autocomp_active)
709 return;
710
711 if (!sr_class || !(sr_class->enable) || !(sr_class->configure)) {
712 dev_warn(&sr->pdev->dev, "%s: smartreflex class driver not"
713 "registered\n", __func__);
714 return;
715 }
716
Jean Pihet80821c92012-04-24 10:22:12 +0530717 sr_class->enable(sr);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530718}
719
720/**
721 * omap_sr_disable() - API to disable SR without resetting the voltage
722 * processor voltage
723 * @voltdm: VDD pointer to which the SR module to be configured belongs to.
724 *
725 * This API is to be called from the kernel in order to disable
726 * a particular smartreflex module. This API will in turn call
727 * into the registered smartreflex class disable API. This API will tell
728 * the smartreflex class disable not to reset the VP voltage after
729 * disabling smartreflex.
730 */
731void omap_sr_disable(struct voltagedomain *voltdm)
732{
733 struct omap_sr *sr = _sr_lookup(voltdm);
734
735 if (IS_ERR(sr)) {
Jean Pihet8b765d72012-04-24 10:41:27 +0530736 pr_warning("%s: omap_sr struct for voltdm not found\n", __func__);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530737 return;
738 }
739
740 if (!sr->autocomp_active)
741 return;
742
743 if (!sr_class || !(sr_class->disable)) {
744 dev_warn(&sr->pdev->dev, "%s: smartreflex class driver not"
745 "registered\n", __func__);
746 return;
747 }
748
Jean Pihet80821c92012-04-24 10:22:12 +0530749 sr_class->disable(sr, 0);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530750}
751
752/**
753 * omap_sr_disable_reset_volt() - API to disable SR and reset the
754 * voltage processor voltage
755 * @voltdm: VDD pointer to which the SR module to be configured belongs to.
756 *
757 * This API is to be called from the kernel in order to disable
758 * a particular smartreflex module. This API will in turn call
759 * into the registered smartreflex class disable API. This API will tell
760 * the smartreflex class disable to reset the VP voltage after
761 * disabling smartreflex.
762 */
763void omap_sr_disable_reset_volt(struct voltagedomain *voltdm)
764{
765 struct omap_sr *sr = _sr_lookup(voltdm);
766
767 if (IS_ERR(sr)) {
Jean Pihet8b765d72012-04-24 10:41:27 +0530768 pr_warning("%s: omap_sr struct for voltdm not found\n", __func__);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530769 return;
770 }
771
772 if (!sr->autocomp_active)
773 return;
774
775 if (!sr_class || !(sr_class->disable)) {
776 dev_warn(&sr->pdev->dev, "%s: smartreflex class driver not"
777 "registered\n", __func__);
778 return;
779 }
780
Jean Pihet80821c92012-04-24 10:22:12 +0530781 sr_class->disable(sr, 1);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530782}
783
784/**
785 * omap_sr_register_pmic() - API to register pmic specific info.
786 * @pmic_data: The structure containing pmic specific data.
787 *
788 * This API is to be called from the PMIC specific code to register with
789 * smartreflex driver pmic specific info. Currently the only info required
790 * is the smartreflex init on the PMIC side.
791 */
792void omap_sr_register_pmic(struct omap_sr_pmic_data *pmic_data)
793{
794 if (!pmic_data) {
795 pr_warning("%s: Trying to register NULL PMIC data structure"
796 "with smartreflex\n", __func__);
797 return;
798 }
799
800 sr_pmic_data = pmic_data;
801}
802
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100803/* PM Debug FS entries to enable and disable smartreflex. */
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530804static int omap_sr_autocomp_show(void *data, u64 *val)
805{
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100806 struct omap_sr *sr_info = data;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530807
808 if (!sr_info) {
Stefan Weil83535842011-01-30 20:29:38 +0100809 pr_warning("%s: omap_sr struct not found\n", __func__);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530810 return -EINVAL;
811 }
812
813 *val = sr_info->autocomp_active;
814
815 return 0;
816}
817
818static int omap_sr_autocomp_store(void *data, u64 val)
819{
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100820 struct omap_sr *sr_info = data;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530821
822 if (!sr_info) {
Stefan Weil83535842011-01-30 20:29:38 +0100823 pr_warning("%s: omap_sr struct not found\n", __func__);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530824 return -EINVAL;
825 }
826
827 /* Sanity check */
Felipe Balbid6173692012-02-29 23:33:47 +0100828 if (val > 1) {
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530829 pr_warning("%s: Invalid argument %lld\n", __func__, val);
830 return -EINVAL;
831 }
832
Nishanth Menonac77a6f2011-02-14 21:14:17 +0530833 /* control enable/disable only if there is a delta in value */
834 if (sr_info->autocomp_active != val) {
835 if (!val)
836 sr_stop_vddautocomp(sr_info);
837 else
838 sr_start_vddautocomp(sr_info);
839 }
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530840
841 return 0;
842}
843
844DEFINE_SIMPLE_ATTRIBUTE(pm_sr_fops, omap_sr_autocomp_show,
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100845 omap_sr_autocomp_store, "%llu\n");
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530846
847static int __init omap_sr_probe(struct platform_device *pdev)
848{
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100849 struct omap_sr *sr_info;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530850 struct omap_sr_data *pdata = pdev->dev.platform_data;
851 struct resource *mem, *irq;
Kevin Hilman633ef8b742011-04-05 14:39:11 -0700852 struct dentry *nvalue_dir;
Thara Gopinath077fcec2010-10-27 20:29:37 +0530853 int i, ret = 0;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530854
Felipe Balbi4018bfe2012-02-29 23:33:46 +0100855 sr_info = kzalloc(sizeof(struct omap_sr), GFP_KERNEL);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530856 if (!sr_info) {
857 dev_err(&pdev->dev, "%s: unable to allocate sr_info\n",
858 __func__);
859 return -ENOMEM;
860 }
861
Felipe Balbi1079a8b2012-02-29 23:33:44 +0100862 platform_set_drvdata(pdev, sr_info);
863
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530864 if (!pdata) {
865 dev_err(&pdev->dev, "%s: platform data missing\n", __func__);
Stefan Weil720bc782011-01-30 20:26:27 +0100866 ret = -EINVAL;
867 goto err_free_devinfo;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530868 }
869
870 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
871 if (!mem) {
872 dev_err(&pdev->dev, "%s: no mem resource\n", __func__);
873 ret = -ENODEV;
874 goto err_free_devinfo;
875 }
876
Aaro Koskinenda9e73922011-04-26 02:25:16 -0700877 mem = request_mem_region(mem->start, resource_size(mem),
878 dev_name(&pdev->dev));
879 if (!mem) {
880 dev_err(&pdev->dev, "%s: no mem region\n", __func__);
881 ret = -EBUSY;
882 goto err_free_devinfo;
883 }
884
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530885 irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
886
887 pm_runtime_enable(&pdev->dev);
Nishanth Menone13d8f32011-07-09 14:37:21 -0700888 pm_runtime_irq_safe(&pdev->dev);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530889
Jean Pihet8b765d72012-04-24 10:41:27 +0530890 sr_info->name = kasprintf(GFP_KERNEL, "%s", pdata->name);
891 if (!sr_info->name) {
892 dev_err(&pdev->dev, "%s: Unable to alloc SR instance name\n",
893 __func__);
894 ret = -ENOMEM;
895 goto err_release_region;
896 }
897
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530898 sr_info->pdev = pdev;
899 sr_info->srid = pdev->id;
900 sr_info->voltdm = pdata->voltdm;
901 sr_info->nvalue_table = pdata->nvalue_table;
902 sr_info->nvalue_count = pdata->nvalue_count;
903 sr_info->senn_mod = pdata->senn_mod;
904 sr_info->senp_mod = pdata->senp_mod;
Jean Pihet98aed082012-10-04 18:47:11 +0200905 sr_info->err_weight = pdata->err_weight;
906 sr_info->err_maxlimit = pdata->err_maxlimit;
907 sr_info->accum_data = pdata->accum_data;
908 sr_info->senn_avgweight = pdata->senn_avgweight;
909 sr_info->senp_avgweight = pdata->senp_avgweight;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530910 sr_info->autocomp_active = false;
911 sr_info->ip_type = pdata->ip_type;
Jean Pihet98aed082012-10-04 18:47:11 +0200912
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530913 sr_info->base = ioremap(mem->start, resource_size(mem));
914 if (!sr_info->base) {
915 dev_err(&pdev->dev, "%s: ioremap fail\n", __func__);
916 ret = -ENOMEM;
Jean Pihetce3810c2012-09-24 16:16:40 +0200917 goto err_free_name;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530918 }
919
920 if (irq)
921 sr_info->irq = irq->start;
922
923 sr_set_clk_length(sr_info);
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530924
925 list_add(&sr_info->node, &sr_list);
926
927 /*
928 * Call into late init to do intializations that require
929 * both sr driver and sr class driver to be initiallized.
930 */
931 if (sr_class) {
932 ret = sr_late_init(sr_info);
933 if (ret) {
934 pr_warning("%s: Error in SR late init\n", __func__);
Julia Lawall14ea9602012-01-12 10:55:17 +0100935 goto err_iounmap;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530936 }
937 }
938
939 dev_info(&pdev->dev, "%s: SmartReflex driver initialized\n", __func__);
Kevin Hilman633ef8b742011-04-05 14:39:11 -0700940 if (!sr_dbg_dir) {
941 sr_dbg_dir = debugfs_create_dir("smartreflex", NULL);
Jean Pihet54b28cd2012-02-29 23:33:48 +0100942 if (IS_ERR_OR_NULL(sr_dbg_dir)) {
Kevin Hilman633ef8b742011-04-05 14:39:11 -0700943 ret = PTR_ERR(sr_dbg_dir);
944 pr_err("%s:sr debugfs dir creation failed(%d)\n",
945 __func__, ret);
946 goto err_iounmap;
947 }
Shweta Gulatib3329a32011-02-15 13:40:30 +0530948 }
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530949
Jean Pihet8b765d72012-04-24 10:41:27 +0530950 sr_info->dbg_dir = debugfs_create_dir(sr_info->name, sr_dbg_dir);
Jean Pihet54b28cd2012-02-29 23:33:48 +0100951 if (IS_ERR_OR_NULL(sr_info->dbg_dir)) {
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530952 dev_err(&pdev->dev, "%s: Unable to create debugfs directory\n",
953 __func__);
Anand S Sawantb1ace382011-02-17 21:27:30 +0530954 ret = PTR_ERR(sr_info->dbg_dir);
Jean Pihetce3810c2012-09-24 16:16:40 +0200955 goto err_debugfs;
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530956 }
957
Anand S Sawantb1ace382011-02-17 21:27:30 +0530958 (void) debugfs_create_file("autocomp", S_IRUGO | S_IWUSR,
959 sr_info->dbg_dir, (void *)sr_info, &pm_sr_fops);
960 (void) debugfs_create_x32("errweight", S_IRUGO, sr_info->dbg_dir,
Thara Gopinath077fcec2010-10-27 20:29:37 +0530961 &sr_info->err_weight);
Anand S Sawantb1ace382011-02-17 21:27:30 +0530962 (void) debugfs_create_x32("errmaxlimit", S_IRUGO, sr_info->dbg_dir,
Thara Gopinath077fcec2010-10-27 20:29:37 +0530963 &sr_info->err_maxlimit);
Thara Gopinath077fcec2010-10-27 20:29:37 +0530964
Anand S Sawantb1ace382011-02-17 21:27:30 +0530965 nvalue_dir = debugfs_create_dir("nvalue", sr_info->dbg_dir);
Jean Pihet54b28cd2012-02-29 23:33:48 +0100966 if (IS_ERR_OR_NULL(nvalue_dir)) {
Thara Gopinath077fcec2010-10-27 20:29:37 +0530967 dev_err(&pdev->dev, "%s: Unable to create debugfs directory"
968 "for n-values\n", __func__);
Shweta Gulatib3329a32011-02-15 13:40:30 +0530969 ret = PTR_ERR(nvalue_dir);
Aaro Koskinen283a1c12011-04-26 02:25:32 -0700970 goto err_debugfs;
Thara Gopinath077fcec2010-10-27 20:29:37 +0530971 }
972
Jean Pihet5e7f2e12012-04-25 11:19:44 +0530973 if (sr_info->nvalue_count == 0 || !sr_info->nvalue_table) {
974 dev_warn(&pdev->dev, "%s: %s: No Voltage table for the corresponding vdd. Cannot create debugfs entries for n-values\n",
975 __func__, sr_info->name);
976
Shweta Gulatib3329a32011-02-15 13:40:30 +0530977 ret = -ENODATA;
Aaro Koskinen283a1c12011-04-26 02:25:32 -0700978 goto err_debugfs;
Thara Gopinath077fcec2010-10-27 20:29:37 +0530979 }
980
981 for (i = 0; i < sr_info->nvalue_count; i++) {
Aaro Koskinen865212a2011-02-07 16:08:04 +0200982 char name[NVALUE_NAME_LEN + 1];
Thara Gopinath077fcec2010-10-27 20:29:37 +0530983
Jean Pihet5e7f2e12012-04-25 11:19:44 +0530984 snprintf(name, sizeof(name), "volt_%lu",
985 sr_info->nvalue_table[i].volt_nominal);
Vasiliy Kulikov1232a182011-02-04 12:23:20 +0000986 (void) debugfs_create_x32(name, S_IRUGO | S_IWUSR, nvalue_dir,
Thara Gopinath077fcec2010-10-27 20:29:37 +0530987 &(sr_info->nvalue_table[i].nvalue));
Jean Pihet308d1bd2012-04-24 23:41:54 +0530988 snprintf(name, sizeof(name), "errminlimit_%lu",
989 sr_info->nvalue_table[i].volt_nominal);
990 (void) debugfs_create_x32(name, S_IRUGO | S_IWUSR, nvalue_dir,
991 &(sr_info->nvalue_table[i].errminlimit));
992
Thara Gopinath077fcec2010-10-27 20:29:37 +0530993 }
Thara Gopinath984aa6d2010-05-29 22:02:22 +0530994
995 return ret;
996
Aaro Koskinen283a1c12011-04-26 02:25:32 -0700997err_debugfs:
998 debugfs_remove_recursive(sr_info->dbg_dir);
Aaro Koskinen0c49cc12011-04-26 02:25:21 -0700999err_iounmap:
Aaro Koskinen833d78f2011-04-26 02:25:27 -07001000 list_del(&sr_info->node);
Aaro Koskinen0c49cc12011-04-26 02:25:21 -07001001 iounmap(sr_info->base);
Jean Pihetce3810c2012-09-24 16:16:40 +02001002err_free_name:
1003 kfree(sr_info->name);
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301004err_release_region:
1005 release_mem_region(mem->start, resource_size(mem));
1006err_free_devinfo:
1007 kfree(sr_info);
1008
1009 return ret;
1010}
1011
Bill Pemberton415ec692012-11-19 13:26:07 -05001012static int omap_sr_remove(struct platform_device *pdev)
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301013{
1014 struct omap_sr_data *pdata = pdev->dev.platform_data;
1015 struct omap_sr *sr_info;
1016 struct resource *mem;
1017
1018 if (!pdata) {
1019 dev_err(&pdev->dev, "%s: platform data missing\n", __func__);
1020 return -EINVAL;
1021 }
1022
1023 sr_info = _sr_lookup(pdata->voltdm);
Julia Lawall28693ec2011-01-24 20:55:22 +01001024 if (IS_ERR(sr_info)) {
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301025 dev_warn(&pdev->dev, "%s: omap_sr struct not found\n",
1026 __func__);
Jean Pihet63371fa2012-02-29 23:33:49 +01001027 return PTR_ERR(sr_info);
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301028 }
1029
1030 if (sr_info->autocomp_active)
1031 sr_stop_vddautocomp(sr_info);
Anand S Sawantb1ace382011-02-17 21:27:30 +05301032 if (sr_info->dbg_dir)
1033 debugfs_remove_recursive(sr_info->dbg_dir);
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301034
Andrii Tseglytskyibd4a36b2013-05-30 13:08:35 +03001035 pm_runtime_disable(&pdev->dev);
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301036 list_del(&sr_info->node);
1037 iounmap(sr_info->base);
Jean Pihet8b765d72012-04-24 10:41:27 +05301038 kfree(sr_info->name);
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301039 kfree(sr_info);
1040 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1041 release_mem_region(mem->start, resource_size(mem));
1042
1043 return 0;
1044}
1045
Bill Pemberton415ec692012-11-19 13:26:07 -05001046static void omap_sr_shutdown(struct platform_device *pdev)
Nishanth Menon1f55bc1852012-03-01 00:29:44 +01001047{
1048 struct omap_sr_data *pdata = pdev->dev.platform_data;
1049 struct omap_sr *sr_info;
1050
1051 if (!pdata) {
1052 dev_err(&pdev->dev, "%s: platform data missing\n", __func__);
1053 return;
1054 }
1055
1056 sr_info = _sr_lookup(pdata->voltdm);
1057 if (IS_ERR(sr_info)) {
1058 dev_warn(&pdev->dev, "%s: omap_sr struct not found\n",
1059 __func__);
1060 return;
1061 }
1062
1063 if (sr_info->autocomp_active)
1064 sr_stop_vddautocomp(sr_info);
1065
1066 return;
1067}
1068
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301069static struct platform_driver smartreflex_driver = {
Bill Pemberton28ea73f2012-11-19 13:20:40 -05001070 .remove = omap_sr_remove,
1071 .shutdown = omap_sr_shutdown,
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301072 .driver = {
Andrii Tseglytskyi33da2822013-05-30 13:08:36 +03001073 .name = DRIVER_NAME,
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301074 },
1075};
1076
1077static int __init sr_init(void)
1078{
1079 int ret = 0;
1080
1081 /*
1082 * sr_init is a late init. If by then a pmic specific API is not
1083 * registered either there is no need for anything to be done on
1084 * the PMIC side or somebody has forgotten to register a PMIC
1085 * handler. Warn for the second condition.
1086 */
1087 if (sr_pmic_data && sr_pmic_data->sr_pmic_init)
1088 sr_pmic_data->sr_pmic_init();
1089 else
1090 pr_warning("%s: No PMIC hook to init smartreflex\n", __func__);
1091
1092 ret = platform_driver_probe(&smartreflex_driver, omap_sr_probe);
1093 if (ret) {
1094 pr_err("%s: platform driver register failed for SR\n",
1095 __func__);
1096 return ret;
1097 }
1098
1099 return 0;
1100}
Felipe Balbi1a21a682012-02-29 23:33:45 +01001101late_initcall(sr_init);
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301102
1103static void __exit sr_exit(void)
1104{
1105 platform_driver_unregister(&smartreflex_driver);
1106}
Thara Gopinath984aa6d2010-05-29 22:02:22 +05301107module_exit(sr_exit);
1108
1109MODULE_DESCRIPTION("OMAP Smartreflex Driver");
1110MODULE_LICENSE("GPL");
1111MODULE_ALIAS("platform:" DRIVER_NAME);
1112MODULE_AUTHOR("Texas Instruments Inc");