summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNaga Radhesh <naga.radheshy@stericsson.com>2012-01-17 16:16:43 +0530
committerPhilippe Langlais <philippe.langlais@stericsson.com>2012-05-22 11:01:39 +0200
commit2ab2bbebe4ad7f2e6edef2f4fb11d275ec9b0737 (patch)
tree6547c5ac47586d6bdd9323241b713a05638900eb
parenta3f15a7ec440dbccb72f0da6bf65f5c21797a69c (diff)
ab8500-pwm:AB8505:Enable support for PWMLED blink
Enable support for PWM OUT LED blinking for AB8505.Instead of having 3 pwm instances from ab8500 core file add it as platform data. ST-Ericsson ID: 366316 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: Trivial Change-Id:I63cd5510d3c1071613871946f7c624d2e2026568 Signed-off-by: Naga Radhesh <naga.radheshy@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/45669 Reviewed-by: QABUILD Reviewed-by: Arun MURTHY <arun.murthy@stericsson.com> Reviewed-by: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com>
-rw-r--r--drivers/mfd/ab8500-core.c8
-rw-r--r--drivers/misc/ab8500-pwm.c96
-rw-r--r--include/linux/mfd/ab8500/pwmleds.h20
-rw-r--r--include/linux/mfd/abx500/ab8500.h2
4 files changed, 106 insertions, 20 deletions
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index e92f51b1136..8137ac22816 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -803,14 +803,6 @@ static struct mfd_cell __devinitdata abx500_common_devs[] = {
.name = "ab8500-pwm",
.id = 1,
},
- {
- .name = "ab8500-pwm",
- .id = 2,
- },
- {
- .name = "ab8500-pwm",
- .id = 3,
- },
{ .name = "ab8500-leds", },
{
.name = "ab8500-denc",
diff --git a/drivers/misc/ab8500-pwm.c b/drivers/misc/ab8500-pwm.c
index 7a928667169..d7a62767a58 100644
--- a/drivers/misc/ab8500-pwm.c
+++ b/drivers/misc/ab8500-pwm.c
@@ -12,7 +12,7 @@
#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500/ab8500.h>
#include <linux/module.h>
-
+#include <linux/mfd/ab8500/pwmleds.h>
/*
* PWM Out generators
* Bank: 0x10
@@ -20,6 +20,11 @@
#define AB8500_PWM_OUT_CTRL1_REG 0x60
#define AB8500_PWM_OUT_CTRL2_REG 0x61
#define AB8500_PWM_OUT_CTRL7_REG 0x66
+#define AB8505_PWM_OUT_BLINK_CTRL1_REG 0x68
+#define AB8505_PWM_OUT_BLINK_CTRL4_REG 0x6B
+#define AB8505_PWM_OUT_BLINK_CTRL_DUTYBIT 4
+#define AB8505_PWM_OUT_BLINK_DUTYMASK (0x0F << AB8505_PWM_OUT_BLINK_CTRL_DUTYBIT)
+
/* backlight driver constants */
#define ENABLE_PWM 1
@@ -31,11 +36,67 @@ struct pwm_device {
struct clk *clk;
const char *label;
unsigned int pwm_id;
+ unsigned int blink_en;
+ struct ab8500 *parent;
bool clk_enabled;
};
static LIST_HEAD(pwm_list);
+int pwm_config_blink(struct pwm_device *pwm, int duty_ns, int period_ns)
+{
+ int ret;
+ unsigned int value;
+ u8 reg;
+ if ((!is_ab8505(pwm->parent)) || (!pwm->blink_en)) {
+ dev_err(pwm->dev, "setting blinking for this "
+ "device not supported\n");
+ return -EINVAL;
+ }
+ /*
+ * get the period value that is to be written to
+ * AB8500_PWM_OUT_BLINK_CTRL1 REGS[0:2]
+ */
+ value = period_ns & 0x07;
+ /*
+ * get blink duty value to be written to
+ * AB8500_PWM_OUT_BLINK_CTRL REGS[7:4]
+ */
+ value |= ((duty_ns << AB8505_PWM_OUT_BLINK_CTRL_DUTYBIT) &
+ AB8505_PWM_OUT_BLINK_DUTYMASK);
+
+ reg = AB8505_PWM_OUT_BLINK_CTRL1_REG + (pwm->pwm_id - 1);
+
+ ret = abx500_set_register_interruptible(pwm->dev, AB8500_MISC,
+ reg, (u8)value);
+ if (ret < 0)
+ dev_err(pwm->dev, "%s: Failed to config PWM blink,Error %d\n",
+ pwm->label, ret);
+ return ret;
+}
+
+int pwm_blink_ctrl(struct pwm_device *pwm , int enable)
+{
+ int ret;
+
+ if ((!is_ab8505(pwm->parent)) || (!pwm->blink_en)) {
+ dev_err(pwm->dev, "setting blinking for this "
+ "device not supported\n");
+ return -EINVAL;
+ }
+ /*
+ * Enable/disable blinking feature for corresponding PWMOUT
+ * channel depending on value of enable.
+ */
+ ret = abx500_mask_and_set_register_interruptible(pwm->dev,
+ AB8500_MISC, AB8505_PWM_OUT_BLINK_CTRL4_REG,
+ 1 << (pwm->pwm_id-1), enable << (pwm->pwm_id-1));
+ if (ret < 0)
+ dev_err(pwm->dev, "%s: Failed to control PWM blink,Error %d\n",
+ pwm->label, ret);
+ return ret;
+}
+
int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
{
int ret = 0;
@@ -82,7 +143,7 @@ int pwm_enable(struct pwm_device *pwm)
AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG,
1 << (pwm->pwm_id-1), 1 << (pwm->pwm_id-1));
if (ret < 0)
- dev_err(pwm->dev, "%s: Failed to disable PWM, Error %d\n",
+ dev_err(pwm->dev, "%s: Failed to enable PWM, Error %d\n",
pwm->label, ret);
return ret;
}
@@ -123,7 +184,6 @@ EXPORT_SYMBOL(pwm_disable);
struct pwm_device *pwm_request(int pwm_id, const char *label)
{
struct pwm_device *pwm;
-
list_for_each_entry(pwm, &pwm_list, node) {
if (pwm->pwm_id == pwm_id) {
pwm->label = label;
@@ -144,38 +204,50 @@ EXPORT_SYMBOL(pwm_free);
static int __devinit ab8500_pwm_probe(struct platform_device *pdev)
{
+ struct ab8500 *parent = dev_get_drvdata(pdev->dev.parent);
+ struct ab8500_platform_data *plat = dev_get_platdata(parent->dev);
+ struct ab8500_pwmled_platform_data *pdata = plat->pwmled;
struct pwm_device *pwm;
- int ret = 0;
+ int ret = 0 , i;
/*
* Nothing to be done in probe, this is required to get the
* device which is required for ab8500 read and write
*/
- pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
+ pwm = kzalloc(((sizeof(struct pwm_device)) * pdata->num_pwm),
+ GFP_KERNEL);
if (pwm == NULL) {
dev_err(&pdev->dev, "failed to allocate memory\n");
return -ENOMEM;
}
- pwm->dev = &pdev->dev;
- pwm->pwm_id = pdev->id;
- list_add_tail(&pwm->node, &pwm_list);
- platform_set_drvdata(pdev, pwm);
-
+ for (i = 0; i < pdata->num_pwm; i++) {
+ pwm[i].dev = &pdev->dev;
+ pwm[i].parent = parent;
+ pwm[i].blink_en = pdata->leds[i].blink_en;
+ pwm[i].pwm_id = pdata->leds[i].pwm_id;
+ list_add_tail(&pwm[i].node, &pwm_list);
+ }
pwm->clk = clk_get(pwm->dev, NULL);
if (IS_ERR(pwm->clk)) {
dev_err(pwm->dev, "clock request failed\n");
ret = PTR_ERR(pwm->clk);
- kfree(pwm);
- return ret;
+ goto fail;
}
+ platform_set_drvdata(pdev, pwm);
pwm->clk_enabled = false;
dev_dbg(pwm->dev, "pwm probe successful\n");
return ret;
+
+fail:
+ list_del(&pwm->node);
+ kfree(pwm);
+ return ret;
}
static int __devexit ab8500_pwm_remove(struct platform_device *pdev)
{
struct pwm_device *pwm = platform_get_drvdata(pdev);
+
list_del(&pwm->node);
clk_put(pwm->clk);
dev_dbg(&pdev->dev, "pwm driver removed\n");
diff --git a/include/linux/mfd/ab8500/pwmleds.h b/include/linux/mfd/ab8500/pwmleds.h
new file mode 100644
index 00000000000..e31658280a0
--- /dev/null
+++ b/include/linux/mfd/ab8500/pwmleds.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright ST-Ericsson 2012.
+ *
+ * Author: Naga Radhesh <naga.radheshy@stericsson.com>
+ * Licensed under GPLv2.
+ */
+#ifndef _AB8500_PWMLED_H
+#define _AB8500_PWMLED_H
+
+struct ab8500_led_pwm {
+ int pwm_id;
+ int blink_en;
+};
+
+struct ab8500_pwmled_platform_data {
+ int num_pwm;
+ struct ab8500_led_pwm *leds;
+};
+
+#endif
diff --git a/include/linux/mfd/abx500/ab8500.h b/include/linux/mfd/abx500/ab8500.h
index 7e056197b98..a51161222e1 100644
--- a/include/linux/mfd/abx500/ab8500.h
+++ b/include/linux/mfd/abx500/ab8500.h
@@ -278,6 +278,7 @@ struct ab8500_sysctrl_platform_data;
* @battery: machine-specific battery management data
* @charger: machine-specific charger data
* @btemp: machine-specific battery temp data
+ * @pwmled: machine-specific pwmled data
*/
struct ab8500_platform_data {
int irq_base;
@@ -297,6 +298,7 @@ struct ab8500_platform_data {
struct ab8500_chargalg_platform_data *chargalg;
struct ab8500_gpio_platform_data *gpio;
struct ab8500_sysctrl_platform_data *sysctrl;
+ struct ab8500_pwmled_platform_data *pwmled;
};
extern int __devinit ab8500_init(struct ab8500 *ab8500,