mfd: Add device tree probe support for mc13xxx

This adds device tree probe support for mc13xxx mfd driver.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
This commit is contained in:
Shawn Guo 2011-12-12 18:52:57 +01:00 committed by Samuel Ortiz
parent af9081ae64
commit 876989d586
2 changed files with 128 additions and 31 deletions

View File

@ -0,0 +1,53 @@
* Freescale MC13783/MC13892 Power Management Integrated Circuit (PMIC)
Required properties:
- compatible : Should be "fsl,mc13783" or "fsl,mc13892"
Optional properties:
- fsl,mc13xxx-uses-adc : Indicate the ADC is being used
- fsl,mc13xxx-uses-codec : Indicate the Audio Codec is being used
- fsl,mc13xxx-uses-rtc : Indicate the RTC is being used
- fsl,mc13xxx-uses-touch : Indicate the touchscreen controller is being used
Sub-nodes:
- regulators : Contain the regulator nodes. The name of regulator node
is being used by mc13xxx regulator driver to find the correct relator
device.
The bindings details of individual regulator device can be found in:
Documentation/devicetree/bindings/regulator/regulator.txt
Examples:
ecspi@70010000 { /* ECSPI1 */
fsl,spi-num-chipselects = <2>;
cs-gpios = <&gpio3 24 0>, /* GPIO4_24 */
<&gpio3 25 0>; /* GPIO4_25 */
status = "okay";
pmic: mc13892@0 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,mc13892";
spi-max-frequency = <6000000>;
reg = <0>;
interrupt-parent = <&gpio0>;
interrupts = <8>;
regulators {
sw1_reg: mc13892__sw1 {
regulator-min-microvolt = <600000>;
regulator-max-microvolt = <1375000>;
regulator-boot-on;
regulator-always-on;
};
sw2_reg: mc13892__sw2 {
regulator-min-microvolt = <900000>;
regulator-max-microvolt = <1850000>;
regulator-boot-on;
regulator-always-on;
};
};
};
};

View File

