xref: /openbmc/linux/drivers/soc/ti/smartreflex.c (revision ecc23d0a422a3118fcf6e4f0a46e17a6c2047b02)
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