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