From 1543e317f1da31b75942316931e8f491a8920811 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Thu, 04 Jan 2024 10:08:02 +0000
Subject: [PATCH] disable FB
---
kernel/drivers/iio/adc/sc27xx_adc.c | 279 ++++++++++++++++++++++++++++++++-----------------------
1 files changed, 161 insertions(+), 118 deletions(-)
diff --git a/kernel/drivers/iio/adc/sc27xx_adc.c b/kernel/drivers/iio/adc/sc27xx_adc.c
index 2b60efe..2b463e1 100644
--- a/kernel/drivers/iio/adc/sc27xx_adc.c
+++ b/kernel/drivers/iio/adc/sc27xx_adc.c
@@ -3,12 +3,13 @@
#include <linux/hwspinlock.h>
#include <linux/iio/iio.h>
-#include <linux/interrupt.h>
#include <linux/module.h>
+#include <linux/nvmem-consumer.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
+#include <linux/slab.h>
/* PMIC global registers definition */
#define SC27XX_MODULE_EN 0xc08
@@ -35,8 +36,8 @@
/* Bits and mask definition for SC27XX_ADC_CH_CFG register */
#define SC27XX_ADC_CHN_ID_MASK GENMASK(4, 0)
-#define SC27XX_ADC_SCALE_MASK GENMASK(10, 8)
-#define SC27XX_ADC_SCALE_SHIFT 8
+#define SC27XX_ADC_SCALE_MASK GENMASK(10, 9)
+#define SC27XX_ADC_SCALE_SHIFT 9
/* Bits definitions for SC27XX_ADC_INT_EN registers */
#define SC27XX_ADC_IRQ_EN BIT(0)
@@ -44,11 +45,18 @@
/* Bits definitions for SC27XX_ADC_INT_CLR registers */
#define SC27XX_ADC_IRQ_CLR BIT(0)
+/* Bits definitions for SC27XX_ADC_INT_RAW registers */
+#define SC27XX_ADC_IRQ_RAW BIT(0)
+
/* Mask definition for SC27XX_ADC_DATA register */
#define SC27XX_ADC_DATA_MASK GENMASK(11, 0)
/* Timeout (ms) for the trylock of hardware spinlocks */
#define SC27XX_ADC_HWLOCK_TIMEOUT 5000
+
+/* Timeout (us) for ADC data conversion according to ADC datasheet */
+#define SC27XX_ADC_RDY_TIMEOUT 1000000
+#define SC27XX_ADC_POLL_RAW_STATUS 500
/* Maximum ADC channel number */
#define SC27XX_ADC_CHANNEL_MAX 32
@@ -67,10 +75,8 @@
* subsystems which will access the unique ADC controller.
*/
struct hwspinlock *hwlock;
- struct completion completion;
int channel_scale[SC27XX_ADC_CHANNEL_MAX];
u32 base;
- int value;
int irq;
};
@@ -87,15 +93,72 @@
* should use the small-scale graph, and if more than 1.2v, we should use the
* big-scale graph.
*/
-static const struct sc27xx_adc_linear_graph big_scale_graph = {
+static struct sc27xx_adc_linear_graph big_scale_graph = {
4200, 3310,
3600, 2832,
};
-static const struct sc27xx_adc_linear_graph small_scale_graph = {
+static struct sc27xx_adc_linear_graph small_scale_graph = {
1000, 3413,
100, 341,
};
+
+static const struct sc27xx_adc_linear_graph sc2731_big_scale_graph_calib = {
+ 4200, 850,
+ 3600, 728,
+};
+
+static const struct sc27xx_adc_linear_graph sc2731_small_scale_graph_calib = {
+ 1000, 838,
+ 100, 84,
+};
+
+static int sc27xx_adc_get_calib_data(u32 calib_data, int calib_adc)
+{
+ return ((calib_data & 0xff) + calib_adc - 128) * 4;
+}
+
+static int sc27xx_adc_scale_calibration(struct sc27xx_adc_data *data,
+ bool big_scale)
+{
+ const struct sc27xx_adc_linear_graph *calib_graph;
+ struct sc27xx_adc_linear_graph *graph;
+ struct nvmem_cell *cell;
+ const char *cell_name;
+ u32 calib_data = 0;
+ void *buf;
+ size_t len;
+
+ if (big_scale) {
+ calib_graph = &sc2731_big_scale_graph_calib;
+ graph = &big_scale_graph;
+ cell_name = "big_scale_calib";
+ } else {
+ calib_graph = &sc2731_small_scale_graph_calib;
+ graph = &small_scale_graph;
+ cell_name = "small_scale_calib";
+ }
+
+ cell = nvmem_cell_get(data->dev, cell_name);
+ if (IS_ERR(cell))
+ return PTR_ERR(cell);
+
+ buf = nvmem_cell_read(cell, &len);
+ nvmem_cell_put(cell);
+
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
+
+ memcpy(&calib_data, buf, min(len, sizeof(u32)));
+
+ /* Only need to calibrate the adc values in the linear graph. */
+ graph->adc0 = sc27xx_adc_get_calib_data(calib_data, calib_graph->adc0);
+ graph->adc1 = sc27xx_adc_get_calib_data(calib_data >> 8,
+ calib_graph->adc1);
+
+ kfree(buf);
+ return 0;
+}
static int sc27xx_adc_get_ratio(int channel, int scale)
{
@@ -126,9 +189,7 @@
int scale, int *val)
{
int ret;
- u32 tmp;
-
- reinit_completion(&data->completion);
+ u32 tmp, value, status;
ret = hwspin_lock_timeout_raw(data->hwlock, SC27XX_ADC_HWLOCK_TIMEOUT);
if (ret) {
@@ -140,6 +201,11 @@
SC27XX_ADC_EN, SC27XX_ADC_EN);
if (ret)
goto unlock_adc;
+
+ ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_INT_CLR,
+ SC27XX_ADC_IRQ_CLR, SC27XX_ADC_IRQ_CLR);
+ if (ret)
+ goto disable_adc;
/* Configure the channel id and scale */
tmp = (scale << SC27XX_ADC_SCALE_SHIFT) & SC27XX_ADC_SCALE_MASK;
@@ -164,7 +230,21 @@
if (ret)
goto disable_adc;
- wait_for_completion(&data->completion);
+ ret = regmap_read_poll_timeout(data->regmap,
+ data->base + SC27XX_ADC_INT_RAW,
+ status, (status & SC27XX_ADC_IRQ_RAW),
+ SC27XX_ADC_POLL_RAW_STATUS,
+ SC27XX_ADC_RDY_TIMEOUT);
+ if (ret) {
+ dev_err(data->dev, "read adc timeout, status = 0x%x\n", status);
+ goto disable_adc;
+ }
+
+ ret = regmap_read(data->regmap, data->base + SC27XX_ADC_DATA, &value);
+ if (ret)
+ goto disable_adc;
+
+ value &= SC27XX_ADC_DATA_MASK;
disable_adc:
regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CTL,
@@ -173,30 +253,9 @@
hwspin_unlock_raw(data->hwlock);
if (!ret)
- *val = data->value;
+ *val = value;
return ret;
-}
-
-static irqreturn_t sc27xx_adc_isr(int irq, void *dev_id)
-{
- struct sc27xx_adc_data *data = dev_id;
- int ret;
-
- ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_INT_CLR,
- SC27XX_ADC_IRQ_CLR, SC27XX_ADC_IRQ_CLR);
- if (ret)
- return IRQ_RETVAL(ret);
-
- ret = regmap_read(data->regmap, data->base + SC27XX_ADC_DATA,
- &data->value);
- if (ret)
- return IRQ_RETVAL(ret);
-
- data->value &= SC27XX_ADC_DATA_MASK;
- complete(&data->completion);
-
- return IRQ_HANDLED;
}
static void sc27xx_adc_volt_ratio(struct sc27xx_adc_data *data,
@@ -209,7 +268,7 @@
*div_denominator = ratio & SC27XX_RATIO_DENOMINATOR_MASK;
}
-static int sc27xx_adc_to_volt(const struct sc27xx_adc_linear_graph *graph,
+static int sc27xx_adc_to_volt(struct sc27xx_adc_linear_graph *graph,
int raw_adc)
{
int tmp;
@@ -273,6 +332,17 @@
int ret, tmp;
switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ mutex_lock(&indio_dev->mlock);
+ ret = sc27xx_adc_read(data, chan->channel, scale, &tmp);
+ mutex_unlock(&indio_dev->mlock);
+
+ if (ret)
+ return ret;
+
+ *val = tmp;
+ return IIO_VAL_INT;
+
case IIO_CHAN_INFO_PROCESSED:
mutex_lock(&indio_dev->mlock);
ret = sc27xx_adc_read_processed(data, chan->channel, scale,
@@ -315,48 +385,47 @@
.write_raw = &sc27xx_adc_write_raw,
};
-#define SC27XX_ADC_CHANNEL(index) { \
+#define SC27XX_ADC_CHANNEL(index, mask) { \
.type = IIO_VOLTAGE, \
.channel = index, \
- .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | \
- BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_separate = mask | BIT(IIO_CHAN_INFO_SCALE), \
.datasheet_name = "CH##index", \
.indexed = 1, \
}
static const struct iio_chan_spec sc27xx_channels[] = {
- SC27XX_ADC_CHANNEL(0),
- SC27XX_ADC_CHANNEL(1),
- SC27XX_ADC_CHANNEL(2),
- SC27XX_ADC_CHANNEL(3),
- SC27XX_ADC_CHANNEL(4),
- SC27XX_ADC_CHANNEL(5),
- SC27XX_ADC_CHANNEL(6),
- SC27XX_ADC_CHANNEL(7),
- SC27XX_ADC_CHANNEL(8),
- SC27XX_ADC_CHANNEL(9),
- SC27XX_ADC_CHANNEL(10),
- SC27XX_ADC_CHANNEL(11),
- SC27XX_ADC_CHANNEL(12),
- SC27XX_ADC_CHANNEL(13),
- SC27XX_ADC_CHANNEL(14),
- SC27XX_ADC_CHANNEL(15),
- SC27XX_ADC_CHANNEL(16),
- SC27XX_ADC_CHANNEL(17),
- SC27XX_ADC_CHANNEL(18),
- SC27XX_ADC_CHANNEL(19),
- SC27XX_ADC_CHANNEL(20),
- SC27XX_ADC_CHANNEL(21),
- SC27XX_ADC_CHANNEL(22),
- SC27XX_ADC_CHANNEL(23),
- SC27XX_ADC_CHANNEL(24),
- SC27XX_ADC_CHANNEL(25),
- SC27XX_ADC_CHANNEL(26),
- SC27XX_ADC_CHANNEL(27),
- SC27XX_ADC_CHANNEL(28),
- SC27XX_ADC_CHANNEL(29),
- SC27XX_ADC_CHANNEL(30),
- SC27XX_ADC_CHANNEL(31),
+ SC27XX_ADC_CHANNEL(0, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(1, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(2, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(3, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(4, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(5, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(6, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(7, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(8, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(9, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(10, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(11, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(12, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(13, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(14, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(15, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(16, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(17, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(18, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(19, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(20, BIT(IIO_CHAN_INFO_RAW)),
+ SC27XX_ADC_CHANNEL(21, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(22, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(23, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(24, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(25, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(26, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(27, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(28, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(29, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(30, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(31, BIT(IIO_CHAN_INFO_PROCESSED)),
};
static int sc27xx_adc_enable(struct sc27xx_adc_data *data)
@@ -375,8 +444,12 @@
if (ret)
goto disable_adc;
- ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_INT_EN,
- SC27XX_ADC_IRQ_EN, SC27XX_ADC_IRQ_EN);
+ /* ADC channel scales' calibration from nvmem device */
+ ret = sc27xx_adc_scale_calibration(data, true);
+ if (ret)
+ goto disable_clk;
+
+ ret = sc27xx_adc_scale_calibration(data, false);
if (ret)
goto disable_clk;
@@ -396,9 +469,6 @@
{
struct sc27xx_adc_data *data = _data;
- regmap_update_bits(data->regmap, data->base + SC27XX_ADC_INT_EN,
- SC27XX_ADC_IRQ_EN, 0);
-
/* Disable ADC work clock and controller clock */
regmap_update_bits(data->regmap, SC27XX_ARM_CLK_EN,
SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN, 0);
@@ -407,97 +477,70 @@
SC27XX_MODULE_ADC_EN, 0);
}
-static void sc27xx_adc_free_hwlock(void *_data)
-{
- struct hwspinlock *hwlock = _data;
-
- hwspin_lock_free(hwlock);
-}
-
static int sc27xx_adc_probe(struct platform_device *pdev)
{
- struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
struct sc27xx_adc_data *sc27xx_data;
struct iio_dev *indio_dev;
int ret;
- indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*sc27xx_data));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*sc27xx_data));
if (!indio_dev)
return -ENOMEM;
sc27xx_data = iio_priv(indio_dev);
- sc27xx_data->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ sc27xx_data->regmap = dev_get_regmap(dev->parent, NULL);
if (!sc27xx_data->regmap) {
- dev_err(&pdev->dev, "failed to get ADC regmap\n");
+ dev_err(dev, "failed to get ADC regmap\n");
return -ENODEV;
}
ret = of_property_read_u32(np, "reg", &sc27xx_data->base);
if (ret) {
- dev_err(&pdev->dev, "failed to get ADC base address\n");
+ dev_err(dev, "failed to get ADC base address\n");
return ret;
}
sc27xx_data->irq = platform_get_irq(pdev, 0);
- if (sc27xx_data->irq < 0) {
- dev_err(&pdev->dev, "failed to get ADC irq number\n");
+ if (sc27xx_data->irq < 0)
return sc27xx_data->irq;
- }
ret = of_hwspin_lock_get_id(np, 0);
if (ret < 0) {
- dev_err(&pdev->dev, "failed to get hwspinlock id\n");
+ dev_err(dev, "failed to get hwspinlock id\n");
return ret;
}
- sc27xx_data->hwlock = hwspin_lock_request_specific(ret);
+ sc27xx_data->hwlock = devm_hwspin_lock_request_specific(dev, ret);
if (!sc27xx_data->hwlock) {
- dev_err(&pdev->dev, "failed to request hwspinlock\n");
+ dev_err(dev, "failed to request hwspinlock\n");
return -ENXIO;
}
- ret = devm_add_action(&pdev->dev, sc27xx_adc_free_hwlock,
- sc27xx_data->hwlock);
- if (ret) {
- sc27xx_adc_free_hwlock(sc27xx_data->hwlock);
- dev_err(&pdev->dev, "failed to add hwspinlock action\n");
- return ret;
- }
-
- init_completion(&sc27xx_data->completion);
- sc27xx_data->dev = &pdev->dev;
+ sc27xx_data->dev = dev;
ret = sc27xx_adc_enable(sc27xx_data);
if (ret) {
- dev_err(&pdev->dev, "failed to enable ADC module\n");
+ dev_err(dev, "failed to enable ADC module\n");
return ret;
}
- ret = devm_add_action(&pdev->dev, sc27xx_adc_disable, sc27xx_data);
+ ret = devm_add_action_or_reset(dev, sc27xx_adc_disable, sc27xx_data);
if (ret) {
- sc27xx_adc_disable(sc27xx_data);
- dev_err(&pdev->dev, "failed to add ADC disable action\n");
+ dev_err(dev, "failed to add ADC disable action\n");
return ret;
}
- ret = devm_request_threaded_irq(&pdev->dev, sc27xx_data->irq, NULL,
- sc27xx_adc_isr, IRQF_ONESHOT,
- pdev->name, sc27xx_data);
- if (ret) {
- dev_err(&pdev->dev, "failed to request ADC irq\n");
- return ret;
- }
-
- indio_dev->dev.parent = &pdev->dev;
- indio_dev->name = dev_name(&pdev->dev);
+ indio_dev->name = dev_name(dev);
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &sc27xx_info;
indio_dev->channels = sc27xx_channels;
indio_dev->num_channels = ARRAY_SIZE(sc27xx_channels);
- ret = devm_iio_device_register(&pdev->dev, indio_dev);
+ ret = devm_iio_device_register(dev, indio_dev);
if (ret)
- dev_err(&pdev->dev, "could not register iio (ADC)");
+ dev_err(dev, "could not register iio (ADC)");
return ret;
}
--
Gitblit v1.6.2