saradc: refactor the driver based on the iio sub-system

PD#146222: saradc: refactor the driver based on the iio sub-system

the sar adc driver has been moved from directory input/saradc
into directory iio/adc, and is refactored base on the standard
iio sub-system.

the iio sub-system provide two ways to access sar adc resources:
1. standard api for consumer driver
it can be found at the file "include/linux/iio/consumer.h".

2. sysfs interface for user space(X: 0-7)
  - obtain 10-bit sample value:
  cat sys/bus/iio/devices/iio:device0/in_voltage[X]_input

  - obtain raw sample value(10-bit or 12-bit):
  cat sys/bus/iio/devices/iio:device0/in_voltage[X]_raw

  - obtain mean raw sample value:
  cat sys/bus/iio/devices/iio:device0/in_voltage[X]_mean_raw

test pass on the gxl skt, axg skt, m200.

Change-Id: I6c8877c782c51a01993557cabc0d43f212a8e524
Signed-off-by: xingyu.chen <xingyu.chen@amlogic.com>
This commit is contained in:
Xingyu Chen
2017-03-14 11:06:43 +08:00
committed by Jianxin Pan
parent 99a3f48127
commit 30e7250dfd
30 changed files with 1419 additions and 846 deletions

View File

@@ -1,24 +0,0 @@
Amlogic Successive Approximation Register (SAR) A/D Converter bindings
Required properties:
- compatible: Must be "amlogic, saradc".
- clocks: The clock provided by the SoC to the device.
- clock-names: Shall be "saradc_clk" for the device.
- resets: Shall be "GCLK_IDX_SARADC" for the device.
- reg: Physical base address of the controller and length of memory mapped
region.
Optional properties:
- status: Shall be "ok" or "okay" if enabled or "disabled" if disabled.
Default is "ok".
Example:
saradc: saradc {
compatible = "amlogic, saradc";
status = "okay";
clocks = <&clock CLK_XTAL>;
clock-names = "saradc_clk";
resets = <&clock GCLK_IDX_SARADC>;
reg = <0x0 0xc1108680 0x0 0x30
0x0 0xc883c3d8 0x0 0x08>;
};

View File

@@ -0,0 +1,38 @@
* Amlogic Meson SAR (Successive Approximation Register) A/D converter
Required properties:
- compatible: depending on the SoC this should be one of:
- "amlogic,meson-axg-saradc" for AXG
- "amlogic,meson-gxl-saradc" for GXL
- "amlogic,meson-gxm-saradc" for GXM
- "amlogic,meson-m8b-saradc" for M8B
along with the generic "amlogic,meson-saradc"
- reg: the physical base address and length of the registers
- interrupts: the interrupt indicating end of sampling
- clocks: phandle and clock identifier (see clock-names)
- clock-names: mandatory clocks:
- "xtal" for the reference clock (typically XTAL)
- "saradc_clk" for the SAR ADC (sampling) clock
optional clocks:
- "clk81_gate" for the clk81 clock gate
- #io-channel-cells: must be 1, see ../iio-bindings.txt
Optional properties:
- status: Shall be "ok" or "okay" if enabled or "disabled" if disabled.
Default is "ok".
Example:
saradc:saradc {
compatible = "amlogic,meson-axg-saradc";
status = "okay";
#io-channel-cells = <1>;
clocks = <&xtal>, <&clkc CLKID_SARADC_GATE>;
clock-names = "xtal", "saradc_clk";
interrupts = <GIC_SPI 73 IRQ_TYPE_EDGE_RISING>;
reg = <0x0 0xff809000 0x0 0x38>;
}

View File

