xref: /openbmc/linux/drivers/soc/qcom/icc-bwmon.c (revision ec63dcd3)
1b9c2ae6cSKrzysztof Kozlowski // SPDX-License-Identifier: GPL-2.0-only
2b9c2ae6cSKrzysztof Kozlowski /*
3b9c2ae6cSKrzysztof Kozlowski  * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
4b9c2ae6cSKrzysztof Kozlowski  * Copyright (C) 2021-2022 Linaro Ltd
5b9c2ae6cSKrzysztof Kozlowski  * Author: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>, based on
6b9c2ae6cSKrzysztof Kozlowski  *         previous work of Thara Gopinath and msm-4.9 downstream sources.
7b9c2ae6cSKrzysztof Kozlowski  */
8*ec63dcd3SKrzysztof Kozlowski 
9*ec63dcd3SKrzysztof Kozlowski #include <linux/err.h>
10b9c2ae6cSKrzysztof Kozlowski #include <linux/interconnect.h>
11b9c2ae6cSKrzysztof Kozlowski #include <linux/interrupt.h>
12b9c2ae6cSKrzysztof Kozlowski #include <linux/io.h>
13b9c2ae6cSKrzysztof Kozlowski #include <linux/kernel.h>
14b9c2ae6cSKrzysztof Kozlowski #include <linux/module.h>
15b9c2ae6cSKrzysztof Kozlowski #include <linux/of_device.h>
16b9c2ae6cSKrzysztof Kozlowski #include <linux/platform_device.h>
17b9c2ae6cSKrzysztof Kozlowski #include <linux/pm_opp.h>
18*ec63dcd3SKrzysztof Kozlowski #include <linux/regmap.h>
19b9c2ae6cSKrzysztof Kozlowski #include <linux/sizes.h>
20b9c2ae6cSKrzysztof Kozlowski 
21b9c2ae6cSKrzysztof Kozlowski /*
22b9c2ae6cSKrzysztof Kozlowski  * The BWMON samples data throughput within 'sample_ms' time. With three
23b9c2ae6cSKrzysztof Kozlowski  * configurable thresholds (Low, Medium and High) gives four windows (called
24b9c2ae6cSKrzysztof Kozlowski  * zones) of current bandwidth:
25b9c2ae6cSKrzysztof Kozlowski  *
26b9c2ae6cSKrzysztof Kozlowski  * Zone 0: byte count < THRES_LO
27b9c2ae6cSKrzysztof Kozlowski  * Zone 1: THRES_LO < byte count < THRES_MED
28b9c2ae6cSKrzysztof Kozlowski  * Zone 2: THRES_MED < byte count < THRES_HIGH
29b9c2ae6cSKrzysztof Kozlowski  * Zone 3: THRES_HIGH < byte count
30b9c2ae6cSKrzysztof Kozlowski  *
31b9c2ae6cSKrzysztof Kozlowski  * Zones 0 and 2 are not used by this driver.
32b9c2ae6cSKrzysztof Kozlowski  */
33b9c2ae6cSKrzysztof Kozlowski 
34b9c2ae6cSKrzysztof Kozlowski /* Internal sampling clock frequency */
35b9c2ae6cSKrzysztof Kozlowski #define HW_TIMER_HZ				19200000
36b9c2ae6cSKrzysztof Kozlowski 
37*ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_GLOBAL_IRQ_CLEAR		0x008
38*ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_GLOBAL_IRQ_ENABLE		0x00c
39*ec63dcd3SKrzysztof Kozlowski /*
40*ec63dcd3SKrzysztof Kozlowski  * All values here and further are matching regmap fields, so without absolute
41*ec63dcd3SKrzysztof Kozlowski  * register offsets.
42*ec63dcd3SKrzysztof Kozlowski  */
43*ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_GLOBAL_IRQ_ENABLE_ENABLE	BIT(0)
44b9c2ae6cSKrzysztof Kozlowski 
45*ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_IRQ_STATUS			0x100
46*ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_IRQ_CLEAR			0x108
47b9c2ae6cSKrzysztof Kozlowski 
48*ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_IRQ_ENABLE			0x10c
49*ec63dcd3SKrzysztof Kozlowski #define BWMON_IRQ_ENABLE_MASK			(BIT(1) | BIT(3))
50*ec63dcd3SKrzysztof Kozlowski 
51*ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_ENABLE				0x2a0
52b9c2ae6cSKrzysztof Kozlowski #define BWMON_ENABLE_ENABLE			BIT(0)
53b9c2ae6cSKrzysztof Kozlowski 
54*ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_CLEAR				0x2a4
55b9c2ae6cSKrzysztof Kozlowski #define BWMON_CLEAR_CLEAR			BIT(0)
56956deab5SKrzysztof Kozlowski #define BWMON_CLEAR_CLEAR_ALL			BIT(1)
57b9c2ae6cSKrzysztof Kozlowski 
58*ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_SAMPLE_WINDOW			0x2a8
59*ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_THRESHOLD_HIGH			0x2ac
60*ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_THRESHOLD_MED			0x2b0
61*ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_THRESHOLD_LOW			0x2b4
62b9c2ae6cSKrzysztof Kozlowski 
63*ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_ZONE_ACTIONS			0x2b8
64b9c2ae6cSKrzysztof Kozlowski /*
65b9c2ae6cSKrzysztof Kozlowski  * Actions to perform on some zone 'z' when current zone hits the threshold:
66b9c2ae6cSKrzysztof Kozlowski  * Increment counter of zone 'z'
67b9c2ae6cSKrzysztof Kozlowski  */
68b9c2ae6cSKrzysztof Kozlowski #define BWMON_ZONE_ACTIONS_INCREMENT(z)		(0x2 << ((z) * 2))
69b9c2ae6cSKrzysztof Kozlowski /* Clear counter of zone 'z' */
70b9c2ae6cSKrzysztof Kozlowski #define BWMON_ZONE_ACTIONS_CLEAR(z)		(0x1 << ((z) * 2))
71b9c2ae6cSKrzysztof Kozlowski 
72b9c2ae6cSKrzysztof Kozlowski /* Zone 0 threshold hit: Clear zone count */
73b9c2ae6cSKrzysztof Kozlowski #define BWMON_ZONE_ACTIONS_ZONE0		(BWMON_ZONE_ACTIONS_CLEAR(0))
74b9c2ae6cSKrzysztof Kozlowski 
75b9c2ae6cSKrzysztof Kozlowski /* Zone 1 threshold hit: Increment zone count & clear lower zones */
76b9c2ae6cSKrzysztof Kozlowski #define BWMON_ZONE_ACTIONS_ZONE1		(BWMON_ZONE_ACTIONS_INCREMENT(1) | \
77b9c2ae6cSKrzysztof Kozlowski 						 BWMON_ZONE_ACTIONS_CLEAR(0))
78b9c2ae6cSKrzysztof Kozlowski 
79b9c2ae6cSKrzysztof Kozlowski /* Zone 2 threshold hit: Increment zone count & clear lower zones */
80b9c2ae6cSKrzysztof Kozlowski #define BWMON_ZONE_ACTIONS_ZONE2		(BWMON_ZONE_ACTIONS_INCREMENT(2) | \
81b9c2ae6cSKrzysztof Kozlowski 						 BWMON_ZONE_ACTIONS_CLEAR(1) | \
82b9c2ae6cSKrzysztof Kozlowski 						 BWMON_ZONE_ACTIONS_CLEAR(0))
83b9c2ae6cSKrzysztof Kozlowski 
84b9c2ae6cSKrzysztof Kozlowski /* Zone 3 threshold hit: Increment zone count & clear lower zones */
85b9c2ae6cSKrzysztof Kozlowski #define BWMON_ZONE_ACTIONS_ZONE3		(BWMON_ZONE_ACTIONS_INCREMENT(3) | \
86b9c2ae6cSKrzysztof Kozlowski 						 BWMON_ZONE_ACTIONS_CLEAR(2) | \
87b9c2ae6cSKrzysztof Kozlowski 						 BWMON_ZONE_ACTIONS_CLEAR(1) | \
88b9c2ae6cSKrzysztof Kozlowski 						 BWMON_ZONE_ACTIONS_CLEAR(0))
89b9c2ae6cSKrzysztof Kozlowski 
90b9c2ae6cSKrzysztof Kozlowski /*
91*ec63dcd3SKrzysztof Kozlowski  * There is no clear documentation/explanation of BWMON_V4_THRESHOLD_COUNT
92b9c2ae6cSKrzysztof Kozlowski  * register. Based on observations, this is number of times one threshold has to
93b9c2ae6cSKrzysztof Kozlowski  * be reached, to trigger interrupt in given zone.
94b9c2ae6cSKrzysztof Kozlowski  *
95b9c2ae6cSKrzysztof Kozlowski  * 0xff are maximum values meant to ignore the zones 0 and 2.
96b9c2ae6cSKrzysztof Kozlowski  */
97*ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_THRESHOLD_COUNT		0x2bc
98b9c2ae6cSKrzysztof Kozlowski #define BWMON_THRESHOLD_COUNT_ZONE0_DEFAULT	0xff
99b9c2ae6cSKrzysztof Kozlowski #define BWMON_THRESHOLD_COUNT_ZONE2_DEFAULT	0xff
100b9c2ae6cSKrzysztof Kozlowski 
101*ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_ZONE_MAX(zone)			(0x2e0 + 4 * (zone))
102*ec63dcd3SKrzysztof Kozlowski 
103*ec63dcd3SKrzysztof Kozlowski enum bwmon_fields {
104*ec63dcd3SKrzysztof Kozlowski 	F_GLOBAL_IRQ_CLEAR,
105*ec63dcd3SKrzysztof Kozlowski 	F_GLOBAL_IRQ_ENABLE,
106*ec63dcd3SKrzysztof Kozlowski 	F_IRQ_STATUS,
107*ec63dcd3SKrzysztof Kozlowski 	F_IRQ_CLEAR,
108*ec63dcd3SKrzysztof Kozlowski 	F_IRQ_ENABLE,
109*ec63dcd3SKrzysztof Kozlowski 	F_ENABLE,
110*ec63dcd3SKrzysztof Kozlowski 	F_CLEAR,
111*ec63dcd3SKrzysztof Kozlowski 	F_SAMPLE_WINDOW,
112*ec63dcd3SKrzysztof Kozlowski 	F_THRESHOLD_HIGH,
113*ec63dcd3SKrzysztof Kozlowski 	F_THRESHOLD_MED,
114*ec63dcd3SKrzysztof Kozlowski 	F_THRESHOLD_LOW,
115*ec63dcd3SKrzysztof Kozlowski 	F_ZONE_ACTIONS_ZONE0,
116*ec63dcd3SKrzysztof Kozlowski 	F_ZONE_ACTIONS_ZONE1,
117*ec63dcd3SKrzysztof Kozlowski 	F_ZONE_ACTIONS_ZONE2,
118*ec63dcd3SKrzysztof Kozlowski 	F_ZONE_ACTIONS_ZONE3,
119*ec63dcd3SKrzysztof Kozlowski 	F_THRESHOLD_COUNT_ZONE0,
120*ec63dcd3SKrzysztof Kozlowski 	F_THRESHOLD_COUNT_ZONE1,
121*ec63dcd3SKrzysztof Kozlowski 	F_THRESHOLD_COUNT_ZONE2,
122*ec63dcd3SKrzysztof Kozlowski 	F_THRESHOLD_COUNT_ZONE3,
123*ec63dcd3SKrzysztof Kozlowski 	F_ZONE0_MAX,
124*ec63dcd3SKrzysztof Kozlowski 	F_ZONE1_MAX,
125*ec63dcd3SKrzysztof Kozlowski 	F_ZONE2_MAX,
126*ec63dcd3SKrzysztof Kozlowski 	F_ZONE3_MAX,
127*ec63dcd3SKrzysztof Kozlowski 
128*ec63dcd3SKrzysztof Kozlowski 	F_NUM_FIELDS
129*ec63dcd3SKrzysztof Kozlowski };
130b9c2ae6cSKrzysztof Kozlowski 
131b9c2ae6cSKrzysztof Kozlowski struct icc_bwmon_data {
132b9c2ae6cSKrzysztof Kozlowski 	unsigned int sample_ms;
133650db9faSKrzysztof Kozlowski 	unsigned int count_unit_kb; /* kbytes */
134b9c2ae6cSKrzysztof Kozlowski 	unsigned int default_highbw_kbps;
135b9c2ae6cSKrzysztof Kozlowski 	unsigned int default_medbw_kbps;
136b9c2ae6cSKrzysztof Kozlowski 	unsigned int default_lowbw_kbps;
137b9c2ae6cSKrzysztof Kozlowski 	u8 zone1_thres_count;
138b9c2ae6cSKrzysztof Kozlowski 	u8 zone3_thres_count;
139*ec63dcd3SKrzysztof Kozlowski 
140*ec63dcd3SKrzysztof Kozlowski 	const struct regmap_config *regmap_cfg;
141*ec63dcd3SKrzysztof Kozlowski 	const struct reg_field *regmap_fields;
142b9c2ae6cSKrzysztof Kozlowski };
143b9c2ae6cSKrzysztof Kozlowski 
144b9c2ae6cSKrzysztof Kozlowski struct icc_bwmon {
145b9c2ae6cSKrzysztof Kozlowski 	struct device *dev;
1461dd5246eSKrzysztof Kozlowski 	const struct icc_bwmon_data *data;
147b9c2ae6cSKrzysztof Kozlowski 	int irq;
148b9c2ae6cSKrzysztof Kozlowski 
149*ec63dcd3SKrzysztof Kozlowski 	struct regmap *regmap;
150*ec63dcd3SKrzysztof Kozlowski 	struct regmap_field *regs[F_NUM_FIELDS];
151*ec63dcd3SKrzysztof Kozlowski 
152b9c2ae6cSKrzysztof Kozlowski 	unsigned int max_bw_kbps;
153b9c2ae6cSKrzysztof Kozlowski 	unsigned int min_bw_kbps;
154b9c2ae6cSKrzysztof Kozlowski 	unsigned int target_kbps;
155b9c2ae6cSKrzysztof Kozlowski 	unsigned int current_kbps;
156b9c2ae6cSKrzysztof Kozlowski };
157b9c2ae6cSKrzysztof Kozlowski 
158*ec63dcd3SKrzysztof Kozlowski /* BWMON v4 */
159*ec63dcd3SKrzysztof Kozlowski static const struct reg_field msm8998_bwmon_reg_fields[] = {
160*ec63dcd3SKrzysztof Kozlowski 	[F_GLOBAL_IRQ_CLEAR]	= REG_FIELD(BWMON_V4_GLOBAL_IRQ_CLEAR, 0, 0),
161*ec63dcd3SKrzysztof Kozlowski 	[F_GLOBAL_IRQ_ENABLE]	= REG_FIELD(BWMON_V4_GLOBAL_IRQ_ENABLE, 0, 0),
162*ec63dcd3SKrzysztof Kozlowski 	[F_IRQ_STATUS]		= REG_FIELD(BWMON_V4_IRQ_STATUS, 4, 7),
163*ec63dcd3SKrzysztof Kozlowski 	[F_IRQ_CLEAR]		= REG_FIELD(BWMON_V4_IRQ_CLEAR, 4, 7),
164*ec63dcd3SKrzysztof Kozlowski 	[F_IRQ_ENABLE]		= REG_FIELD(BWMON_V4_IRQ_ENABLE, 4, 7),
165*ec63dcd3SKrzysztof Kozlowski 	/* F_ENABLE covers entire register to disable other features */
166*ec63dcd3SKrzysztof Kozlowski 	[F_ENABLE]		= REG_FIELD(BWMON_V4_ENABLE, 0, 31),
167*ec63dcd3SKrzysztof Kozlowski 	[F_CLEAR]		= REG_FIELD(BWMON_V4_CLEAR, 0, 1),
168*ec63dcd3SKrzysztof Kozlowski 	[F_SAMPLE_WINDOW]	= REG_FIELD(BWMON_V4_SAMPLE_WINDOW, 0, 23),
169*ec63dcd3SKrzysztof Kozlowski 	[F_THRESHOLD_HIGH]	= REG_FIELD(BWMON_V4_THRESHOLD_HIGH, 0, 11),
170*ec63dcd3SKrzysztof Kozlowski 	[F_THRESHOLD_MED]	= REG_FIELD(BWMON_V4_THRESHOLD_MED, 0, 11),
171*ec63dcd3SKrzysztof Kozlowski 	[F_THRESHOLD_LOW]	= REG_FIELD(BWMON_V4_THRESHOLD_LOW, 0, 11),
172*ec63dcd3SKrzysztof Kozlowski 	[F_ZONE_ACTIONS_ZONE0]	= REG_FIELD(BWMON_V4_ZONE_ACTIONS, 0, 7),
173*ec63dcd3SKrzysztof Kozlowski 	[F_ZONE_ACTIONS_ZONE1]	= REG_FIELD(BWMON_V4_ZONE_ACTIONS, 8, 15),
174*ec63dcd3SKrzysztof Kozlowski 	[F_ZONE_ACTIONS_ZONE2]	= REG_FIELD(BWMON_V4_ZONE_ACTIONS, 16, 23),
175*ec63dcd3SKrzysztof Kozlowski 	[F_ZONE_ACTIONS_ZONE3]	= REG_FIELD(BWMON_V4_ZONE_ACTIONS, 24, 31),
176*ec63dcd3SKrzysztof Kozlowski 	[F_THRESHOLD_COUNT_ZONE0]	= REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 0, 7),
177*ec63dcd3SKrzysztof Kozlowski 	[F_THRESHOLD_COUNT_ZONE1]	= REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 8, 15),
178*ec63dcd3SKrzysztof Kozlowski 	[F_THRESHOLD_COUNT_ZONE2]	= REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 16, 23),
179*ec63dcd3SKrzysztof Kozlowski 	[F_THRESHOLD_COUNT_ZONE3]	= REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 24, 31),
180*ec63dcd3SKrzysztof Kozlowski 	[F_ZONE0_MAX]		= REG_FIELD(BWMON_V4_ZONE_MAX(0), 0, 11),
181*ec63dcd3SKrzysztof Kozlowski 	[F_ZONE1_MAX]		= REG_FIELD(BWMON_V4_ZONE_MAX(1), 0, 11),
182*ec63dcd3SKrzysztof Kozlowski 	[F_ZONE2_MAX]		= REG_FIELD(BWMON_V4_ZONE_MAX(2), 0, 11),
183*ec63dcd3SKrzysztof Kozlowski 	[F_ZONE3_MAX]		= REG_FIELD(BWMON_V4_ZONE_MAX(3), 0, 11),
184*ec63dcd3SKrzysztof Kozlowski };
185*ec63dcd3SKrzysztof Kozlowski 
186*ec63dcd3SKrzysztof Kozlowski static const struct regmap_range msm8998_bwmon_reg_noread_ranges[] = {
187*ec63dcd3SKrzysztof Kozlowski 	regmap_reg_range(BWMON_V4_GLOBAL_IRQ_CLEAR, BWMON_V4_GLOBAL_IRQ_CLEAR),
188*ec63dcd3SKrzysztof Kozlowski 	regmap_reg_range(BWMON_V4_IRQ_CLEAR, BWMON_V4_IRQ_CLEAR),
189*ec63dcd3SKrzysztof Kozlowski 	regmap_reg_range(BWMON_V4_CLEAR, BWMON_V4_CLEAR),
190*ec63dcd3SKrzysztof Kozlowski };
191*ec63dcd3SKrzysztof Kozlowski 
192*ec63dcd3SKrzysztof Kozlowski static const struct regmap_access_table msm8998_bwmon_reg_read_table = {
193*ec63dcd3SKrzysztof Kozlowski 	.no_ranges	= msm8998_bwmon_reg_noread_ranges,
194*ec63dcd3SKrzysztof Kozlowski 	.n_no_ranges	= ARRAY_SIZE(msm8998_bwmon_reg_noread_ranges),
195*ec63dcd3SKrzysztof Kozlowski };
196*ec63dcd3SKrzysztof Kozlowski 
197*ec63dcd3SKrzysztof Kozlowski static const struct regmap_range msm8998_bwmon_reg_volatile_ranges[] = {
198*ec63dcd3SKrzysztof Kozlowski 	regmap_reg_range(BWMON_V4_IRQ_STATUS, BWMON_V4_IRQ_STATUS),
199*ec63dcd3SKrzysztof Kozlowski 	regmap_reg_range(BWMON_V4_ZONE_MAX(0), BWMON_V4_ZONE_MAX(3)),
200*ec63dcd3SKrzysztof Kozlowski };
201*ec63dcd3SKrzysztof Kozlowski 
202*ec63dcd3SKrzysztof Kozlowski static const struct regmap_access_table msm8998_bwmon_reg_volatile_table = {
203*ec63dcd3SKrzysztof Kozlowski 	.yes_ranges	= msm8998_bwmon_reg_volatile_ranges,
204*ec63dcd3SKrzysztof Kozlowski 	.n_yes_ranges	= ARRAY_SIZE(msm8998_bwmon_reg_volatile_ranges),
205*ec63dcd3SKrzysztof Kozlowski };
206*ec63dcd3SKrzysztof Kozlowski 
207*ec63dcd3SKrzysztof Kozlowski /*
208*ec63dcd3SKrzysztof Kozlowski  * Fill the cache for non-readable registers only as rest does not really
209*ec63dcd3SKrzysztof Kozlowski  * matter and can be read from the device.
210*ec63dcd3SKrzysztof Kozlowski  */
211*ec63dcd3SKrzysztof Kozlowski static const struct reg_default msm8998_bwmon_reg_defaults[] = {
212*ec63dcd3SKrzysztof Kozlowski 	{ BWMON_V4_GLOBAL_IRQ_CLEAR, 0x0 },
213*ec63dcd3SKrzysztof Kozlowski 	{ BWMON_V4_IRQ_CLEAR, 0x0 },
214*ec63dcd3SKrzysztof Kozlowski 	{ BWMON_V4_CLEAR, 0x0 },
215*ec63dcd3SKrzysztof Kozlowski };
216*ec63dcd3SKrzysztof Kozlowski 
217*ec63dcd3SKrzysztof Kozlowski static const struct regmap_config msm8998_bwmon_regmap_cfg = {
218*ec63dcd3SKrzysztof Kozlowski 	.reg_bits		= 32,
219*ec63dcd3SKrzysztof Kozlowski 	.reg_stride		= 4,
220*ec63dcd3SKrzysztof Kozlowski 	.val_bits		= 32,
221*ec63dcd3SKrzysztof Kozlowski 	/*
222*ec63dcd3SKrzysztof Kozlowski 	 * No concurrent access expected - driver has one interrupt handler,
223*ec63dcd3SKrzysztof Kozlowski 	 * regmap is not shared, no driver or user-space API.
224*ec63dcd3SKrzysztof Kozlowski 	 */
225*ec63dcd3SKrzysztof Kozlowski 	.disable_locking	= true,
226*ec63dcd3SKrzysztof Kozlowski 	.rd_table		= &msm8998_bwmon_reg_read_table,
227*ec63dcd3SKrzysztof Kozlowski 	.volatile_table		= &msm8998_bwmon_reg_volatile_table,
228*ec63dcd3SKrzysztof Kozlowski 	.reg_defaults		= msm8998_bwmon_reg_defaults,
229*ec63dcd3SKrzysztof Kozlowski 	.num_reg_defaults	= ARRAY_SIZE(msm8998_bwmon_reg_defaults),
230*ec63dcd3SKrzysztof Kozlowski 	/*
231*ec63dcd3SKrzysztof Kozlowski 	 * Cache is necessary for using regmap fields with non-readable
232*ec63dcd3SKrzysztof Kozlowski 	 * registers.
233*ec63dcd3SKrzysztof Kozlowski 	 */
234*ec63dcd3SKrzysztof Kozlowski 	.cache_type		= REGCACHE_RBTREE,
235*ec63dcd3SKrzysztof Kozlowski };
236*ec63dcd3SKrzysztof Kozlowski 
237956deab5SKrzysztof Kozlowski static void bwmon_clear_counters(struct icc_bwmon *bwmon, bool clear_all)
238b9c2ae6cSKrzysztof Kozlowski {
239956deab5SKrzysztof Kozlowski 	unsigned int val = BWMON_CLEAR_CLEAR;
240956deab5SKrzysztof Kozlowski 
241956deab5SKrzysztof Kozlowski 	if (clear_all)
242956deab5SKrzysztof Kozlowski 		val |= BWMON_CLEAR_CLEAR_ALL;
243b9c2ae6cSKrzysztof Kozlowski 	/*
244b9c2ae6cSKrzysztof Kozlowski 	 * Clear counters. The order and barriers are
245b9c2ae6cSKrzysztof Kozlowski 	 * important. Quoting downstream Qualcomm msm-4.9 tree:
246b9c2ae6cSKrzysztof Kozlowski 	 *
247b9c2ae6cSKrzysztof Kozlowski 	 * The counter clear and IRQ clear bits are not in the same 4KB
248b9c2ae6cSKrzysztof Kozlowski 	 * region. So, we need to make sure the counter clear is completed
249b9c2ae6cSKrzysztof Kozlowski 	 * before we try to clear the IRQ or do any other counter operations.
250b9c2ae6cSKrzysztof Kozlowski 	 */
251*ec63dcd3SKrzysztof Kozlowski 	regmap_field_force_write(bwmon->regs[F_CLEAR], val);
252b9c2ae6cSKrzysztof Kozlowski }
253b9c2ae6cSKrzysztof Kozlowski 
254b9c2ae6cSKrzysztof Kozlowski static void bwmon_clear_irq(struct icc_bwmon *bwmon)
255b9c2ae6cSKrzysztof Kozlowski {
256b9c2ae6cSKrzysztof Kozlowski 	/*
257b9c2ae6cSKrzysztof Kozlowski 	 * Clear zone and global interrupts. The order and barriers are
258b9c2ae6cSKrzysztof Kozlowski 	 * important. Quoting downstream Qualcomm msm-4.9 tree:
259b9c2ae6cSKrzysztof Kozlowski 	 *
260b9c2ae6cSKrzysztof Kozlowski 	 * Synchronize the local interrupt clear in mon_irq_clear()
261b9c2ae6cSKrzysztof Kozlowski 	 * with the global interrupt clear here. Otherwise, the CPU
262b9c2ae6cSKrzysztof Kozlowski 	 * may reorder the two writes and clear the global interrupt
263b9c2ae6cSKrzysztof Kozlowski 	 * before the local interrupt, causing the global interrupt
264b9c2ae6cSKrzysztof Kozlowski 	 * to be retriggered by the local interrupt still being high.
265b9c2ae6cSKrzysztof Kozlowski 	 *
266b9c2ae6cSKrzysztof Kozlowski 	 * Similarly, because the global registers are in a different
267b9c2ae6cSKrzysztof Kozlowski 	 * region than the local registers, we need to ensure any register
268b9c2ae6cSKrzysztof Kozlowski 	 * writes to enable the monitor after this call are ordered with the
269b9c2ae6cSKrzysztof Kozlowski 	 * clearing here so that local writes don't happen before the
270b9c2ae6cSKrzysztof Kozlowski 	 * interrupt is cleared.
271b9c2ae6cSKrzysztof Kozlowski 	 */
272*ec63dcd3SKrzysztof Kozlowski 	regmap_field_force_write(bwmon->regs[F_IRQ_CLEAR], BWMON_IRQ_ENABLE_MASK);
273*ec63dcd3SKrzysztof Kozlowski 	regmap_field_force_write(bwmon->regs[F_GLOBAL_IRQ_CLEAR],
274*ec63dcd3SKrzysztof Kozlowski 				 BWMON_V4_GLOBAL_IRQ_ENABLE_ENABLE);
275b9c2ae6cSKrzysztof Kozlowski }
276b9c2ae6cSKrzysztof Kozlowski 
277b9c2ae6cSKrzysztof Kozlowski static void bwmon_disable(struct icc_bwmon *bwmon)
278b9c2ae6cSKrzysztof Kozlowski {
279b9c2ae6cSKrzysztof Kozlowski 	/* Disable interrupts. Strict ordering, see bwmon_clear_irq(). */
280*ec63dcd3SKrzysztof Kozlowski 	regmap_field_write(bwmon->regs[F_GLOBAL_IRQ_ENABLE], 0x0);
281*ec63dcd3SKrzysztof Kozlowski 	regmap_field_write(bwmon->regs[F_IRQ_ENABLE], 0x0);
282b9c2ae6cSKrzysztof Kozlowski 
283b9c2ae6cSKrzysztof Kozlowski 	/*
284b9c2ae6cSKrzysztof Kozlowski 	 * Disable bwmon. Must happen before bwmon_clear_irq() to avoid spurious
285b9c2ae6cSKrzysztof Kozlowski 	 * IRQ.
286b9c2ae6cSKrzysztof Kozlowski 	 */
287*ec63dcd3SKrzysztof Kozlowski 	regmap_field_write(bwmon->regs[F_ENABLE], 0x0);
288b9c2ae6cSKrzysztof Kozlowski }
289b9c2ae6cSKrzysztof Kozlowski 
290b9c2ae6cSKrzysztof Kozlowski static void bwmon_enable(struct icc_bwmon *bwmon, unsigned int irq_enable)
291b9c2ae6cSKrzysztof Kozlowski {
292b9c2ae6cSKrzysztof Kozlowski 	/* Enable interrupts */
293*ec63dcd3SKrzysztof Kozlowski 	regmap_field_write(bwmon->regs[F_GLOBAL_IRQ_ENABLE],
294*ec63dcd3SKrzysztof Kozlowski 			   BWMON_V4_GLOBAL_IRQ_ENABLE_ENABLE);
295*ec63dcd3SKrzysztof Kozlowski 	regmap_field_write(bwmon->regs[F_IRQ_ENABLE], irq_enable);
296b9c2ae6cSKrzysztof Kozlowski 
297b9c2ae6cSKrzysztof Kozlowski 	/* Enable bwmon */
298*ec63dcd3SKrzysztof Kozlowski 	regmap_field_write(bwmon->regs[F_ENABLE], BWMON_ENABLE_ENABLE);
299b9c2ae6cSKrzysztof Kozlowski }
300b9c2ae6cSKrzysztof Kozlowski 
301650db9faSKrzysztof Kozlowski static unsigned int bwmon_kbps_to_count(struct icc_bwmon *bwmon,
302650db9faSKrzysztof Kozlowski 					unsigned int kbps)
303b9c2ae6cSKrzysztof Kozlowski {
304650db9faSKrzysztof Kozlowski 	return kbps / bwmon->data->count_unit_kb;
305b9c2ae6cSKrzysztof Kozlowski }
306b9c2ae6cSKrzysztof Kozlowski 
307*ec63dcd3SKrzysztof Kozlowski static void bwmon_set_threshold(struct icc_bwmon *bwmon,
308*ec63dcd3SKrzysztof Kozlowski 				struct regmap_field *reg, unsigned int kbps)
309b9c2ae6cSKrzysztof Kozlowski {
310b9c2ae6cSKrzysztof Kozlowski 	unsigned int thres;
311b9c2ae6cSKrzysztof Kozlowski 
312650db9faSKrzysztof Kozlowski 	thres = mult_frac(bwmon_kbps_to_count(bwmon, kbps),
313650db9faSKrzysztof Kozlowski 			  bwmon->data->sample_ms, MSEC_PER_SEC);
314*ec63dcd3SKrzysztof Kozlowski 	regmap_field_write(reg, thres);
315b9c2ae6cSKrzysztof Kozlowski }
316b9c2ae6cSKrzysztof Kozlowski 
3171dd5246eSKrzysztof Kozlowski static void bwmon_start(struct icc_bwmon *bwmon)
318b9c2ae6cSKrzysztof Kozlowski {
3191dd5246eSKrzysztof Kozlowski 	const struct icc_bwmon_data *data = bwmon->data;
320b9c2ae6cSKrzysztof Kozlowski 	int window;
321b9c2ae6cSKrzysztof Kozlowski 
322956deab5SKrzysztof Kozlowski 	bwmon_clear_counters(bwmon, true);
323b9c2ae6cSKrzysztof Kozlowski 
3241dd5246eSKrzysztof Kozlowski 	window = mult_frac(bwmon->data->sample_ms, HW_TIMER_HZ, MSEC_PER_SEC);
325b9c2ae6cSKrzysztof Kozlowski 	/* Maximum sampling window: 0xfffff */
326*ec63dcd3SKrzysztof Kozlowski 	regmap_field_write(bwmon->regs[F_SAMPLE_WINDOW], window);
327b9c2ae6cSKrzysztof Kozlowski 
328*ec63dcd3SKrzysztof Kozlowski 	bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_HIGH],
329b9c2ae6cSKrzysztof Kozlowski 			    data->default_highbw_kbps);
330*ec63dcd3SKrzysztof Kozlowski 	bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_MED],
331b9c2ae6cSKrzysztof Kozlowski 			    data->default_medbw_kbps);
332*ec63dcd3SKrzysztof Kozlowski 	bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_LOW],
333b9c2ae6cSKrzysztof Kozlowski 			    data->default_lowbw_kbps);
334b9c2ae6cSKrzysztof Kozlowski 
335*ec63dcd3SKrzysztof Kozlowski 	regmap_field_write(bwmon->regs[F_THRESHOLD_COUNT_ZONE0],
336*ec63dcd3SKrzysztof Kozlowski 			   BWMON_THRESHOLD_COUNT_ZONE0_DEFAULT);
337*ec63dcd3SKrzysztof Kozlowski 	regmap_field_write(bwmon->regs[F_THRESHOLD_COUNT_ZONE1],
338*ec63dcd3SKrzysztof Kozlowski 			   data->zone1_thres_count);
339*ec63dcd3SKrzysztof Kozlowski 	regmap_field_write(bwmon->regs[F_THRESHOLD_COUNT_ZONE2],
340*ec63dcd3SKrzysztof Kozlowski 			   BWMON_THRESHOLD_COUNT_ZONE2_DEFAULT);
341*ec63dcd3SKrzysztof Kozlowski 	regmap_field_write(bwmon->regs[F_THRESHOLD_COUNT_ZONE3],
342*ec63dcd3SKrzysztof Kozlowski 			   data->zone3_thres_count);
343*ec63dcd3SKrzysztof Kozlowski 
344*ec63dcd3SKrzysztof Kozlowski 	regmap_field_write(bwmon->regs[F_ZONE_ACTIONS_ZONE0],
345*ec63dcd3SKrzysztof Kozlowski 			   BWMON_ZONE_ACTIONS_ZONE0);
346*ec63dcd3SKrzysztof Kozlowski 	regmap_field_write(bwmon->regs[F_ZONE_ACTIONS_ZONE1],
347*ec63dcd3SKrzysztof Kozlowski 			   BWMON_ZONE_ACTIONS_ZONE1);
348*ec63dcd3SKrzysztof Kozlowski 	regmap_field_write(bwmon->regs[F_ZONE_ACTIONS_ZONE2],
349*ec63dcd3SKrzysztof Kozlowski 			   BWMON_ZONE_ACTIONS_ZONE2);
350*ec63dcd3SKrzysztof Kozlowski 	regmap_field_write(bwmon->regs[F_ZONE_ACTIONS_ZONE3],
351*ec63dcd3SKrzysztof Kozlowski 			   BWMON_ZONE_ACTIONS_ZONE3);
352b9c2ae6cSKrzysztof Kozlowski 
353b9c2ae6cSKrzysztof Kozlowski 	bwmon_clear_irq(bwmon);
354b9c2ae6cSKrzysztof Kozlowski 	bwmon_enable(bwmon, BWMON_IRQ_ENABLE_MASK);
355b9c2ae6cSKrzysztof Kozlowski }
356b9c2ae6cSKrzysztof Kozlowski 
357b9c2ae6cSKrzysztof Kozlowski static irqreturn_t bwmon_intr(int irq, void *dev_id)
358b9c2ae6cSKrzysztof Kozlowski {
359b9c2ae6cSKrzysztof Kozlowski 	struct icc_bwmon *bwmon = dev_id;
360b9c2ae6cSKrzysztof Kozlowski 	unsigned int status, max;
361b9c2ae6cSKrzysztof Kozlowski 	int zone;
362b9c2ae6cSKrzysztof Kozlowski 
363*ec63dcd3SKrzysztof Kozlowski 	if (regmap_field_read(bwmon->regs[F_IRQ_STATUS], &status))
364*ec63dcd3SKrzysztof Kozlowski 		return IRQ_NONE;
365*ec63dcd3SKrzysztof Kozlowski 
366b9c2ae6cSKrzysztof Kozlowski 	status &= BWMON_IRQ_ENABLE_MASK;
367b9c2ae6cSKrzysztof Kozlowski 	if (!status) {
368b9c2ae6cSKrzysztof Kozlowski 		/*
369b9c2ae6cSKrzysztof Kozlowski 		 * Only zone 1 and zone 3 interrupts are enabled but zone 2
370b9c2ae6cSKrzysztof Kozlowski 		 * threshold could be hit and trigger interrupt even if not
371b9c2ae6cSKrzysztof Kozlowski 		 * enabled.
372b9c2ae6cSKrzysztof Kozlowski 		 * Such spurious interrupt might come with valuable max count or
373b9c2ae6cSKrzysztof Kozlowski 		 * not, so solution would be to always check all
374b9c2ae6cSKrzysztof Kozlowski 		 * BWMON_ZONE_MAX() registers to find the highest value.
375b9c2ae6cSKrzysztof Kozlowski 		 * Such case is currently ignored.
376b9c2ae6cSKrzysztof Kozlowski 		 */
377b9c2ae6cSKrzysztof Kozlowski 		return IRQ_NONE;
378b9c2ae6cSKrzysztof Kozlowski 	}
379b9c2ae6cSKrzysztof Kozlowski 
380b9c2ae6cSKrzysztof Kozlowski 	bwmon_disable(bwmon);
381b9c2ae6cSKrzysztof Kozlowski 
382*ec63dcd3SKrzysztof Kozlowski 	zone = get_bitmask_order(status) - 1;
383b9c2ae6cSKrzysztof Kozlowski 	/*
384b9c2ae6cSKrzysztof Kozlowski 	 * Zone max bytes count register returns count units within sampling
385b9c2ae6cSKrzysztof Kozlowski 	 * window.  Downstream kernel for BWMONv4 (called BWMON type 2 in
386b9c2ae6cSKrzysztof Kozlowski 	 * downstream) always increments the max bytes count by one.
387b9c2ae6cSKrzysztof Kozlowski 	 */
388*ec63dcd3SKrzysztof Kozlowski 	if (regmap_field_read(bwmon->regs[F_ZONE0_MAX + zone], &max))
389*ec63dcd3SKrzysztof Kozlowski 		return IRQ_NONE;
390*ec63dcd3SKrzysztof Kozlowski 
391*ec63dcd3SKrzysztof Kozlowski 	max += 1;
392650db9faSKrzysztof Kozlowski 	max *= bwmon->data->count_unit_kb;
3931dd5246eSKrzysztof Kozlowski 	bwmon->target_kbps = mult_frac(max, MSEC_PER_SEC, bwmon->data->sample_ms);
394b9c2ae6cSKrzysztof Kozlowski 
395b9c2ae6cSKrzysztof Kozlowski 	return IRQ_WAKE_THREAD;
396b9c2ae6cSKrzysztof Kozlowski }
397b9c2ae6cSKrzysztof Kozlowski 
398b9c2ae6cSKrzysztof Kozlowski static irqreturn_t bwmon_intr_thread(int irq, void *dev_id)
399b9c2ae6cSKrzysztof Kozlowski {
400b9c2ae6cSKrzysztof Kozlowski 	struct icc_bwmon *bwmon = dev_id;
401b9c2ae6cSKrzysztof Kozlowski 	unsigned int irq_enable = 0;
402b9c2ae6cSKrzysztof Kozlowski 	struct dev_pm_opp *opp, *target_opp;
403b9c2ae6cSKrzysztof Kozlowski 	unsigned int bw_kbps, up_kbps, down_kbps;
404b9c2ae6cSKrzysztof Kozlowski 
405b9c2ae6cSKrzysztof Kozlowski 	bw_kbps = bwmon->target_kbps;
406b9c2ae6cSKrzysztof Kozlowski 
407b9c2ae6cSKrzysztof Kozlowski 	target_opp = dev_pm_opp_find_bw_ceil(bwmon->dev, &bw_kbps, 0);
408b9c2ae6cSKrzysztof Kozlowski 	if (IS_ERR(target_opp) && PTR_ERR(target_opp) == -ERANGE)
409b9c2ae6cSKrzysztof Kozlowski 		target_opp = dev_pm_opp_find_bw_floor(bwmon->dev, &bw_kbps, 0);
410b9c2ae6cSKrzysztof Kozlowski 
411b9c2ae6cSKrzysztof Kozlowski 	bwmon->target_kbps = bw_kbps;
412b9c2ae6cSKrzysztof Kozlowski 
413b9c2ae6cSKrzysztof Kozlowski 	bw_kbps--;
414b9c2ae6cSKrzysztof Kozlowski 	opp = dev_pm_opp_find_bw_floor(bwmon->dev, &bw_kbps, 0);
415b9c2ae6cSKrzysztof Kozlowski 	if (IS_ERR(opp) && PTR_ERR(opp) == -ERANGE)
416b9c2ae6cSKrzysztof Kozlowski 		down_kbps = bwmon->target_kbps;
417b9c2ae6cSKrzysztof Kozlowski 	else
418b9c2ae6cSKrzysztof Kozlowski 		down_kbps = bw_kbps;
419b9c2ae6cSKrzysztof Kozlowski 
420b9c2ae6cSKrzysztof Kozlowski 	up_kbps = bwmon->target_kbps + 1;
421b9c2ae6cSKrzysztof Kozlowski 
422b9c2ae6cSKrzysztof Kozlowski 	if (bwmon->target_kbps >= bwmon->max_bw_kbps)
423*ec63dcd3SKrzysztof Kozlowski 		irq_enable = BIT(1);
424b9c2ae6cSKrzysztof Kozlowski 	else if (bwmon->target_kbps <= bwmon->min_bw_kbps)
425*ec63dcd3SKrzysztof Kozlowski 		irq_enable = BIT(3);
426b9c2ae6cSKrzysztof Kozlowski 	else
427b9c2ae6cSKrzysztof Kozlowski 		irq_enable = BWMON_IRQ_ENABLE_MASK;
428b9c2ae6cSKrzysztof Kozlowski 
429*ec63dcd3SKrzysztof Kozlowski 	bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_HIGH],
430*ec63dcd3SKrzysztof Kozlowski 			    up_kbps);
431*ec63dcd3SKrzysztof Kozlowski 	bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_MED],
432*ec63dcd3SKrzysztof Kozlowski 			    down_kbps);
433956deab5SKrzysztof Kozlowski 	bwmon_clear_counters(bwmon, false);
434b9c2ae6cSKrzysztof Kozlowski 	bwmon_clear_irq(bwmon);
435b9c2ae6cSKrzysztof Kozlowski 	bwmon_enable(bwmon, irq_enable);
436b9c2ae6cSKrzysztof Kozlowski 
437b9c2ae6cSKrzysztof Kozlowski 	if (bwmon->target_kbps == bwmon->current_kbps)
438b9c2ae6cSKrzysztof Kozlowski 		goto out;
439b9c2ae6cSKrzysztof Kozlowski 
440b9c2ae6cSKrzysztof Kozlowski 	dev_pm_opp_set_opp(bwmon->dev, target_opp);
441b9c2ae6cSKrzysztof Kozlowski 	bwmon->current_kbps = bwmon->target_kbps;
442b9c2ae6cSKrzysztof Kozlowski 
443b9c2ae6cSKrzysztof Kozlowski out:
444b9c2ae6cSKrzysztof Kozlowski 	dev_pm_opp_put(target_opp);
445b9c2ae6cSKrzysztof Kozlowski 	if (!IS_ERR(opp))
446b9c2ae6cSKrzysztof Kozlowski 		dev_pm_opp_put(opp);
447b9c2ae6cSKrzysztof Kozlowski 
448b9c2ae6cSKrzysztof Kozlowski 	return IRQ_HANDLED;
449b9c2ae6cSKrzysztof Kozlowski }
450b9c2ae6cSKrzysztof Kozlowski 
451*ec63dcd3SKrzysztof Kozlowski static int bwmon_init_regmap(struct platform_device *pdev,
452*ec63dcd3SKrzysztof Kozlowski 			     struct icc_bwmon *bwmon)
453*ec63dcd3SKrzysztof Kozlowski {
454*ec63dcd3SKrzysztof Kozlowski 	struct device *dev = &pdev->dev;
455*ec63dcd3SKrzysztof Kozlowski 	void __iomem *base;
456*ec63dcd3SKrzysztof Kozlowski 	struct regmap *map;
457*ec63dcd3SKrzysztof Kozlowski 	int ret;
458*ec63dcd3SKrzysztof Kozlowski 
459*ec63dcd3SKrzysztof Kozlowski 	base = devm_platform_ioremap_resource(pdev, 0);
460*ec63dcd3SKrzysztof Kozlowski 	if (IS_ERR(base))
461*ec63dcd3SKrzysztof Kozlowski 		return dev_err_probe(dev, PTR_ERR(base),
462*ec63dcd3SKrzysztof Kozlowski 				     "failed to map bwmon registers\n");
463*ec63dcd3SKrzysztof Kozlowski 
464*ec63dcd3SKrzysztof Kozlowski 	map = devm_regmap_init_mmio(dev, base, bwmon->data->regmap_cfg);
465*ec63dcd3SKrzysztof Kozlowski 	if (IS_ERR(map))
466*ec63dcd3SKrzysztof Kozlowski 		return dev_err_probe(dev, PTR_ERR(map),
467*ec63dcd3SKrzysztof Kozlowski 				     "failed to initialize regmap\n");
468*ec63dcd3SKrzysztof Kozlowski 
469*ec63dcd3SKrzysztof Kozlowski 	BUILD_BUG_ON(ARRAY_SIZE(msm8998_bwmon_reg_fields) != F_NUM_FIELDS);
470*ec63dcd3SKrzysztof Kozlowski 	ret = devm_regmap_field_bulk_alloc(dev, map, bwmon->regs,
471*ec63dcd3SKrzysztof Kozlowski 					   bwmon->data->regmap_fields,
472*ec63dcd3SKrzysztof Kozlowski 					   F_NUM_FIELDS);
473*ec63dcd3SKrzysztof Kozlowski 
474*ec63dcd3SKrzysztof Kozlowski 	return ret;
475*ec63dcd3SKrzysztof Kozlowski }
476*ec63dcd3SKrzysztof Kozlowski 
477b9c2ae6cSKrzysztof Kozlowski static int bwmon_probe(struct platform_device *pdev)
478b9c2ae6cSKrzysztof Kozlowski {
479b9c2ae6cSKrzysztof Kozlowski 	struct device *dev = &pdev->dev;
480b9c2ae6cSKrzysztof Kozlowski 	struct dev_pm_opp *opp;
481b9c2ae6cSKrzysztof Kozlowski 	struct icc_bwmon *bwmon;
482b9c2ae6cSKrzysztof Kozlowski 	int ret;
483b9c2ae6cSKrzysztof Kozlowski 
484b9c2ae6cSKrzysztof Kozlowski 	bwmon = devm_kzalloc(dev, sizeof(*bwmon), GFP_KERNEL);
485b9c2ae6cSKrzysztof Kozlowski 	if (!bwmon)
486b9c2ae6cSKrzysztof Kozlowski 		return -ENOMEM;
487b9c2ae6cSKrzysztof Kozlowski 
4881dd5246eSKrzysztof Kozlowski 	bwmon->data = of_device_get_match_data(dev);
489b9c2ae6cSKrzysztof Kozlowski 
490*ec63dcd3SKrzysztof Kozlowski 	ret = bwmon_init_regmap(pdev, bwmon);
491*ec63dcd3SKrzysztof Kozlowski 	if (ret)
492*ec63dcd3SKrzysztof Kozlowski 		return ret;
493b9c2ae6cSKrzysztof Kozlowski 
494b9c2ae6cSKrzysztof Kozlowski 	bwmon->irq = platform_get_irq(pdev, 0);
495947bb0d1SYang Li 	if (bwmon->irq < 0)
496b9c2ae6cSKrzysztof Kozlowski 		return bwmon->irq;
497b9c2ae6cSKrzysztof Kozlowski 
498b9c2ae6cSKrzysztof Kozlowski 	ret = devm_pm_opp_of_add_table(dev);
499b9c2ae6cSKrzysztof Kozlowski 	if (ret)
500b9c2ae6cSKrzysztof Kozlowski 		return dev_err_probe(dev, ret, "failed to add OPP table\n");
501b9c2ae6cSKrzysztof Kozlowski 
502b9c2ae6cSKrzysztof Kozlowski 	bwmon->max_bw_kbps = UINT_MAX;
503b9c2ae6cSKrzysztof Kozlowski 	opp = dev_pm_opp_find_bw_floor(dev, &bwmon->max_bw_kbps, 0);
504b9c2ae6cSKrzysztof Kozlowski 	if (IS_ERR(opp))
505b9c2ae6cSKrzysztof Kozlowski 		return dev_err_probe(dev, ret, "failed to find max peak bandwidth\n");
506b9c2ae6cSKrzysztof Kozlowski 
507b9c2ae6cSKrzysztof Kozlowski 	bwmon->min_bw_kbps = 0;
508b9c2ae6cSKrzysztof Kozlowski 	opp = dev_pm_opp_find_bw_ceil(dev, &bwmon->min_bw_kbps, 0);
509b9c2ae6cSKrzysztof Kozlowski 	if (IS_ERR(opp))
510b9c2ae6cSKrzysztof Kozlowski 		return dev_err_probe(dev, ret, "failed to find min peak bandwidth\n");
511b9c2ae6cSKrzysztof Kozlowski 
512b9c2ae6cSKrzysztof Kozlowski 	bwmon->dev = dev;
513b9c2ae6cSKrzysztof Kozlowski 
514b9c2ae6cSKrzysztof Kozlowski 	bwmon_disable(bwmon);
515b9c2ae6cSKrzysztof Kozlowski 	ret = devm_request_threaded_irq(dev, bwmon->irq, bwmon_intr,
516b9c2ae6cSKrzysztof Kozlowski 					bwmon_intr_thread,
517b9c2ae6cSKrzysztof Kozlowski 					IRQF_ONESHOT, dev_name(dev), bwmon);
518b9c2ae6cSKrzysztof Kozlowski 	if (ret)
519b9c2ae6cSKrzysztof Kozlowski 		return dev_err_probe(dev, ret, "failed to request IRQ\n");
520b9c2ae6cSKrzysztof Kozlowski 
521b9c2ae6cSKrzysztof Kozlowski 	platform_set_drvdata(pdev, bwmon);
5221dd5246eSKrzysztof Kozlowski 	bwmon_start(bwmon);
523b9c2ae6cSKrzysztof Kozlowski 
524b9c2ae6cSKrzysztof Kozlowski 	return 0;
525b9c2ae6cSKrzysztof Kozlowski }
526b9c2ae6cSKrzysztof Kozlowski 
527b9c2ae6cSKrzysztof Kozlowski static int bwmon_remove(struct platform_device *pdev)
528b9c2ae6cSKrzysztof Kozlowski {
529b9c2ae6cSKrzysztof Kozlowski 	struct icc_bwmon *bwmon = platform_get_drvdata(pdev);
530b9c2ae6cSKrzysztof Kozlowski 
531b9c2ae6cSKrzysztof Kozlowski 	bwmon_disable(bwmon);
532b9c2ae6cSKrzysztof Kozlowski 
533b9c2ae6cSKrzysztof Kozlowski 	return 0;
534b9c2ae6cSKrzysztof Kozlowski }
535b9c2ae6cSKrzysztof Kozlowski 
536b9c2ae6cSKrzysztof Kozlowski static const struct icc_bwmon_data msm8998_bwmon_data = {
537b9c2ae6cSKrzysztof Kozlowski 	.sample_ms = 4,
538650db9faSKrzysztof Kozlowski 	.count_unit_kb = 64,
539b9c2ae6cSKrzysztof Kozlowski 	.default_highbw_kbps = 4800 * 1024, /* 4.8 GBps */
540b9c2ae6cSKrzysztof Kozlowski 	.default_medbw_kbps = 512 * 1024, /* 512 MBps */
541b9c2ae6cSKrzysztof Kozlowski 	.default_lowbw_kbps = 0,
542b9c2ae6cSKrzysztof Kozlowski 	.zone1_thres_count = 16,
543b9c2ae6cSKrzysztof Kozlowski 	.zone3_thres_count = 1,
544*ec63dcd3SKrzysztof Kozlowski 	.regmap_fields = msm8998_bwmon_reg_fields,
545*ec63dcd3SKrzysztof Kozlowski 	.regmap_cfg = &msm8998_bwmon_regmap_cfg,
546b9c2ae6cSKrzysztof Kozlowski };
547b9c2ae6cSKrzysztof Kozlowski 
548b9c2ae6cSKrzysztof Kozlowski static const struct of_device_id bwmon_of_match[] = {
549b9c2ae6cSKrzysztof Kozlowski 	{ .compatible = "qcom,msm8998-bwmon", .data = &msm8998_bwmon_data },
550b9c2ae6cSKrzysztof Kozlowski 	{}
551b9c2ae6cSKrzysztof Kozlowski };
552b9c2ae6cSKrzysztof Kozlowski MODULE_DEVICE_TABLE(of, bwmon_of_match);
553b9c2ae6cSKrzysztof Kozlowski 
554b9c2ae6cSKrzysztof Kozlowski static struct platform_driver bwmon_driver = {
555b9c2ae6cSKrzysztof Kozlowski 	.probe = bwmon_probe,
556b9c2ae6cSKrzysztof Kozlowski 	.remove = bwmon_remove,
557b9c2ae6cSKrzysztof Kozlowski 	.driver = {
558b9c2ae6cSKrzysztof Kozlowski 		.name = "qcom-bwmon",
559b9c2ae6cSKrzysztof Kozlowski 		.of_match_table = bwmon_of_match,
560b9c2ae6cSKrzysztof Kozlowski 	},
561b9c2ae6cSKrzysztof Kozlowski };
562b9c2ae6cSKrzysztof Kozlowski module_platform_driver(bwmon_driver);
563b9c2ae6cSKrzysztof Kozlowski 
564b9c2ae6cSKrzysztof Kozlowski MODULE_AUTHOR("Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>");
565b9c2ae6cSKrzysztof Kozlowski MODULE_DESCRIPTION("QCOM BWMON driver");
566b9c2ae6cSKrzysztof Kozlowski MODULE_LICENSE("GPL");
567