From d4d32dd85f76c04dfe55b6bf2bd74bece1c037d0 Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 20 Oct 2016 16:36:56 +0800 Subject: [PATCH] saradc: add saradc driver for gxl/gxm PD#138714: initial add saradc driver 1.add input/saradc 2.saradc support in gxl 3.saradc support in gxm 4.add bindings/amlogic/input/amlogic-saradc.txt Change-Id: I95f523300c453d59bea6a3e92b962cbb195b613c Signed-off-by: Xingyu Chen --- .../bindings/amlogic/input/amlogic-saradc.txt | 24 + MAINTAINERS | 4 + arch/arm64/boot/dts/amlogic/mesongxl.dtsi | 9 + arch/arm64/boot/dts/amlogic/mesongxm.dtsi | 9 + arch/arm64/configs/meson64_defconfig | 2 + drivers/amlogic/Kconfig | 2 + drivers/amlogic/Makefile | 2 + drivers/amlogic/input/Kconfig | 16 + drivers/amlogic/input/Makefile | 8 + drivers/amlogic/input/saradc/Kconfig | 8 + drivers/amlogic/input/saradc/Makefile | 9 + drivers/amlogic/input/saradc/saradc.c | 566 ++++++++++++++++++ drivers/amlogic/input/saradc/saradc_reg.h | 59 ++ include/linux/amlogic/saradc.h | 50 ++ 14 files changed, 768 insertions(+) create mode 100644 Documentation/devicetree/bindings/amlogic/input/amlogic-saradc.txt create mode 100644 drivers/amlogic/input/Kconfig create mode 100644 drivers/amlogic/input/Makefile create mode 100644 drivers/amlogic/input/saradc/Kconfig create mode 100644 drivers/amlogic/input/saradc/Makefile create mode 100644 drivers/amlogic/input/saradc/saradc.c create mode 100644 drivers/amlogic/input/saradc/saradc_reg.h create mode 100644 include/linux/amlogic/saradc.h diff --git a/Documentation/devicetree/bindings/amlogic/input/amlogic-saradc.txt b/Documentation/devicetree/bindings/amlogic/input/amlogic-saradc.txt new file mode 100644 index 000000000000..75d3e8826b60 --- /dev/null +++ b/Documentation/devicetree/bindings/amlogic/input/amlogic-saradc.txt @@ -0,0 +1,24 @@ +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>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 8aaed3a74178..bfa700f15499 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13446,3 +13446,7 @@ F: scripts/amlogic/configs/ AMLOGIC CRYPTO DMA M: Matthew Shyu F: drivers/amlogic/crypto/* + +AMLOGIC saradc +M: Xingyu Chen +F: drivers/amlogic/input/saradc/* diff --git a/arch/arm64/boot/dts/amlogic/mesongxl.dtsi b/arch/arm64/boot/dts/amlogic/mesongxl.dtsi index b157c485e3a2..611d22e4fe3d 100644 --- a/arch/arm64/boot/dts/amlogic/mesongxl.dtsi +++ b/arch/arm64/boot/dts/amlogic/mesongxl.dtsi @@ -699,5 +699,14 @@ interrupts = <0 188 1 0 189 1>; reg = <0x0 0xc883e000 0x0 0x28>; }; + + saradc: saradc { + compatible = "amlogic, saradc"; + status = "okay"; + clocks = <&clkc CLKID_SARADC>; + clock-names = "saradc_clk"; + reg = <0x0 0xc1108680 0x0 0x30 + 0x0 0xc883c3d8 0x0 0x08>; + }; }; diff --git a/arch/arm64/boot/dts/amlogic/mesongxm.dtsi b/arch/arm64/boot/dts/amlogic/mesongxm.dtsi index acc0ab7d140c..20a8d337c357 100644 --- a/arch/arm64/boot/dts/amlogic/mesongxm.dtsi +++ b/arch/arm64/boot/dts/amlogic/mesongxm.dtsi @@ -744,5 +744,14 @@ interrupts = <0 188 1 0 189 1>; reg = <0x0 0xc883e000 0x0 0x28>; }; + + saradc: saradc { + compatible = "amlogic, saradc"; + status = "okay"; + clocks = <&clkc CLKID_SARADC>; + clock-names = "saradc_clk"; + reg = <0x0 0xc1108680 0x0 0x30 + 0x0 0xc883c3d8 0x0 0x08>; + }; }; diff --git a/arch/arm64/configs/meson64_defconfig b/arch/arm64/configs/meson64_defconfig index f41e73195a2e..0e9531b47653 100644 --- a/arch/arm64/configs/meson64_defconfig +++ b/arch/arm64/configs/meson64_defconfig @@ -168,6 +168,8 @@ CONFIG_AMLOGIC_TIMER=y CONFIG_AMLOGIC_BC_TIMER=y CONFIG_AMLOGIC_CLK=y CONFIG_AMLOGIC_CRYPTO=y +CONFIG_AMLOGIC_INPUT=y +CONFIG_AMLOGIC_SARADC=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y diff --git a/drivers/amlogic/Kconfig b/drivers/amlogic/Kconfig index 0b277df52d90..010a8d4987f8 100644 --- a/drivers/amlogic/Kconfig +++ b/drivers/amlogic/Kconfig @@ -32,5 +32,7 @@ source "drivers/amlogic/clocksource/Kconfig" source "drivers/amlogic/clk/Kconfig" source "drivers/amlogic/crypto/Kconfig" + +source "drivers/amlogic/input/Kconfig" endmenu endif diff --git a/drivers/amlogic/Makefile b/drivers/amlogic/Makefile index b55af52c5478..1d5152719cd9 100644 --- a/drivers/amlogic/Makefile +++ b/drivers/amlogic/Makefile @@ -29,3 +29,5 @@ obj-$(CONFIG_AMLOGIC_TIMER) += clocksource/ obj-$(CONFIG_AMLOGIC_CLK) += clk/ obj-$(CONFIG_AMLOGIC_CRYPTO) += crypto/ + +obj-$(CONFIG_AMLOGIC_INPUT) += input/ diff --git a/drivers/amlogic/input/Kconfig b/drivers/amlogic/input/Kconfig new file mode 100644 index 000000000000..c3c509410f5e --- /dev/null +++ b/drivers/amlogic/input/Kconfig @@ -0,0 +1,16 @@ +# +# Input device configuration +# + +menuconfig AMLOGIC_INPUT + bool "Input Device Support" + default n + help + "Input devices include keyboard, touchscreen, remote, sensor, etc." + +if AMLOGIC_INPUT + +source "drivers/amlogic/input/saradc/Kconfig" + +endif + diff --git a/drivers/amlogic/input/Makefile b/drivers/amlogic/input/Makefile new file mode 100644 index 000000000000..b331933700e0 --- /dev/null +++ b/drivers/amlogic/input/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for the input core drivers. +# + +# Each configuration option enables a list of files. + +obj-$(CONFIG_AMLOGIC_INPUT) += saradc/ + diff --git a/drivers/amlogic/input/saradc/Kconfig b/drivers/amlogic/input/saradc/Kconfig new file mode 100644 index 000000000000..c0e8f6a08001 --- /dev/null +++ b/drivers/amlogic/input/saradc/Kconfig @@ -0,0 +1,8 @@ +# +# 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. diff --git a/drivers/amlogic/input/saradc/Makefile b/drivers/amlogic/input/saradc/Makefile new file mode 100644 index 000000000000..8c7dce8e923a --- /dev/null +++ b/drivers/amlogic/input/saradc/Makefile @@ -0,0 +1,9 @@ +# +# Makefile for the input core drivers. +# + +# Each configuration option enables a list of files. + +obj-$(CONFIG_AMLOGIC_SARADC) += saradc.o + + diff --git a/drivers/amlogic/input/saradc/saradc.c b/drivers/amlogic/input/saradc/saradc.c new file mode 100644 index 000000000000..b93f175c3419 --- /dev/null +++ b/drivers/amlogic/input/saradc/saradc.c @@ -0,0 +1,566 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 + +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; +}; + +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<> bits_offset) & bits_mask; +} +EXPORT_SYMBOL(getb); + +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); + setb(mem_base, CLK_EN, 1); + setb(adc->clk_mem_base, REGC_CLK_EN, 1); + } else { + setb(adc->clk_mem_base, REGC_CLK_EN, 0); + 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; + setb(mem_base, CLK_DIV, clk_div); + setb(adc->clk_mem_base, REGC_CLK_DIV, clk_div); + setb(adc->clk_mem_base, REGC_CLK_SRC, 0); + 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); + 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 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_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 (is_meson_gxbb_cpu() || is_meson_gxtvbb_cpu()) + flag_12bit = 0; + else + flag_12bit = 1; + + 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; + } + 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); + 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; + + 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"); */ + class_register(&saradc_class); + return platform_driver_register(&saradc_driver); +} + +static void __exit saradc_exit(void) +{ + /* printk(KERN_INFO "SARADC Driver exit.\n"); */ + platform_driver_unregister(&saradc_driver); + class_unregister(&saradc_class); +} + +module_init(saradc_init); +module_exit(saradc_exit); + +MODULE_AUTHOR("aml"); +MODULE_DESCRIPTION("SARADC Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/amlogic/input/saradc/saradc_reg.h b/drivers/amlogic/input/saradc/saradc_reg.h new file mode 100644 index 000000000000..79c2f81cb90c --- /dev/null +++ b/drivers/amlogic/input/saradc/saradc_reg.h @@ -0,0 +1,59 @@ +/* + * 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 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, 1) +#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) +#define BANDGAP_EN bits_desc(SARADC_REG11, 13, 1) +/* 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 diff --git a/include/linux/amlogic/saradc.h b/include/linux/amlogic/saradc.h new file mode 100644 index 000000000000..6624dc367cb9 --- /dev/null +++ b/include/linux/amlogic/saradc.h @@ -0,0 +1,50 @@ +/* + * 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 + +#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); + +#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