xref: /openbmc/linux/drivers/counter/intel-qep.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1b711f687SJarkko Nikula // SPDX-License-Identifier: GPL-2.0
2b711f687SJarkko Nikula /*
3b711f687SJarkko Nikula  * Intel Quadrature Encoder Peripheral driver
4b711f687SJarkko Nikula  *
5b711f687SJarkko Nikula  * Copyright (C) 2019-2021 Intel Corporation
6b711f687SJarkko Nikula  *
7b711f687SJarkko Nikula  * Author: Felipe Balbi (Intel)
8b711f687SJarkko Nikula  * Author: Jarkko Nikula <jarkko.nikula@linux.intel.com>
9b711f687SJarkko Nikula  * Author: Raymond Tan <raymond.tan@intel.com>
10b711f687SJarkko Nikula  */
11b711f687SJarkko Nikula #include <linux/counter.h>
12b711f687SJarkko Nikula #include <linux/kernel.h>
13b711f687SJarkko Nikula #include <linux/module.h>
14b711f687SJarkko Nikula #include <linux/mutex.h>
15b711f687SJarkko Nikula #include <linux/pci.h>
16b711f687SJarkko Nikula #include <linux/pm_runtime.h>
17b711f687SJarkko Nikula 
18b711f687SJarkko Nikula #define INTEL_QEPCON			0x00
19b711f687SJarkko Nikula #define INTEL_QEPFLT			0x04
20b711f687SJarkko Nikula #define INTEL_QEPCOUNT			0x08
21b711f687SJarkko Nikula #define INTEL_QEPMAX			0x0c
22b711f687SJarkko Nikula #define INTEL_QEPWDT			0x10
23b711f687SJarkko Nikula #define INTEL_QEPCAPDIV			0x14
24b711f687SJarkko Nikula #define INTEL_QEPCNTR			0x18
25b711f687SJarkko Nikula #define INTEL_QEPCAPBUF			0x1c
26b711f687SJarkko Nikula #define INTEL_QEPINT_STAT		0x20
27b711f687SJarkko Nikula #define INTEL_QEPINT_MASK		0x24
28b711f687SJarkko Nikula 
29b711f687SJarkko Nikula /* QEPCON */
30b711f687SJarkko Nikula #define INTEL_QEPCON_EN			BIT(0)
31b711f687SJarkko Nikula #define INTEL_QEPCON_FLT_EN		BIT(1)
32b711f687SJarkko Nikula #define INTEL_QEPCON_EDGE_A		BIT(2)
33b711f687SJarkko Nikula #define INTEL_QEPCON_EDGE_B		BIT(3)
34b711f687SJarkko Nikula #define INTEL_QEPCON_EDGE_INDX		BIT(4)
35b711f687SJarkko Nikula #define INTEL_QEPCON_SWPAB		BIT(5)
36b711f687SJarkko Nikula #define INTEL_QEPCON_OP_MODE		BIT(6)
37b711f687SJarkko Nikula #define INTEL_QEPCON_PH_ERR		BIT(7)
38b711f687SJarkko Nikula #define INTEL_QEPCON_COUNT_RST_MODE	BIT(8)
39b711f687SJarkko Nikula #define INTEL_QEPCON_INDX_GATING_MASK	GENMASK(10, 9)
40b711f687SJarkko Nikula #define INTEL_QEPCON_INDX_GATING(n)	(((n) & 3) << 9)
41b711f687SJarkko Nikula #define INTEL_QEPCON_INDX_PAL_PBL	INTEL_QEPCON_INDX_GATING(0)
42b711f687SJarkko Nikula #define INTEL_QEPCON_INDX_PAL_PBH	INTEL_QEPCON_INDX_GATING(1)
43b711f687SJarkko Nikula #define INTEL_QEPCON_INDX_PAH_PBL	INTEL_QEPCON_INDX_GATING(2)
44b711f687SJarkko Nikula #define INTEL_QEPCON_INDX_PAH_PBH	INTEL_QEPCON_INDX_GATING(3)
45b711f687SJarkko Nikula #define INTEL_QEPCON_CAP_MODE		BIT(11)
46b711f687SJarkko Nikula #define INTEL_QEPCON_FIFO_THRE_MASK	GENMASK(14, 12)
47b711f687SJarkko Nikula #define INTEL_QEPCON_FIFO_THRE(n)	((((n) - 1) & 7) << 12)
48b711f687SJarkko Nikula #define INTEL_QEPCON_FIFO_EMPTY		BIT(15)
49b711f687SJarkko Nikula 
50b711f687SJarkko Nikula /* QEPFLT */
51b711f687SJarkko Nikula #define INTEL_QEPFLT_MAX_COUNT(n)	((n) & 0x1fffff)
52b711f687SJarkko Nikula 
53b711f687SJarkko Nikula /* QEPINT */
54b711f687SJarkko Nikula #define INTEL_QEPINT_FIFOCRIT		BIT(5)
55b711f687SJarkko Nikula #define INTEL_QEPINT_FIFOENTRY		BIT(4)
56b711f687SJarkko Nikula #define INTEL_QEPINT_QEPDIR		BIT(3)
57b711f687SJarkko Nikula #define INTEL_QEPINT_QEPRST_UP		BIT(2)
58b711f687SJarkko Nikula #define INTEL_QEPINT_QEPRST_DOWN	BIT(1)
59b711f687SJarkko Nikula #define INTEL_QEPINT_WDT		BIT(0)
60b711f687SJarkko Nikula 
61b711f687SJarkko Nikula #define INTEL_QEPINT_MASK_ALL		GENMASK(5, 0)
62b711f687SJarkko Nikula 
63b711f687SJarkko Nikula #define INTEL_QEP_CLK_PERIOD_NS		10
64b711f687SJarkko Nikula 
65b711f687SJarkko Nikula struct intel_qep {
66b711f687SJarkko Nikula 	struct mutex lock;
67b711f687SJarkko Nikula 	struct device *dev;
68b711f687SJarkko Nikula 	void __iomem *regs;
69b711f687SJarkko Nikula 	bool enabled;
70b711f687SJarkko Nikula 	/* Context save registers */
71b711f687SJarkko Nikula 	u32 qepcon;
72b711f687SJarkko Nikula 	u32 qepflt;
73b711f687SJarkko Nikula 	u32 qepmax;
74b711f687SJarkko Nikula };
75b711f687SJarkko Nikula 
intel_qep_readl(struct intel_qep * qep,u32 offset)76b711f687SJarkko Nikula static inline u32 intel_qep_readl(struct intel_qep *qep, u32 offset)
77b711f687SJarkko Nikula {
78b711f687SJarkko Nikula 	return readl(qep->regs + offset);
79b711f687SJarkko Nikula }
80b711f687SJarkko Nikula 
intel_qep_writel(struct intel_qep * qep,u32 offset,u32 value)81b711f687SJarkko Nikula static inline void intel_qep_writel(struct intel_qep *qep,
82b711f687SJarkko Nikula 				    u32 offset, u32 value)
83b711f687SJarkko Nikula {
84b711f687SJarkko Nikula 	writel(value, qep->regs + offset);
85b711f687SJarkko Nikula }
86b711f687SJarkko Nikula 
intel_qep_init(struct intel_qep * qep)87b711f687SJarkko Nikula static void intel_qep_init(struct intel_qep *qep)
88b711f687SJarkko Nikula {
89b711f687SJarkko Nikula 	u32 reg;
90b711f687SJarkko Nikula 
91b711f687SJarkko Nikula 	reg = intel_qep_readl(qep, INTEL_QEPCON);
92b711f687SJarkko Nikula 	reg &= ~INTEL_QEPCON_EN;
93b711f687SJarkko Nikula 	intel_qep_writel(qep, INTEL_QEPCON, reg);
94b711f687SJarkko Nikula 	qep->enabled = false;
95b711f687SJarkko Nikula 	/*
96b711f687SJarkko Nikula 	 * Make sure peripheral is disabled by flushing the write with
97b711f687SJarkko Nikula 	 * a dummy read
98b711f687SJarkko Nikula 	 */
99b711f687SJarkko Nikula 	reg = intel_qep_readl(qep, INTEL_QEPCON);
100b711f687SJarkko Nikula 
101b711f687SJarkko Nikula 	reg &= ~(INTEL_QEPCON_OP_MODE | INTEL_QEPCON_FLT_EN);
102b711f687SJarkko Nikula 	reg |= INTEL_QEPCON_EDGE_A | INTEL_QEPCON_EDGE_B |
103b711f687SJarkko Nikula 	       INTEL_QEPCON_EDGE_INDX | INTEL_QEPCON_COUNT_RST_MODE;
104b711f687SJarkko Nikula 	intel_qep_writel(qep, INTEL_QEPCON, reg);
105b711f687SJarkko Nikula 	intel_qep_writel(qep, INTEL_QEPINT_MASK, INTEL_QEPINT_MASK_ALL);
106b711f687SJarkko Nikula }
107b711f687SJarkko Nikula 
intel_qep_count_read(struct counter_device * counter,struct counter_count * count,u64 * val)108b711f687SJarkko Nikula static int intel_qep_count_read(struct counter_device *counter,
109aaec1a0fSWilliam Breathitt Gray 				struct counter_count *count, u64 *val)
110b711f687SJarkko Nikula {
11153ada095SUwe Kleine-König 	struct intel_qep *const qep = counter_priv(counter);
112b711f687SJarkko Nikula 
113b711f687SJarkko Nikula 	pm_runtime_get_sync(qep->dev);
114b711f687SJarkko Nikula 	*val = intel_qep_readl(qep, INTEL_QEPCOUNT);
115b711f687SJarkko Nikula 	pm_runtime_put(qep->dev);
116b711f687SJarkko Nikula 
117b711f687SJarkko Nikula 	return 0;
118b711f687SJarkko Nikula }
119b711f687SJarkko Nikula 
120394a0150SWilliam Breathitt Gray static const enum counter_function intel_qep_count_functions[] = {
121394a0150SWilliam Breathitt Gray 	COUNTER_FUNCTION_QUADRATURE_X4,
122b711f687SJarkko Nikula };
123b711f687SJarkko Nikula 
intel_qep_function_read(struct counter_device * counter,struct counter_count * count,enum counter_function * function)124aaec1a0fSWilliam Breathitt Gray static int intel_qep_function_read(struct counter_device *counter,
125b711f687SJarkko Nikula 				   struct counter_count *count,
126aaec1a0fSWilliam Breathitt Gray 				   enum counter_function *function)
127b711f687SJarkko Nikula {
128aaec1a0fSWilliam Breathitt Gray 	*function = COUNTER_FUNCTION_QUADRATURE_X4;
129b711f687SJarkko Nikula 
130b711f687SJarkko Nikula 	return 0;
131b711f687SJarkko Nikula }
132b711f687SJarkko Nikula 
133b711f687SJarkko Nikula static const enum counter_synapse_action intel_qep_synapse_actions[] = {
134b711f687SJarkko Nikula 	COUNTER_SYNAPSE_ACTION_BOTH_EDGES,
135b711f687SJarkko Nikula };
136b711f687SJarkko Nikula 
intel_qep_action_read(struct counter_device * counter,struct counter_count * count,struct counter_synapse * synapse,enum counter_synapse_action * action)137aaec1a0fSWilliam Breathitt Gray static int intel_qep_action_read(struct counter_device *counter,
138b711f687SJarkko Nikula 				 struct counter_count *count,
139b711f687SJarkko Nikula 				 struct counter_synapse *synapse,
140aaec1a0fSWilliam Breathitt Gray 				 enum counter_synapse_action *action)
141b711f687SJarkko Nikula {
142aaec1a0fSWilliam Breathitt Gray 	*action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES;
143b711f687SJarkko Nikula 	return 0;
144b711f687SJarkko Nikula }
145b711f687SJarkko Nikula 
146b711f687SJarkko Nikula static const struct counter_ops intel_qep_counter_ops = {
147b711f687SJarkko Nikula 	.count_read = intel_qep_count_read,
148aaec1a0fSWilliam Breathitt Gray 	.function_read = intel_qep_function_read,
149aaec1a0fSWilliam Breathitt Gray 	.action_read = intel_qep_action_read,
150b711f687SJarkko Nikula };
151b711f687SJarkko Nikula 
152b711f687SJarkko Nikula #define INTEL_QEP_SIGNAL(_id, _name) {				\
153b711f687SJarkko Nikula 	.id = (_id),						\
154b711f687SJarkko Nikula 	.name = (_name),					\
155b711f687SJarkko Nikula }
156b711f687SJarkko Nikula 
157b711f687SJarkko Nikula static struct counter_signal intel_qep_signals[] = {
158b711f687SJarkko Nikula 	INTEL_QEP_SIGNAL(0, "Phase A"),
159b711f687SJarkko Nikula 	INTEL_QEP_SIGNAL(1, "Phase B"),
160b711f687SJarkko Nikula 	INTEL_QEP_SIGNAL(2, "Index"),
161b711f687SJarkko Nikula };
162b711f687SJarkko Nikula 
163b711f687SJarkko Nikula #define INTEL_QEP_SYNAPSE(_signal_id) {				\
164b711f687SJarkko Nikula 	.actions_list = intel_qep_synapse_actions,		\
165b711f687SJarkko Nikula 	.num_actions = ARRAY_SIZE(intel_qep_synapse_actions),	\
166b711f687SJarkko Nikula 	.signal = &intel_qep_signals[(_signal_id)],		\
167b711f687SJarkko Nikula }
168b711f687SJarkko Nikula 
169b711f687SJarkko Nikula static struct counter_synapse intel_qep_count_synapses[] = {
170b711f687SJarkko Nikula 	INTEL_QEP_SYNAPSE(0),
171b711f687SJarkko Nikula 	INTEL_QEP_SYNAPSE(1),
172b711f687SJarkko Nikula 	INTEL_QEP_SYNAPSE(2),
173b711f687SJarkko Nikula };
174b711f687SJarkko Nikula 
intel_qep_ceiling_read(struct counter_device * counter,struct counter_count * count,u64 * ceiling)175aaec1a0fSWilliam Breathitt Gray static int intel_qep_ceiling_read(struct counter_device *counter,
176aaec1a0fSWilliam Breathitt Gray 				  struct counter_count *count, u64 *ceiling)
177b711f687SJarkko Nikula {
17853ada095SUwe Kleine-König 	struct intel_qep *qep = counter_priv(counter);
179b711f687SJarkko Nikula 
180b711f687SJarkko Nikula 	pm_runtime_get_sync(qep->dev);
181aaec1a0fSWilliam Breathitt Gray 	*ceiling = intel_qep_readl(qep, INTEL_QEPMAX);
182b711f687SJarkko Nikula 	pm_runtime_put(qep->dev);
183b711f687SJarkko Nikula 
184aaec1a0fSWilliam Breathitt Gray 	return 0;
185b711f687SJarkko Nikula }
186b711f687SJarkko Nikula 
intel_qep_ceiling_write(struct counter_device * counter,struct counter_count * count,u64 max)187aaec1a0fSWilliam Breathitt Gray static int intel_qep_ceiling_write(struct counter_device *counter,
188aaec1a0fSWilliam Breathitt Gray 				   struct counter_count *count, u64 max)
189b711f687SJarkko Nikula {
19053ada095SUwe Kleine-König 	struct intel_qep *qep = counter_priv(counter);
191aaec1a0fSWilliam Breathitt Gray 	int ret = 0;
192b711f687SJarkko Nikula 
193aaec1a0fSWilliam Breathitt Gray 	/* Intel QEP ceiling configuration only supports 32-bit values */
194aaec1a0fSWilliam Breathitt Gray 	if (max != (u32)max)
195aaec1a0fSWilliam Breathitt Gray 		return -ERANGE;
196b711f687SJarkko Nikula 
197b711f687SJarkko Nikula 	mutex_lock(&qep->lock);
198b711f687SJarkko Nikula 	if (qep->enabled) {
199b711f687SJarkko Nikula 		ret = -EBUSY;
200b711f687SJarkko Nikula 		goto out;
201b711f687SJarkko Nikula 	}
202b711f687SJarkko Nikula 
203b711f687SJarkko Nikula 	pm_runtime_get_sync(qep->dev);
204b711f687SJarkko Nikula 	intel_qep_writel(qep, INTEL_QEPMAX, max);
205b711f687SJarkko Nikula 	pm_runtime_put(qep->dev);
206b711f687SJarkko Nikula 
207b711f687SJarkko Nikula out:
208b711f687SJarkko Nikula 	mutex_unlock(&qep->lock);
209b711f687SJarkko Nikula 	return ret;
210b711f687SJarkko Nikula }
211b711f687SJarkko Nikula 
intel_qep_enable_read(struct counter_device * counter,struct counter_count * count,u8 * enable)212aaec1a0fSWilliam Breathitt Gray static int intel_qep_enable_read(struct counter_device *counter,
213aaec1a0fSWilliam Breathitt Gray 				 struct counter_count *count, u8 *enable)
214b711f687SJarkko Nikula {
21553ada095SUwe Kleine-König 	struct intel_qep *qep = counter_priv(counter);
216b711f687SJarkko Nikula 
217aaec1a0fSWilliam Breathitt Gray 	*enable = qep->enabled;
218aaec1a0fSWilliam Breathitt Gray 
219aaec1a0fSWilliam Breathitt Gray 	return 0;
220b711f687SJarkko Nikula }
221b711f687SJarkko Nikula 
intel_qep_enable_write(struct counter_device * counter,struct counter_count * count,u8 val)222aaec1a0fSWilliam Breathitt Gray static int intel_qep_enable_write(struct counter_device *counter,
223aaec1a0fSWilliam Breathitt Gray 				  struct counter_count *count, u8 val)
224b711f687SJarkko Nikula {
22553ada095SUwe Kleine-König 	struct intel_qep *qep = counter_priv(counter);
226b711f687SJarkko Nikula 	u32 reg;
227aaec1a0fSWilliam Breathitt Gray 	bool changed;
228b711f687SJarkko Nikula 
229b711f687SJarkko Nikula 	mutex_lock(&qep->lock);
230b711f687SJarkko Nikula 	changed = val ^ qep->enabled;
231b711f687SJarkko Nikula 	if (!changed)
232b711f687SJarkko Nikula 		goto out;
233b711f687SJarkko Nikula 
234b711f687SJarkko Nikula 	pm_runtime_get_sync(qep->dev);
235b711f687SJarkko Nikula 	reg = intel_qep_readl(qep, INTEL_QEPCON);
236b711f687SJarkko Nikula 	if (val) {
237b711f687SJarkko Nikula 		/* Enable peripheral and keep runtime PM always on */
238b711f687SJarkko Nikula 		reg |= INTEL_QEPCON_EN;
239b711f687SJarkko Nikula 		pm_runtime_get_noresume(qep->dev);
240b711f687SJarkko Nikula 	} else {
241b711f687SJarkko Nikula 		/* Let runtime PM be idle and disable peripheral */
242b711f687SJarkko Nikula 		pm_runtime_put_noidle(qep->dev);
243b711f687SJarkko Nikula 		reg &= ~INTEL_QEPCON_EN;
244b711f687SJarkko Nikula 	}
245b711f687SJarkko Nikula 	intel_qep_writel(qep, INTEL_QEPCON, reg);
246b711f687SJarkko Nikula 	pm_runtime_put(qep->dev);
247b711f687SJarkko Nikula 	qep->enabled = val;
248b711f687SJarkko Nikula 
249b711f687SJarkko Nikula out:
250b711f687SJarkko Nikula 	mutex_unlock(&qep->lock);
251aaec1a0fSWilliam Breathitt Gray 	return 0;
252b711f687SJarkko Nikula }
253b711f687SJarkko Nikula 
intel_qep_spike_filter_ns_read(struct counter_device * counter,struct counter_count * count,u64 * length)254aaec1a0fSWilliam Breathitt Gray static int intel_qep_spike_filter_ns_read(struct counter_device *counter,
255b711f687SJarkko Nikula 					  struct counter_count *count,
256aaec1a0fSWilliam Breathitt Gray 					  u64 *length)
257b711f687SJarkko Nikula {
25853ada095SUwe Kleine-König 	struct intel_qep *qep = counter_priv(counter);
259b711f687SJarkko Nikula 	u32 reg;
260b711f687SJarkko Nikula 
261b711f687SJarkko Nikula 	pm_runtime_get_sync(qep->dev);
262b711f687SJarkko Nikula 	reg = intel_qep_readl(qep, INTEL_QEPCON);
263b711f687SJarkko Nikula 	if (!(reg & INTEL_QEPCON_FLT_EN)) {
264b711f687SJarkko Nikula 		pm_runtime_put(qep->dev);
265aaec1a0fSWilliam Breathitt Gray 		return 0;
266b711f687SJarkko Nikula 	}
267b711f687SJarkko Nikula 	reg = INTEL_QEPFLT_MAX_COUNT(intel_qep_readl(qep, INTEL_QEPFLT));
268b711f687SJarkko Nikula 	pm_runtime_put(qep->dev);
269b711f687SJarkko Nikula 
270aaec1a0fSWilliam Breathitt Gray 	*length = (reg + 2) * INTEL_QEP_CLK_PERIOD_NS;
271aaec1a0fSWilliam Breathitt Gray 
272aaec1a0fSWilliam Breathitt Gray 	return 0;
273b711f687SJarkko Nikula }
274b711f687SJarkko Nikula 
intel_qep_spike_filter_ns_write(struct counter_device * counter,struct counter_count * count,u64 length)275aaec1a0fSWilliam Breathitt Gray static int intel_qep_spike_filter_ns_write(struct counter_device *counter,
276b711f687SJarkko Nikula 					   struct counter_count *count,
277aaec1a0fSWilliam Breathitt Gray 					   u64 length)
278b711f687SJarkko Nikula {
27953ada095SUwe Kleine-König 	struct intel_qep *qep = counter_priv(counter);
280aaec1a0fSWilliam Breathitt Gray 	u32 reg;
281b711f687SJarkko Nikula 	bool enable;
282aaec1a0fSWilliam Breathitt Gray 	int ret = 0;
283b711f687SJarkko Nikula 
284b711f687SJarkko Nikula 	/*
285b711f687SJarkko Nikula 	 * Spike filter length is (MAX_COUNT + 2) clock periods.
286b711f687SJarkko Nikula 	 * Disable filter when userspace writes 0, enable for valid
287b711f687SJarkko Nikula 	 * nanoseconds values and error out otherwise.
288b711f687SJarkko Nikula 	 */
289aaec1a0fSWilliam Breathitt Gray 	do_div(length, INTEL_QEP_CLK_PERIOD_NS);
290b711f687SJarkko Nikula 	if (length == 0) {
291b711f687SJarkko Nikula 		enable = false;
292b711f687SJarkko Nikula 		length = 0;
293b711f687SJarkko Nikula 	} else if (length >= 2) {
294b711f687SJarkko Nikula 		enable = true;
295b711f687SJarkko Nikula 		length -= 2;
296b711f687SJarkko Nikula 	} else {
297b711f687SJarkko Nikula 		return -EINVAL;
298b711f687SJarkko Nikula 	}
299b711f687SJarkko Nikula 
300b711f687SJarkko Nikula 	if (length > INTEL_QEPFLT_MAX_COUNT(length))
301e2ff3198SWilliam Breathitt Gray 		return -ERANGE;
302b711f687SJarkko Nikula 
303b711f687SJarkko Nikula 	mutex_lock(&qep->lock);
304b711f687SJarkko Nikula 	if (qep->enabled) {
305b711f687SJarkko Nikula 		ret = -EBUSY;
306b711f687SJarkko Nikula 		goto out;
307b711f687SJarkko Nikula 	}
308b711f687SJarkko Nikula 
309b711f687SJarkko Nikula 	pm_runtime_get_sync(qep->dev);
310b711f687SJarkko Nikula 	reg = intel_qep_readl(qep, INTEL_QEPCON);
311b711f687SJarkko Nikula 	if (enable)
312b711f687SJarkko Nikula 		reg |= INTEL_QEPCON_FLT_EN;
313b711f687SJarkko Nikula 	else
314b711f687SJarkko Nikula 		reg &= ~INTEL_QEPCON_FLT_EN;
315b711f687SJarkko Nikula 	intel_qep_writel(qep, INTEL_QEPFLT, length);
316b711f687SJarkko Nikula 	intel_qep_writel(qep, INTEL_QEPCON, reg);
317b711f687SJarkko Nikula 	pm_runtime_put(qep->dev);
318b711f687SJarkko Nikula 
319b711f687SJarkko Nikula out:
320b711f687SJarkko Nikula 	mutex_unlock(&qep->lock);
321b711f687SJarkko Nikula 	return ret;
322b711f687SJarkko Nikula }
323b711f687SJarkko Nikula 
intel_qep_preset_enable_read(struct counter_device * counter,struct counter_count * count,u8 * preset_enable)324aaec1a0fSWilliam Breathitt Gray static int intel_qep_preset_enable_read(struct counter_device *counter,
325b711f687SJarkko Nikula 					struct counter_count *count,
326aaec1a0fSWilliam Breathitt Gray 					u8 *preset_enable)
327b711f687SJarkko Nikula {
32853ada095SUwe Kleine-König 	struct intel_qep *qep = counter_priv(counter);
329b711f687SJarkko Nikula 	u32 reg;
330b711f687SJarkko Nikula 
331b711f687SJarkko Nikula 	pm_runtime_get_sync(qep->dev);
332b711f687SJarkko Nikula 	reg = intel_qep_readl(qep, INTEL_QEPCON);
333b711f687SJarkko Nikula 	pm_runtime_put(qep->dev);
334aaec1a0fSWilliam Breathitt Gray 
335aaec1a0fSWilliam Breathitt Gray 	*preset_enable = !(reg & INTEL_QEPCON_COUNT_RST_MODE);
336aaec1a0fSWilliam Breathitt Gray 
337aaec1a0fSWilliam Breathitt Gray 	return 0;
338b711f687SJarkko Nikula }
339b711f687SJarkko Nikula 
intel_qep_preset_enable_write(struct counter_device * counter,struct counter_count * count,u8 val)340aaec1a0fSWilliam Breathitt Gray static int intel_qep_preset_enable_write(struct counter_device *counter,
341aaec1a0fSWilliam Breathitt Gray 					 struct counter_count *count, u8 val)
342b711f687SJarkko Nikula {
34353ada095SUwe Kleine-König 	struct intel_qep *qep = counter_priv(counter);
344b711f687SJarkko Nikula 	u32 reg;
345aaec1a0fSWilliam Breathitt Gray 	int ret = 0;
346b711f687SJarkko Nikula 
347b711f687SJarkko Nikula 	mutex_lock(&qep->lock);
348b711f687SJarkko Nikula 	if (qep->enabled) {
349b711f687SJarkko Nikula 		ret = -EBUSY;
350b711f687SJarkko Nikula 		goto out;
351b711f687SJarkko Nikula 	}
352b711f687SJarkko Nikula 
353b711f687SJarkko Nikula 	pm_runtime_get_sync(qep->dev);
354b711f687SJarkko Nikula 	reg = intel_qep_readl(qep, INTEL_QEPCON);
355b711f687SJarkko Nikula 	if (val)
356b711f687SJarkko Nikula 		reg &= ~INTEL_QEPCON_COUNT_RST_MODE;
357b711f687SJarkko Nikula 	else
358b711f687SJarkko Nikula 		reg |= INTEL_QEPCON_COUNT_RST_MODE;
359b711f687SJarkko Nikula 
360b711f687SJarkko Nikula 	intel_qep_writel(qep, INTEL_QEPCON, reg);
361b711f687SJarkko Nikula 	pm_runtime_put(qep->dev);
362b711f687SJarkko Nikula 
363b711f687SJarkko Nikula out:
364b711f687SJarkko Nikula 	mutex_unlock(&qep->lock);
365b711f687SJarkko Nikula 
366b711f687SJarkko Nikula 	return ret;
367b711f687SJarkko Nikula }
368b711f687SJarkko Nikula 
369aaec1a0fSWilliam Breathitt Gray static struct counter_comp intel_qep_count_ext[] = {
370aaec1a0fSWilliam Breathitt Gray 	COUNTER_COMP_ENABLE(intel_qep_enable_read, intel_qep_enable_write),
371aaec1a0fSWilliam Breathitt Gray 	COUNTER_COMP_CEILING(intel_qep_ceiling_read, intel_qep_ceiling_write),
372aaec1a0fSWilliam Breathitt Gray 	COUNTER_COMP_PRESET_ENABLE(intel_qep_preset_enable_read,
373aaec1a0fSWilliam Breathitt Gray 				   intel_qep_preset_enable_write),
374aaec1a0fSWilliam Breathitt Gray 	COUNTER_COMP_COUNT_U64("spike_filter_ns",
375aaec1a0fSWilliam Breathitt Gray 			       intel_qep_spike_filter_ns_read,
376aaec1a0fSWilliam Breathitt Gray 			       intel_qep_spike_filter_ns_write),
377b711f687SJarkko Nikula };
378b711f687SJarkko Nikula 
379b711f687SJarkko Nikula static struct counter_count intel_qep_counter_count[] = {
380b711f687SJarkko Nikula 	{
381b711f687SJarkko Nikula 		.id = 0,
382b711f687SJarkko Nikula 		.name = "Channel 1 Count",
383b711f687SJarkko Nikula 		.functions_list = intel_qep_count_functions,
384b711f687SJarkko Nikula 		.num_functions = ARRAY_SIZE(intel_qep_count_functions),
385b711f687SJarkko Nikula 		.synapses = intel_qep_count_synapses,
386b711f687SJarkko Nikula 		.num_synapses = ARRAY_SIZE(intel_qep_count_synapses),
387b711f687SJarkko Nikula 		.ext = intel_qep_count_ext,
388b711f687SJarkko Nikula 		.num_ext = ARRAY_SIZE(intel_qep_count_ext),
389b711f687SJarkko Nikula 	},
390b711f687SJarkko Nikula };
391b711f687SJarkko Nikula 
intel_qep_probe(struct pci_dev * pci,const struct pci_device_id * id)392b711f687SJarkko Nikula static int intel_qep_probe(struct pci_dev *pci, const struct pci_device_id *id)
393b711f687SJarkko Nikula {
394e99dec87SUwe Kleine-König 	struct counter_device *counter;
395b711f687SJarkko Nikula 	struct intel_qep *qep;
396b711f687SJarkko Nikula 	struct device *dev = &pci->dev;
397b711f687SJarkko Nikula 	void __iomem *regs;
398b711f687SJarkko Nikula 	int ret;
399b711f687SJarkko Nikula 
400e99dec87SUwe Kleine-König 	counter = devm_counter_alloc(dev, sizeof(*qep));
401e99dec87SUwe Kleine-König 	if (!counter)
402b711f687SJarkko Nikula 		return -ENOMEM;
403e99dec87SUwe Kleine-König 	qep = counter_priv(counter);
404b711f687SJarkko Nikula 
405b711f687SJarkko Nikula 	ret = pcim_enable_device(pci);
406b711f687SJarkko Nikula 	if (ret)
407b711f687SJarkko Nikula 		return ret;
408b711f687SJarkko Nikula 
409b711f687SJarkko Nikula 	pci_set_master(pci);
410b711f687SJarkko Nikula 
411b711f687SJarkko Nikula 	ret = pcim_iomap_regions(pci, BIT(0), pci_name(pci));
412b711f687SJarkko Nikula 	if (ret)
413b711f687SJarkko Nikula 		return ret;
414b711f687SJarkko Nikula 
415b711f687SJarkko Nikula 	regs = pcim_iomap_table(pci)[0];
416b711f687SJarkko Nikula 	if (!regs)
417b711f687SJarkko Nikula 		return -ENOMEM;
418b711f687SJarkko Nikula 
419b711f687SJarkko Nikula 	qep->dev = dev;
420b711f687SJarkko Nikula 	qep->regs = regs;
421b711f687SJarkko Nikula 	mutex_init(&qep->lock);
422b711f687SJarkko Nikula 
423b711f687SJarkko Nikula 	intel_qep_init(qep);
424b711f687SJarkko Nikula 	pci_set_drvdata(pci, qep);
425b711f687SJarkko Nikula 
426e99dec87SUwe Kleine-König 	counter->name = pci_name(pci);
427e99dec87SUwe Kleine-König 	counter->parent = dev;
428e99dec87SUwe Kleine-König 	counter->ops = &intel_qep_counter_ops;
429e99dec87SUwe Kleine-König 	counter->counts = intel_qep_counter_count;
430e99dec87SUwe Kleine-König 	counter->num_counts = ARRAY_SIZE(intel_qep_counter_count);
431e99dec87SUwe Kleine-König 	counter->signals = intel_qep_signals;
432e99dec87SUwe Kleine-König 	counter->num_signals = ARRAY_SIZE(intel_qep_signals);
433b711f687SJarkko Nikula 	qep->enabled = false;
434b711f687SJarkko Nikula 
435b711f687SJarkko Nikula 	pm_runtime_put(dev);
436b711f687SJarkko Nikula 	pm_runtime_allow(dev);
437b711f687SJarkko Nikula 
438e99dec87SUwe Kleine-König 	ret = devm_counter_add(&pci->dev, counter);
439e99dec87SUwe Kleine-König 	if (ret < 0)
440e99dec87SUwe Kleine-König 		return dev_err_probe(&pci->dev, ret, "Failed to add counter\n");
441e99dec87SUwe Kleine-König 
442e99dec87SUwe Kleine-König 	return 0;
443b711f687SJarkko Nikula }
444b711f687SJarkko Nikula 
intel_qep_remove(struct pci_dev * pci)445b711f687SJarkko Nikula static void intel_qep_remove(struct pci_dev *pci)
446b711f687SJarkko Nikula {
447b711f687SJarkko Nikula 	struct intel_qep *qep = pci_get_drvdata(pci);
448b711f687SJarkko Nikula 	struct device *dev = &pci->dev;
449b711f687SJarkko Nikula 
450b711f687SJarkko Nikula 	pm_runtime_forbid(dev);
451b711f687SJarkko Nikula 	if (!qep->enabled)
452b711f687SJarkko Nikula 		pm_runtime_get(dev);
453b711f687SJarkko Nikula 
454b711f687SJarkko Nikula 	intel_qep_writel(qep, INTEL_QEPCON, 0);
455b711f687SJarkko Nikula }
456b711f687SJarkko Nikula 
intel_qep_suspend(struct device * dev)457ac3bd9d6SJarkko Nikula static int __maybe_unused intel_qep_suspend(struct device *dev)
458b711f687SJarkko Nikula {
45993466212SJarkko Nikula 	struct pci_dev *pdev = to_pci_dev(dev);
460b711f687SJarkko Nikula 	struct intel_qep *qep = pci_get_drvdata(pdev);
461b711f687SJarkko Nikula 
462b711f687SJarkko Nikula 	qep->qepcon = intel_qep_readl(qep, INTEL_QEPCON);
463b711f687SJarkko Nikula 	qep->qepflt = intel_qep_readl(qep, INTEL_QEPFLT);
464b711f687SJarkko Nikula 	qep->qepmax = intel_qep_readl(qep, INTEL_QEPMAX);
465b711f687SJarkko Nikula 
466b711f687SJarkko Nikula 	return 0;
467b711f687SJarkko Nikula }
468b711f687SJarkko Nikula 
intel_qep_resume(struct device * dev)469ac3bd9d6SJarkko Nikula static int __maybe_unused intel_qep_resume(struct device *dev)
470b711f687SJarkko Nikula {
47193466212SJarkko Nikula 	struct pci_dev *pdev = to_pci_dev(dev);
472b711f687SJarkko Nikula 	struct intel_qep *qep = pci_get_drvdata(pdev);
473b711f687SJarkko Nikula 
474b711f687SJarkko Nikula 	/*
475b711f687SJarkko Nikula 	 * Make sure peripheral is disabled when restoring registers and
476b711f687SJarkko Nikula 	 * control register bits that are writable only when the peripheral
477b711f687SJarkko Nikula 	 * is disabled
478b711f687SJarkko Nikula 	 */
479b711f687SJarkko Nikula 	intel_qep_writel(qep, INTEL_QEPCON, 0);
480b711f687SJarkko Nikula 	intel_qep_readl(qep, INTEL_QEPCON);
481b711f687SJarkko Nikula 
482b711f687SJarkko Nikula 	intel_qep_writel(qep, INTEL_QEPFLT, qep->qepflt);
483b711f687SJarkko Nikula 	intel_qep_writel(qep, INTEL_QEPMAX, qep->qepmax);
484b711f687SJarkko Nikula 	intel_qep_writel(qep, INTEL_QEPINT_MASK, INTEL_QEPINT_MASK_ALL);
485b711f687SJarkko Nikula 
486b711f687SJarkko Nikula 	/* Restore all other control register bits except enable status */
487b711f687SJarkko Nikula 	intel_qep_writel(qep, INTEL_QEPCON, qep->qepcon & ~INTEL_QEPCON_EN);
488b711f687SJarkko Nikula 	intel_qep_readl(qep, INTEL_QEPCON);
489b711f687SJarkko Nikula 
490b711f687SJarkko Nikula 	/* Restore enable status */
491b711f687SJarkko Nikula 	intel_qep_writel(qep, INTEL_QEPCON, qep->qepcon);
492b711f687SJarkko Nikula 
493b711f687SJarkko Nikula 	return 0;
494b711f687SJarkko Nikula }
495b711f687SJarkko Nikula 
496b711f687SJarkko Nikula static UNIVERSAL_DEV_PM_OPS(intel_qep_pm_ops,
497b711f687SJarkko Nikula 			    intel_qep_suspend, intel_qep_resume, NULL);
498b711f687SJarkko Nikula 
499b711f687SJarkko Nikula static const struct pci_device_id intel_qep_id_table[] = {
500b711f687SJarkko Nikula 	/* EHL */
501b711f687SJarkko Nikula 	{ PCI_VDEVICE(INTEL, 0x4bc3), },
502b711f687SJarkko Nikula 	{ PCI_VDEVICE(INTEL, 0x4b81), },
503b711f687SJarkko Nikula 	{ PCI_VDEVICE(INTEL, 0x4b82), },
504b711f687SJarkko Nikula 	{ PCI_VDEVICE(INTEL, 0x4b83), },
505b711f687SJarkko Nikula 	{  } /* Terminating Entry */
506b711f687SJarkko Nikula };
507b711f687SJarkko Nikula MODULE_DEVICE_TABLE(pci, intel_qep_id_table);
508b711f687SJarkko Nikula 
509b711f687SJarkko Nikula static struct pci_driver intel_qep_driver = {
510b711f687SJarkko Nikula 	.name = "intel-qep",
511b711f687SJarkko Nikula 	.id_table = intel_qep_id_table,
512b711f687SJarkko Nikula 	.probe = intel_qep_probe,
513b711f687SJarkko Nikula 	.remove = intel_qep_remove,
514b711f687SJarkko Nikula 	.driver = {
515b711f687SJarkko Nikula 		.pm = &intel_qep_pm_ops,
516b711f687SJarkko Nikula 	}
517b711f687SJarkko Nikula };
518b711f687SJarkko Nikula 
519b711f687SJarkko Nikula module_pci_driver(intel_qep_driver);
520b711f687SJarkko Nikula 
521b711f687SJarkko Nikula MODULE_AUTHOR("Felipe Balbi (Intel)");
522b711f687SJarkko Nikula MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@linux.intel.com>");
523b711f687SJarkko Nikula MODULE_AUTHOR("Raymond Tan <raymond.tan@intel.com>");
524b711f687SJarkko Nikula MODULE_LICENSE("GPL");
525b711f687SJarkko Nikula MODULE_DESCRIPTION("Intel Quadrature Encoder Peripheral driver");
526*3216e551SWilliam Breathitt Gray MODULE_IMPORT_NS(COUNTER);
527