ahci: imx: Add imx53 SATA temperature sensor support
Add a hwmon entry to get the temperature from the die of imx53 SATA. The original patch was made by Richard Zhu for kernel 2.6.x: ENGR00134041-MX53-Add-the-SATA-AHCI-temperature-monitor.patch Signed-off-by: Fabien Lahoudere <fabien.lahoudere@collabora.co.uk> Signed-off-by: Tejun Heo <tj@kernel.org>
This commit is contained in:
parent
de2518201e
commit
54643a83b4
1 changed files with 195 additions and 0 deletions
|
@ -26,6 +26,9 @@
|
|||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
|
||||
#include <linux/libata.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/thermal.h>
|
||||
#include "ahci.h"
|
||||
|
||||
#define DRV_NAME "ahci-imx"
|
||||
|
@ -214,6 +217,180 @@ static int imx_sata_phy_reset(struct ahci_host_priv *hpriv)
|
|||
return timeout ? 0 : -ETIMEDOUT;
|
||||
}
|
||||
|
||||
enum {
|
||||
/* SATA PHY Register */
|
||||
SATA_PHY_CR_CLOCK_CRCMP_LT_LIMIT = 0x0001,
|
||||
SATA_PHY_CR_CLOCK_DAC_CTL = 0x0008,
|
||||
SATA_PHY_CR_CLOCK_RTUNE_CTL = 0x0009,
|
||||
SATA_PHY_CR_CLOCK_ADC_OUT = 0x000A,
|
||||
SATA_PHY_CR_CLOCK_MPLL_TST = 0x0017,
|
||||
};
|
||||
|
||||
static int read_adc_sum(void *dev, u16 rtune_ctl_reg, void __iomem * mmio)
|
||||
{
|
||||
u16 adc_out_reg, read_sum;
|
||||
u32 index, read_attempt;
|
||||
const u32 attempt_limit = 100;
|
||||
|
||||
imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_RTUNE_CTL, mmio);
|
||||
imx_phy_reg_write(rtune_ctl_reg, mmio);
|
||||
|
||||
/* two dummy read */
|
||||
index = 0;
|
||||
read_attempt = 0;
|
||||
adc_out_reg = 0;
|
||||
imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_ADC_OUT, mmio);
|
||||
while (index < 2) {
|
||||
imx_phy_reg_read(&adc_out_reg, mmio);
|
||||
/* check if valid */
|
||||
if (adc_out_reg & 0x400)
|
||||
index++;
|
||||
|
||||
read_attempt++;
|
||||
if (read_attempt > attempt_limit) {
|
||||
dev_err(dev, "Read REG more than %d times!\n",
|
||||
attempt_limit);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
index = 0;
|
||||
read_attempt = 0;
|
||||
read_sum = 0;
|
||||
while (index < 80) {
|
||||
imx_phy_reg_read(&adc_out_reg, mmio);
|
||||
if (adc_out_reg & 0x400) {
|
||||
read_sum = read_sum + (adc_out_reg & 0x3FF);
|
||||
index++;
|
||||
}
|
||||
read_attempt++;
|
||||
if (read_attempt > attempt_limit) {
|
||||
dev_err(dev, "Read REG more than %d times!\n",
|
||||
attempt_limit);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Use the U32 to make 1000 precision */
|
||||
return (read_sum * 1000) / 80;
|
||||
}
|
||||
|
||||
/* SATA AHCI temperature monitor */
|
||||
static int sata_ahci_read_temperature(void *dev, int *temp)
|
||||
{
|
||||
u16 mpll_test_reg, rtune_ctl_reg, dac_ctl_reg, read_sum;
|
||||
u32 str1, str2, str3, str4;
|
||||
int m1, m2, a;
|
||||
struct ahci_host_priv *hpriv = dev_get_drvdata(dev);
|
||||
void __iomem *mmio = hpriv->mmio;
|
||||
|
||||
/* check rd-wr to reg */
|
||||
read_sum = 0;
|
||||
imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_CRCMP_LT_LIMIT, mmio);
|
||||
imx_phy_reg_write(read_sum, mmio);
|
||||
imx_phy_reg_read(&read_sum, mmio);
|
||||
if ((read_sum & 0xffff) != 0)
|
||||
dev_err(dev, "Read/Write REG error, 0x%x!\n", read_sum);
|
||||
|
||||
imx_phy_reg_write(0x5A5A, mmio);
|
||||
imx_phy_reg_read(&read_sum, mmio);
|
||||
if ((read_sum & 0xffff) != 0x5A5A)
|
||||
dev_err(dev, "Read/Write REG error, 0x%x!\n", read_sum);
|
||||
|
||||
imx_phy_reg_write(0x1234, mmio);
|
||||
imx_phy_reg_read(&read_sum, mmio);
|
||||
if ((read_sum & 0xffff) != 0x1234)
|
||||
dev_err(dev, "Read/Write REG error, 0x%x!\n", read_sum);
|
||||
|
||||
/* start temperature test */
|
||||
imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_MPLL_TST, mmio);
|
||||
imx_phy_reg_read(&mpll_test_reg, mmio);
|
||||
imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_RTUNE_CTL, mmio);
|
||||
imx_phy_reg_read(&rtune_ctl_reg, mmio);
|
||||
imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_DAC_CTL, mmio);
|
||||
imx_phy_reg_read(&dac_ctl_reg, mmio);
|
||||
|
||||
/* mpll_tst.meas_iv ([12:2]) */
|
||||
str1 = (mpll_test_reg >> 2) & 0x7FF;
|
||||
/* rtune_ctl.mode ([1:0]) */
|
||||
str2 = (rtune_ctl_reg) & 0x3;
|
||||
/* dac_ctl.dac_mode ([14:12]) */
|
||||
str3 = (dac_ctl_reg >> 12) & 0x7;
|
||||
/* rtune_ctl.sel_atbp ([4]) */
|
||||
str4 = (rtune_ctl_reg >> 4);
|
||||
|
||||
/* Calculate the m1 */
|
||||
/* mpll_tst.meas_iv */
|
||||
mpll_test_reg = (mpll_test_reg & 0xE03) | (512) << 2;
|
||||
/* rtune_ctl.mode */
|
||||
rtune_ctl_reg = (rtune_ctl_reg & 0xFFC) | (1);
|
||||
/* dac_ctl.dac_mode */
|
||||
dac_ctl_reg = (dac_ctl_reg & 0x8FF) | (4) << 12;
|
||||
/* rtune_ctl.sel_atbp */
|
||||
rtune_ctl_reg = (rtune_ctl_reg & 0xFEF) | (0) << 4;
|
||||
imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_MPLL_TST, mmio);
|
||||
imx_phy_reg_write(mpll_test_reg, mmio);
|
||||
imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_DAC_CTL, mmio);
|
||||
imx_phy_reg_write(dac_ctl_reg, mmio);
|
||||
m1 = read_adc_sum(dev, rtune_ctl_reg, mmio);
|
||||
|
||||
/* Calculate the m2 */
|
||||
/* rtune_ctl.sel_atbp */
|
||||
rtune_ctl_reg = (rtune_ctl_reg & 0xFEF) | (1) << 4;
|
||||
m2 = read_adc_sum(dev, rtune_ctl_reg, mmio);
|
||||
|
||||
/* restore the status */
|
||||
/* mpll_tst.meas_iv */
|
||||
mpll_test_reg = (mpll_test_reg & 0xE03) | (str1) << 2;
|
||||
/* rtune_ctl.mode */
|
||||
rtune_ctl_reg = (rtune_ctl_reg & 0xFFC) | (str2);
|
||||
/* dac_ctl.dac_mode */
|
||||
dac_ctl_reg = (dac_ctl_reg & 0x8FF) | (str3) << 12;
|
||||
/* rtune_ctl.sel_atbp */
|
||||
rtune_ctl_reg = (rtune_ctl_reg & 0xFEF) | (str4) << 4;
|
||||
|
||||
imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_MPLL_TST, mmio);
|
||||
imx_phy_reg_write(mpll_test_reg, mmio);
|
||||
imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_DAC_CTL, mmio);
|
||||
imx_phy_reg_write(dac_ctl_reg, mmio);
|
||||
imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_RTUNE_CTL, mmio);
|
||||
imx_phy_reg_write(rtune_ctl_reg, mmio);
|
||||
|
||||
/* Compute temperature */
|
||||
if (!(m2 / 1000))
|
||||
m2 = 1000;
|
||||
a = (m2 - m1) / (m2/1000);
|
||||
*temp = ((-559) * a * a) / 1000 + (1379) * a + (-458000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t sata_ahci_show_temp(struct device *dev,
|
||||
struct device_attribute *da,
|
||||
char *buf)
|
||||
{
|
||||
unsigned int temp = 0;
|
||||
int err;
|
||||
|
||||
err = sata_ahci_read_temperature(dev, &temp);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return sprintf(buf, "%u\n", temp);
|
||||
}
|
||||
|
||||
static const struct thermal_zone_of_device_ops fsl_sata_ahci_of_thermal_ops = {
|
||||
.get_temp = sata_ahci_read_temperature,
|
||||
};
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, sata_ahci_show_temp, NULL, 0);
|
||||
|
||||
static struct attribute *fsl_sata_ahci_attrs[] = {
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
ATTRIBUTE_GROUPS(fsl_sata_ahci);
|
||||
|
||||
static int imx_sata_enable(struct ahci_host_priv *hpriv)
|
||||
{
|
||||
struct imx_ahci_priv *imxpriv = hpriv->plat_data;
|
||||
|
@ -597,6 +774,24 @@ static int imx_ahci_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (imxpriv->type == AHCI_IMX53) {
|
||||
/* Add the temperature monitor */
|
||||
struct device *hwmon_dev;
|
||||
|
||||
hwmon_dev =
|
||||
devm_hwmon_device_register_with_groups(dev,
|
||||
"sata_ahci",
|
||||
hpriv,
|
||||
fsl_sata_ahci_groups);
|
||||
if (IS_ERR(hwmon_dev)) {
|
||||
ret = PTR_ERR(hwmon_dev);
|
||||
goto disable_clk;
|
||||
}
|
||||
devm_thermal_zone_of_sensor_register(hwmon_dev, 0, hwmon_dev,
|
||||
&fsl_sata_ahci_of_thermal_ops);
|
||||
dev_info(dev, "%s: sensor 'sata_ahci'\n", dev_name(hwmon_dev));
|
||||
}
|
||||
|
||||
ret = imx_sata_enable(hpriv);
|
||||
if (ret)
|
||||
goto disable_clk;
|
||||
|
|
Loading…
Reference in a new issue