Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

jz4780: 3.18 ADC fixes #39

Merged
merged 6 commits into from
Jul 7, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions Documentation/devicetree/bindings/mfd/ingenic,jz4740-adc.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
* Ingenic JZ4740 ADC

Required properties:
- compatible: should be "ingenic,jz4740-adc"
- reg: Should contain the address & length of registers
- interrupts: Should specify the interrupt provided by parent.
- clocks: Should contain a single clock specifier for the ADC clock.
- clock-names: Should be "adc".

Example:

adc@0x10070000 {
compatible = "ingenic,jz4740-adc";
reg = <0x10070000 0x30>;

interrupt-parent = <&intc>;
interrupts = <18>;

clocks = <&cgu JZ4780_CLK_SADC>;
clock-names = "adc";
};

11 changes: 11 additions & 0 deletions arch/mips/boot/dts/jz4780.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,17 @@
};
};
};

adc@0x10070000 {
compatible = "ingenic,jz4780-adc";
reg = <0x10070000 0x30>;

interrupt-parent = <&intc>;
interrupts = <18>;

clocks = <&cgu JZ4780_CLK_SADC>;
clock-names = "adc";
};
};

ahb2 {
Expand Down
5 changes: 3 additions & 2 deletions arch/mips/include/asm/mach-jz4740/irq.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,9 @@
#define JZ4740_IRQ_INTC_GPIO(x) (JZ4740_IRQ_GPIO0 - (x))
#define JZ4740_IRQ_GPIO(x) (JZ4740_IRQ(NR_INTC_IRQS + 16) + (x))

#define JZ4740_IRQ_ADC_BASE JZ4740_IRQ(NR_INTC_IRQS + 144)
#define JZ4740_IRQ_ADC_BASE JZ4740_IRQ(256)
#define JZ4740_IRQ_ADC_COUNT 6

#define NR_IRQS (JZ4740_IRQ_ADC_BASE + 6)
#define NR_IRQS (JZ4740_IRQ_ADC_BASE + JZ4740_IRQ_ADC_COUNT)

#endif
2 changes: 1 addition & 1 deletion drivers/hwmon/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -597,7 +597,7 @@ config SENSORS_IT87

config SENSORS_JZ4740
tristate "Ingenic JZ4740 SoC ADC driver"
depends on MACH_JZ4740 && MFD_JZ4740_ADC
depends on (MACH_JZ4740 || MACH_JZ4780) && MFD_JZ4740_ADC
help
If you say yes here you get support for reading adc values from the ADCIN
pin on Ingenic JZ4740 SoC based boards.
Expand Down
31 changes: 29 additions & 2 deletions drivers/hwmon/jz4740-hwmon.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
#include <linux/mfd/core.h>

#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/jz4740-adc.h>

struct jz4740_hwmon {
void __iomem *base;
Expand All @@ -38,6 +40,7 @@ struct jz4740_hwmon {
struct completion read_completion;

struct mutex lock;
enum jz4740_adc_version version;
};

static ssize_t jz4740_hwmon_show_name(struct device *dev,
Expand All @@ -59,6 +62,8 @@ static ssize_t jz4740_hwmon_read_adcin(struct device *dev,
{
struct jz4740_hwmon *hwmon = dev_get_drvdata(dev);
struct completion *completion = &hwmon->read_completion;
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
unsigned int channel = 1;
long t;
unsigned long val;
int ret;
Expand All @@ -70,6 +75,18 @@ static ssize_t jz4740_hwmon_read_adcin(struct device *dev,
enable_irq(hwmon->irq);
hwmon->cell->enable(to_platform_device(dev));

if (hwmon->version >= JZ_ADC_JZ4780) {
switch(attr->index) {
case 1: channel = JZ_ADC_CONFIG_AUX1_EN;
break;
case 2: channel = JZ_ADC_CONFIG_AUX2_EN;
break;
default: dev_err(dev, "invalid channel attribute");
}

jz4740_adc_set_config(dev->parent, JZ_ADC_CONFIG_CMD_MASK , channel);
}

t = wait_for_completion_interruptible_timeout(completion, HZ);

if (t > 0) {
Expand All @@ -89,11 +106,17 @@ static ssize_t jz4740_hwmon_read_adcin(struct device *dev,
}

static DEVICE_ATTR(name, S_IRUGO, jz4740_hwmon_show_name, NULL);
static DEVICE_ATTR(in0_input, S_IRUGO, jz4740_hwmon_read_adcin, NULL);
static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, jz4740_hwmon_read_adcin, NULL , 1);
#ifdef CONFIG_MACH_JZ4780
static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, jz4740_hwmon_read_adcin, NULL , 2);
#endif

static struct attribute *jz4740_hwmon_attributes[] = {
&dev_attr_name.attr,
&dev_attr_in0_input.attr,
&sensor_dev_attr_in0_input.dev_attr.attr,
#ifdef CONFIG_MACH_JZ4780
&sensor_dev_attr_in1_input.dev_attr.attr,
#endif
NULL
};

Expand All @@ -105,6 +128,7 @@ static int jz4740_hwmon_probe(struct platform_device *pdev)
{
int ret;
struct jz4740_hwmon *hwmon;
struct jz4740_adc *adc;
struct resource *mem;

hwmon = devm_kzalloc(&pdev->dev, sizeof(*hwmon), GFP_KERNEL);
Expand Down Expand Up @@ -150,6 +174,9 @@ static int jz4740_hwmon_probe(struct platform_device *pdev)
goto err_remove_file;
}

adc = platform_get_drvdata(to_platform_device(pdev->dev.parent));
hwmon->version = adc->version;

return 0;

err_remove_file:
Expand Down
2 changes: 1 addition & 1 deletion drivers/mfd/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ config MFD_JZ4740_ADC
bool "Janz JZ4740 ADC core"
select MFD_CORE
select GENERIC_IRQ_CHIP
depends on MACH_JZ4740
depends on (MACH_JZ4740 || MACH_JZ4780)
help
Say yes here if you want support for the ADC unit in the JZ4740 SoC.
This driver is necessary for jz4740-battery and jz4740-hwmon driver.
Expand Down
34 changes: 19 additions & 15 deletions drivers/mfd/jz4740-adc.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
*/

#include <linux/err.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
Expand All @@ -39,6 +41,8 @@
#define JZ_REG_ADC_TOUCHSCREEN_BASE 0x10
#define JZ_REG_ADC_BATTERY_BASE 0x1c
#define JZ_REG_ADC_HWMON_BASE 0x20
#define JZ_REG_ADC_CMD 0x24
#define JZ_REG_ADC_CLKDIV 0x28

#define JZ_ADC_ENABLE_TOUCH BIT(2)
#define JZ_ADC_ENABLE_BATTERY BIT(1)
Expand All @@ -52,19 +56,6 @@ enum {
JZ_ADC_IRQ_PENDOWN,
};

struct jz4740_adc {
struct resource *mem;
void __iomem *base;

int irq;
struct irq_chip_generic *gc;

struct clk *clk;
atomic_t clk_ref;

spinlock_t lock;
};

static void jz4740_adc_irq_demux(unsigned int irq, struct irq_desc *desc)
{
struct irq_chip_generic *gc = irq_desc_get_handler_data(desc);
Expand Down Expand Up @@ -202,12 +193,19 @@ static const struct mfd_cell jz4740_adc_cells[] = {
},
};

static struct of_device_id jz4740_adc_of_match[] = {
{ .compatible = "ingenic,jz4740-adc", .data = (void *)JZ_ADC_JZ4740 },
{ .compatible = "ingenic,jz4780-adc", .data = (void *)JZ_ADC_JZ4780 },
{ },
};

static int jz4740_adc_probe(struct platform_device *pdev)
{
struct irq_chip_generic *gc;
struct irq_chip_type *ct;
struct jz4740_adc *adc;
struct resource *mem_base;
const struct of_device_id *match;
int ret;
int irq_base;

Expand All @@ -217,14 +215,17 @@ static int jz4740_adc_probe(struct platform_device *pdev)
return -ENOMEM;
}

match = of_match_device(of_match_ptr(jz4740_adc_of_match), &pdev->dev);
adc->version = (enum jz4740_adc_version)match->data;

adc->irq = platform_get_irq(pdev, 0);
if (adc->irq < 0) {
ret = adc->irq;
dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret);
return ret;
}

irq_base = platform_get_irq(pdev, 1);
irq_base = irq_alloc_descs(-1, 0, JZ4740_IRQ_ADC_COUNT, 0);
if (irq_base < 0) {
dev_err(&pdev->dev, "Failed to get irq base: %d\n", irq_base);
return irq_base;
Expand Down Expand Up @@ -259,7 +260,9 @@ static int jz4740_adc_probe(struct platform_device *pdev)
}

spin_lock_init(&adc->lock);
atomic_set(&adc->clk_ref, 0);

atomic_set(&adc->clk_ref, 1);
clk_prepare_enable(adc->clk);

platform_set_drvdata(pdev, adc);

Expand Down Expand Up @@ -324,6 +327,7 @@ static struct platform_driver jz4740_adc_driver = {
.remove = jz4740_adc_remove,
.driver = {
.name = "jz4740-adc",
.of_match_table = jz4740_adc_of_match,
.owner = THIS_MODULE,
},
};
Expand Down
22 changes: 22 additions & 0 deletions include/linux/jz4740-adc.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,32 @@ int jz4740_adc_set_config(struct device *dev, uint32_t mask, uint32_t val);
#define JZ_ADC_CONFIG_SAMPLE_NUM_MASK (0x7 << 10)
#define JZ_ADC_CONFIG_CLKDIV_MASK (0xf << 5)
#define JZ_ADC_CONFIG_BAT_MB BIT(4)
#define JZ_ADC_CONFIG_CMD_MASK 0x3
#define JZ_ADC_CONFIG_AUX1_EN 0x1
#define JZ_ADC_CONFIG_AUX2_EN 0x2

#define JZ_ADC_CONFIG_DNUM(dnum) ((dnum) << 16)
#define JZ_ADC_CONFIG_XYZ_OFFSET(dnum) ((xyz) << 13)
#define JZ_ADC_CONFIG_SAMPLE_NUM(x) ((x) << 10)
#define JZ_ADC_CONFIG_CLKDIV(div) ((div) << 5)

enum jz4740_adc_version {
JZ_ADC_JZ4740,
JZ_ADC_JZ4780,
};

struct jz4740_adc {
struct resource *mem;
void __iomem *base;

int irq;
struct irq_chip_generic *gc;

struct clk *clk;
atomic_t clk_ref;

spinlock_t lock;
enum jz4740_adc_version version;
};

#endif