// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2014 - 2018, NVIDIA CORPORATION. All rights reserved. * * Author: * Mikko Perttunen <[email protected]> * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and * may be copied, distributed, and modified under those terms. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ #include <linux/debugfs.h> #include <linux/bitops.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/irq.h> #include <linux/irqdomain.h> #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> #include <linux/reset.h> #include <linux/thermal.h> #include <dt-bindings/thermal/tegra124-soctherm.h> #include "../thermal_core.h" #include "soctherm.h" #define SENSOR_CONFIG0 … #define SENSOR_CONFIG0_STOP … #define SENSOR_CONFIG0_CPTR_OVER … #define SENSOR_CONFIG0_OVER … #define SENSOR_CONFIG0_TCALC_OVER … #define SENSOR_CONFIG0_TALL_MASK … #define SENSOR_CONFIG0_TALL_SHIFT … #define SENSOR_CONFIG1 … #define SENSOR_CONFIG1_TSAMPLE_MASK … #define SENSOR_CONFIG1_TSAMPLE_SHIFT … #define SENSOR_CONFIG1_TIDDQ_EN_MASK … #define SENSOR_CONFIG1_TIDDQ_EN_SHIFT … #define SENSOR_CONFIG1_TEN_COUNT_MASK … #define SENSOR_CONFIG1_TEN_COUNT_SHIFT … #define SENSOR_CONFIG1_TEMP_ENABLE … /* * SENSOR_CONFIG2 is defined in soctherm.h * because, it will be used by tegra_soctherm_fuse.c */ #define SENSOR_STATUS0 … #define SENSOR_STATUS0_VALID_MASK … #define SENSOR_STATUS0_CAPTURE_MASK … #define SENSOR_STATUS1 … #define SENSOR_STATUS1_TEMP_VALID_MASK … #define SENSOR_STATUS1_TEMP_MASK … #define READBACK_VALUE_MASK … #define READBACK_VALUE_SHIFT … #define READBACK_ADD_HALF … #define READBACK_NEGATE … /* * THERMCTL_LEVEL0_GROUP_CPU is defined in soctherm.h * because it will be used by tegraxxx_soctherm.c */ #define THERMCTL_LVL0_CPU0_EN_MASK … #define THERMCTL_LVL0_CPU0_CPU_THROT_MASK … #define THERMCTL_LVL0_CPU0_CPU_THROT_LIGHT … #define THERMCTL_LVL0_CPU0_CPU_THROT_HEAVY … #define THERMCTL_LVL0_CPU0_GPU_THROT_MASK … #define THERMCTL_LVL0_CPU0_GPU_THROT_LIGHT … #define THERMCTL_LVL0_CPU0_GPU_THROT_HEAVY … #define THERMCTL_LVL0_CPU0_MEM_THROT_MASK … #define THERMCTL_LVL0_CPU0_STATUS_MASK … #define THERMCTL_LVL0_UP_STATS … #define THERMCTL_LVL0_DN_STATS … #define THERMCTL_INTR_STATUS … #define TH_INTR_MD0_MASK … #define TH_INTR_MU0_MASK … #define TH_INTR_GD0_MASK … #define TH_INTR_GU0_MASK … #define TH_INTR_CD0_MASK … #define TH_INTR_CU0_MASK … #define TH_INTR_PD0_MASK … #define TH_INTR_PU0_MASK … #define TH_INTR_IGNORE_MASK … #define THERMCTL_STATS_CTL … #define STATS_CTL_CLR_DN … #define STATS_CTL_EN_DN … #define STATS_CTL_CLR_UP … #define STATS_CTL_EN_UP … #define OC1_CFG … #define OC1_CFG_LONG_LATENCY_MASK … #define OC1_CFG_HW_RESTORE_MASK … #define OC1_CFG_PWR_GOOD_MASK_MASK … #define OC1_CFG_THROTTLE_MODE_MASK … #define OC1_CFG_ALARM_POLARITY_MASK … #define OC1_CFG_EN_THROTTLE_MASK … #define OC1_CNT_THRESHOLD … #define OC1_THROTTLE_PERIOD … #define OC1_ALARM_COUNT … #define OC1_FILTER … #define OC1_STATS … #define OC_INTR_STATUS … #define OC_INTR_ENABLE … #define OC_INTR_DISABLE … #define OC_STATS_CTL … #define OC_STATS_CTL_CLR_ALL … #define OC_STATS_CTL_EN_ALL … #define OC_INTR_OC1_MASK … #define OC_INTR_OC2_MASK … #define OC_INTR_OC3_MASK … #define OC_INTR_OC4_MASK … #define OC_INTR_OC5_MASK … #define THROT_GLOBAL_CFG … #define THROT_GLOBAL_ENB_MASK … #define CPU_PSKIP_STATUS … #define XPU_PSKIP_STATUS_M_MASK … #define XPU_PSKIP_STATUS_N_MASK … #define XPU_PSKIP_STATUS_SW_OVERRIDE_MASK … #define XPU_PSKIP_STATUS_ENABLED_MASK … #define THROT_PRIORITY_LOCK … #define THROT_PRIORITY_LOCK_PRIORITY_MASK … #define THROT_STATUS … #define THROT_STATUS_BREACH_MASK … #define THROT_STATUS_STATE_MASK … #define THROT_STATUS_ENABLED_MASK … #define THROT_PSKIP_CTRL_LITE_CPU … #define THROT_PSKIP_CTRL_ENABLE_MASK … #define THROT_PSKIP_CTRL_DIVIDEND_MASK … #define THROT_PSKIP_CTRL_DIVISOR_MASK … #define THROT_PSKIP_CTRL_VECT_GPU_MASK … #define THROT_PSKIP_CTRL_VECT_CPU_MASK … #define THROT_PSKIP_CTRL_VECT2_CPU_MASK … #define THROT_VECT_NONE … #define THROT_VECT_LOW … #define THROT_VECT_MED … #define THROT_VECT_HIGH … #define THROT_PSKIP_RAMP_LITE_CPU … #define THROT_PSKIP_RAMP_SEQ_BYPASS_MODE_MASK … #define THROT_PSKIP_RAMP_DURATION_MASK … #define THROT_PSKIP_RAMP_STEP_MASK … #define THROT_PRIORITY_LITE … #define THROT_PRIORITY_LITE_PRIO_MASK … #define THROT_DELAY_LITE … #define THROT_DELAY_LITE_DELAY_MASK … /* car register offsets needed for enabling HW throttling */ #define CAR_SUPER_CCLKG_DIVIDER … #define CDIVG_USE_THERM_CONTROLS_MASK … /* ccroc register offsets needed for enabling HW throttling for Tegra132 */ #define CCROC_SUPER_CCLKG_DIVIDER … #define CCROC_GLOBAL_CFG … #define CCROC_THROT_PSKIP_RAMP_CPU … #define CCROC_THROT_PSKIP_RAMP_SEQ_BYPASS_MODE_MASK … #define CCROC_THROT_PSKIP_RAMP_DURATION_MASK … #define CCROC_THROT_PSKIP_RAMP_STEP_MASK … #define CCROC_THROT_PSKIP_CTRL_CPU … #define CCROC_THROT_PSKIP_CTRL_ENB_MASK … #define CCROC_THROT_PSKIP_CTRL_DIVIDEND_MASK … #define CCROC_THROT_PSKIP_CTRL_DIVISOR_MASK … /* get val from register(r) mask bits(m) */ #define REG_GET_MASK(r, m) … /* set val(v) to mask bits(m) of register(r) */ #define REG_SET_MASK(r, m, v) … /* get dividend from the depth */ #define THROT_DEPTH_DIVIDEND(depth) … /* gk20a nv_therm interface N:3 Mapping. Levels defined in tegra124-soctherm.h * level vector * NONE 3'b000 * LOW 3'b001 * MED 3'b011 * HIGH 3'b111 */ #define THROT_LEVEL_TO_DEPTH(level) … /* get THROT_PSKIP_xxx offset per LIGHT/HEAVY throt and CPU/GPU dev */ #define THROT_OFFSET … #define THROT_PSKIP_CTRL(throt, dev) … #define THROT_PSKIP_RAMP(throt, dev) … /* get THROT_xxx_CTRL offset per LIGHT/HEAVY throt */ #define THROT_PRIORITY_CTRL(throt) … #define THROT_DELAY_CTRL(throt) … #define ALARM_OFFSET … #define ALARM_CFG(throt) … #define ALARM_CNT_THRESHOLD(throt) … #define ALARM_THROTTLE_PERIOD(throt) … #define ALARM_ALARM_COUNT(throt) … #define ALARM_FILTER(throt) … #define ALARM_STATS(throt) … /* get CCROC_THROT_PSKIP_xxx offset per HIGH/MED/LOW vect*/ #define CCROC_THROT_OFFSET … #define CCROC_THROT_PSKIP_CTRL_CPU_REG(vect) … #define CCROC_THROT_PSKIP_RAMP_CPU_REG(vect) … /* get THERMCTL_LEVELx offset per CPU/GPU/MEM/TSENSE rg and LEVEL0~3 lv */ #define THERMCTL_LVL_REGS_SIZE … #define THERMCTL_LVL_REG(rg, lv) … #define OC_THROTTLE_MODE_DISABLED … #define OC_THROTTLE_MODE_BRIEF … static const int min_low_temp = …; static const int max_high_temp = …; enum soctherm_throttle_id { … }; enum soctherm_oc_irq_id { … }; enum soctherm_throttle_dev_id { … }; static const char *const throt_names[] = …; struct tegra_soctherm; struct tegra_thermctl_zone { … }; struct soctherm_oc_cfg { … }; struct soctherm_throt_cfg { … }; struct tegra_soctherm { … }; struct soctherm_oc_irq_chip_data { … }; static struct soctherm_oc_irq_chip_data soc_irq_cdata; /** * ccroc_writel() - writes a value to a CCROC register * @ts: pointer to a struct tegra_soctherm * @value: the value to write * @reg: the register offset * * Writes @v to @reg. No return value. */ static inline void ccroc_writel(struct tegra_soctherm *ts, u32 value, u32 reg) { … } /** * ccroc_readl() - reads specified register from CCROC IP block * @ts: pointer to a struct tegra_soctherm * @reg: register address to be read * * Return: the value of the register */ static inline u32 ccroc_readl(struct tegra_soctherm *ts, u32 reg) { … } static void enable_tsensor(struct tegra_soctherm *tegra, unsigned int i) { … } /* * Translate from soctherm readback format to millicelsius. * The soctherm readback format in bits is as follows: * TTTTTTTT H______N * where T's contain the temperature in Celsius, * H denotes an addition of 0.5 Celsius and N denotes negation * of the final value. */ static int translate_temp(u16 val) { … } static int tegra_thermctl_get_temp(struct thermal_zone_device *tz, int *out_temp) { … } /** * enforce_temp_range() - check and enforce temperature range [min, max] * @dev: struct device * of the SOC_THERM instance * @trip_temp: the trip temperature to check * * Checks and enforces the permitted temperature range that SOC_THERM * HW can support This is * done while taking care of precision. * * Return: The precision adjusted capped temperature in millicelsius. */ static int enforce_temp_range(struct device *dev, int trip_temp) { … } /** * thermtrip_program() - Configures the hardware to shut down the * system if a given sensor group reaches a given temperature * @dev: ptr to the struct device for the SOC_THERM IP block * @sg: pointer to the sensor group to set the thermtrip temperature for * @trip_temp: the temperature in millicelsius to trigger the thermal trip at * * Sets the thermal trip threshold of the given sensor group to be the * @trip_temp. If this threshold is crossed, the hardware will shut * down. * * Note that, although @trip_temp is specified in millicelsius, the * hardware is programmed in degrees Celsius. * * Return: 0 upon success, or %-EINVAL upon failure. */ static int thermtrip_program(struct device *dev, const struct tegra_tsensor_group *sg, int trip_temp) { … } /** * throttrip_program() - Configures the hardware to throttle the * pulse if a given sensor group reaches a given temperature * @dev: ptr to the struct device for the SOC_THERM IP block * @sg: pointer to the sensor group to set the thermtrip temperature for * @stc: pointer to the throttle need to be triggered * @trip_temp: the temperature in millicelsius to trigger the thermal trip at * * Sets the thermal trip threshold and throttle event of the given sensor * group. If this threshold is crossed, the hardware will trigger the * throttle. * * Note that, although @trip_temp is specified in millicelsius, the * hardware is programmed in degrees Celsius. * * Return: 0 upon success, or %-EINVAL upon failure. */ static int throttrip_program(struct device *dev, const struct tegra_tsensor_group *sg, struct soctherm_throt_cfg *stc, int trip_temp) { … } static struct soctherm_throt_cfg * find_throttle_cfg_by_name(struct tegra_soctherm *ts, const char *name) { … } static int tsensor_group_thermtrip_get(struct tegra_soctherm *ts, int id) { … } static int tegra_thermctl_set_trip_temp(struct thermal_zone_device *tz, const struct thermal_trip *trip, int temp) { … } static void thermal_irq_enable(struct tegra_thermctl_zone *zn) { … } static void thermal_irq_disable(struct tegra_thermctl_zone *zn) { … } static int tegra_thermctl_set_trips(struct thermal_zone_device *tz, int lo, int hi) { … } static const struct thermal_zone_device_ops tegra_of_thermal_ops = …; static int get_hot_temp(struct thermal_zone_device *tz, int *trip_id, int *temp) { … } /** * tegra_soctherm_set_hwtrips() - set HW trip point from DT data * @dev: struct device * of the SOC_THERM instance * @sg: pointer to the sensor group to set the thermtrip temperature for * @tz: struct thermal_zone_device * * * Configure the SOC_THERM HW trip points, setting "THERMTRIP" * "THROTTLE" trip points , using "thermtrips", "critical" or "hot" * type trip_temp * from thermal zone. * After they have been configured, THERMTRIP or THROTTLE will take * action when the configured SoC thermal sensor group reaches a * certain temperature. * * Return: 0 upon success, or a negative error code on failure. * "Success" does not mean that trips was enabled; it could also * mean that no node was found in DT. * THERMTRIP has been enabled successfully when a message similar to * this one appears on the serial console: * "thermtrip: will shut down when sensor group XXX reaches YYYYYY mC" * THROTTLE has been enabled successfully when a message similar to * this one appears on the serial console: * ""throttrip: will throttle when sensor group XXX reaches YYYYYY mC" */ static int tegra_soctherm_set_hwtrips(struct device *dev, const struct tegra_tsensor_group *sg, struct thermal_zone_device *tz) { … } static irqreturn_t soctherm_thermal_isr(int irq, void *dev_id) { … } /** * soctherm_thermal_isr_thread() - Handles a thermal interrupt request * @irq: The interrupt number being requested; not used * @dev_id: Opaque pointer to tegra_soctherm; * * Clears the interrupt status register if there are expected * interrupt bits set. * The interrupt(s) are then handled by updating the corresponding * thermal zones. * * An error is logged if any unexpected interrupt bits are set. * * Disabled interrupts are re-enabled. * * Return: %IRQ_HANDLED. Interrupt was handled and no further processing * is needed. */ static irqreturn_t soctherm_thermal_isr_thread(int irq, void *dev_id) { … } /** * soctherm_oc_intr_enable() - Enables the soctherm over-current interrupt * @ts: pointer to a struct tegra_soctherm * @alarm: The soctherm throttle id * @enable: Flag indicating enable the soctherm over-current * interrupt or disable it * * Enables a specific over-current pins @alarm to raise an interrupt if the flag * is set and the alarm corresponds to OC1, OC2, OC3, or OC4. */ static void soctherm_oc_intr_enable(struct tegra_soctherm *ts, enum soctherm_throttle_id alarm, bool enable) { … } /** * soctherm_handle_alarm() - Handles soctherm alarms * @alarm: The soctherm throttle id * * "Handles" over-current alarms (OC1, OC2, OC3, and OC4) by printing * a warning or informative message. * * Return: -EINVAL for @alarm = THROTTLE_OC3, otherwise 0 (success). */ static int soctherm_handle_alarm(enum soctherm_throttle_id alarm) { … } /** * soctherm_edp_isr_thread() - log an over-current interrupt request * @irq: OC irq number. Currently not being used. See description * @arg: a void pointer for callback, currently not being used * * Over-current events are handled in hardware. This function is called to log * and handle any OC events that happened. Additionally, it checks every * over-current interrupt registers for registers are set but * was not expected (i.e. any discrepancy in interrupt status) by the function, * the discrepancy will logged. * * Return: %IRQ_HANDLED */ static irqreturn_t soctherm_edp_isr_thread(int irq, void *arg) { … } /** * soctherm_edp_isr() - Disables any active interrupts * @irq: The interrupt request number * @arg: Opaque pointer to an argument * * Writes to the OC_INTR_DISABLE register the over current interrupt status, * masking any asserted interrupts. Doing this prevents the same interrupts * from triggering this isr repeatedly. The thread woken by this isr will * handle asserted interrupts and subsequently unmask/re-enable them. * * The OC_INTR_DISABLE register indicates which OC interrupts * have been disabled. * * Return: %IRQ_WAKE_THREAD, handler requests to wake the handler thread */ static irqreturn_t soctherm_edp_isr(int irq, void *arg) { … } /** * soctherm_oc_irq_lock() - locks the over-current interrupt request * @data: Interrupt request data * * Looks up the chip data from @data and locks the mutex associated with * a particular over-current interrupt request. */ static void soctherm_oc_irq_lock(struct irq_data *data) { … } /** * soctherm_oc_irq_sync_unlock() - Unlocks the OC interrupt request * @data: Interrupt request data * * Looks up the interrupt request data @data and unlocks the mutex associated * with a particular over-current interrupt request. */ static void soctherm_oc_irq_sync_unlock(struct irq_data *data) { … } /** * soctherm_oc_irq_enable() - Enables the SOC_THERM over-current interrupt queue * @data: irq_data structure of the chip * * Sets the irq_enable bit of SOC_THERM allowing SOC_THERM * to respond to over-current interrupts. * */ static void soctherm_oc_irq_enable(struct irq_data *data) { … } /** * soctherm_oc_irq_disable() - Disables overcurrent interrupt requests * @data: The interrupt request information * * Clears the interrupt request enable bit of the overcurrent * interrupt request chip data. * * Return: Nothing is returned (void) */ static void soctherm_oc_irq_disable(struct irq_data *data) { … } static int soctherm_oc_irq_set_type(struct irq_data *data, unsigned int type) { … } /** * soctherm_oc_irq_map() - SOC_THERM interrupt request domain mapper * @h: Interrupt request domain * @virq: Virtual interrupt request number * @hw: Hardware interrupt request number * * Mapping callback function for SOC_THERM's irq_domain. When a SOC_THERM * interrupt request is called, the irq_domain takes the request's virtual * request number (much like a virtual memory address) and maps it to a * physical hardware request number. * * When a mapping doesn't already exist for a virtual request number, the * irq_domain calls this function to associate the virtual request number with * a hardware request number. * * Return: 0 */ static int soctherm_oc_irq_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { … } /** * soctherm_irq_domain_xlate_twocell() - xlate for soctherm interrupts * @d: Interrupt request domain * @ctrlr: Controller device tree node * @intspec: Array of u32s from DTs "interrupt" property * @intsize: Number of values inside the intspec array * @out_hwirq: HW IRQ value associated with this interrupt * @out_type: The IRQ SENSE type for this interrupt. * * This Device Tree IRQ specifier translation function will translate a * specific "interrupt" as defined by 2 DT values where the cell values map * the hwirq number + 1 and linux irq flags. Since the output is the hwirq * number, this function will subtract 1 from the value listed in DT. * * Return: 0 */ static int soctherm_irq_domain_xlate_twocell(struct irq_domain *d, struct device_node *ctrlr, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_type) { … } static const struct irq_domain_ops soctherm_oc_domain_ops = …; /** * soctherm_oc_int_init() - Initial enabling of the over * current interrupts * @np: The devicetree node for soctherm * @num_irqs: The number of new interrupt requests * * Sets the over current interrupt request chip data * * Return: 0 on success or if overcurrent interrupts are not enabled, * -ENOMEM (out of memory), or irq_base if the function failed to * allocate the irqs */ static int soctherm_oc_int_init(struct device_node *np, int num_irqs) { … } #ifdef CONFIG_DEBUG_FS static int regs_show(struct seq_file *s, void *data) { … } DEFINE_SHOW_ATTRIBUTE(…); static void soctherm_debug_init(struct platform_device *pdev) { … } #else static inline void soctherm_debug_init(struct platform_device *pdev) {} #endif static int soctherm_clk_enable(struct platform_device *pdev, bool enable) { … } static int throt_get_cdev_max_state(struct thermal_cooling_device *cdev, unsigned long *max_state) { … } static int throt_get_cdev_cur_state(struct thermal_cooling_device *cdev, unsigned long *cur_state) { … } static int throt_set_cdev_state(struct thermal_cooling_device *cdev, unsigned long cur_state) { … } static const struct thermal_cooling_device_ops throt_cooling_ops = …; static int soctherm_thermtrips_parse(struct platform_device *pdev) { … } static void soctherm_oc_cfg_parse(struct device *dev, struct device_node *np_oc, struct soctherm_throt_cfg *stc) { … } static int soctherm_throt_cfg_parse(struct device *dev, struct device_node *np, struct soctherm_throt_cfg *stc) { … } /** * soctherm_init_hw_throt_cdev() - Parse the HW throttle configurations * and register them as cooling devices. * @pdev: Pointer to platform_device struct */ static void soctherm_init_hw_throt_cdev(struct platform_device *pdev) { … } /** * throttlectl_cpu_level_cfg() - programs CCROC NV_THERM level config * @ts: pointer to a struct tegra_soctherm * @level: describing the level LOW/MED/HIGH of throttling * * It's necessary to set up the CPU-local CCROC NV_THERM instance with * the M/N values desired for each level. This function does this. * * This function pre-programs the CCROC NV_THERM levels in terms of * pre-configured "Low", "Medium" or "Heavy" throttle levels which are * mapped to THROT_LEVEL_LOW, THROT_LEVEL_MED and THROT_LEVEL_HVY. */ static void throttlectl_cpu_level_cfg(struct tegra_soctherm *ts, int level) { … } /** * throttlectl_cpu_level_select() - program CPU pulse skipper config * @ts: pointer to a struct tegra_soctherm * @throt: the LIGHT/HEAVY of throttle event id * * Pulse skippers are used to throttle clock frequencies. This * function programs the pulse skippers based on @throt and platform * data. This function is used on SoCs which have CPU-local pulse * skipper control, such as T13x. It programs soctherm's interface to * Denver:CCROC NV_THERM in terms of Low, Medium and HIGH throttling * vectors. PSKIP_BYPASS mode is set as required per HW spec. */ static void throttlectl_cpu_level_select(struct tegra_soctherm *ts, enum soctherm_throttle_id throt) { … } /** * throttlectl_cpu_mn() - program CPU pulse skipper configuration * @ts: pointer to a struct tegra_soctherm * @throt: the LIGHT/HEAVY of throttle event id * * Pulse skippers are used to throttle clock frequencies. This * function programs the pulse skippers based on @throt and platform * data. This function is used for CPUs that have "remote" pulse * skipper control, e.g., the CPU pulse skipper is controlled by the * SOC_THERM IP block. (SOC_THERM is located outside the CPU * complex.) */ static void throttlectl_cpu_mn(struct tegra_soctherm *ts, enum soctherm_throttle_id throt) { … } /** * throttlectl_gpu_level_select() - selects throttling level for GPU * @ts: pointer to a struct tegra_soctherm * @throt: the LIGHT/HEAVY of throttle event id * * This function programs soctherm's interface to GK20a NV_THERM to select * pre-configured "Low", "Medium" or "Heavy" throttle levels. * * Return: boolean true if HW was programmed */ static void throttlectl_gpu_level_select(struct tegra_soctherm *ts, enum soctherm_throttle_id throt) { … } static int soctherm_oc_cfg_program(struct tegra_soctherm *ts, enum soctherm_throttle_id throt) { … } /** * soctherm_throttle_program() - programs pulse skippers' configuration * @ts: pointer to a struct tegra_soctherm * @throt: the LIGHT/HEAVY of the throttle event id. * * Pulse skippers are used to throttle clock frequencies. * This function programs the pulse skippers. */ static void soctherm_throttle_program(struct tegra_soctherm *ts, enum soctherm_throttle_id throt) { … } static void tegra_soctherm_throttle(struct device *dev) { … } static int soctherm_interrupts_init(struct platform_device *pdev, struct tegra_soctherm *tegra) { … } static void soctherm_init(struct platform_device *pdev) { … } static const struct of_device_id tegra_soctherm_of_match[] = …; MODULE_DEVICE_TABLE(of, tegra_soctherm_of_match); static int tegra_soctherm_probe(struct platform_device *pdev) { … } static void tegra_soctherm_remove(struct platform_device *pdev) { … } static int __maybe_unused soctherm_suspend(struct device *dev) { … } static int __maybe_unused soctherm_resume(struct device *dev) { … } static SIMPLE_DEV_PM_OPS(tegra_soctherm_pm, soctherm_suspend, soctherm_resume); static struct platform_driver tegra_soctherm_driver = …; module_platform_driver(…) …; MODULE_AUTHOR(…) …; MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …;