mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-05 10:29:37 +00:00
thermal: exynos: Add driver support for exynos5440 TMU sensor
This patch modifies TMU controller to add changes needed to work with exynos5440 platform. This sensor registers 3 instance of the tmu controller with the thermal zone and hence reports 3 temperature output. This controller supports upto five trip points. For critical threshold the driver uses the core driver thermal framework for shutdown. Acked-by: Jonghwa Lee <jonghwa3.lee@samsung.com> Acked-by: Kukjin Kim <kgene.kim@samsung.com> Signed-off-by: Jungseok Lee <jays.lee@samsung.com> Signed-off-by: Amit Daniel Kachhap <amit.daniel@samsung.com> Acked-by: Eduardo Valentin <eduardo.valentin@ti.com> Signed-off-by: Eduardo Valentin <eduardo.valentin@ti.com>
This commit is contained in:
parent
d9b6ee148d
commit
a0395eee7c
4 changed files with 90 additions and 9 deletions
|
@ -27,7 +27,7 @@
|
|||
#define SENSOR_NAME_LEN 16
|
||||
#define MAX_TRIP_COUNT 8
|
||||
#define MAX_COOLING_DEVICE 4
|
||||
#define MAX_THRESHOLD_LEVS 4
|
||||
#define MAX_THRESHOLD_LEVS 5
|
||||
|
||||
#define ACTIVE_INTERVAL 500
|
||||
#define IDLE_INTERVAL 10000
|
||||
|
|
|
@ -156,7 +156,26 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
|
|||
__raw_writel(1, data->base + reg->triminfo_ctrl);
|
||||
|
||||
/* Save trimming info in order to perform calibration */
|
||||
trim_info = readl(data->base + reg->triminfo_data);
|
||||
if (data->soc == SOC_ARCH_EXYNOS5440) {
|
||||
/*
|
||||
* For exynos5440 soc triminfo value is swapped between TMU0 and
|
||||
* TMU2, so the below logic is needed.
|
||||
*/
|
||||
switch (data->id) {
|
||||
case 0:
|
||||
trim_info = readl(data->base +
|
||||
EXYNOS5440_EFUSE_SWAP_OFFSET + reg->triminfo_data);
|
||||
break;
|
||||
case 1:
|
||||
trim_info = readl(data->base + reg->triminfo_data);
|
||||
break;
|
||||
case 2:
|
||||
trim_info = readl(data->base -
|
||||
EXYNOS5440_EFUSE_SWAP_OFFSET + reg->triminfo_data);
|
||||
}
|
||||
} else {
|
||||
trim_info = readl(data->base + reg->triminfo_data);
|
||||
}
|
||||
data->temp_error1 = trim_info & EXYNOS_TMU_TEMP_MASK;
|
||||
data->temp_error2 = ((trim_info >> reg->triminfo_85_shift) &
|
||||
EXYNOS_TMU_TEMP_MASK);
|
||||
|
@ -201,7 +220,7 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
|
|||
reg->threshold_th0 + i * sizeof(reg->threshold_th0));
|
||||
|
||||
writel(reg->inten_rise_mask, data->base + reg->tmu_intclear);
|
||||
} else if (data->soc == SOC_ARCH_EXYNOS) {
|
||||
} else {
|
||||
/* Write temperature code for rising and falling threshold */
|
||||
for (i = 0;
|
||||
i < trigger_levs && i < EXYNOS_MAX_TRIGGER_PER_REG; i++) {
|
||||
|
@ -241,14 +260,26 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
|
|||
ret = threshold_code;
|
||||
goto out;
|
||||
}
|
||||
rising_threshold |= threshold_code << 8 * i;
|
||||
writel(rising_threshold,
|
||||
data->base + reg->threshold_th0);
|
||||
if (i == EXYNOS_MAX_TRIGGER_PER_REG - 1) {
|
||||
/* 1-4 level to be assigned in th0 reg */
|
||||
rising_threshold |= threshold_code << 8 * i;
|
||||
writel(rising_threshold,
|
||||
data->base + reg->threshold_th0);
|
||||
} else if (i == EXYNOS_MAX_TRIGGER_PER_REG) {
|
||||
/* 5th level to be assigned in th2 reg */
|
||||
rising_threshold =
|
||||
threshold_code << reg->threshold_th3_l0_shift;
|
||||
writel(rising_threshold,
|
||||
data->base + reg->threshold_th2);
|
||||
}
|
||||
con = readl(data->base + reg->tmu_ctrl);
|
||||
con |= (1 << reg->therm_trip_en_shift);
|
||||
writel(con, data->base + reg->tmu_ctrl);
|
||||
}
|
||||
}
|
||||
/*Clear the PMIN in the common TMU register*/
|
||||
if (reg->tmu_pmin && !data->id)
|
||||
writel(0, data->base_common + reg->tmu_pmin);
|
||||
out:
|
||||
clk_disable(data->clk);
|
||||
mutex_unlock(&data->lock);
|
||||
|
@ -377,7 +408,14 @@ static void exynos_tmu_work(struct work_struct *work)
|
|||
struct exynos_tmu_data, irq_work);
|
||||
struct exynos_tmu_platform_data *pdata = data->pdata;
|
||||
const struct exynos_tmu_registers *reg = pdata->registers;
|
||||
unsigned int val_irq;
|
||||
unsigned int val_irq, val_type;
|
||||
|
||||
/* Find which sensor generated this interrupt */
|
||||
if (reg->tmu_irqstatus) {
|
||||
val_type = readl(data->base_common + reg->tmu_irqstatus);
|
||||
if (!((val_type >> data->id) & 0x1))
|
||||
goto out;
|
||||
}
|
||||
|
||||
exynos_report_trigger(data->reg_conf);
|
||||
mutex_lock(&data->lock);
|
||||
|
@ -390,7 +428,7 @@ static void exynos_tmu_work(struct work_struct *work)
|
|||
|
||||
clk_disable(data->clk);
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
out:
|
||||
enable_irq(data->irq);
|
||||
}
|
||||
|
||||
|
@ -538,7 +576,8 @@ static int exynos_tmu_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
|
||||
if (pdata->type == SOC_ARCH_EXYNOS ||
|
||||
pdata->type == SOC_ARCH_EXYNOS4210)
|
||||
pdata->type == SOC_ARCH_EXYNOS4210 ||
|
||||
pdata->type == SOC_ARCH_EXYNOS5440)
|
||||
data->soc = pdata->type;
|
||||
else {
|
||||
ret = -EINVAL;
|
||||
|
|
|
@ -40,6 +40,7 @@ enum calibration_mode {
|
|||
enum soc_type {
|
||||
SOC_ARCH_EXYNOS4210 = 1,
|
||||
SOC_ARCH_EXYNOS,
|
||||
SOC_ARCH_EXYNOS5440,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -131,6 +132,8 @@ enum soc_type {
|
|||
* @emul_temp_shift: shift bits of emulation temperature.
|
||||
* @emul_time_shift: shift bits of emulation time.
|
||||
* @emul_time_mask: mask bits of emulation time.
|
||||
* @tmu_irqstatus: register to find which TMU generated interrupts.
|
||||
* @tmu_pmin: register to get/set the Pmin value.
|
||||
*/
|
||||
struct exynos_tmu_registers {
|
||||
u32 triminfo_data;
|
||||
|
@ -198,6 +201,9 @@ struct exynos_tmu_registers {
|
|||
u32 emul_temp_shift;
|
||||
u32 emul_time_shift;
|
||||
u32 emul_time_mask;
|
||||
|
||||
u32 tmu_irqstatus;
|
||||
u32 tmu_pmin;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -93,6 +93,42 @@
|
|||
|
||||
#define EXYNOS_MAX_TRIGGER_PER_REG 4
|
||||
|
||||
/*exynos5440 specific registers*/
|
||||
#define EXYNOS5440_TMU_S0_7_TRIM 0x000
|
||||
#define EXYNOS5440_TMU_S0_7_CTRL 0x020
|
||||
#define EXYNOS5440_TMU_S0_7_DEBUG 0x040
|
||||
#define EXYNOS5440_TMU_S0_7_STATUS 0x060
|
||||
#define EXYNOS5440_TMU_S0_7_TEMP 0x0f0
|
||||
#define EXYNOS5440_TMU_S0_7_TH0 0x110
|
||||
#define EXYNOS5440_TMU_S0_7_TH1 0x130
|
||||
#define EXYNOS5440_TMU_S0_7_TH2 0x150
|
||||
#define EXYNOS5440_TMU_S0_7_EVTEN 0x1F0
|
||||
#define EXYNOS5440_TMU_S0_7_IRQEN 0x210
|
||||
#define EXYNOS5440_TMU_S0_7_IRQ 0x230
|
||||
/* exynos5440 common registers */
|
||||
#define EXYNOS5440_TMU_IRQ_STATUS 0x000
|
||||
#define EXYNOS5440_TMU_PMIN 0x004
|
||||
#define EXYNOS5440_TMU_TEMP 0x008
|
||||
|
||||
#define EXYNOS5440_TMU_RISE_INT_MASK 0xf
|
||||
#define EXYNOS5440_TMU_RISE_INT_SHIFT 0
|
||||
#define EXYNOS5440_TMU_FALL_INT_MASK 0xf
|
||||
#define EXYNOS5440_TMU_FALL_INT_SHIFT 4
|
||||
#define EXYNOS5440_TMU_INTEN_RISE0_SHIFT 0
|
||||
#define EXYNOS5440_TMU_INTEN_RISE1_SHIFT 1
|
||||
#define EXYNOS5440_TMU_INTEN_RISE2_SHIFT 2
|
||||
#define EXYNOS5440_TMU_INTEN_RISE3_SHIFT 3
|
||||
#define EXYNOS5440_TMU_INTEN_FALL0_SHIFT 4
|
||||
#define EXYNOS5440_TMU_INTEN_FALL1_SHIFT 5
|
||||
#define EXYNOS5440_TMU_INTEN_FALL2_SHIFT 6
|
||||
#define EXYNOS5440_TMU_INTEN_FALL3_SHIFT 7
|
||||
#define EXYNOS5440_TMU_TH_RISE0_SHIFT 0
|
||||
#define EXYNOS5440_TMU_TH_RISE1_SHIFT 8
|
||||
#define EXYNOS5440_TMU_TH_RISE2_SHIFT 16
|
||||
#define EXYNOS5440_TMU_TH_RISE3_SHIFT 24
|
||||
#define EXYNOS5440_TMU_TH_RISE4_SHIFT 24
|
||||
#define EXYNOS5440_EFUSE_SWAP_OFFSET 8
|
||||
|
||||
#if defined(CONFIG_CPU_EXYNOS4210)
|
||||
extern struct exynos_tmu_init_data const exynos4210_default_tmu_data;
|
||||
#define EXYNOS4210_TMU_DRV_DATA (&exynos4210_default_tmu_data)
|
||||
|
|
Loading…
Reference in a new issue