1bca815d6SUlf Hansson // SPDX-License-Identifier: GPL-2.0
2bca815d6SUlf Hansson /*
3bca815d6SUlf Hansson * OMAP SmartReflex Voltage Control
4bca815d6SUlf Hansson *
5bca815d6SUlf Hansson * Author: Thara Gopinath <thara@ti.com>
6bca815d6SUlf Hansson *
7bca815d6SUlf Hansson * Copyright (C) 2012 Texas Instruments, Inc.
8bca815d6SUlf Hansson * Thara Gopinath <thara@ti.com>
9bca815d6SUlf Hansson *
10bca815d6SUlf Hansson * Copyright (C) 2008 Nokia Corporation
11bca815d6SUlf Hansson * Kalle Jokiniemi
12bca815d6SUlf Hansson *
13bca815d6SUlf Hansson * Copyright (C) 2007 Texas Instruments, Inc.
14bca815d6SUlf Hansson * Lesly A M <x0080970@ti.com>
15bca815d6SUlf Hansson */
16bca815d6SUlf Hansson
17bca815d6SUlf Hansson #include <linux/module.h>
18bca815d6SUlf Hansson #include <linux/mod_devicetable.h>
19bca815d6SUlf Hansson #include <linux/interrupt.h>
20bca815d6SUlf Hansson #include <linux/clk.h>
21bca815d6SUlf Hansson #include <linux/io.h>
22bca815d6SUlf Hansson #include <linux/debugfs.h>
23bca815d6SUlf Hansson #include <linux/delay.h>
24bca815d6SUlf Hansson #include <linux/slab.h>
25bca815d6SUlf Hansson #include <linux/pm_runtime.h>
26bca815d6SUlf Hansson #include <linux/power/smartreflex.h>
27bca815d6SUlf Hansson
28bca815d6SUlf Hansson #define DRIVER_NAME "smartreflex"
29bca815d6SUlf Hansson #define SMARTREFLEX_NAME_LEN 32
30bca815d6SUlf Hansson #define NVALUE_NAME_LEN 40
31bca815d6SUlf Hansson #define SR_DISABLE_TIMEOUT 200
32bca815d6SUlf Hansson
33bca815d6SUlf Hansson /* sr_list contains all the instances of smartreflex module */
34bca815d6SUlf Hansson static LIST_HEAD(sr_list);
35bca815d6SUlf Hansson
36bca815d6SUlf Hansson static struct omap_sr_class_data *sr_class;
37bca815d6SUlf Hansson static struct dentry *sr_dbg_dir;
38bca815d6SUlf Hansson
sr_write_reg(struct omap_sr * sr,unsigned offset,u32 value)39bca815d6SUlf Hansson static inline void sr_write_reg(struct omap_sr *sr, unsigned offset, u32 value)
40bca815d6SUlf Hansson {
41bca815d6SUlf Hansson __raw_writel(value, (sr->base + offset));
42bca815d6SUlf Hansson }
43bca815d6SUlf Hansson
sr_modify_reg(struct omap_sr * sr,unsigned offset,u32 mask,u32 value)44bca815d6SUlf Hansson static inline void sr_modify_reg(struct omap_sr *sr, unsigned offset, u32 mask,
45bca815d6SUlf Hansson u32 value)
46bca815d6SUlf Hansson {
47bca815d6SUlf Hansson u32 reg_val;
48bca815d6SUlf Hansson
49bca815d6SUlf Hansson /*
50bca815d6SUlf Hansson * Smartreflex error config register is special as it contains
51bca815d6SUlf Hansson * certain status bits which if written a 1 into means a clear
52bca815d6SUlf Hansson * of those bits. So in order to make sure no accidental write of
53bca815d6SUlf Hansson * 1 happens to those status bits, do a clear of them in the read
54bca815d6SUlf Hansson * value. This mean this API doesn't rewrite values in these bits
55bca815d6SUlf Hansson * if they are currently set, but does allow the caller to write
56bca815d6SUlf Hansson * those bits.
57bca815d6SUlf Hansson */
58bca815d6SUlf Hansson if (sr->ip_type == SR_TYPE_V1 && offset == ERRCONFIG_V1)
59bca815d6SUlf Hansson mask |= ERRCONFIG_STATUS_V1_MASK;
60bca815d6SUlf Hansson else if (sr->ip_type == SR_TYPE_V2 && offset == ERRCONFIG_V2)
61bca815d6SUlf Hansson mask |= ERRCONFIG_VPBOUNDINTST_V2;
62bca815d6SUlf Hansson
63bca815d6SUlf Hansson reg_val = __raw_readl(sr->base + offset);
64bca815d6SUlf Hansson reg_val &= ~mask;
65bca815d6SUlf Hansson
66bca815d6SUlf Hansson value &= mask;
67bca815d6SUlf Hansson
68bca815d6SUlf Hansson reg_val |= value;
69bca815d6SUlf Hansson
70bca815d6SUlf Hansson __raw_writel(reg_val, (sr->base + offset));
71bca815d6SUlf Hansson }
72bca815d6SUlf Hansson
sr_read_reg(struct omap_sr * sr,unsigned offset)73bca815d6SUlf Hansson static inline u32 sr_read_reg(struct omap_sr *sr, unsigned offset)
74bca815d6SUlf Hansson {
75bca815d6SUlf Hansson return __raw_readl(sr->base + offset);
76bca815d6SUlf Hansson }
77bca815d6SUlf Hansson
_sr_lookup(struct voltagedomain * voltdm)78bca815d6SUlf Hansson static struct omap_sr *_sr_lookup(struct voltagedomain *voltdm)
79bca815d6SUlf Hansson {
80bca815d6SUlf Hansson struct omap_sr *sr_info;
81bca815d6SUlf Hansson
82bca815d6SUlf Hansson if (!voltdm) {
83bca815d6SUlf Hansson pr_err("%s: Null voltage domain passed!\n", __func__);
84bca815d6SUlf Hansson return ERR_PTR(-EINVAL);
85bca815d6SUlf Hansson }
86bca815d6SUlf Hansson
87bca815d6SUlf Hansson list_for_each_entry(sr_info, &sr_list, node) {
88bca815d6SUlf Hansson if (voltdm == sr_info->voltdm)
89bca815d6SUlf Hansson return sr_info;
90bca815d6SUlf Hansson }
91bca815d6SUlf Hansson
92bca815d6SUlf Hansson return ERR_PTR(-ENODATA);
93bca815d6SUlf Hansson }
94bca815d6SUlf Hansson
sr_interrupt(int irq,void * data)95bca815d6SUlf Hansson static irqreturn_t sr_interrupt(int irq, void *data)
96bca815d6SUlf Hansson {
97bca815d6SUlf Hansson struct omap_sr *sr_info = data;
98bca815d6SUlf Hansson u32 status = 0;
99bca815d6SUlf Hansson
100bca815d6SUlf Hansson switch (sr_info->ip_type) {
101bca815d6SUlf Hansson case SR_TYPE_V1:
102bca815d6SUlf Hansson /* Read the status bits */
103bca815d6SUlf Hansson status = sr_read_reg(sr_info, ERRCONFIG_V1);
104bca815d6SUlf Hansson
105bca815d6SUlf Hansson /* Clear them by writing back */
106bca815d6SUlf Hansson sr_write_reg(sr_info, ERRCONFIG_V1, status);
107bca815d6SUlf Hansson break;
108bca815d6SUlf Hansson case SR_TYPE_V2:
109bca815d6SUlf Hansson /* Read the status bits */
110bca815d6SUlf Hansson status = sr_read_reg(sr_info, IRQSTATUS);
111bca815d6SUlf Hansson
112bca815d6SUlf Hansson /* Clear them by writing back */
113bca815d6SUlf Hansson sr_write_reg(sr_info, IRQSTATUS, status);
114bca815d6SUlf Hansson break;
115bca815d6SUlf Hansson default:
116bca815d6SUlf Hansson dev_err(&sr_info->pdev->dev, "UNKNOWN IP type %d\n",
117bca815d6SUlf Hansson sr_info->ip_type);
118bca815d6SUlf Hansson return IRQ_NONE;
119bca815d6SUlf Hansson }
120bca815d6SUlf Hansson
121bca815d6SUlf Hansson if (sr_class->notify)
122bca815d6SUlf Hansson sr_class->notify(sr_info, status);
123bca815d6SUlf Hansson
124bca815d6SUlf Hansson return IRQ_HANDLED;
125bca815d6SUlf Hansson }
126bca815d6SUlf Hansson
sr_set_clk_length(struct omap_sr * sr)127bca815d6SUlf Hansson static void sr_set_clk_length(struct omap_sr *sr)
128bca815d6SUlf Hansson {
129bca815d6SUlf Hansson u32 fclk_speed;
130bca815d6SUlf Hansson
131bca815d6SUlf Hansson /* Try interconnect target module fck first if it already exists */
132ed4520d6STony Lindgren if (IS_ERR(sr->fck))
133bca815d6SUlf Hansson return;
134bca815d6SUlf Hansson
135ed4520d6STony Lindgren fclk_speed = clk_get_rate(sr->fck);
136bca815d6SUlf Hansson
137bca815d6SUlf Hansson switch (fclk_speed) {
138bca815d6SUlf Hansson case 12000000:
139bca815d6SUlf Hansson sr->clk_length = SRCLKLENGTH_12MHZ_SYSCLK;
140bca815d6SUlf Hansson break;
141bca815d6SUlf Hansson case 13000000:
142bca815d6SUlf Hansson sr->clk_length = SRCLKLENGTH_13MHZ_SYSCLK;
143bca815d6SUlf Hansson break;
144bca815d6SUlf Hansson case 19200000:
145bca815d6SUlf Hansson sr->clk_length = SRCLKLENGTH_19MHZ_SYSCLK;
146bca815d6SUlf Hansson break;
147bca815d6SUlf Hansson case 26000000:
148bca815d6SUlf Hansson sr->clk_length = SRCLKLENGTH_26MHZ_SYSCLK;
149bca815d6SUlf Hansson break;
150bca815d6SUlf Hansson case 38400000:
151bca815d6SUlf Hansson sr->clk_length = SRCLKLENGTH_38MHZ_SYSCLK;
152bca815d6SUlf Hansson break;
153bca815d6SUlf Hansson default:
154bca815d6SUlf Hansson dev_err(&sr->pdev->dev, "%s: Invalid fclk rate: %d\n",
155bca815d6SUlf Hansson __func__, fclk_speed);
156bca815d6SUlf Hansson break;
157bca815d6SUlf Hansson }
158bca815d6SUlf Hansson }
159bca815d6SUlf Hansson
sr_start_vddautocomp(struct omap_sr * sr)160bca815d6SUlf Hansson static void sr_start_vddautocomp(struct omap_sr *sr)
161bca815d6SUlf Hansson {
162bca815d6SUlf Hansson if (!sr_class || !(sr_class->enable) || !(sr_class->configure)) {
163bca815d6SUlf Hansson dev_warn(&sr->pdev->dev,
164bca815d6SUlf Hansson "%s: smartreflex class driver not registered\n",
165bca815d6SUlf Hansson __func__);
166bca815d6SUlf Hansson return;
167bca815d6SUlf Hansson }
168bca815d6SUlf Hansson
169bca815d6SUlf Hansson if (!sr_class->enable(sr))
170bca815d6SUlf Hansson sr->autocomp_active = true;
171bca815d6SUlf Hansson }
172bca815d6SUlf Hansson
sr_stop_vddautocomp(struct omap_sr * sr)173bca815d6SUlf Hansson static void sr_stop_vddautocomp(struct omap_sr *sr)
174bca815d6SUlf Hansson {
175bca815d6SUlf Hansson if (!sr_class || !(sr_class->disable)) {
176bca815d6SUlf Hansson dev_warn(&sr->pdev->dev,
177bca815d6SUlf Hansson "%s: smartreflex class driver not registered\n",
178bca815d6SUlf Hansson __func__);
179bca815d6SUlf Hansson return;
180bca815d6SUlf Hansson }
181bca815d6SUlf Hansson
182bca815d6SUlf Hansson if (sr->autocomp_active) {
183bca815d6SUlf Hansson sr_class->disable(sr, 1);
184bca815d6SUlf Hansson sr->autocomp_active = false;
185bca815d6SUlf Hansson }
186bca815d6SUlf Hansson }
187bca815d6SUlf Hansson
188bca815d6SUlf Hansson /*
189bca815d6SUlf Hansson * This function handles the initializations which have to be done
190bca815d6SUlf Hansson * only when both sr device and class driver regiter has
191bca815d6SUlf Hansson * completed. This will be attempted to be called from both sr class
192bca815d6SUlf Hansson * driver register and sr device intializtion API's. Only one call
193bca815d6SUlf Hansson * will ultimately succeed.
194bca815d6SUlf Hansson *
195bca815d6SUlf Hansson * Currently this function registers interrupt handler for a particular SR
196bca815d6SUlf Hansson * if smartreflex class driver is already registered and has
197bca815d6SUlf Hansson * requested for interrupts and the SR interrupt line in present.
198bca815d6SUlf Hansson */
sr_late_init(struct omap_sr * sr_info)199bca815d6SUlf Hansson static int sr_late_init(struct omap_sr *sr_info)
200bca815d6SUlf Hansson {
201bca815d6SUlf Hansson int ret = 0;
202bca815d6SUlf Hansson
203bca815d6SUlf Hansson if (sr_class->notify && sr_class->notify_flags && sr_info->irq) {
204bca815d6SUlf Hansson ret = devm_request_irq(&sr_info->pdev->dev, sr_info->irq,
205*bfd19f48SJinjie Ruan sr_interrupt, IRQF_NO_AUTOEN,
206*bfd19f48SJinjie Ruan sr_info->name, sr_info);
207bca815d6SUlf Hansson if (ret)
208bca815d6SUlf Hansson goto error;
209bca815d6SUlf Hansson }
210bca815d6SUlf Hansson
211bca815d6SUlf Hansson return ret;
212bca815d6SUlf Hansson
213bca815d6SUlf Hansson error:
214bca815d6SUlf Hansson list_del(&sr_info->node);
215bca815d6SUlf Hansson dev_err(&sr_info->pdev->dev, "%s: ERROR in registering interrupt handler. Smartreflex will not function as desired\n",
216bca815d6SUlf Hansson __func__);
217bca815d6SUlf Hansson
218bca815d6SUlf Hansson return ret;
219bca815d6SUlf Hansson }
220bca815d6SUlf Hansson
sr_v1_disable(struct omap_sr * sr)221bca815d6SUlf Hansson static void sr_v1_disable(struct omap_sr *sr)
222bca815d6SUlf Hansson {
223bca815d6SUlf Hansson int timeout = 0;
224bca815d6SUlf Hansson int errconf_val = ERRCONFIG_MCUACCUMINTST | ERRCONFIG_MCUVALIDINTST |
225bca815d6SUlf Hansson ERRCONFIG_MCUBOUNDINTST;
226bca815d6SUlf Hansson
227bca815d6SUlf Hansson /* Enable MCUDisableAcknowledge interrupt */
228bca815d6SUlf Hansson sr_modify_reg(sr, ERRCONFIG_V1,
229bca815d6SUlf Hansson ERRCONFIG_MCUDISACKINTEN, ERRCONFIG_MCUDISACKINTEN);
230bca815d6SUlf Hansson
231bca815d6SUlf Hansson /* SRCONFIG - disable SR */
232bca815d6SUlf Hansson sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0x0);
233bca815d6SUlf Hansson
234bca815d6SUlf Hansson /* Disable all other SR interrupts and clear the status as needed */
235bca815d6SUlf Hansson if (sr_read_reg(sr, ERRCONFIG_V1) & ERRCONFIG_VPBOUNDINTST_V1)
236bca815d6SUlf Hansson errconf_val |= ERRCONFIG_VPBOUNDINTST_V1;
237bca815d6SUlf Hansson sr_modify_reg(sr, ERRCONFIG_V1,
238bca815d6SUlf Hansson (ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUVALIDINTEN |
239bca815d6SUlf Hansson ERRCONFIG_MCUBOUNDINTEN | ERRCONFIG_VPBOUNDINTEN_V1),
240bca815d6SUlf Hansson errconf_val);
241bca815d6SUlf Hansson
242bca815d6SUlf Hansson /*
243bca815d6SUlf Hansson * Wait for SR to be disabled.
244bca815d6SUlf Hansson * wait until ERRCONFIG.MCUDISACKINTST = 1. Typical latency is 1us.
245bca815d6SUlf Hansson */
246bca815d6SUlf Hansson sr_test_cond_timeout((sr_read_reg(sr, ERRCONFIG_V1) &
247bca815d6SUlf Hansson ERRCONFIG_MCUDISACKINTST), SR_DISABLE_TIMEOUT,
248bca815d6SUlf Hansson timeout);
249bca815d6SUlf Hansson
250bca815d6SUlf Hansson if (timeout >= SR_DISABLE_TIMEOUT)
251bca815d6SUlf Hansson dev_warn(&sr->pdev->dev, "%s: Smartreflex disable timedout\n",
252bca815d6SUlf Hansson __func__);
253bca815d6SUlf Hansson
254bca815d6SUlf Hansson /* Disable MCUDisableAcknowledge interrupt & clear pending interrupt */
255bca815d6SUlf Hansson sr_modify_reg(sr, ERRCONFIG_V1, ERRCONFIG_MCUDISACKINTEN,
256bca815d6SUlf Hansson ERRCONFIG_MCUDISACKINTST);
257bca815d6SUlf Hansson }
258bca815d6SUlf Hansson
sr_v2_disable(struct omap_sr * sr)259bca815d6SUlf Hansson static void sr_v2_disable(struct omap_sr *sr)
260bca815d6SUlf Hansson {
261bca815d6SUlf Hansson int timeout = 0;
262bca815d6SUlf Hansson
263bca815d6SUlf Hansson /* Enable MCUDisableAcknowledge interrupt */
264bca815d6SUlf Hansson sr_write_reg(sr, IRQENABLE_SET, IRQENABLE_MCUDISABLEACKINT);
265bca815d6SUlf Hansson
266bca815d6SUlf Hansson /* SRCONFIG - disable SR */
267bca815d6SUlf Hansson sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0x0);
268bca815d6SUlf Hansson
269bca815d6SUlf Hansson /*
270bca815d6SUlf Hansson * Disable all other SR interrupts and clear the status
271bca815d6SUlf Hansson * write to status register ONLY on need basis - only if status
272bca815d6SUlf Hansson * is set.
273bca815d6SUlf Hansson */
274bca815d6SUlf Hansson if (sr_read_reg(sr, ERRCONFIG_V2) & ERRCONFIG_VPBOUNDINTST_V2)
275bca815d6SUlf Hansson sr_modify_reg(sr, ERRCONFIG_V2, ERRCONFIG_VPBOUNDINTEN_V2,
276bca815d6SUlf Hansson ERRCONFIG_VPBOUNDINTST_V2);
277bca815d6SUlf Hansson else
278bca815d6SUlf Hansson sr_modify_reg(sr, ERRCONFIG_V2, ERRCONFIG_VPBOUNDINTEN_V2,
279bca815d6SUlf Hansson 0x0);
280bca815d6SUlf Hansson sr_write_reg(sr, IRQENABLE_CLR, (IRQENABLE_MCUACCUMINT |
281bca815d6SUlf Hansson IRQENABLE_MCUVALIDINT |
282bca815d6SUlf Hansson IRQENABLE_MCUBOUNDSINT));
283bca815d6SUlf Hansson sr_write_reg(sr, IRQSTATUS, (IRQSTATUS_MCUACCUMINT |
284bca815d6SUlf Hansson IRQSTATUS_MCVALIDINT |
285bca815d6SUlf Hansson IRQSTATUS_MCBOUNDSINT));
286bca815d6SUlf Hansson
287bca815d6SUlf Hansson /*
288bca815d6SUlf Hansson * Wait for SR to be disabled.
289bca815d6SUlf Hansson * wait until IRQSTATUS.MCUDISACKINTST = 1. Typical latency is 1us.
290bca815d6SUlf Hansson */
291bca815d6SUlf Hansson sr_test_cond_timeout((sr_read_reg(sr, IRQSTATUS) &
292bca815d6SUlf Hansson IRQSTATUS_MCUDISABLEACKINT), SR_DISABLE_TIMEOUT,
293bca815d6SUlf Hansson timeout);
294bca815d6SUlf Hansson
295bca815d6SUlf Hansson if (timeout >= SR_DISABLE_TIMEOUT)
296bca815d6SUlf Hansson dev_warn(&sr->pdev->dev, "%s: Smartreflex disable timedout\n",
297bca815d6SUlf Hansson __func__);
298bca815d6SUlf Hansson
299bca815d6SUlf Hansson /* Disable MCUDisableAcknowledge interrupt & clear pending interrupt */
300bca815d6SUlf Hansson sr_write_reg(sr, IRQENABLE_CLR, IRQENABLE_MCUDISABLEACKINT);
301bca815d6SUlf Hansson sr_write_reg(sr, IRQSTATUS, IRQSTATUS_MCUDISABLEACKINT);
302bca815d6SUlf Hansson }
303bca815d6SUlf Hansson
sr_retrieve_nvalue_row(struct omap_sr * sr,u32 efuse_offs)304bca815d6SUlf Hansson static struct omap_sr_nvalue_table *sr_retrieve_nvalue_row(
305bca815d6SUlf Hansson struct omap_sr *sr, u32 efuse_offs)
306bca815d6SUlf Hansson {
307bca815d6SUlf Hansson int i;
308bca815d6SUlf Hansson
309bca815d6SUlf Hansson if (!sr->nvalue_table) {
310bca815d6SUlf Hansson dev_warn(&sr->pdev->dev, "%s: Missing ntarget value table\n",
311bca815d6SUlf Hansson __func__);
312bca815d6SUlf Hansson return NULL;
313bca815d6SUlf Hansson }
314bca815d6SUlf Hansson
315bca815d6SUlf Hansson for (i = 0; i < sr->nvalue_count; i++) {
316bca815d6SUlf Hansson if (sr->nvalue_table[i].efuse_offs == efuse_offs)
317bca815d6SUlf Hansson return &sr->nvalue_table[i];
318bca815d6SUlf Hansson }
319bca815d6SUlf Hansson
320bca815d6SUlf Hansson return NULL;
321bca815d6SUlf Hansson }
322bca815d6SUlf Hansson
323bca815d6SUlf Hansson /* Public Functions */
324bca815d6SUlf Hansson
325bca815d6SUlf Hansson /**
326bca815d6SUlf Hansson * sr_configure_errgen() - Configures the SmartReflex to perform AVS using the
327bca815d6SUlf Hansson * error generator module.
328bca815d6SUlf Hansson * @sr: SR module to be configured.
329bca815d6SUlf Hansson *
330bca815d6SUlf Hansson * This API is to be called from the smartreflex class driver to
331bca815d6SUlf Hansson * configure the error generator module inside the smartreflex module.
332bca815d6SUlf Hansson * SR settings if using the ERROR module inside Smartreflex.
333bca815d6SUlf Hansson * SR CLASS 3 by default uses only the ERROR module where as
334bca815d6SUlf Hansson * SR CLASS 2 can choose between ERROR module and MINMAXAVG
335bca815d6SUlf Hansson * module. Returns 0 on success and error value in case of failure.
336bca815d6SUlf Hansson */
sr_configure_errgen(struct omap_sr * sr)337bca815d6SUlf Hansson int sr_configure_errgen(struct omap_sr *sr)
338bca815d6SUlf Hansson {
339bca815d6SUlf Hansson u32 sr_config, sr_errconfig, errconfig_offs;
340bca815d6SUlf Hansson u32 vpboundint_en, vpboundint_st;
341bca815d6SUlf Hansson u32 senp_en = 0, senn_en = 0;
342bca815d6SUlf Hansson u8 senp_shift, senn_shift;
343bca815d6SUlf Hansson
344bca815d6SUlf Hansson if (!sr) {
345bca815d6SUlf Hansson pr_warn("%s: NULL omap_sr from %pS\n",
346bca815d6SUlf Hansson __func__, (void *)_RET_IP_);
347bca815d6SUlf Hansson return -EINVAL;
348bca815d6SUlf Hansson }
349bca815d6SUlf Hansson
350bca815d6SUlf Hansson if (!sr->clk_length)
351bca815d6SUlf Hansson sr_set_clk_length(sr);
352bca815d6SUlf Hansson
353bca815d6SUlf Hansson senp_en = sr->senp_mod;
354bca815d6SUlf Hansson senn_en = sr->senn_mod;
355bca815d6SUlf Hansson
356bca815d6SUlf Hansson sr_config = (sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
357bca815d6SUlf Hansson SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN;
358bca815d6SUlf Hansson
359bca815d6SUlf Hansson switch (sr->ip_type) {
360bca815d6SUlf Hansson case SR_TYPE_V1:
361bca815d6SUlf Hansson sr_config |= SRCONFIG_DELAYCTRL;
362bca815d6SUlf Hansson senn_shift = SRCONFIG_SENNENABLE_V1_SHIFT;
363bca815d6SUlf Hansson senp_shift = SRCONFIG_SENPENABLE_V1_SHIFT;
364bca815d6SUlf Hansson errconfig_offs = ERRCONFIG_V1;
365bca815d6SUlf Hansson vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V1;
366bca815d6SUlf Hansson vpboundint_st = ERRCONFIG_VPBOUNDINTST_V1;
367bca815d6SUlf Hansson break;
368bca815d6SUlf Hansson case SR_TYPE_V2:
369bca815d6SUlf Hansson senn_shift = SRCONFIG_SENNENABLE_V2_SHIFT;
370bca815d6SUlf Hansson senp_shift = SRCONFIG_SENPENABLE_V2_SHIFT;
371bca815d6SUlf Hansson errconfig_offs = ERRCONFIG_V2;
372bca815d6SUlf Hansson vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V2;
373bca815d6SUlf Hansson vpboundint_st = ERRCONFIG_VPBOUNDINTST_V2;
374bca815d6SUlf Hansson break;
375bca815d6SUlf Hansson default:
376bca815d6SUlf Hansson dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex module without specifying the ip\n",
377bca815d6SUlf Hansson __func__);
378bca815d6SUlf Hansson return -EINVAL;
379bca815d6SUlf Hansson }
380bca815d6SUlf Hansson
381bca815d6SUlf Hansson sr_config |= ((senn_en << senn_shift) | (senp_en << senp_shift));
382bca815d6SUlf Hansson sr_write_reg(sr, SRCONFIG, sr_config);
383bca815d6SUlf Hansson sr_errconfig = (sr->err_weight << ERRCONFIG_ERRWEIGHT_SHIFT) |
384bca815d6SUlf Hansson (sr->err_maxlimit << ERRCONFIG_ERRMAXLIMIT_SHIFT) |
385bca815d6SUlf Hansson (sr->err_minlimit << ERRCONFIG_ERRMINLIMIT_SHIFT);
386bca815d6SUlf Hansson sr_modify_reg(sr, errconfig_offs, (SR_ERRWEIGHT_MASK |
387bca815d6SUlf Hansson SR_ERRMAXLIMIT_MASK | SR_ERRMINLIMIT_MASK),
388bca815d6SUlf Hansson sr_errconfig);
389bca815d6SUlf Hansson
390bca815d6SUlf Hansson /* Enabling the interrupts if the ERROR module is used */
391bca815d6SUlf Hansson sr_modify_reg(sr, errconfig_offs, (vpboundint_en | vpboundint_st),
392bca815d6SUlf Hansson vpboundint_en);
393bca815d6SUlf Hansson
394bca815d6SUlf Hansson return 0;
395bca815d6SUlf Hansson }
396bca815d6SUlf Hansson
397bca815d6SUlf Hansson /**
398bca815d6SUlf Hansson * sr_disable_errgen() - Disables SmartReflex AVS module's errgen component
399bca815d6SUlf Hansson * @sr: SR module to be configured.
400bca815d6SUlf Hansson *
401bca815d6SUlf Hansson * This API is to be called from the smartreflex class driver to
402bca815d6SUlf Hansson * disable the error generator module inside the smartreflex module.
403bca815d6SUlf Hansson *
404bca815d6SUlf Hansson * Returns 0 on success and error value in case of failure.
405bca815d6SUlf Hansson */
sr_disable_errgen(struct omap_sr * sr)406bca815d6SUlf Hansson int sr_disable_errgen(struct omap_sr *sr)
407bca815d6SUlf Hansson {
408bca815d6SUlf Hansson u32 errconfig_offs;
409bca815d6SUlf Hansson u32 vpboundint_en, vpboundint_st;
410bca815d6SUlf Hansson
411bca815d6SUlf Hansson if (!sr) {
412bca815d6SUlf Hansson pr_warn("%s: NULL omap_sr from %pS\n",
413bca815d6SUlf Hansson __func__, (void *)_RET_IP_);
414bca815d6SUlf Hansson return -EINVAL;
415bca815d6SUlf Hansson }
416bca815d6SUlf Hansson
417bca815d6SUlf Hansson switch (sr->ip_type) {
418bca815d6SUlf Hansson case SR_TYPE_V1:
419bca815d6SUlf Hansson errconfig_offs = ERRCONFIG_V1;
420bca815d6SUlf Hansson vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V1;
421bca815d6SUlf Hansson vpboundint_st = ERRCONFIG_VPBOUNDINTST_V1;
422bca815d6SUlf Hansson break;
423bca815d6SUlf Hansson case SR_TYPE_V2:
424bca815d6SUlf Hansson errconfig_offs = ERRCONFIG_V2;
425bca815d6SUlf Hansson vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V2;
426bca815d6SUlf Hansson vpboundint_st = ERRCONFIG_VPBOUNDINTST_V2;
427bca815d6SUlf Hansson break;
428bca815d6SUlf Hansson default:
429bca815d6SUlf Hansson dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex module without specifying the ip\n",
430bca815d6SUlf Hansson __func__);
431bca815d6SUlf Hansson return -EINVAL;
432bca815d6SUlf Hansson }
433bca815d6SUlf Hansson
434bca815d6SUlf Hansson /* Disable the Sensor and errorgen */
435bca815d6SUlf Hansson sr_modify_reg(sr, SRCONFIG, SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN, 0);
436bca815d6SUlf Hansson
437bca815d6SUlf Hansson /*
438bca815d6SUlf Hansson * Disable the interrupts of ERROR module
439bca815d6SUlf Hansson * NOTE: modify is a read, modify,write - an implicit OCP barrier
440bca815d6SUlf Hansson * which is required is present here - sequencing is critical
441bca815d6SUlf Hansson * at this point (after errgen is disabled, vpboundint disable)
442bca815d6SUlf Hansson */
443bca815d6SUlf Hansson sr_modify_reg(sr, errconfig_offs, vpboundint_en | vpboundint_st, 0);
444bca815d6SUlf Hansson
445bca815d6SUlf Hansson return 0;
446bca815d6SUlf Hansson }
447bca815d6SUlf Hansson
448bca815d6SUlf Hansson /**
449bca815d6SUlf Hansson * sr_configure_minmax() - Configures the SmartReflex to perform AVS using the
450bca815d6SUlf Hansson * minmaxavg module.
451bca815d6SUlf Hansson * @sr: SR module to be configured.
452bca815d6SUlf Hansson *
453bca815d6SUlf Hansson * This API is to be called from the smartreflex class driver to
454bca815d6SUlf Hansson * configure the minmaxavg module inside the smartreflex module.
455bca815d6SUlf Hansson * SR settings if using the ERROR module inside Smartreflex.
456bca815d6SUlf Hansson * SR CLASS 3 by default uses only the ERROR module where as
457bca815d6SUlf Hansson * SR CLASS 2 can choose between ERROR module and MINMAXAVG
458bca815d6SUlf Hansson * module. Returns 0 on success and error value in case of failure.
459bca815d6SUlf Hansson */
sr_configure_minmax(struct omap_sr * sr)460bca815d6SUlf Hansson int sr_configure_minmax(struct omap_sr *sr)
461bca815d6SUlf Hansson {
462bca815d6SUlf Hansson u32 sr_config, sr_avgwt;
463bca815d6SUlf Hansson u32 senp_en = 0, senn_en = 0;
464bca815d6SUlf Hansson u8 senp_shift, senn_shift;
465bca815d6SUlf Hansson
466bca815d6SUlf Hansson if (!sr) {
467bca815d6SUlf Hansson pr_warn("%s: NULL omap_sr from %pS\n",
468bca815d6SUlf Hansson __func__, (void *)_RET_IP_);
469bca815d6SUlf Hansson return -EINVAL;
470bca815d6SUlf Hansson }
471bca815d6SUlf Hansson
472bca815d6SUlf Hansson if (!sr->clk_length)
473bca815d6SUlf Hansson sr_set_clk_length(sr);
474bca815d6SUlf Hansson
475bca815d6SUlf Hansson senp_en = sr->senp_mod;
476bca815d6SUlf Hansson senn_en = sr->senn_mod;
477bca815d6SUlf Hansson
478bca815d6SUlf Hansson sr_config = (sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
479bca815d6SUlf Hansson SRCONFIG_SENENABLE |
480bca815d6SUlf Hansson (sr->accum_data << SRCONFIG_ACCUMDATA_SHIFT);
481bca815d6SUlf Hansson
482bca815d6SUlf Hansson switch (sr->ip_type) {
483bca815d6SUlf Hansson case SR_TYPE_V1:
484bca815d6SUlf Hansson sr_config |= SRCONFIG_DELAYCTRL;
485bca815d6SUlf Hansson senn_shift = SRCONFIG_SENNENABLE_V1_SHIFT;
486bca815d6SUlf Hansson senp_shift = SRCONFIG_SENPENABLE_V1_SHIFT;
487bca815d6SUlf Hansson break;
488bca815d6SUlf Hansson case SR_TYPE_V2:
489bca815d6SUlf Hansson senn_shift = SRCONFIG_SENNENABLE_V2_SHIFT;
490bca815d6SUlf Hansson senp_shift = SRCONFIG_SENPENABLE_V2_SHIFT;
491bca815d6SUlf Hansson break;
492bca815d6SUlf Hansson default:
493bca815d6SUlf Hansson dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex module without specifying the ip\n",
494bca815d6SUlf Hansson __func__);
495bca815d6SUlf Hansson return -EINVAL;
496bca815d6SUlf Hansson }
497bca815d6SUlf Hansson
498bca815d6SUlf Hansson sr_config |= ((senn_en << senn_shift) | (senp_en << senp_shift));
499bca815d6SUlf Hansson sr_write_reg(sr, SRCONFIG, sr_config);
500bca815d6SUlf Hansson sr_avgwt = (sr->senp_avgweight << AVGWEIGHT_SENPAVGWEIGHT_SHIFT) |
501bca815d6SUlf Hansson (sr->senn_avgweight << AVGWEIGHT_SENNAVGWEIGHT_SHIFT);
502bca815d6SUlf Hansson sr_write_reg(sr, AVGWEIGHT, sr_avgwt);
503bca815d6SUlf Hansson
504bca815d6SUlf Hansson /*
505bca815d6SUlf Hansson * Enabling the interrupts if MINMAXAVG module is used.
506bca815d6SUlf Hansson * TODO: check if all the interrupts are mandatory
507bca815d6SUlf Hansson */
508bca815d6SUlf Hansson switch (sr->ip_type) {
509bca815d6SUlf Hansson case SR_TYPE_V1:
510bca815d6SUlf Hansson sr_modify_reg(sr, ERRCONFIG_V1,
511bca815d6SUlf Hansson (ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUVALIDINTEN |
512bca815d6SUlf Hansson ERRCONFIG_MCUBOUNDINTEN),
513bca815d6SUlf Hansson (ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUACCUMINTST |
514bca815d6SUlf Hansson ERRCONFIG_MCUVALIDINTEN | ERRCONFIG_MCUVALIDINTST |
515bca815d6SUlf Hansson ERRCONFIG_MCUBOUNDINTEN | ERRCONFIG_MCUBOUNDINTST));
516bca815d6SUlf Hansson break;
517bca815d6SUlf Hansson case SR_TYPE_V2:
518bca815d6SUlf Hansson sr_write_reg(sr, IRQSTATUS,
519bca815d6SUlf Hansson IRQSTATUS_MCUACCUMINT | IRQSTATUS_MCVALIDINT |
520bca815d6SUlf Hansson IRQSTATUS_MCBOUNDSINT | IRQSTATUS_MCUDISABLEACKINT);
521bca815d6SUlf Hansson sr_write_reg(sr, IRQENABLE_SET,
522bca815d6SUlf Hansson IRQENABLE_MCUACCUMINT | IRQENABLE_MCUVALIDINT |
523bca815d6SUlf Hansson IRQENABLE_MCUBOUNDSINT | IRQENABLE_MCUDISABLEACKINT);
524bca815d6SUlf Hansson break;
525bca815d6SUlf Hansson default:
526bca815d6SUlf Hansson dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex module without specifying the ip\n",
527bca815d6SUlf Hansson __func__);
528bca815d6SUlf Hansson return -EINVAL;
529bca815d6SUlf Hansson }
530bca815d6SUlf Hansson
531bca815d6SUlf Hansson return 0;
532bca815d6SUlf Hansson }
533bca815d6SUlf Hansson
534bca815d6SUlf Hansson /**
535bca815d6SUlf Hansson * sr_enable() - Enables the smartreflex module.
536bca815d6SUlf Hansson * @sr: pointer to which the SR module to be configured belongs to.
537bca815d6SUlf Hansson * @volt: The voltage at which the Voltage domain associated with
538bca815d6SUlf Hansson * the smartreflex module is operating at.
539bca815d6SUlf Hansson * This is required only to program the correct Ntarget value.
540bca815d6SUlf Hansson *
541bca815d6SUlf Hansson * This API is to be called from the smartreflex class driver to
542bca815d6SUlf Hansson * enable a smartreflex module. Returns 0 on success. Returns error
543bca815d6SUlf Hansson * value if the voltage passed is wrong or if ntarget value is wrong.
544bca815d6SUlf Hansson */
sr_enable(struct omap_sr * sr,unsigned long volt)545bca815d6SUlf Hansson int sr_enable(struct omap_sr *sr, unsigned long volt)
546bca815d6SUlf Hansson {
547bca815d6SUlf Hansson struct omap_volt_data *volt_data;
548bca815d6SUlf Hansson struct omap_sr_nvalue_table *nvalue_row;
549bca815d6SUlf Hansson int ret;
550bca815d6SUlf Hansson
551bca815d6SUlf Hansson if (!sr) {
552bca815d6SUlf Hansson pr_warn("%s: NULL omap_sr from %pS\n",
553bca815d6SUlf Hansson __func__, (void *)_RET_IP_);
554bca815d6SUlf Hansson return -EINVAL;
555bca815d6SUlf Hansson }
556bca815d6SUlf Hansson
557bca815d6SUlf Hansson volt_data = omap_voltage_get_voltdata(sr->voltdm, volt);
558bca815d6SUlf Hansson
559bca815d6SUlf Hansson if (IS_ERR(volt_data)) {
560bca815d6SUlf Hansson dev_warn(&sr->pdev->dev, "%s: Unable to get voltage table for nominal voltage %ld\n",
561bca815d6SUlf Hansson __func__, volt);
562bca815d6SUlf Hansson return PTR_ERR(volt_data);
563bca815d6SUlf Hansson }
564bca815d6SUlf Hansson
565bca815d6SUlf Hansson nvalue_row = sr_retrieve_nvalue_row(sr, volt_data->sr_efuse_offs);
566bca815d6SUlf Hansson
567bca815d6SUlf Hansson if (!nvalue_row) {
568bca815d6SUlf Hansson dev_warn(&sr->pdev->dev, "%s: failure getting SR data for this voltage %ld\n",
569bca815d6SUlf Hansson __func__, volt);
570bca815d6SUlf Hansson return -ENODATA;
571bca815d6SUlf Hansson }
572bca815d6SUlf Hansson
573bca815d6SUlf Hansson /* errminlimit is opp dependent and hence linked to voltage */
574bca815d6SUlf Hansson sr->err_minlimit = nvalue_row->errminlimit;
575bca815d6SUlf Hansson
576ed4520d6STony Lindgren clk_enable(sr->fck);
577bca815d6SUlf Hansson
578bca815d6SUlf Hansson /* Check if SR is already enabled. If yes do nothing */
579bca815d6SUlf Hansson if (sr_read_reg(sr, SRCONFIG) & SRCONFIG_SRENABLE)
580ed4520d6STony Lindgren goto out_enabled;
581bca815d6SUlf Hansson
582bca815d6SUlf Hansson /* Configure SR */
583bca815d6SUlf Hansson ret = sr_class->configure(sr);
584bca815d6SUlf Hansson if (ret)
585ed4520d6STony Lindgren goto out_enabled;
586bca815d6SUlf Hansson
587bca815d6SUlf Hansson sr_write_reg(sr, NVALUERECIPROCAL, nvalue_row->nvalue);
588bca815d6SUlf Hansson
589bca815d6SUlf Hansson /* SRCONFIG - enable SR */
590bca815d6SUlf Hansson sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, SRCONFIG_SRENABLE);
591ed4520d6STony Lindgren
592ed4520d6STony Lindgren out_enabled:
593ed4520d6STony Lindgren sr->enabled = 1;
594ed4520d6STony Lindgren
595bca815d6SUlf Hansson return 0;
596bca815d6SUlf Hansson }
597bca815d6SUlf Hansson
598bca815d6SUlf Hansson /**
599bca815d6SUlf Hansson * sr_disable() - Disables the smartreflex module.
600bca815d6SUlf Hansson * @sr: pointer to which the SR module to be configured belongs to.
601bca815d6SUlf Hansson *
602bca815d6SUlf Hansson * This API is to be called from the smartreflex class driver to
603bca815d6SUlf Hansson * disable a smartreflex module.
604bca815d6SUlf Hansson */
sr_disable(struct omap_sr * sr)605bca815d6SUlf Hansson void sr_disable(struct omap_sr *sr)
606bca815d6SUlf Hansson {
607bca815d6SUlf Hansson if (!sr) {
608bca815d6SUlf Hansson pr_warn("%s: NULL omap_sr from %pS\n",
609bca815d6SUlf Hansson __func__, (void *)_RET_IP_);
610bca815d6SUlf Hansson return;
611bca815d6SUlf Hansson }
612bca815d6SUlf Hansson
613bca815d6SUlf Hansson /* Check if SR clocks are already disabled. If yes do nothing */
614ed4520d6STony Lindgren if (!sr->enabled)
615bca815d6SUlf Hansson return;
616bca815d6SUlf Hansson
617bca815d6SUlf Hansson /*
618bca815d6SUlf Hansson * Disable SR if only it is indeed enabled. Else just
619bca815d6SUlf Hansson * disable the clocks.
620bca815d6SUlf Hansson */
621bca815d6SUlf Hansson if (sr_read_reg(sr, SRCONFIG) & SRCONFIG_SRENABLE) {
622bca815d6SUlf Hansson switch (sr->ip_type) {
623bca815d6SUlf Hansson case SR_TYPE_V1:
624bca815d6SUlf Hansson sr_v1_disable(sr);
625bca815d6SUlf Hansson break;
626bca815d6SUlf Hansson case SR_TYPE_V2:
627bca815d6SUlf Hansson sr_v2_disable(sr);
628bca815d6SUlf Hansson break;
629bca815d6SUlf Hansson default:
630bca815d6SUlf Hansson dev_err(&sr->pdev->dev, "UNKNOWN IP type %d\n",
631bca815d6SUlf Hansson sr->ip_type);
632bca815d6SUlf Hansson }
633bca815d6SUlf Hansson }
634bca815d6SUlf Hansson
635ed4520d6STony Lindgren clk_disable(sr->fck);
636ed4520d6STony Lindgren sr->enabled = 0;
637bca815d6SUlf Hansson }
638bca815d6SUlf Hansson
639bca815d6SUlf Hansson /**
640bca815d6SUlf Hansson * sr_register_class() - API to register a smartreflex class parameters.
641bca815d6SUlf Hansson * @class_data: The structure containing various sr class specific data.
642bca815d6SUlf Hansson *
643bca815d6SUlf Hansson * This API is to be called by the smartreflex class driver to register itself
644bca815d6SUlf Hansson * with the smartreflex driver during init. Returns 0 on success else the
645bca815d6SUlf Hansson * error value.
646bca815d6SUlf Hansson */
sr_register_class(struct omap_sr_class_data * class_data)647bca815d6SUlf Hansson int sr_register_class(struct omap_sr_class_data *class_data)
648bca815d6SUlf Hansson {
649bca815d6SUlf Hansson struct omap_sr *sr_info;
650bca815d6SUlf Hansson
651bca815d6SUlf Hansson if (!class_data) {
652bca815d6SUlf Hansson pr_warn("%s:, Smartreflex class data passed is NULL\n",
653bca815d6SUlf Hansson __func__);
654bca815d6SUlf Hansson return -EINVAL;
655bca815d6SUlf Hansson }
656bca815d6SUlf Hansson
657bca815d6SUlf Hansson if (sr_class) {
658bca815d6SUlf Hansson pr_warn("%s: Smartreflex class driver already registered\n",
659bca815d6SUlf Hansson __func__);
660bca815d6SUlf Hansson return -EBUSY;
661bca815d6SUlf Hansson }
662bca815d6SUlf Hansson
663bca815d6SUlf Hansson sr_class = class_data;
664bca815d6SUlf Hansson
665bca815d6SUlf Hansson /*
666bca815d6SUlf Hansson * Call into late init to do initializations that require
667bca815d6SUlf Hansson * both sr driver and sr class driver to be initiallized.
668bca815d6SUlf Hansson */
669bca815d6SUlf Hansson list_for_each_entry(sr_info, &sr_list, node)
670bca815d6SUlf Hansson sr_late_init(sr_info);
671bca815d6SUlf Hansson
672bca815d6SUlf Hansson return 0;
673bca815d6SUlf Hansson }
674bca815d6SUlf Hansson
675bca815d6SUlf Hansson /**
676bca815d6SUlf Hansson * omap_sr_enable() - API to enable SR clocks and to call into the
677bca815d6SUlf Hansson * registered smartreflex class enable API.
678bca815d6SUlf Hansson * @voltdm: VDD pointer to which the SR module to be configured belongs to.
679bca815d6SUlf Hansson *
680bca815d6SUlf Hansson * This API is to be called from the kernel in order to enable
681bca815d6SUlf Hansson * a particular smartreflex module. This API will do the initial
682bca815d6SUlf Hansson * configurations to turn on the smartreflex module and in turn call
683bca815d6SUlf Hansson * into the registered smartreflex class enable API.
684bca815d6SUlf Hansson */
omap_sr_enable(struct voltagedomain * voltdm)685bca815d6SUlf Hansson void omap_sr_enable(struct voltagedomain *voltdm)
686bca815d6SUlf Hansson {
687bca815d6SUlf Hansson struct omap_sr *sr = _sr_lookup(voltdm);
688bca815d6SUlf Hansson
689bca815d6SUlf Hansson if (IS_ERR(sr)) {
690bca815d6SUlf Hansson pr_warn("%s: omap_sr struct for voltdm not found\n", __func__);
691bca815d6SUlf Hansson return;
692bca815d6SUlf Hansson }
693bca815d6SUlf Hansson
694bca815d6SUlf Hansson if (!sr->autocomp_active)
695bca815d6SUlf Hansson return;
696bca815d6SUlf Hansson
697bca815d6SUlf Hansson if (!sr_class || !(sr_class->enable) || !(sr_class->configure)) {
698bca815d6SUlf Hansson dev_warn(&sr->pdev->dev, "%s: smartreflex class driver not registered\n",
699bca815d6SUlf Hansson __func__);
700bca815d6SUlf Hansson return;
701bca815d6SUlf Hansson }
702bca815d6SUlf Hansson
703bca815d6SUlf Hansson sr_class->enable(sr);
704bca815d6SUlf Hansson }
705bca815d6SUlf Hansson
706bca815d6SUlf Hansson /**
707bca815d6SUlf Hansson * omap_sr_disable() - API to disable SR without resetting the voltage
708bca815d6SUlf Hansson * processor voltage
709bca815d6SUlf Hansson * @voltdm: VDD pointer to which the SR module to be configured belongs to.
710bca815d6SUlf Hansson *
711bca815d6SUlf Hansson * This API is to be called from the kernel in order to disable
712bca815d6SUlf Hansson * a particular smartreflex module. This API will in turn call
713bca815d6SUlf Hansson * into the registered smartreflex class disable API. This API will tell
714bca815d6SUlf Hansson * the smartreflex class disable not to reset the VP voltage after
715bca815d6SUlf Hansson * disabling smartreflex.
716bca815d6SUlf Hansson */
omap_sr_disable(struct voltagedomain * voltdm)717bca815d6SUlf Hansson void omap_sr_disable(struct voltagedomain *voltdm)
718bca815d6SUlf Hansson {
719bca815d6SUlf Hansson struct omap_sr *sr = _sr_lookup(voltdm);
720bca815d6SUlf Hansson
721bca815d6SUlf Hansson if (IS_ERR(sr)) {
722bca815d6SUlf Hansson pr_warn("%s: omap_sr struct for voltdm not found\n", __func__);
723bca815d6SUlf Hansson return;
724bca815d6SUlf Hansson }
725bca815d6SUlf Hansson
726bca815d6SUlf Hansson if (!sr->autocomp_active)
727bca815d6SUlf Hansson return;
728bca815d6SUlf Hansson
729bca815d6SUlf Hansson if (!sr_class || !(sr_class->disable)) {
730bca815d6SUlf Hansson dev_warn(&sr->pdev->dev, "%s: smartreflex class driver not registered\n",
731bca815d6SUlf Hansson __func__);
732bca815d6SUlf Hansson return;
733bca815d6SUlf Hansson }
734bca815d6SUlf Hansson
735bca815d6SUlf Hansson sr_class->disable(sr, 0);
736bca815d6SUlf Hansson }
737bca815d6SUlf Hansson
738bca815d6SUlf Hansson /**
739bca815d6SUlf Hansson * omap_sr_disable_reset_volt() - API to disable SR and reset the
740bca815d6SUlf Hansson * voltage processor voltage
741bca815d6SUlf Hansson * @voltdm: VDD pointer to which the SR module to be configured belongs to.
742bca815d6SUlf Hansson *
743bca815d6SUlf Hansson * This API is to be called from the kernel in order to disable
744bca815d6SUlf Hansson * a particular smartreflex module. This API will in turn call
745bca815d6SUlf Hansson * into the registered smartreflex class disable API. This API will tell
746bca815d6SUlf Hansson * the smartreflex class disable to reset the VP voltage after
747bca815d6SUlf Hansson * disabling smartreflex.
748bca815d6SUlf Hansson */
omap_sr_disable_reset_volt(struct voltagedomain * voltdm)749bca815d6SUlf Hansson void omap_sr_disable_reset_volt(struct voltagedomain *voltdm)
750bca815d6SUlf Hansson {
751bca815d6SUlf Hansson struct omap_sr *sr = _sr_lookup(voltdm);
752bca815d6SUlf Hansson
753bca815d6SUlf Hansson if (IS_ERR(sr)) {
754bca815d6SUlf Hansson pr_warn("%s: omap_sr struct for voltdm not found\n", __func__);
755bca815d6SUlf Hansson return;
756bca815d6SUlf Hansson }
757bca815d6SUlf Hansson
758bca815d6SUlf Hansson if (!sr->autocomp_active)
759bca815d6SUlf Hansson return;
760bca815d6SUlf Hansson
761bca815d6SUlf Hansson if (!sr_class || !(sr_class->disable)) {
762bca815d6SUlf Hansson dev_warn(&sr->pdev->dev, "%s: smartreflex class driver not registered\n",
763bca815d6SUlf Hansson __func__);
764bca815d6SUlf Hansson return;
765bca815d6SUlf Hansson }
766bca815d6SUlf Hansson
767bca815d6SUlf Hansson sr_class->disable(sr, 1);
768bca815d6SUlf Hansson }
769bca815d6SUlf Hansson
770bca815d6SUlf Hansson /* PM Debug FS entries to enable and disable smartreflex. */
omap_sr_autocomp_show(void * data,u64 * val)771bca815d6SUlf Hansson static int omap_sr_autocomp_show(void *data, u64 *val)
772bca815d6SUlf Hansson {
773bca815d6SUlf Hansson struct omap_sr *sr_info = data;
774bca815d6SUlf Hansson
775bca815d6SUlf Hansson if (!sr_info) {
776bca815d6SUlf Hansson pr_warn("%s: omap_sr struct not found\n", __func__);
777bca815d6SUlf Hansson return -EINVAL;
778bca815d6SUlf Hansson }
779bca815d6SUlf Hansson
780bca815d6SUlf Hansson *val = sr_info->autocomp_active;
781bca815d6SUlf Hansson
782bca815d6SUlf Hansson return 0;
783bca815d6SUlf Hansson }
784bca815d6SUlf Hansson
omap_sr_autocomp_store(void * data,u64 val)785bca815d6SUlf Hansson static int omap_sr_autocomp_store(void *data, u64 val)
786bca815d6SUlf Hansson {
787bca815d6SUlf Hansson struct omap_sr *sr_info = data;
788bca815d6SUlf Hansson
789bca815d6SUlf Hansson if (!sr_info) {
790bca815d6SUlf Hansson pr_warn("%s: omap_sr struct not found\n", __func__);
791bca815d6SUlf Hansson return -EINVAL;
792bca815d6SUlf Hansson }
793bca815d6SUlf Hansson
794bca815d6SUlf Hansson /* Sanity check */
795bca815d6SUlf Hansson if (val > 1) {
796bca815d6SUlf Hansson pr_warn("%s: Invalid argument %lld\n", __func__, val);
797bca815d6SUlf Hansson return -EINVAL;
798bca815d6SUlf Hansson }
799bca815d6SUlf Hansson
800bca815d6SUlf Hansson /* control enable/disable only if there is a delta in value */
801bca815d6SUlf Hansson if (sr_info->autocomp_active != val) {
802bca815d6SUlf Hansson if (!val)
803bca815d6SUlf Hansson sr_stop_vddautocomp(sr_info);
804bca815d6SUlf Hansson else
805bca815d6SUlf Hansson sr_start_vddautocomp(sr_info);
806bca815d6SUlf Hansson }
807bca815d6SUlf Hansson
808bca815d6SUlf Hansson return 0;
809bca815d6SUlf Hansson }
810bca815d6SUlf Hansson
811bca815d6SUlf Hansson DEFINE_SIMPLE_ATTRIBUTE(pm_sr_fops, omap_sr_autocomp_show,
812bca815d6SUlf Hansson omap_sr_autocomp_store, "%llu\n");
813bca815d6SUlf Hansson
omap_sr_probe(struct platform_device * pdev)814bca815d6SUlf Hansson static int omap_sr_probe(struct platform_device *pdev)
815bca815d6SUlf Hansson {
816bca815d6SUlf Hansson struct omap_sr *sr_info;
817bca815d6SUlf Hansson struct omap_sr_data *pdata = pdev->dev.platform_data;
818bca815d6SUlf Hansson struct dentry *nvalue_dir;
819bca815d6SUlf Hansson int i, ret = 0;
820bca815d6SUlf Hansson
821bca815d6SUlf Hansson sr_info = devm_kzalloc(&pdev->dev, sizeof(struct omap_sr), GFP_KERNEL);
822bca815d6SUlf Hansson if (!sr_info)
823bca815d6SUlf Hansson return -ENOMEM;
824bca815d6SUlf Hansson
825bca815d6SUlf Hansson sr_info->name = devm_kzalloc(&pdev->dev,
826bca815d6SUlf Hansson SMARTREFLEX_NAME_LEN, GFP_KERNEL);
827bca815d6SUlf Hansson if (!sr_info->name)
828bca815d6SUlf Hansson return -ENOMEM;
829bca815d6SUlf Hansson
830bca815d6SUlf Hansson platform_set_drvdata(pdev, sr_info);
831bca815d6SUlf Hansson
832bca815d6SUlf Hansson if (!pdata) {
833bca815d6SUlf Hansson dev_err(&pdev->dev, "%s: platform data missing\n", __func__);
834bca815d6SUlf Hansson return -EINVAL;
835bca815d6SUlf Hansson }
836bca815d6SUlf Hansson
8379f60d9d3SYang Li sr_info->base = devm_platform_ioremap_resource(pdev, 0);
838a9c7d88dSQiheng Lin if (IS_ERR(sr_info->base))
839bca815d6SUlf Hansson return PTR_ERR(sr_info->base);
840bca815d6SUlf Hansson
841001d7c83SLad Prabhakar ret = platform_get_irq_optional(pdev, 0);
842001d7c83SLad Prabhakar if (ret < 0 && ret != -ENXIO)
843001d7c83SLad Prabhakar return dev_err_probe(&pdev->dev, ret, "failed to get IRQ resource\n");
844001d7c83SLad Prabhakar if (ret > 0)
845001d7c83SLad Prabhakar sr_info->irq = ret;
846bca815d6SUlf Hansson
847ed4520d6STony Lindgren sr_info->fck = devm_clk_get(pdev->dev.parent, "fck");
848ed4520d6STony Lindgren if (IS_ERR(sr_info->fck))
849ed4520d6STony Lindgren return PTR_ERR(sr_info->fck);
850ed4520d6STony Lindgren clk_prepare(sr_info->fck);
851ed4520d6STony Lindgren
852bca815d6SUlf Hansson pm_runtime_enable(&pdev->dev);
853bca815d6SUlf Hansson
854bca815d6SUlf Hansson snprintf(sr_info->name, SMARTREFLEX_NAME_LEN, "%s", pdata->name);
855bca815d6SUlf Hansson
856bca815d6SUlf Hansson sr_info->pdev = pdev;
857bca815d6SUlf Hansson sr_info->srid = pdev->id;
858bca815d6SUlf Hansson sr_info->voltdm = pdata->voltdm;
859bca815d6SUlf Hansson sr_info->nvalue_table = pdata->nvalue_table;
860bca815d6SUlf Hansson sr_info->nvalue_count = pdata->nvalue_count;
861bca815d6SUlf Hansson sr_info->senn_mod = pdata->senn_mod;
862bca815d6SUlf Hansson sr_info->senp_mod = pdata->senp_mod;
863bca815d6SUlf Hansson sr_info->err_weight = pdata->err_weight;
864bca815d6SUlf Hansson sr_info->err_maxlimit = pdata->err_maxlimit;
865bca815d6SUlf Hansson sr_info->accum_data = pdata->accum_data;
866bca815d6SUlf Hansson sr_info->senn_avgweight = pdata->senn_avgweight;
867bca815d6SUlf Hansson sr_info->senp_avgweight = pdata->senp_avgweight;
868bca815d6SUlf Hansson sr_info->autocomp_active = false;
869bca815d6SUlf Hansson sr_info->ip_type = pdata->ip_type;
870bca815d6SUlf Hansson
871bca815d6SUlf Hansson sr_set_clk_length(sr_info);
872bca815d6SUlf Hansson
873bca815d6SUlf Hansson list_add(&sr_info->node, &sr_list);
874bca815d6SUlf Hansson
875bca815d6SUlf Hansson /*
876bca815d6SUlf Hansson * Call into late init to do initializations that require
877bca815d6SUlf Hansson * both sr driver and sr class driver to be initiallized.
878bca815d6SUlf Hansson */
879bca815d6SUlf Hansson if (sr_class) {
880bca815d6SUlf Hansson ret = sr_late_init(sr_info);
881bca815d6SUlf Hansson if (ret) {
882bca815d6SUlf Hansson pr_warn("%s: Error in SR late init\n", __func__);
883bca815d6SUlf Hansson goto err_list_del;
884bca815d6SUlf Hansson }
885bca815d6SUlf Hansson }
886bca815d6SUlf Hansson
887bca815d6SUlf Hansson dev_info(&pdev->dev, "%s: SmartReflex driver initialized\n", __func__);
888bca815d6SUlf Hansson if (!sr_dbg_dir)
889bca815d6SUlf Hansson sr_dbg_dir = debugfs_create_dir("smartreflex", NULL);
890bca815d6SUlf Hansson
891bca815d6SUlf Hansson sr_info->dbg_dir = debugfs_create_dir(sr_info->name, sr_dbg_dir);
892bca815d6SUlf Hansson
893bca815d6SUlf Hansson debugfs_create_file("autocomp", S_IRUGO | S_IWUSR, sr_info->dbg_dir,
894bca815d6SUlf Hansson sr_info, &pm_sr_fops);
895bca815d6SUlf Hansson debugfs_create_x32("errweight", S_IRUGO, sr_info->dbg_dir,
896bca815d6SUlf Hansson &sr_info->err_weight);
897bca815d6SUlf Hansson debugfs_create_x32("errmaxlimit", S_IRUGO, sr_info->dbg_dir,
898bca815d6SUlf Hansson &sr_info->err_maxlimit);
899bca815d6SUlf Hansson
900bca815d6SUlf Hansson nvalue_dir = debugfs_create_dir("nvalue", sr_info->dbg_dir);
901bca815d6SUlf Hansson
902bca815d6SUlf Hansson if (sr_info->nvalue_count == 0 || !sr_info->nvalue_table) {
903bca815d6SUlf Hansson dev_warn(&pdev->dev, "%s: %s: No Voltage table for the corresponding vdd. Cannot create debugfs entries for n-values\n",
904bca815d6SUlf Hansson __func__, sr_info->name);
905bca815d6SUlf Hansson
906bca815d6SUlf Hansson ret = -ENODATA;
907bca815d6SUlf Hansson goto err_debugfs;
908bca815d6SUlf Hansson }
909bca815d6SUlf Hansson
910bca815d6SUlf Hansson for (i = 0; i < sr_info->nvalue_count; i++) {
911bca815d6SUlf Hansson char name[NVALUE_NAME_LEN + 1];
912bca815d6SUlf Hansson
913bca815d6SUlf Hansson snprintf(name, sizeof(name), "volt_%lu",
914bca815d6SUlf Hansson sr_info->nvalue_table[i].volt_nominal);
915bca815d6SUlf Hansson debugfs_create_x32(name, S_IRUGO | S_IWUSR, nvalue_dir,
916bca815d6SUlf Hansson &(sr_info->nvalue_table[i].nvalue));
917bca815d6SUlf Hansson snprintf(name, sizeof(name), "errminlimit_%lu",
918bca815d6SUlf Hansson sr_info->nvalue_table[i].volt_nominal);
919bca815d6SUlf Hansson debugfs_create_x32(name, S_IRUGO | S_IWUSR, nvalue_dir,
920bca815d6SUlf Hansson &(sr_info->nvalue_table[i].errminlimit));
921bca815d6SUlf Hansson
922bca815d6SUlf Hansson }
923bca815d6SUlf Hansson
924001d7c83SLad Prabhakar return 0;
925bca815d6SUlf Hansson
926bca815d6SUlf Hansson err_debugfs:
927bca815d6SUlf Hansson debugfs_remove_recursive(sr_info->dbg_dir);
928bca815d6SUlf Hansson err_list_del:
92969460e68SZhang Qilong pm_runtime_disable(&pdev->dev);
930bca815d6SUlf Hansson list_del(&sr_info->node);
931ed4520d6STony Lindgren clk_unprepare(sr_info->fck);
932bca815d6SUlf Hansson
933bca815d6SUlf Hansson return ret;
934bca815d6SUlf Hansson }
935bca815d6SUlf Hansson
omap_sr_remove(struct platform_device * pdev)936bca815d6SUlf Hansson static int omap_sr_remove(struct platform_device *pdev)
937bca815d6SUlf Hansson {
938ed4520d6STony Lindgren struct device *dev = &pdev->dev;
93904523aceSUwe Kleine-König struct omap_sr *sr_info = platform_get_drvdata(pdev);
940bca815d6SUlf Hansson
941bca815d6SUlf Hansson if (sr_info->autocomp_active)
942bca815d6SUlf Hansson sr_stop_vddautocomp(sr_info);
943bca815d6SUlf Hansson debugfs_remove_recursive(sr_info->dbg_dir);
944bca815d6SUlf Hansson
945ed4520d6STony Lindgren pm_runtime_disable(dev);
946ed4520d6STony Lindgren clk_unprepare(sr_info->fck);
947bca815d6SUlf Hansson list_del(&sr_info->node);
948bca815d6SUlf Hansson return 0;
949bca815d6SUlf Hansson }
950bca815d6SUlf Hansson
omap_sr_shutdown(struct platform_device * pdev)951bca815d6SUlf Hansson static void omap_sr_shutdown(struct platform_device *pdev)
952bca815d6SUlf Hansson {
95304523aceSUwe Kleine-König struct omap_sr *sr_info = platform_get_drvdata(pdev);
954bca815d6SUlf Hansson
955bca815d6SUlf Hansson if (sr_info->autocomp_active)
956bca815d6SUlf Hansson sr_stop_vddautocomp(sr_info);
957bca815d6SUlf Hansson
958bca815d6SUlf Hansson return;
959bca815d6SUlf Hansson }
960bca815d6SUlf Hansson
961bca815d6SUlf Hansson static const struct of_device_id omap_sr_match[] = {
962bca815d6SUlf Hansson { .compatible = "ti,omap3-smartreflex-core", },
963bca815d6SUlf Hansson { .compatible = "ti,omap3-smartreflex-mpu-iva", },
964bca815d6SUlf Hansson { .compatible = "ti,omap4-smartreflex-core", },
965bca815d6SUlf Hansson { .compatible = "ti,omap4-smartreflex-mpu", },
966bca815d6SUlf Hansson { .compatible = "ti,omap4-smartreflex-iva", },
967bca815d6SUlf Hansson { },
968bca815d6SUlf Hansson };
969bca815d6SUlf Hansson MODULE_DEVICE_TABLE(of, omap_sr_match);
970bca815d6SUlf Hansson
971bca815d6SUlf Hansson static struct platform_driver smartreflex_driver = {
972bca815d6SUlf Hansson .probe = omap_sr_probe,
973bca815d6SUlf Hansson .remove = omap_sr_remove,
974bca815d6SUlf Hansson .shutdown = omap_sr_shutdown,
975bca815d6SUlf Hansson .driver = {
976bca815d6SUlf Hansson .name = DRIVER_NAME,
977bca815d6SUlf Hansson .of_match_table = omap_sr_match,
978bca815d6SUlf Hansson },
979bca815d6SUlf Hansson };
980bca815d6SUlf Hansson
sr_init(void)981bca815d6SUlf Hansson static int __init sr_init(void)
982bca815d6SUlf Hansson {
983bca815d6SUlf Hansson int ret = 0;
984bca815d6SUlf Hansson
985bca815d6SUlf Hansson ret = platform_driver_register(&smartreflex_driver);
986bca815d6SUlf Hansson if (ret) {
987bca815d6SUlf Hansson pr_err("%s: platform driver register failed for SR\n",
988bca815d6SUlf Hansson __func__);
989bca815d6SUlf Hansson return ret;
990bca815d6SUlf Hansson }
991bca815d6SUlf Hansson
992bca815d6SUlf Hansson return 0;
993bca815d6SUlf Hansson }
994bca815d6SUlf Hansson late_initcall(sr_init);
995bca815d6SUlf Hansson
sr_exit(void)996bca815d6SUlf Hansson static void __exit sr_exit(void)
997bca815d6SUlf Hansson {
998bca815d6SUlf Hansson platform_driver_unregister(&smartreflex_driver);
999bca815d6SUlf Hansson }
1000bca815d6SUlf Hansson module_exit(sr_exit);
1001bca815d6SUlf Hansson
1002bca815d6SUlf Hansson MODULE_DESCRIPTION("OMAP Smartreflex Driver");
1003bca815d6SUlf Hansson MODULE_LICENSE("GPL");
1004bca815d6SUlf Hansson MODULE_ALIAS("platform:" DRIVER_NAME);
1005bca815d6SUlf Hansson MODULE_AUTHOR("Texas Instruments Inc");
1006