@@ -13450,7 +13450,9 @@ F: drivers/amlogic/crypto/*
AMLOGIC saradc
M: Xingyu Chen <xingyu.chen@amlogic.com>
F: drivers/amlogic/input/saradc/*
F: drivers/amlogic/iio/adc/*
F: include/dt-bindings/iio/adc/amlogic-saradc.h
F: Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt
AMLOGIC adc_keypad
M: Xingyu Chen <xingyu.chen@amlogic.com>

View File

@@ -18,6 +18,7 @@
#include <dt-bindings/clock/meson8b-clkc.h>
#include <dt-bindings/gpio/meson8b-gpio.h>
#include <dt-bindings/reset/amlogic,meson8b-reset.h>
#include <dt-bindings/iio/adc/amlogic-saradc.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
#include <dt-bindings/input/meson_rc.h>
@@ -802,10 +803,12 @@ dwc2_b {
};
saradc: saradc {
compatible = "amlogic, saradc";
compatible = "amlogic,meson-m8b-saradc";
status = "okay";
clocks = <&clkc CLKID_SAR_ADC>;
clock-names = "saradc_clk";
#io-channel-cells = <1>;
clocks = <&clkc CLKID_XTAL>, <&clkc CLKID_SAR_ADC>;
clock-names = "xtal", "clk81_gate";
interrupts = <0 73 1>;
reg = <0xc1108680 0x30>;
};

View File

@@ -380,6 +380,8 @@
compatible = "amlogic, aml-thermal";
device_name = "thermal";
#thermal-sensor-cells = <1>;
io-channels = <&saradc SARADC_CH6>;
io-channel-names = "TEMP_CHAN";
cooling_devices {
cpufreq_cool_cluster0 {
min_state = <768000>;

View File

@@ -307,6 +307,8 @@
compatible = "amlogic, aml-thermal";
device_name = "thermal";
#thermal-sensor-cells = <1>;
io-channels = <&saradc SARADC_CH6>;
io-channel-names = "TEMP_CHAN";
cooling_devices {
cpufreq_cool_cluster0 {
min_state = <768000>;

View File

@@ -225,6 +225,8 @@
compatible = "amlogic, aml-thermal";
device_name = "thermal";
#thermal-sensor-cells = <1>;
io-channels = <&saradc SARADC_CH6>;
io-channel-names = "TEMP_CHAN";
cooling_devices {
cpufreq_cool_cluster0 {
min_state = <768000>;

View File

@@ -177,7 +177,6 @@ CONFIG_AMLOGIC_M8B_CLK=y
CONFIG_AMLOGIC_CRYPTO=y
CONFIG_AMLOGIC_CRYPTO_BLKMV=y
CONFIG_AMLOGIC_INPUT=y
CONFIG_AMLOGIC_SARADC=y
CONFIG_AMLOGIC_REMOTE=y
CONFIG_AMLOGIC_MESON_REMOTE=y
CONFIG_AMLOGIC_EFUSE=y
@@ -211,6 +210,8 @@ CONFIG_AMLOGIC_PMU_OF=y
CONFIG_AMLOGIC_PMU=y
CONFIG_AMLOGIC_1218=y
CONFIG_AMLOGIC_M8B_DVFS=y
CONFIG_AMLOGIC_IIO=y
CONFIG_AMLOGIC_SARADC=y
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
CONFIG_DMA_CMA=y
@@ -300,6 +301,7 @@ CONFIG_CHROME_PLATFORMS=y
CONFIG_PM_DEVFREQ=y
CONFIG_EXTCON=y
CONFIG_MEMORY=y
CONFIG_IIO=y
CONFIG_PWM=y
CONFIG_RESET_CONTROLLER=y
CONFIG_GENERIC_PHY=y

View File

@@ -18,6 +18,7 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/amlogic,axg-clkc.h>
#include <dt-bindings/clock/amlogic,axg-audio-clk.h>
#include <dt-bindings/iio/adc/amlogic-saradc.h>
#include <dt-bindings/gpio/mesonaxg-gpio.h>
#include <dt-bindings/pwm/pwm.h>
#include <dt-bindings/pwm/meson.h>
@@ -686,6 +687,16 @@
interrupts = <0 180 1 0 181 1>;
reg = <0x0 0xff63e000 0x0 0x48>;
};
saradc:saradc {
compatible = "amlogic,meson-axg-saradc";
status = "okay";
#io-channel-cells = <1>;
clocks = <&xtal>, <&clkc CLKID_SARADC_GATE>;
clock-names = "xtal", "saradc_clk";
interrupts = <GIC_SPI 73 IRQ_TYPE_EDGE_RISING>;
reg = <0x0 0xff809000 0x0 0x38>;
};
};/* end of / */
&pinctrl_aobus {

View File

@@ -18,6 +18,7 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/reset/amlogic,gxl-reset.h>
#include <dt-bindings/clock/amlogic,gxl-clkc.h>
#include <dt-bindings/iio/adc/amlogic-saradc.h>
#include <dt-bindings/gpio/gxl.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/pwm/meson.h>
@@ -1010,12 +1011,14 @@ i2c_ao: i2c@c8100500{ /*I2C-AO*/
};
saradc: saradc {
compatible = "amlogic, saradc";
compatible = "amlogic,meson-gxl-saradc";
status = "okay";
clocks = <&clkc CLKID_SARADC>;
clock-names = "saradc_clk";
reg = <0x0 0xc1108680 0x0 0x30
0x0 0xc883c3d8 0x0 0x08>;
#io-channel-cells = <1>;
clocks = <&xtal>, <&clkc CLKID_SARADC>,
<&clkc CLKID_SARADC_COMP>;
clock-names = "xtal", "clk81_gate", "saradc_clk";
interrupts = <GIC_SPI 73 IRQ_TYPE_EDGE_RISING>;
reg = <0x0 0xc1108680 0x0 0x38>;
};
efuse: efuse{

View File

@@ -18,6 +18,7 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/reset/amlogic,gxl-reset.h>
#include <dt-bindings/clock/amlogic,gxl-clkc.h>
#include <dt-bindings/iio/adc/amlogic-saradc.h>
#include <dt-bindings/gpio/gxl.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/pwm/meson.h>
@@ -1138,12 +1139,14 @@
};
saradc: saradc {
compatible = "amlogic, saradc";
compatible = "amlogic,meson-gxl-saradc";
status = "okay";
clocks = <&clkc CLKID_SARADC>;
clock-names = "saradc_clk";
reg = <0x0 0xc1108680 0x0 0x30
0x0 0xc883c3d8 0x0 0x08>;
#io-channel-cells = <1>;
clocks = <&xtal>, <&clkc CLKID_SARADC>,
<&clkc CLKID_SARADC_COMP>;
clock-names = "xtal", "clk81_gate", "saradc_clk";
interrupts = <GIC_SPI 73 IRQ_TYPE_EDGE_RISING>;
reg = <0x0 0xc1108680 0x0 0x38>;
};
efuse: efuse{

View File

@@ -222,8 +222,6 @@ CONFIG_AMLOGIC_CRYPTO=y
CONFIG_AMLOGIC_CRYPTO_DMA=y
CONFIG_AMLOGIC_INPUT=y
CONFIG_AMLOGIC_INPUT_KEYBOARD=y
CONFIG_AMLOGIC_ADC_KEYPADS=y
CONFIG_AMLOGIC_SARADC=y
CONFIG_AMLOGIC_REMOTE=y
CONFIG_AMLOGIC_MESON_REMOTE=y
CONFIG_AMLOGIC_IRBLASTER=y
@@ -301,6 +299,8 @@ CONFIG_AMLOGIC_WIFI=y
CONFIG_AMLOGIC_BT_DEVICE=y
CONFIG_AMLOGIC_DVB_COMPAT=y
CONFIG_AMLOGIC_PCIE=y
CONFIG_AMLOGIC_IIO=y
CONFIG_AMLOGIC_SARADC=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
@@ -436,6 +436,7 @@ CONFIG_DEVFREQ_GOV_PERFORMANCE=y
CONFIG_DEVFREQ_GOV_POWERSAVE=y
CONFIG_DEVFREQ_GOV_USERSPACE=y
CONFIG_EXTCON=y
CONFIG_IIO=y
CONFIG_PWM=y
CONFIG_ANDROID=y
CONFIG_ANDROID_BINDER_IPC=y

View File

@@ -102,5 +102,7 @@ source "drivers/amlogic/pci/Kconfig"
source "drivers/amlogic/irblaster/Kconfig"
source "drivers/amlogic/iio/Kconfig"
endmenu
endif

View File

@@ -85,3 +85,5 @@ obj-$(CONFIG_AMLOGIC_POWER) += power/
obj-$(CONFIG_AMLOGIC_PCIE) += pci/
obj-$(CONFIG_AMLOGIC_IRBLASTER) += irblaster/
obj-$(CONFIG_AMLOGIC_IIO) += iio/

View File

@@ -0,0 +1,16 @@
#
# Industrial I/O subsystem configuration
#
menuconfig AMLOGIC_IIO
tristate "Industrial I/O support"
help
The industrial I/O subsystem provides a unified framework for
drivers for many different types of embedded sensors using a
number of different physical interfaces (i2c, spi, etc).
if AMLOGIC_IIO
source "drivers/amlogic/iio/adc/Kconfig"
endif #IIO

View File

@@ -0,0 +1,5 @@
#
# Makefile for the industrial I/O core.
#
obj-$(CONFIG_AMLOGIC_IIO) += adc/

View File

@@ -0,0 +1,16 @@
#
# ADC drivers
#
# When adding new entries keep the list in alphabetical order
menu "Analog to digital converters"
config AMLOGIC_SARADC
bool "Meson SAR ADC support"
depends on REGMAP_MMIO
depends on IIO
default n
help
Say Y here if you want to use the Meson SAR ADC.
endmenu

View File

@@ -0,0 +1,7 @@
#
#Makefile for IIO ADC drivers
#
obj-$(CONFIG_AMLOGIC_SARADC) += meson_saradc.o

File diff suppressed because it is too large Load Diff

View File

@@ -12,8 +12,6 @@ if AMLOGIC_INPUT
source "drivers/amlogic/input/keyboard/Kconfig"
source "drivers/amlogic/input/saradc/Kconfig"
source "drivers/amlogic/input/remote/Kconfig"
endif

View File

@@ -6,6 +6,4 @@
obj-$(CONFIG_AMLOGIC_INPUT_KEYBOARD) += keyboard/
obj-$(CONFIG_AMLOGIC_SARADC) += saradc/
obj-$(CONFIG_AMLOGIC_REMOTE) += remote/

View File

@@ -1,8 +0,0 @@
#
# Input core configuration
#
config AMLOGIC_SARADC
bool "Meson SAR ADC support"
default n
help
Say Y here if you want to use the Meson SAR ADC.

View File

@@ -1,9 +0,0 @@
#
# Makefile for the input core drivers.
#
# Each configuration option enables a list of files.
obj-$(CONFIG_AMLOGIC_SARADC) += saradc.o

View File

@@ -1,650 +0,0 @@
/*
* drivers/amlogic/input/saradc/saradc.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/amlogic/saradc.h>
#include <linux/amlogic/iomap.h>
#include <linux/amlogic/cpu_version.h>
#include <asm/barrier.h>
#include "saradc_reg.h"
/* #define ENABLE_DYNAMIC_POWER */
#define CLEAN_BUFF_BEFORE_SARADC 1
/* flag_12bit = 0 : 10 bit */
/* flag_12bit = 1 : 12 bit */
static char flag_12bit;
#define saradc_info(x...) dev_info(adc->dev, x)
#define saradc_dbg(x...) /* dev_info(adc->dev, x) */
#define saradc_err(x...) dev_err(adc->dev, x)
#define SARADC_STATE_IDLE 0
#define SARADC_STATE_BUSY 1
#define SARADC_STATE_SUSPEND 2
const char *ch7_vol[] = {
"gnd",
"vdd/4",
"vdd/2",
"vdd*3/4",
"vdd",
"unused",
"unused",
"unused"
};
struct saradc {
struct device *dev;
void __iomem *mem_base;
void __iomem *clk_mem_base;
struct clk *clk;
spinlock_t lock;
int ref_val;
int ref_nominal;
int coef;
int state;
int ch7_sel;
};
static struct saradc *gp_saradc;
void setb(
void __iomem *mem_base,
unsigned int bits_desc,
unsigned int bits_val)
{
unsigned int mem_offset, val;
unsigned int bits_offset, bits_mask;
if (IS_ERR(mem_base))
return;
mem_offset = of_mem_offset(bits_desc);
bits_offset = of_bits_offset(bits_desc);
bits_mask = (1L<<of_bits_len(bits_desc))-1;
val = readl(mem_base+mem_offset);
val &= ~(bits_mask << bits_offset);
val |= (bits_val & bits_mask) << bits_offset;
writel(val, mem_base+mem_offset);
}
EXPORT_SYMBOL(setb);
unsigned int getb(
void __iomem *mem_base,
unsigned int bits_desc)
{
unsigned int mem_offset, val;
unsigned int bits_offset, bits_mask;
if (IS_ERR(mem_base))
return -1;
mem_offset = of_mem_offset(bits_desc);
bits_offset = of_bits_offset(bits_desc);
bits_mask = (1L<<of_bits_len(bits_desc))-1;
val = readl(mem_base+mem_offset);
return (val >> bits_offset) & bits_mask;
}
EXPORT_SYMBOL(getb);
#ifdef CONFIG_AMLOGIC_M8B_TEMP_SENSOR
#ifndef CONFIG_MACH_MESON8
void temp_set_trim(unsigned char val)
{
int tmp;
tmp = aml_read_cbus(P_HHI_DPLL_TOP_0);
tmp = (tmp & (~(1 << 9))) | ((val & 0x1) << 9);
aml_write_cbus(P_HHI_DPLL_TOP_0, tmp);
}
#endif
void temp_sensor_adc_init(int triming)
{
struct saradc *adc = gp_saradc;
void __iomem *mem_base;
mem_base = adc->mem_base;
setb(mem_base, TEMP_SELECT, 1);
setb(mem_base, TEMP_TRIM, triming & 0xf);
#ifndef CONFIG_MACH_MESON8
temp_set_trim(triming >> 4);
#endif
setb(mem_base, TEMP_EN0, 1);
setb(mem_base, TEMP_EN1, 1);
}
EXPORT_SYMBOL(temp_sensor_adc_init);
#endif
static void saradc_power_control(struct saradc *adc, int on)
{
void __iomem *mem_base = adc->mem_base;
if (on) {
setb(mem_base, BANDGAP_EN, 1);
setb(mem_base, ADC_EN, 1);
udelay(5);
if (cpu_after_eq(MESON_CPU_MAJOR_ID_GXBB))
setb(adc->clk_mem_base, REGC_CLK_EN, 1);
else
setb(mem_base, CLK_EN, 1);
} else {
if (cpu_after_eq(MESON_CPU_MAJOR_ID_GXBB))
setb(adc->clk_mem_base, REGC_CLK_EN, 0);
else
setb(mem_base, CLK_EN, 0);
setb(mem_base, ADC_EN, 0);
setb(mem_base, BANDGAP_EN, 0);
}
}
static void saradc_reset(struct saradc *adc)
{
void __iomem *mem_base = adc->mem_base;
int clk_div;
if (getb(mem_base, FLAG_INITIALIZED)) {
saradc_info("initialized by BL30\n");
#ifndef ENABLE_DYNAMIC_POWER
saradc_power_control(adc, 1);
#endif
return;
}
writel(0x84004040, mem_base+SARADC_REG0);
writel(0, mem_base+SARADC_CH_LIST);
writel(0xaaaa, mem_base+SARADC_AVG_CNTL);
if (flag_12bit)
writel(0x9b88000a, mem_base+SARADC_REG3);
else
writel(0x9388000a, mem_base+SARADC_REG3);
/* set SARADC_DELAY with 0x190a380a when 32k */
writel(0x10a000a, mem_base+SARADC_DELAY);
writel(0x3eb1a0c, mem_base+SARADC_AUX_SW);
writel(0x3eb1a0c, mem_base+SARADC_AUX_SW);
writel(0x8c000c, mem_base+SARADC_CH10_SW);
writel(0xc000c, mem_base+SARADC_DETECT_IDLE_SW);
clk_prepare_enable(adc->clk);
clk_div = clk_get_rate(adc->clk) / 1200000;
if (cpu_after_eq(MESON_CPU_MAJOR_ID_GXBB)) {
setb(adc->clk_mem_base, REGC_CLK_DIV, clk_div);
setb(adc->clk_mem_base, REGC_CLK_SRC, 0);
} else {
setb(mem_base, CLK_DIV, clk_div);
}
saradc_info("initialized by kernel, clk_div=%d\n", clk_div);
#ifndef ENABLE_DYNAMIC_POWER
saradc_power_control(adc, 1);
#endif
}
static int saradc_internal_cal(struct saradc *adc)
{
int val[5], nominal[5] = {0, 256, 512, 768, 1023};
int i;
saradc_info("calibration start:\n");
adc->coef = 0;
for (i = 0; i < 5; i++) {
setb(adc->mem_base, CAL_CNTL, i);
udelay(10);
val[i] = get_adc_sample(0, CHAN_7);
saradc_info("nominal=%d, value=%d\n", nominal[i], val[i]);
if (val[i] < 0)
goto cal_end;
}
adc->ref_val = val[2];
adc->ref_nominal = nominal[2];
if (val[3] > val[1]) {
adc->coef = (nominal[3] - nominal[1]) << 12;
adc->coef /= val[3] - val[1];
}
cal_end:
saradc_info("calibration end: coef=%d\n", adc->coef);
setb(adc->mem_base, CAL_CNTL, 7);
adc->ch7_sel = 7;
return 0;
}
static int saradc_get_cal_value(struct saradc *adc, int val)
{
int nominal;
/*((nominal - ref_nominal) << 10) / (val - ref_val) = coef*/
/*==> nominal = ((val - ref_val) * coef >> 10) + ref_nominal*/
nominal = val;
if ((adc->coef > 0) && (val > 0)) {
nominal = (val - adc->ref_val) * adc->coef;
nominal >>= 12;
nominal += adc->ref_nominal;
}
if (nominal < 0)
nominal = 0;
if (nominal > 1023)
nominal = 1023;
return nominal;
}
static int saradc_get_cal_value_12bit(struct saradc *adc, int val)
{
int nominal;
/*((nominal - ref_nominal) << 10) / (val - ref_val) = coef*/
/*==> nominal = ((val - ref_val) * coef >> 10) + ref_nominal*/
nominal = val;
if ((adc->coef > 0) && (val > 0)) {
nominal = (val - adc->ref_val) * adc->coef;
nominal >>= 12;
nominal += adc->ref_nominal;
}
if (nominal < 0)
nominal = 0;
if (nominal > 4095)
nominal = 4095;
return nominal;
}
/*if_10bit=1:10bit*/
/*if_10bit=0:12bit*/
int get_adc_sample_early(int dev_id, int ch, char if_10bit)
{
struct saradc *adc;
void __iomem *mem_base;
int value, count, sum;
int max = 0;
int min = 0x3ff;
int min_12bit = 0xfff;
unsigned long flags;
if (!if_10bit)
min = min_12bit;
adc = gp_saradc;
mem_base = adc->mem_base;
if (!adc || getb(mem_base, FLAG_BUSY_BL30)
|| (adc->state != SARADC_STATE_IDLE))
return -1;
spin_lock_irqsave(&adc->lock, flags);
adc->state = SARADC_STATE_BUSY;
setb(mem_base, FLAG_BUSY_KERNEL, 1);
isb();
dsb(sy);
udelay(1);
if (getb(mem_base, FLAG_BUSY_BL30)) {
value = -1;
goto end;
}
#ifdef ENABLE_DYNAMIC_POWER
saradc_power_control(adc, 1);
#endif
#if CLEAN_BUFF_BEFORE_SARADC
count = 0;
while (getb(mem_base, FIFO_COUNT) && (count < FIFO_MAX)) {
value = readl(mem_base+SARADC_FIFO_RD);
count++;
}
#endif
writel(ch, mem_base+SARADC_CH_LIST);
setb(mem_base, DETECT_MUX, ch);
setb(mem_base, IDLE_MUX, ch);
setb(mem_base, SAMPLE_ENGINE_EN, 1);
setb(mem_base, START_SAMPLE, 1);
count = 0;
do {
udelay(1);
if (++count > 1000) {
saradc_err("busy, %x\n", readl(mem_base+SARADC_REG0));
value = -1;
goto end1;
}
} while (getb(mem_base, ALL_BUSY));
count = 0;
sum = 0;
while (getb(mem_base, FIFO_COUNT) && (count < FIFO_MAX)) {
value = readl(mem_base+SARADC_FIFO_RD);
if (((value>>12) & 0x07) == ch) {
if (if_10bit) {
if (flag_12bit) {
value &= 0xffc;
value >>= 2;
} else
value &= 0x3ff;
} else
value &= 0xfff;
if (value > max)
max = value;
if (value < min)
min = value;
sum += value;
count++;
}
}
if (!count) {
value = -1;
goto end1;
}
if (count > 2) {
sum -= (max + min);
count -= 2;
}
value = sum / count;
saradc_dbg("before cal: %d, count=%d\n", value, count);
if (adc->coef) {
if (if_10bit)
value = saradc_get_cal_value(adc, value);
else
value = saradc_get_cal_value_12bit(adc, value);
saradc_dbg("after cal: %d\n", value);
}
end1:
setb(mem_base, STOP_SAMPLE, 1);
setb(mem_base, SAMPLE_ENGINE_EN, 0);
#ifdef ENABLE_DYNAMIC_POWER
saradc_power_control(0);
#endif
end:
setb(mem_base, FLAG_BUSY_KERNEL, 0);
isb();
dsb(sy);
udelay(1);
adc->state = SARADC_STATE_IDLE;
spin_unlock_irqrestore(&adc->lock, flags);
return value;
}
int get_adc_sample(int dev_id, int ch)
{
int val;
val = get_adc_sample_early(dev_id, ch, 1);
return val;
}
EXPORT_SYMBOL(get_adc_sample);
int get_adc_sample_12bit(int dev_id, int ch)
{
int val;
val = get_adc_sample_early(dev_id, ch, 0);
return val;
}
EXPORT_SYMBOL(get_adc_sample_12bit);
static void __iomem *
saradc_get_reg_addr(struct platform_device *pdev, int index)
{
struct resource *res;
void __iomem *reg_addr;
res = platform_get_resource(pdev, IORESOURCE_MEM, index);
if (!res) {
dev_err(&pdev->dev, "reg: cannot obtain I/O memory region");
return 0;
}
if (!devm_request_mem_region(&pdev->dev, res->start,
resource_size(res), dev_name(&pdev->dev))) {
dev_err(&pdev->dev, "Memory region busy\n");
return 0;
}
reg_addr = devm_ioremap_nocache(&pdev->dev, res->start,
resource_size(res));
return reg_addr;
}
static ssize_t ch0_show(struct class *cla,
struct class_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", get_adc_sample(0, 0));
}
static ssize_t ch1_show(struct class *cla,
struct class_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", get_adc_sample(0, 1));
}
static ssize_t ch2_show(struct class *cla,
struct class_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", get_adc_sample(0, 2));
}
static ssize_t ch3_show(struct class *cla,
struct class_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", get_adc_sample(0, 3));
}
static ssize_t ch4_show(struct class *cla,
struct class_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", get_adc_sample(0, 4));
}
static ssize_t ch5_show(struct class *cla,
struct class_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", get_adc_sample(0, 5));
}
static ssize_t ch6_show(struct class *cla,
struct class_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", get_adc_sample(0, 6));
}
static ssize_t ch7_show(struct class *cla,
struct class_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", get_adc_sample(0, 7));
}
static ssize_t ch7_mux_show(struct class *cla,
struct class_attribute *attr, char *buf)
{
int i;
int len = 0;
struct saradc *adc = gp_saradc;
len = sprintf(buf, "current: [%d]%s\n\n",
adc->ch7_sel, ch7_vol[adc->ch7_sel]);
for (i = 0; i < ARRAY_SIZE(ch7_vol); i++)
len += sprintf(buf + len, "%d: %s\n", i, ch7_vol[i]);
return len;
}
static ssize_t ch7_mux_store(struct class *cla,
struct class_attribute *attr, const char *buf, size_t count)
{
int val;
struct saradc *adc = gp_saradc;
if (kstrtoint(buf, 0, &val) != 0)
return -EINVAL;
if (val >= ARRAY_SIZE(ch7_vol))
return -EINVAL;
setb(adc->mem_base, CAL_CNTL, val);
adc->ch7_sel = val;
return count;
}
static struct class_attribute saradc_class_attrs[] = {
__ATTR_RO(ch0),
__ATTR_RO(ch1),
__ATTR_RO(ch2),
__ATTR_RO(ch3),
__ATTR_RO(ch4),
__ATTR_RO(ch5),
__ATTR_RO(ch6),
__ATTR_RO(ch7),
__ATTR_RW(ch7_mux),
__ATTR_NULL
};
static struct class saradc_class = {
.name = "saradc",
.class_attrs = saradc_class_attrs,
};
static int saradc_probe(struct platform_device *pdev)
{
int err;
struct saradc *adc;
if (cpu_after_eq(MESON_CPU_MAJOR_ID_GXL))
flag_12bit = 1;
else
flag_12bit = 0;
adc = kzalloc(sizeof(struct saradc), GFP_KERNEL);
if (!adc) {
err = -ENOMEM;
goto end_err;
}
adc->dev = &pdev->dev;
if (!pdev->dev.of_node) {
err = -EINVAL;
goto end_free;
}
adc->mem_base = saradc_get_reg_addr(pdev, 0);
if (!adc->mem_base) {
err = -ENODEV;
goto end_free;
}
if (cpu_after_eq(MESON_CPU_MAJOR_ID_GXBB))
adc->clk_mem_base = saradc_get_reg_addr(pdev, 1);
adc->clk = devm_clk_get(&pdev->dev, "saradc_clk");
if (IS_ERR(adc->clk)) {
err = -ENOENT;
goto end_free;
}
saradc_reset(adc);
gp_saradc = adc;
dev_set_drvdata(&pdev->dev, adc);
spin_lock_init(&adc->lock);
adc->state = SARADC_STATE_IDLE;
saradc_internal_cal(adc);
class_register(&saradc_class);
return 0;
end_free:
kfree(adc);
end_err:
dev_err(&pdev->dev, "error=%d\n", err);
return err;
}
static int saradc_suspend(struct platform_device *pdev, pm_message_t state)
{
struct saradc *adc = (struct saradc *)dev_get_drvdata(&pdev->dev);
unsigned long flags;
spin_lock_irqsave(&adc->lock, flags);
saradc_power_control(adc, 0);
adc->state = SARADC_STATE_SUSPEND;
spin_unlock_irqrestore(&adc->lock, flags);
return 0;
}
static int saradc_resume(struct platform_device *pdev)
{
struct saradc *adc = (struct saradc *)dev_get_drvdata(&pdev->dev);
unsigned long flags;
spin_lock_irqsave(&adc->lock, flags);
saradc_power_control(adc, 1);
adc->state = SARADC_STATE_IDLE;
spin_unlock_irqrestore(&adc->lock, flags);
return 0;
}
static int saradc_remove(struct platform_device *pdev)
{
struct saradc *adc = (struct saradc *)dev_get_drvdata(&pdev->dev);
unsigned long flags;
class_unregister(&saradc_class);
spin_lock_irqsave(&adc->lock, flags);
saradc_power_control(adc, 0);
spin_unlock_irqrestore(&adc->lock, flags);
kfree(adc);
return 0;
}
static void saradc_shutdown(struct platform_device *pdev)
{
struct saradc *adc = (struct saradc *)dev_get_drvdata(&pdev->dev);
unsigned long flags;
spin_lock_irqsave(&adc->lock, flags);
saradc_power_control(adc, 0);
spin_unlock_irqrestore(&adc->lock, flags);
}
#ifdef CONFIG_OF
static const struct of_device_id saradc_dt_match[] = {
{ .compatible = "amlogic, saradc"},
{},
};
#else
#define saradc_dt_match NULL
#endif
static struct platform_driver saradc_driver = {
.probe = saradc_probe,
.remove = saradc_remove,
.suspend = saradc_suspend,
.resume = saradc_resume,
.shutdown = saradc_shutdown,
.driver = {
.name = "saradc",
.of_match_table = saradc_dt_match,
},
};
static int __init saradc_init(void)
{
/* printk(KERN_INFO "SARADC Driver init.\n"); */
return platform_driver_register(&saradc_driver);
}
static void __exit saradc_exit(void)
{
/* printk(KERN_INFO "SARADC Driver exit.\n"); */
platform_driver_unregister(&saradc_driver);
}
module_init(saradc_init);
module_exit(saradc_exit);
MODULE_AUTHOR("aml");
MODULE_DESCRIPTION("SARADC Driver");
MODULE_LICENSE("GPL");

View File

@@ -1,69 +0,0 @@
/*
* drivers/amlogic/input/saradc/saradc_reg.h
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#ifndef __SARADC_REG_H__
#define __SARADC_REG_H__
#define SARADC_REG0 (0<<2)
#define SARADC_CH_LIST (1<<2)
#define SARADC_AVG_CNTL (2<<2)
#define SARADC_REG3 (3<<2)
#define SARADC_DELAY (4<<2)
#define SARADC_LAST_RD (5<<2)
#define SARADC_FIFO_RD (6<<2)
#define SARADC_AUX_SW (7<<2)
#define SARADC_CH10_SW (8<<2)
#define SARADC_DETECT_IDLE_SW (9<<2)
#define SARADC_DELTA_10 (10<<2)
#define SARADC_REG11 (11<<2)
#define P_HHI_DPLL_TOP_0 0x10c6
#define SAMPLE_ENGINE_EN bits_desc(SARADC_REG0, 0, 1)
#define START_SAMPLE bits_desc(SARADC_REG0, 2, 1)
#define STOP_SAMPLE bits_desc(SARADC_REG0, 14, 1)
#define FIFO_COUNT bits_desc(SARADC_REG0, 21, 5)
#define SAMPLE_BUSY bits_desc(SARADC_REG0, 28, 1)
#define AVG_BUSY bits_desc(SARADC_REG0, 29, 1)
#define DELTA_BUSY bits_desc(SARADC_REG0, 30, 1)
#define ALL_BUSY bits_desc(SARADC_REG0, 28, 3)
#define CLK_DIV bits_desc(SARADC_REG3, 10, 6)
#define ADC_EN bits_desc(SARADC_REG3, 21, 1)
#define CAL_CNTL bits_desc(SARADC_REG3, 23, 3)
#define FLAG_INITIALIZED bits_desc(SARADC_REG3, 28, 1) /* for bl30 */
#define CLK_EN bits_desc(SARADC_REG3, 30, 1)
#define FLAG_BUSY_KERNEL bits_desc(SARADC_DELAY, 14, 1) /* for bl30 */
#define FLAG_BUSY_BL30 bits_desc(SARADC_DELAY, 15, 1) /* for bl30 */
#define IDLE_MUX bits_desc(SARADC_DETECT_IDLE_SW, 7, 3)
#define DETECT_MUX bits_desc(SARADC_DETECT_IDLE_SW, 23, 3)
#ifdef CONFIG_MACH_MESON8B
#define BANDGAP_EN bits_desc(SARADC_DELTA_10, 10, 1)
#define TEMP_TRIM bits_desc(SARADC_DELTA_10, 11, 4)
#define TEMP_EN0 bits_desc(SARADC_DELTA_10, 15, 1)
#define TEMP_EN1 bits_desc(SARADC_DELTA_10, 26, 1)
#define TEMP_SELECT bits_desc(SARADC_DELTA_10, 27, 1)
#else
#define BANDGAP_EN bits_desc(SARADC_REG11, 13, 1)
#endif
/* saradc clock register */
#define REGC_CLK_DIV bits_desc(0, 0, 8)
#define REGC_CLK_EN bits_desc(0, 8, 1)
#define REGC_CLK_SRC bits_desc(0, 9, 3)
#define FIFO_MAX 32
#endif

View File

@@ -132,7 +132,6 @@ static const char * const log_comment[] = {
"pio begin",
"pio end"
};
static void spicc_log_init(struct spicc *spicc)
{
spicc->log = 0;
@@ -212,6 +211,37 @@ static void spicc_log_print(struct spicc *spicc)
#define spicc_log_print(spicc)
#endif
static void setb(void __iomem *mem_base,
unsigned int bits_desc,
unsigned int bits_val) {
unsigned int mem_offset, val;
unsigned int bits_offset, bits_mask;
if (IS_ERR(mem_base))
return;
mem_offset = of_mem_offset(bits_desc);
bits_offset = of_bits_offset(bits_desc);
bits_mask = (1L<<of_bits_len(bits_desc))-1;
val = readl(mem_base+mem_offset);
val &= ~(bits_mask << bits_offset);
val |= (bits_val & bits_mask) << bits_offset;
writel(val, mem_base+mem_offset);
}
static unsigned int getb(void __iomem *mem_base,
unsigned int bits_desc) {
unsigned int mem_offset, val;
unsigned int bits_offset, bits_mask;
if (IS_ERR(mem_base))
return -1;
mem_offset = of_mem_offset(bits_desc);
bits_offset = of_bits_offset(bits_desc);
bits_mask = (1L<<of_bits_len(bits_desc))-1;
val = readl(mem_base+mem_offset);
return (val >> bits_offset) & bits_mask;
}
/* Note this is chip_select enable or disable */
void spicc_chip_select(struct spi_device *spi, bool select)
{

View File

@@ -18,8 +18,6 @@
#ifndef __SPICC_H__
#define __SPICC_H__
#include <linux/amlogic/saradc.h>
#define SPICC_FIFO_SIZE 16
#define SPICC_DEFAULT_BIT_WIDTH 8
#define SPICC_DEFAULT_SPEED_HZ 3000000
@@ -41,6 +39,12 @@
#define SPICC_REG_ENHANCE_CNTL (14<<2)
#define SPICC_REG_ENHANCE_CNTL1 (15<<2)
#define bits_desc(reg_offset, bits_offset, bits_len) \
(((bits_len)<<24)|((bits_offset)<<16)|(reg_offset))
#define of_mem_offset(bd) ((bd)&0xffff)
#define of_bits_offset(bd) (((bd)>>16)&0xff)
#define of_bits_len(bd) (((bd)>>24)&0xff)
#define CON_ENABLE bits_desc(SPICC_REG_CON, 0, 1)
#define CON_MODE bits_desc(SPICC_REG_CON, 1, 1)
#define CON_XCH bits_desc(SPICC_REG_CON, 2, 1)

View File

@@ -27,7 +27,7 @@
#include <linux/amlogic/cpucore_cooling.h>
#include <linux/amlogic/gpucore_cooling.h>
#include <linux/amlogic/gpu_cooling.h>
#include <linux/amlogic/saradc.h>
#include <linux/iio/consumer.h>
#include <linux/amlogic/efuse.h>
#include <linux/cpu.h>
#include <linux/amlogic/aml_thermal_hw.h>
@@ -72,6 +72,7 @@ struct aml_thermal_sensor {
unsigned int cool_dev_num : 9;
struct cpumask mask[NUM_CLUSTERS];
struct cool_dev *cool_devs;
struct iio_channel *temp_chan;
struct thermal_zone_device *tzd;
};
@@ -103,7 +104,7 @@ int thermal_firmware_init(void)
soc_sensor.chip_trimmed = 0;
}
if (soc_sensor.chip_trimmed) {
temp_sensor_adc_init(soc_sensor.ts_c);
iio_write_channel_raw(soc_sensor.temp_chan, soc_sensor.ts_c);
return 0;
} else
return -1;
@@ -113,17 +114,19 @@ EXPORT_SYMBOL(thermal_firmware_init);
int get_cpu_temp(void)
{
int ret = TEMP_NOT_TRIMMED, tempa;
int ret;
int tempa;
int tval = TEMP_NOT_TRIMMED;
if (soc_sensor.chip_trimmed) {
ret = get_adc_sample(0, TEMP_ADC_CHANNEL);
ret = iio_read_channel_processed(soc_sensor.temp_chan, &tval);
if (ret >= 0) {
tempa = (10 * (ret - soc_sensor.fix_value)) / 32 + 27;
ret = tempa;
tempa = (10 * (tval - soc_sensor.fix_value)) / 32 + 27;
tval = tempa;
} else
ret = TEMP_ADC_ERROR;
tval = TEMP_ADC_ERROR;
}
return ret;
return tval;
}
EXPORT_SYMBOL(get_cpu_temp);
@@ -357,6 +360,10 @@ static int aml_thermal_probe(struct platform_device *pdev)
return -EPROBE_DEFER;
}
soc_sensor.temp_chan = devm_iio_channel_get(&pdev->dev, "TEMP_CHAN");
if (IS_ERR(soc_sensor.temp_chan))
return PTR_ERR(soc_sensor.temp_chan);
if (thermal_firmware_init() < 0) {
dev_err(&pdev->dev, "chip is not trimmed, disable thermal\n");
return -EINVAL;

View File

@@ -0,0 +1,19 @@
/*
* This header provides constants for configuring the AMLOGIC SAR ADC
*/
#ifndef _DT_BINDINGS_IIO_ADC_AMLOGIC_H
#define _DT_BINDINGS_IIO_ADC_AMLOGIC_H
#define SARADC_CH0 0
#define SARADC_CH1 1
#define SARADC_CH2 2
#define SARADC_CH3 3
#define SARADC_CH4 4
#define SARADC_CH5 5
#define SARADC_CH6 6
#define SARADC_CH7 7
#define SARADC_CH_NUM 8
#endif

View File

@@ -1,54 +0,0 @@
/*
* include/linux/amlogic/saradc.h
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#ifndef __AML_SARADC_H__
#define __AML_SARADC_H__
#include <linux/io.h>
#define SARADC_DEV_NUM 1
enum {
CHAN_0 = 0,
CHAN_1,
CHAN_2,
CHAN_3,
CHAN_4,
CHAN_5,
CHAN_6,
CHAN_7,
SARADC_CHAN_NUM,
};
extern int get_adc_sample(int dev_id, int ch);
extern int get_adc_sample_12bit(int dev_id, int ch);
#ifdef CONFIG_AMLOGIC_M8B_TEMP_SENSOR
extern void temp_sensor_adc_init(int triming);
#endif
#define bits_desc(reg_offset, bits_offset, bits_len) \
(((bits_len)<<24)|((bits_offset)<<16)|(reg_offset))
#define of_mem_offset(bd) ((bd)&0xffff)
#define of_bits_offset(bd) (((bd)>>16)&0xff)
#define of_bits_len(bd) (((bd)>>24)&0xff)
extern void setb(void __iomem *mem_base, unsigned int bits_desc,
unsigned int bits_val);
extern unsigned int getb(void __iomem *mem_base, unsigned int bits_desc);
#endif