// SPDX-License-Identifier: GPL-2.0-only
/*
* TI Bandgap temperature sensor driver
*
* Copyright (C) 2011-2012 Texas Instruments Incorporated - http://www.ti.com/
* Author: J Keerthy <j-keerthy@ti.com>
* Author: Moiz Sonasath <m-sonasath@ti.com>
* Couple of fixes, DT and MFD adaptation:
* Eduardo Valentin <eduardo.valentin@ti.com>
*/
#include <linux/module.h>
#include <linux/export.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/clk.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/types.h>
#include <linux/spinlock.h>
#include <linux/reboot.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/of_irq.h>
#include <linux/io.h>
#include "ti-bandgap.h"
static int ti_bandgap_force_single_read(struct ti_bandgap *bgp, int id);
/*** Helper functions to access registers and their bitfields ***/
/**
* ti_bandgap_readl() - simple read helper function
* @bgp: pointer to ti_bandgap structure
* @reg: desired register (offset) to be read
*
* Helper function to read bandgap registers. It uses the io remapped area.
* Return: the register value.
*/
static u32 ti_bandgap_readl(struct ti_bandgap *bgp, u32 reg)
{
return readl(bgp->base + reg);
}
/**
* ti_bandgap_writel() - simple write helper function
* @bgp: pointer to ti_bandgap structure
* @val: desired register value to be written
* @reg: desired register (offset) to be written
*
* Helper function to write bandgap registers. It uses the io remapped area.
*/
static void ti_bandgap_writel(struct ti_bandgap *bgp, u32 val, u32 reg)
{
writel(val, bgp->base + reg);
}
/**
* DOC: macro to update bits.
*
* RMW_BITS() - used to read, modify and update bandgap bitfields.
* The value passed will be shifted.
*/
#define RMW_BITS(bgp, id, reg, mask, val) \
do { \
struct temp_sensor_registers *t; \
u32 r; \
\
t = bgp->conf->sensors[(id)].registers; \
r = ti_bandgap_readl(bgp, t->reg); \
r &= ~t->mask; \
r |= (val) << __ffs(t->mask); \
ti_bandgap_writel(bgp, r, t->reg); \
} while (0)
/*** Basic helper functions ***/
/**
* ti_bandgap_power() - controls the power state of a bandgap device
* @bgp: pointer to ti_bandgap structure
* @on: desired power state (1 - on, 0 - off)
*
* Used to power on/off a bandgap device instance. Only used on those
* that features tempsoff bit.
*
* Return: 0 on success, -ENOTSUPP if tempsoff is not supported.
*/
static int ti_bandgap_power(struct ti_bandgap *bgp, bool on)
{
int i;
if (!TI_BANDGAP_HAS(bgp, POWER_SWITCH))
return -ENOTSUPP;
for (i = 0; i < bgp->conf->sensor_count; i++)
/* active on 0 */
RMW_BITS(bgp, i, temp_sensor_ctrl, bgap_tempsoff_mask, !on);
return 0;
}
/**
* ti_errata814_bandgap_read_temp() - helper function to read dra7 sensor temperature
* @bgp: pointer to ti_bandgap structure
* @reg: desired register (offset) to be read
*
* Function to read dra7 bandgap sensor temperature. This is done separately
* so as to workaround the errata "Bandgap Temperature read Dtemp can be
* corrupted" - Errata ID: i814".
* Read accesses to registers listed below can be corrupted due to incorrect
* resynchronization between clock domains.
* Read access to registers below can be corrupted :
* CTRL_CORE_DTEMP_MPU/GPU/CORE/DSPEVE/IVA_n (n = 0 to 4)
* CTRL_CORE_TEMP_SENSOR_MPU/GPU/CORE/DSPEVE/IVA_n
*
* Return: the register value.
*/
static u32 ti_errata814_bandgap_read_temp(struct ti_bandgap *bgp, u32 reg)
{
u32 val1, val2;
val1 = ti_bandgap_readl(bgp, reg);
val2 = ti_bandgap_readl(bgp, reg);
/* If both times we read the same value then that is right */
if (val1 == val2)
return val1;
/* if val1 and val2 are different read it third time */
return ti_bandgap_readl(bgp, reg);
}
/**
* ti_bandgap_read_temp() - helper function to read sensor temperature
* @bgp: pointer to ti_bandgap structure
* @id: bandgap sensor id
*
* Function to concentrate the steps to read sensor temperature register.
* This function is desired because, depending on bandgap device version,
* it might be needed to freeze the bandgap state machine, before fetching
* the register value.
*
* Return: temperature in ADC values.
*/
static u32 ti_bandgap_read_temp(struct ti_bandgap *bgp