@ -18,11 +18,15 @@
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/mfd/core.h> #include <linux/mfd/core.h>
#include <linux/mfd/mc13xxx.h> #include <linux/mfd/mc13xxx.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
struct mc13xxx { struct mc13xxx {
struct spi_device *spidev; struct spi_device *spidev;
struct mutex lock; struct mutex lock;
int irq; int irq;
int flags;
irq_handler_t irqhandler[MC13XXX_NUM_IRQ]; irq_handler_t irqhandler[MC13XXX_NUM_IRQ];
void *irqdata[MC13XXX_NUM_IRQ]; void *irqdata[MC13XXX_NUM_IRQ];
@ -550,10 +554,7 @@ static const char *mc13xxx_get_chipname(struct mc13xxx *mc13xxx)
int mc13xxx_get_flags(struct mc13xxx *mc13xxx) int mc13xxx_get_flags(struct mc13xxx *mc13xxx)
{ {
struct mc13xxx_platform_data *pdata = return mc13xxx->flags;
dev_get_platdata(&mc13xxx->spidev->dev);
return pdata->flags;
} }
EXPORT_SYMBOL(mc13xxx_get_flags); EXPORT_SYMBOL(mc13xxx_get_flags);
@ -696,17 +697,67 @@ static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format)
return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL, 0); return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL, 0);
} }
#ifdef CONFIG_OF
static int mc13xxx_probe_flags_dt(struct mc13xxx *mc13xxx)
{
struct device_node *np = mc13xxx->spidev->dev.of_node;
if (!np)
return -ENODEV;
if (of_get_property(np, "fsl,mc13xxx-uses-adc", NULL))
mc13xxx->flags |= MC13XXX_USE_ADC;
if (of_get_property(np, "fsl,mc13xxx-uses-codec", NULL))
mc13xxx->flags |= MC13XXX_USE_CODEC;
if (of_get_property(np, "fsl,mc13xxx-uses-rtc", NULL))
mc13xxx->flags |= MC13XXX_USE_RTC;
if (of_get_property(np, "fsl,mc13xxx-uses-touch", NULL))
mc13xxx->flags |= MC13XXX_USE_TOUCHSCREEN;
return 0;
}
#else
static inline int mc13xxx_probe_flags_dt(struct mc13xxx *mc13xxx)
{
return -ENODEV;
}
#endif
static const struct spi_device_id mc13xxx_device_id[] = {
{
.name = "mc13783",
.driver_data = MC13XXX_ID_MC13783,
}, {
.name = "mc13892",
.driver_data = MC13XXX_ID_MC13892,
}, {
/* sentinel */
}
};
MODULE_DEVICE_TABLE(spi, mc13xxx_device_id);
static const struct of_device_id mc13xxx_dt_ids[] = {
{ .compatible = "fsl,mc13783", .data = (void *) MC13XXX_ID_MC13783, },
{ .compatible = "fsl,mc13892", .data = (void *) MC13XXX_ID_MC13892, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mc13xxx_dt_ids);
static int mc13xxx_probe(struct spi_device *spi) static int mc13xxx_probe(struct spi_device *spi)
{ {
const struct of_device_id *of_id;
struct spi_driver *sdrv = to_spi_driver(spi->dev.driver);
struct mc13xxx *mc13xxx; struct mc13xxx *mc13xxx;
struct mc13xxx_platform_data *pdata = dev_get_platdata(&spi->dev); struct mc13xxx_platform_data *pdata = dev_get_platdata(&spi->dev);
enum mc13xxx_id id; enum mc13xxx_id id;
int ret; int ret;
if (!pdata) { of_id = of_match_device(mc13xxx_dt_ids, &spi->dev);
dev_err(&spi->dev, "invalid platform data\n"); if (of_id)
return -EINVAL; sdrv->id_table = &mc13xxx_device_id[(enum mc13xxx_id) of_id->data];
}
mc13xxx = kzalloc(sizeof(*mc13xxx), GFP_KERNEL); mc13xxx = kzalloc(sizeof(*mc13xxx), GFP_KERNEL);
if (!mc13xxx) if (!mc13xxx)
@ -749,28 +800,33 @@ err_revision:
mc13xxx_unlock(mc13xxx); mc13xxx_unlock(mc13xxx);
if (pdata->flags & MC13XXX_USE_ADC) if (mc13xxx_probe_flags_dt(mc13xxx) < 0 && pdata)
mc13xxx->flags = pdata->flags;
if (mc13xxx->flags & MC13XXX_USE_ADC)
mc13xxx_add_subdevice(mc13xxx, "%s-adc"); mc13xxx_add_subdevice(mc13xxx, "%s-adc");
if (pdata->flags & MC13XXX_USE_CODEC) if (mc13xxx->flags & MC13XXX_USE_CODEC)
mc13xxx_add_subdevice(mc13xxx, "%s-codec"); mc13xxx_add_subdevice(mc13xxx, "%s-codec");
mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator", if (mc13xxx->flags & MC13XXX_USE_RTC)
&pdata->regulators, sizeof(pdata->regulators));
if (pdata->flags & MC13XXX_USE_RTC)
mc13xxx_add_subdevice(mc13xxx, "%s-rtc"); mc13xxx_add_subdevice(mc13xxx, "%s-rtc");
if (pdata->flags & MC13XXX_USE_TOUCHSCREEN) if (mc13xxx->flags & MC13XXX_USE_TOUCHSCREEN)
mc13xxx_add_subdevice(mc13xxx, "%s-ts"); mc13xxx_add_subdevice(mc13xxx, "%s-ts");
if (pdata->leds) if (pdata) {
mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",
&pdata->regulators, sizeof(pdata->regulators));
mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led", mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led",
pdata->leds, sizeof(*pdata->leds)); pdata->leds, sizeof(*pdata->leds));
if (pdata->buttons)
mc13xxx_add_subdevice_pdata(mc13xxx, "%s-pwrbutton", mc13xxx_add_subdevice_pdata(mc13xxx, "%s-pwrbutton",
pdata->buttons, sizeof(*pdata->buttons)); pdata->buttons, sizeof(*pdata->buttons));
} else {
mc13xxx_add_subdevice(mc13xxx, "%s-regulator");
mc13xxx_add_subdevice(mc13xxx, "%s-led");
mc13xxx_add_subdevice(mc13xxx, "%s-pwrbutton");
}
return 0; return 0;
} }
@ -788,24 +844,12 @@ static int __devexit mc13xxx_remove(struct spi_device *spi)
return 0; return 0;
} }
static const struct spi_device_id mc13xxx_device_id[] = {
{
.name = "mc13783",
.driver_data = MC13XXX_ID_MC13783,
}, {
.name = "mc13892",
.driver_data = MC13XXX_ID_MC13892,
}, {
/* sentinel */
}
};
MODULE_DEVICE_TABLE(spi, mc13xxx_device_id);
static struct spi_driver mc13xxx_driver = { static struct spi_driver mc13xxx_driver = {
.id_table = mc13xxx_device_id, .id_table = mc13xxx_device_id,
.driver = { .driver = {
.name = "mc13xxx", .name = "mc13xxx",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = mc13xxx_dt_ids,
}, },
.probe = mc13xxx_probe, .probe = mc13xxx_probe,
.remove = __devexit_p(mc13xxx_remove), .remove = __devexit_p(mc13xxx_remove),