Skip to content

Commit

Permalink
Merge pull request #39 from mpredfearn/wip-ci20-v3.18-adc
Browse files Browse the repository at this point in the history
jz4780: 3.18 ADC fixes
aux1/aux2 audio inputs on secondary header via sysfs works with these
  • Loading branch information
ZubairLK committed Jul 7, 2015
2 parents f65a81c + 2029a20 commit d39a58a
Show file tree
Hide file tree
Showing 8 changed files with 108 additions and 21 deletions.
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

0 comments on commit d39a58a

Please sign in to comment.