blob: 794522cde389b0955b9fea7171998252527cf459 [file] [edit]
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* s2mpg1x-meter.h
*
* Copyright (C) 2015 Samsung Electronics
*
* header file including shared meter functions of s2mpg1x
*/
#ifndef __LINUX_MFD_S2MPG1X_METER_H
#define __LINUX_MFD_S2MPG1X_METER_H
#include <linux/i2c.h>
#include <linux/mfd/samsung/s2mpg1x.h>
#include <linux/mfd/samsung/s2mpg1x-register.h>
#include <linux/fs.h>
typedef enum {
ADDRESS_CTRL1,
ADDRESS_CTRL2,
ADDRESS_BUCKEN1,
ADDRESS_LPF_C0_0,
ADDRESS_ACC_MODE,
ADDRESS_ACC_DATA,
ADDRESS_ACC_COUNT,
ADDRESS_LPF_MODE,
ADDRESS_LPF_DATA,
ADDRESS_COUNT,
} address_t;
#if IS_ENABLED(CONFIG_SOC_GS101)
static const int ADDRESS_AT[ADDRESS_COUNT][ID_COUNT] = {
[ADDRESS_CTRL1] = { S2MPG10_METER_CTRL1, S2MPG11_METER_CTRL1 },
[ADDRESS_CTRL2] = { S2MPG10_METER_CTRL2, S2MPG11_METER_CTRL2 },
[ADDRESS_BUCKEN1] = { S2MPG10_METER_BUCKEN1, S2MPG11_METER_BUCKEN1 },
[ADDRESS_LPF_C0_0] = { S2MPG10_METER_LPF_C0_0, S2MPG11_METER_LPF_C0_0 },
[ADDRESS_ACC_MODE] = { S2MPG10_METER_CTRL3, S2MPG11_METER_CTRL4 },
[ADDRESS_ACC_DATA] = {
S2MPG10_METER_ACC_DATA_CH0_1,
S2MPG11_METER_ACC_DATA_CH0_1
},
[ADDRESS_ACC_COUNT] = {
S2MPG10_METER_ACC_COUNT_1,
S2MPG11_METER_ACC_COUNT_1
},
[ADDRESS_LPF_MODE] = { S2MPG10_METER_CTRL4, S2MPG11_METER_CTRL5 },
[ADDRESS_LPF_DATA] = {
S2MPG10_METER_LPF_DATA_CH0_1,
S2MPG11_METER_LPF_DATA_CH0_1
},
};
#elif IS_ENABLED(CONFIG_SOC_GS201)
static const int ADDRESS_AT[ADDRESS_COUNT][ID_COUNT] = {
[ADDRESS_CTRL1] = { S2MPG12_METER_CTRL1, S2MPG13_METER_CTRL1 },
[ADDRESS_CTRL2] = { S2MPG12_METER_CTRL2, S2MPG13_METER_CTRL2 },
[ADDRESS_BUCKEN1] = { S2MPG12_METER_BUCKEN1, S2MPG13_METER_BUCKEN1 },
[ADDRESS_LPF_C0_0] = { S2MPG12_METER_LPF_C0_0, S2MPG13_METER_LPF_C0_0 },
[ADDRESS_ACC_MODE] = { S2MPG12_METER_CTRL4, S2MPG13_METER_CTRL4 },
[ADDRESS_ACC_DATA] = {
S2MPG12_METER_ACC_DATA_CH0_1,
S2MPG13_METER_ACC_DATA_CH0_1
},
[ADDRESS_ACC_COUNT] = {
S2MPG12_METER_ACC_COUNT_1,
S2MPG13_METER_ACC_COUNT_1
},
[ADDRESS_LPF_MODE] = { S2MPG12_METER_CTRL6, S2MPG13_METER_CTRL6 },
[ADDRESS_LPF_DATA] = {
S2MPG12_METER_LPF_DATA_CH0_1,
S2MPG13_METER_LPF_DATA_CH0_1
},
};
#endif
static const u32 s2mpg1x_int_sample_rate_uhz[S2MPG1X_INT_FREQ_COUNT] = {
[INT_7P_8125HZ] = 7812500, [INT_15P_625HZ] = 15625000,
[INT_31P_25HZ] = 31250000, [INT_62P_5HZ] = 62500000,
[INT_125HZ] = 125000000, [INT_250HZ] = 250000000,
#if IS_ENABLED(CONFIG_SOC_GS101)
[INT_500HZ] = 500000000,
#endif
[INT_1000HZ] = 1000000000,
};
#if IS_ENABLED(CONFIG_SOC_GS101)
static const u32 s2mpg1x_ext_sample_rate_uhz[S2MPG1X_EXT_FREQ_COUNT] = {
[EXT_7P_628125HZ] = 7628125, [EXT_15P_25625HZ] = 15256250,
[EXT_30P_5125HZ] = 30512500, [EXT_61P_025HZ] = 61025000,
[EXT_122P_05HZ] = 122050000,
};
#elif IS_ENABLED(CONFIG_SOC_GS201)
static const u32 s2mpg1x_ext_sample_rate_uhz[S2MPG1X_EXT_FREQ_COUNT] = {
[EXT_7P_8125HZ] = 7812500, [EXT_15P_625HZ] = 15625000,
[EXT_31P_25HZ] = 31250000, [EXT_62P_5HZ] = 62500000,
[EXT_125HZ] = 125000000,
};
#endif
#if IS_ENABLED(CONFIG_SOC_GS201)
static const u32 s2mpg1x_int_acquisition_time_us[S2MPG1X_INT_FREQ_COUNT] = {
[INT_7P_8125HZ] = 128000, [INT_15P_625HZ] = 64000,
[INT_31P_25HZ] = 32000, [INT_62P_5HZ] = 16000,
[INT_125HZ] = 8000, [INT_250HZ] = 4000,
[INT_1000HZ] = 1000,
};
#endif
static inline int s2mpg1x_meter_get_acquisition_time_us(s2mpg1x_int_samp_rate samp_rate)
{
#if IS_ENABLED(CONFIG_SOC_GS101)
/* Based on the s2mpg1x datasheets, (40 us * channel count) is the
* maximum time required for acquisition of all samples across all
* channels.
*/
return (40 * S2MPG1X_METER_CHANNEL_MAX);
#elif IS_ENABLED(CONFIG_SOC_GS201)
/* The internal data and sample count are not updated at the same timing
* on Pro due to the duty cycling function, and the ASYNC_RD will depend
* on internal sampling rate.
* So at least waiting for internal rail to complete a sampling will be
* necessary to prevent the mismatch of irregular timing. (b/209886118)
*/
return s2mpg1x_int_acquisition_time_us[samp_rate];
#endif
}
#if IS_ENABLED(CONFIG_SOC_GS101)
#define ACQUISITION_TIME_DIVISOR 1
#elif IS_ENABLED(CONFIG_SOC_GS201)
#define ACQUISITION_TIME_DIVISOR 16
#endif
static inline int s2mpg1x_meter_set_async_blocking(enum s2mpg1x_id id,
struct i2c_client *i2c,
u64 *timestamp_capture,
s2mpg1x_int_samp_rate samp_rate)
{
u8 val = 0xFF;
int ret;
u8 reg = ADDRESS_AT[ADDRESS_CTRL2][id];
const u32 acquisition_time_us =
s2mpg1x_meter_get_acquisition_time_us(samp_rate);
const u32 min_acquisition_time_us = acquisition_time_us /
ACQUISITION_TIME_DIVISOR;
int acquisition_delay_count = 0;
/* When 1 is written into ASYNC_RD bit, */
/* transfer the accumulator data to readable registers->self-cleared */
ret = s2mpg1x_update_reg(id, i2c, reg, ASYNC_RD_MASK, ASYNC_RD_MASK);
if (ret != 0) {
// Immediate return if failed
return ret;
}
if (timestamp_capture)
*timestamp_capture = ktime_get_boottime_ns();
/* Verify if acquisition is already complete before a polled delay.
* Return immediately to reduce refresh time if so.
*/
ret = s2mpg1x_read_reg(id, i2c, reg, &val);
if (ret == 0 && (val & ASYNC_RD_MASK) == 0x00)
return ret; /* Read success */
/* Reading has failed OR we sampled during acquisition, so wait the
* acquisition time and return based on the values read.
*/
do {
usleep_range(min_acquisition_time_us,
min_acquisition_time_us + 100);
ret = s2mpg1x_read_reg(id, i2c, reg, &val);
if (ret != 0 || (val & ASYNC_RD_MASK) == 0x00)
return ret;
acquisition_delay_count++;
} while (acquisition_delay_count < ACQUISITION_TIME_DIVISOR);
return -1; /* ASYNC value has not changed */
}
static inline ssize_t s2mpg1x_meter_format_channel(char *buf, ssize_t count,
int ch, const char *name,
const char *units,
u64 acc_data, u32 resolution,
u32 acc_count)
{
// Note: resolution is in iq30
// --> Convert it back to a human readable decimal value
const u32 one_billion = 1000000000;
u64 resolution_max = _IQ30_to_int((u64)resolution * one_billion);
return scnprintf(buf + count, PAGE_SIZE - count,
"CH%d[%s]: 0x%016llx * %lld.%09llu / 0x%08x %s\n", ch,
name, acc_data, resolution_max / one_billion,
resolution_max % one_billion, acc_count, units);
}
static inline int s2mpg1x_meter_set_buck_channel_en(enum s2mpg1x_id id,
struct i2c_client *i2c,
u8 *channels, int num_bytes)
{
if (num_bytes > S2MPG1X_METER_BUCKEN_BUF)
return -EINVAL;
return s2mpg1x_bulk_write(id, i2c, ADDRESS_AT[ADDRESS_BUCKEN1][id],
num_bytes, channels);
}
static inline int s2mpg1x_meter_set_ext_channel_en(enum s2mpg1x_id id,
struct i2c_client *i2c,
u8 channels)
{
return s2mpg1x_update_reg(id, i2c, ADDRESS_AT[ADDRESS_CTRL2][id],
channels << EXT_METER_CHANNEL_EN_OFFSET,
EXT_METER_CHANNEL_EN_MASK);
}
static inline int s2mpg1x_meter_set_int_samp_rate(enum s2mpg1x_id id,
struct i2c_client *i2c,
s2mpg1x_int_samp_rate hz)
{
return s2mpg1x_update_reg(id, i2c, ADDRESS_AT[ADDRESS_CTRL1][id],
hz << INT_SAMP_RATE_SHIFT,
INT_SAMP_RATE_MASK);
}
static inline int s2mpg1x_meter_set_ext_samp_rate(enum s2mpg1x_id id,
struct i2c_client *i2c,
s2mpg1x_ext_samp_rate hz)
{
return s2mpg1x_update_reg(id, i2c, ADDRESS_AT[ADDRESS_CTRL2][id],
hz, EXT_SAMP_RATE_MASK);
}
static inline int s2mpg1x_meter_set_lpf_coefficient(enum s2mpg1x_id id,
struct i2c_client *i2c,
int ch,
u32 val)
{
if (ch >= S2MPG1X_METER_CHANNEL_MAX)
return -EINVAL;
return s2mpg1x_write_reg(id, i2c, ADDRESS_AT[ADDRESS_LPF_C0_0][id] +
ch, val);
}
static inline const u32 *s2mpg1x_meter_get_int_samping_rate_table(void)
{
return s2mpg1x_int_sample_rate_uhz;
}
static inline const u32 *s2mpg1x_meter_get_ext_samping_rate_table(void)
{
return s2mpg1x_ext_sample_rate_uhz;
}
static inline void s2mpg1x_meter_set_mode(enum s2mpg1x_id id,
struct i2c_client *i2c,
s2mpg1x_meter_mode mode,
bool is_acc_mode) // else lpf
{
address_t mode_addr = ADDRESS_ACC_MODE;
if (!is_acc_mode)
mode_addr = ADDRESS_LPF_MODE;
switch (mode) {
case S2MPG1X_METER_POWER:
s2mpg1x_write_reg(id, i2c, ADDRESS_AT[mode_addr][id], 0x00);
#if IS_ENABLED(CONFIG_SOC_GS201)
s2mpg1x_update_reg(id, i2c, ADDRESS_AT[mode_addr][id] + 1, 0x00,
/* mask= */ 0x0F);
#endif
break;
case S2MPG1X_METER_CURRENT:
s2mpg1x_write_reg(id, i2c, ADDRESS_AT[mode_addr][id], 0xFF);
#if IS_ENABLED(CONFIG_SOC_GS201)
s2mpg1x_update_reg(id, i2c, ADDRESS_AT[mode_addr][id] + 1, 0x0F,
/* mask= */ 0x0F);
#endif
break;
}
}
static inline void s2mpg1x_meter_set_acc_mode(enum s2mpg1x_id id,
struct i2c_client *i2c,
s2mpg1x_meter_mode mode)
{
s2mpg1x_meter_set_mode(id, i2c, mode, /* is_acc_mode= */ true);
}
static inline void s2mpg1x_meter_set_lpf_mode(enum s2mpg1x_id id,
struct i2c_client *i2c,
s2mpg1x_meter_mode mode)
{
s2mpg1x_meter_set_mode(id, i2c, mode, /* is_acc_mode= */ false);
}
static inline void s2mpg1x_meter_read_acc_data_reg(enum s2mpg1x_id id,
struct i2c_client *i2c,
u64 *data)
{
int i;
u8 buf[S2MPG1X_METER_ACC_BUF];
u8 reg = ADDRESS_AT[ADDRESS_ACC_DATA][id]; /* first acc data register */
for (i = 0; i < S2MPG1X_METER_CHANNEL_MAX; i++) {
s2mpg1x_bulk_read(id, i2c, reg, S2MPG1X_METER_ACC_BUF, buf);
/* 41 bits of data */
data[i] = ((u64)buf[0] << 0) | ((u64)buf[1] << 8) |
((u64)buf[2] << 16) | ((u64)buf[3] << 24) |
((u64)buf[4] << 32) | (((u64)buf[5] & 0x1) << 40);
reg += S2MPG1X_METER_ACC_BUF;
}
}
static inline void s2mpg1x_meter_read_acc_count(enum s2mpg1x_id id,
struct i2c_client *i2c,
u32 *count)
{
u8 data[S2MPG1X_METER_COUNT_BUF];
u8 reg = ADDRESS_AT[ADDRESS_ACC_COUNT][id]; /* first count register */
s2mpg1x_bulk_read(id, i2c, reg, S2MPG1X_METER_COUNT_BUF, data);
/* ACC_COUNT is 20-bit data */
*count = (data[0] << 0) | (data[1] << 8) | ((data[2] & 0x0F) << 16);
}
static inline void s2mpg1x_meter_read_lpf_data_reg(enum s2mpg1x_id id,
struct i2c_client *i2c,
u32 *data)
{
int i;
u8 buf[S2MPG1X_METER_LPF_BUF];
u8 reg = ADDRESS_AT[ADDRESS_LPF_DATA][id]; /* first lpf data register */
for (i = 0; i < S2MPG1X_METER_CHANNEL_MAX; i++) {
s2mpg1x_bulk_read(id, i2c, reg, S2MPG1X_METER_LPF_BUF, buf);
/* LPF is 21-bit data */
data[i] = buf[0] + (buf[1] << 8) + ((buf[2] & 0x1F) << 16);
reg += S2MPG1X_METER_LPF_BUF;
}
}
/**
* Load measurement into registers and read measurement from the registers
*
* Note: data must be an array with length S2MPG1X_METER_CHANNEL_MAX
*/
static inline int s2mpg1x_meter_measure_acc(enum s2mpg1x_id id,
struct i2c_client *i2c,
struct mutex *meter_lock,
s2mpg1x_meter_mode mode,
u64 *data,
u32 *count,
u64 *timestamp_capture,
s2mpg1x_int_samp_rate samp_rate)
{
mutex_lock(meter_lock);
s2mpg1x_meter_set_acc_mode(id, i2c, mode);
s2mpg1x_meter_set_async_blocking(id, i2c,
timestamp_capture,
samp_rate);
if (data)
s2mpg1x_meter_read_acc_data_reg(id, i2c, data);
if (count)
s2mpg1x_meter_read_acc_count(id, i2c, count);
mutex_unlock(meter_lock);
return 0;
}
#if IS_ENABLED(CONFIG_SOC_GS201)
#define SW_RESET_DELAYTIME_US 2
static inline int s2mpg1x_meter_sw_reset(enum s2mpg1x_id id,
struct i2c_client *i2c,
struct i2c_client *mt_trim,
u8 mt_trim_reg)
{
int ret;
ret = s2mpg1x_update_reg(id, mt_trim, mt_trim_reg, 0x00,
/* mask= */ BIT(7));
if (ret != 0) {
pr_err("odpm: s2mpg1%d-odpm: failed to update mt_trim bit_7 to 0\n", id + 2);
return ret;
}
ret = s2mpg1x_update_reg(id, mt_trim, mt_trim_reg, 0x80,
/* mask= */ BIT(7));
if (ret != 0) {
pr_err("odpm: s2mpg1%d-odpm: failed to update mt_trim bit_7 to 1\n", id + 2);
return ret;
}
usleep_range(SW_RESET_DELAYTIME_US, SW_RESET_DELAYTIME_US + 100);
ret = s2mpg1x_update_reg(id, i2c, ADDRESS_AT[ADDRESS_CTRL1][id], 0x01,
METER_EN_MASK);
if (ret != 0)
pr_err("odpm: s2mpg1%d-odpm: failed to update meter_ctrl1 bit_0 to 1\n", id + 2);
return ret;
}
#endif
#endif /* __LINUX_MFD_S2MPG1X_METER_H */