newton: add support for the pwm led and update board_rk29_newton.c
authorlmc <lmc@rock-chips.com>
Wed, 27 Jul 2011 09:51:04 +0000 (17:51 +0800)
committerlmc <lmc@rock-chips.com>
Wed, 27 Jul 2011 09:51:04 +0000 (17:51 +0800)
arch/arm/configs/rk29_newton_defconfig
arch/arm/mach-rk29/board-rk29-newton.c
arch/arm/mach-rk29/include/mach/board.h
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/leds-newton-pwm.c [new file with mode: 0755]

index e8b7aa2dd03f45b2caa62f2ae0161d8df8ff943d..282bc83974312e71380bf4b30b33c569637b537f 100755 (executable)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.32.27
-# Wed Jul 27 10:06:42 2011
+# Wed Jul 27 17:48:19 2011
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -1687,6 +1687,7 @@ CONFIG_LEDS_CLASS=y
 # CONFIG_LEDS_PCA9532 is not set
 CONFIG_LEDS_GPIO=y
 CONFIG_LEDS_GPIO_PLATFORM=y
+CONFIG_LEDS_NEWTON_PWM=y
 # CONFIG_LEDS_LP3944 is not set
 # CONFIG_LEDS_PCA955X is not set
 # CONFIG_LEDS_BD2802 is not set
index 0b09fe27af8542a4f2487ff455fc80ec8a4b2265..03b2837c2a433df9117c10dc3eae3d416ca9c7b2 100755 (executable)
@@ -1688,6 +1688,7 @@ struct gpio_led rk29_leds[] = {
                        .gpio = RK29_PIN4_PB2,
                        .default_trigger = "timer",
                        .active_low = 0,
+                       .retain_state_suspended = 1,
                        .default_state = LEDS_GPIO_DEFSTATE_OFF,
                },
                {
@@ -1695,6 +1696,7 @@ struct gpio_led rk29_leds[] = {
                        .gpio = RK29_PIN4_PB1,
                        .default_trigger = "timer",
                        .active_low = 0,
+                       .retain_state_suspended = 1,
                        .default_state = LEDS_GPIO_DEFSTATE_OFF,
                },
                {
@@ -1702,6 +1704,7 @@ struct gpio_led rk29_leds[] = {
                        .gpio = RK29_PIN4_PB0,
                        .default_trigger = "timer",
                        .active_low = 0,
+                       .retain_state_suspended = 1,
                        .default_state = LEDS_GPIO_DEFSTATE_OFF,
                },
 };
@@ -1719,6 +1722,35 @@ struct platform_device rk29_device_gpio_leds = {
        },
 };
 #endif
+
+#ifdef CONFIG_LEDS_NEWTON_PWM
+static struct led_newton_pwm rk29_pwm_leds[] = {
+               {
+                       .name = "power_led",
+                       .pwm_id = 1,
+                       .pwm_gpio = RK29_PIN5_PD2,
+                       .pwm_iomux_name = GPIO5D2_PWM1_UART1SIRIN_NAME,
+                       .pwm_iomux_pwm = GPIO5H_PWM1,
+                       .pwm_iomux_gpio = GPIO5H_GPIO5D2,
+                       .freq = 1000,
+                       .period = 255,
+               },
+};
+
+static struct led_newton_pwm_platform_data rk29_pwm_leds_pdata = {
+       .leds = &rk29_pwm_leds,
+       .num_leds       = ARRAY_SIZE(rk29_pwm_leds),
+};
+
+static struct platform_device rk29_device_pwm_leds = {
+       .name   = "leds_newton_pwm",
+       .id     = -1,
+       .dev    = {
+          .platform_data  = &rk29_pwm_leds_pdata,
+       },
+};
+\r#endif
+       
 #ifdef CONFIG_USB_ANDROID
 struct usb_mass_storage_platform_data newton_mass_storage_pdata = {
        .nluns          = 1,
@@ -1747,6 +1779,9 @@ static void __init rk29_board_iomux_init(void)
        rk29_mux_api_set(GPIO4B1_FLASHDATA9_NAME,GPIO4L_GPIO4B1);
        rk29_mux_api_set(GPIO4B2_FLASHDATA10_NAME,GPIO4L_GPIO4B2);
        #endif
+       #ifdef CONFIG_LEDS_NEWTON_PWM
+       rk29_mux_api_set(GPIO5D2_PWM1_UART1SIRIN_NAME, GPIO5H_GPIO5D2);
+       #endif
 }
 
 static struct platform_device *devices[] __initdata = {
@@ -1877,6 +1912,9 @@ static struct platform_device *devices[] __initdata = {
 #ifdef CONFIG_LEDS_GPIO_PLATFORM
        &rk29_device_gpio_leds,
 #endif
+#ifdef CONFIG_LEDS_NEWTON_PWM
+       &rk29_device_pwm_leds,
+#endif
 };
 
 /*****************************************************************************************
index 706abdda19e8a0e5503b321be4d2e3ef1056e5f9..2e3dcfdc6230eeffb85132b1d1ce87c548b06cfb 100755 (executable)
 #include <linux/timer.h>
 #include <linux/notifier.h>
 
+struct led_newton_pwm {
+       const char      *name;
+       unsigned int    pwm_id;
+       unsigned                pwm_gpio;
+       char*                   pwm_iomux_name;
+       unsigned int    pwm_iomux_pwm;
+       unsigned int    pwm_iomux_gpio;
+       unsigned int    freq;/**/
+       unsigned int    period;/*1-100*/
+};
+
+struct led_newton_pwm_platform_data {
+       int                     num_leds;
+       struct led_newton_pwm* leds;
+};
+
 struct irda_info{
     u32 intr_pin;
     int (*iomux_init)(void);
index dab9a1bdb4c12ec55d35d3c5ed7f9c1fcc6e0773..a4e8e8fe4bedd3e1e84a2f16b7bb506c2c88469c 100755 (executable)
@@ -146,6 +146,14 @@ config LEDS_GPIO_OF
          of_platform devices.  For instance, LEDs which are listed in a "dts"
          file.
 
+config LEDS_NEWTON_PWM
+       bool "LED Support for newton pwm"
+       depends on LEDS_CLASS&&ARCH_RK29
+       default n
+       help
+         Let the leds-gpio driver drive LEDs which have been defined as
+         platform devices.  If you don't know what this means, say yes.
+         
 config LEDS_LP3944
        tristate "LED Support for N.S. LP3944 (Fun Light) I2C chip"
        depends on LEDS_CLASS && I2C
index 0263ff237ea28ccb213af0edfe34a7c912b8b5fa..ace2dc6541e1072b5f9a13294a76f36d2f10c255 100755 (executable)
@@ -30,6 +30,7 @@ obj-$(CONFIG_LEDS_WM831X_STATUS)      += leds-wm831x-status.o
 obj-$(CONFIG_LEDS_WM8350)              += leds-wm8350.o
 obj-$(CONFIG_LEDS_PWM)                 += leds-pwm.o
 obj-$(CONFIG_LEDS_ATT1272)                     += leds-att1272.o
+obj-$(CONFIG_LEDS_NEWTON_PWM)                  += leds-newton-pwm.o
 
 # LED SPI Drivers
 obj-$(CONFIG_LEDS_DAC124S085)          += leds-dac124s085.o
diff --git a/drivers/leds/leds-newton-pwm.c b/drivers/leds/leds-newton-pwm.c
new file mode 100755 (executable)
index 0000000..00e3a7d
--- /dev/null
@@ -0,0 +1,304 @@
+/*\r
+ * linux/drivers/leds-newton-pwm.c\r
+ *\r
+ * simple PWM based LED control\r
+ *\r
+ * Copyright 2009 LMC @ rock-chips (lmc@rock-chips.com)\r
+ *\r
+ * based on leds-gpio.c by Raphael Assenat <raph@8d.com>\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License version 2 as\r
+ * published by the Free Software Foundation.\r
+ */\r
+\r
+#include <linux/module.h>\r
+#include <linux/kernel.h>\r
+#include <linux/init.h>\r
+#include <linux/platform_device.h>\r
+#include <linux/fb.h>\r
+#include <linux/leds.h>\r
+#include <linux/err.h>\r
+#include <mach/iomux.h>\r
+#include <linux/gpio.h>\r
+#include <linux/clk.h>\r
+#include <linux/regulator/rk29-pwm-regulator.h>\r
+#include <linux/ctype.h>\r
+#include <mach/board.h>\r
+\r
+#if 0\r
+#define DBG(x...)      printk(KERN_INFO x)\r
+#else\r
+#define DBG(x...)\r
+#endif\r
+\r
+#define pwm_write_reg(id, addr, val)                   __raw_writel(val, addr+(RK29_PWM_BASE+id*0x10)) \r
+#define pwm_read_reg(id, addr)                         __raw_readl(addr+(RK29_PWM_BASE+id*0x10))\r
+#define LED_PWM_DIV    PWM_DIV1024 /*for led the pwm per div 1024 on the register*/\r
+#define LED_PER_DIV                    1000    \r
+#define LED_PWM_FULL   255\r
+\r
+static struct clk *pwm_clk;\r
+\r
+struct led_newton_pwm_data {\r
+       struct led_classdev     cdev;\r
+       unsigned int    pwm_id;\r
+       unsigned                pwm_gpio;\r
+       char*                   pwm_iomux_name;\r
+       unsigned int    pwm_iomux_pwm;\r
+       unsigned int    pwm_iomux_gpio;\r
+       unsigned int    freq;/**/\r
+       unsigned int    period;/*1-100*/\r
+};\r
+\r
+static void led_newton_pwm_set(struct led_classdev *led_cdev,\r
+       enum led_brightness brightness)\r
+{\r
+       struct led_newton_pwm_data *led_dat =\r
+               container_of(led_cdev, struct led_newton_pwm_data, cdev);\r
+       unsigned int period =  led_dat->period;\r
+       \r
+       DBG("Enter %s, brightness = %d,period =%d,freq =%d\n",__FUNCTION__,brightness,period, led_dat->freq);\r
+\r
+       if (brightness == 0||period == 0) {\r
+                // iomux pwm to gpio\r
+                rk29_mux_api_set(led_dat->pwm_iomux_name, led_dat->pwm_iomux_gpio);\r
+                // set gpio to low level        \r
+                gpio_set_value(led_dat->pwm_gpio,GPIO_LOW);\r
+       }else if(period == LED_PWM_FULL){\r
+               // iomux pwm to gpio\r
+                rk29_mux_api_set(led_dat->pwm_iomux_name, led_dat->pwm_iomux_gpio);\r
+                // set gpio to high level       \r
+                gpio_set_value(led_dat->pwm_gpio,GPIO_HIGH);\r
+       } else {\r
+               u32 divh,divTotal;\r
+               int id = led_dat->pwm_id;\r
+       unsigned long clkrate;\r
+\r
+       clkrate = clk_get_rate(pwm_clk);\r
+                 // iomux pwm\r
+               rk29_mux_api_set(led_dat->pwm_iomux_name, led_dat->pwm_iomux_pwm); \r
+               pwm_write_reg(id,PWM_REG_CTRL, LED_PWM_DIV|PWM_RESET);\r
+               divh = clkrate >> (1+(LED_PWM_DIV>>9));/*the register pre div*/\r
+               divh =  divh* led_dat->freq/LED_PER_DIV;\r
+               pwm_write_reg(id,PWM_REG_LRC,(divh == 0)?1:divh);\r
+\r
+               divTotal =pwm_read_reg(id,PWM_REG_LRC);\r
+               divh = divTotal*period/LED_PWM_FULL;\r
+               pwm_write_reg(id, PWM_REG_HRC, divh?divh:1);\r
+               pwm_write_reg(id,PWM_REG_CNTR,0);\r
+               pwm_write_reg(id, PWM_REG_CTRL,pwm_read_reg(id,PWM_REG_CTRL)|LED_PWM_DIV|PWM_ENABLE|PWM_TimeEN);\r
+       }\r
+}\r
+\r
+static ssize_t led_newton_freq_show(struct device *dev, \r
+               struct device_attribute *attr, char *buf)\r
+{\r
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);\r
+       struct led_newton_pwm_data *led_dat =\r
+               container_of(led_cdev, struct led_newton_pwm_data, cdev);\r
+\r
+       return sprintf(buf, "%u\n", led_dat->freq);\r
+}\r
+\r
+static ssize_t led_newton_freq_store(struct device *dev,\r
+               struct device_attribute *attr, const char *buf, size_t size)\r
+{\r
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);\r
+       struct led_newton_pwm_data *led_dat =\r
+               container_of(led_cdev, struct led_newton_pwm_data, cdev);\r
+       \r
+       ssize_t ret = -EINVAL;\r
+       char *after;\r
+       unsigned long state = simple_strtoul(buf, &after, 10);\r
+       size_t count = after - buf;\r
+\r
+       if (*after && isspace(*after))\r
+               count++;\r
+\r
+       if (count == size) {\r
+               ret = count;\r
+               if(state)\r
+                       led_dat->freq = state;\r
+               led_newton_pwm_set( led_cdev, led_cdev->brightness);\r
+       }\r
+\r
+       return ret;\r
+}\r
+\r
+static ssize_t led_newton_period_show(struct device *dev, \r
+               struct device_attribute *attr, char *buf)\r
+{\r
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);\r
+       struct led_newton_pwm_data *led_dat =\r
+               container_of(led_cdev, struct led_newton_pwm_data, cdev);\r
+\r
+       return sprintf(buf, "%u\n", led_dat->period);\r
+}\r
+\r
+static ssize_t led_newton_period_store(struct device *dev,\r
+               struct device_attribute *attr, const char *buf, size_t size)\r
+{\r
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);\r
+       struct led_newton_pwm_data *led_dat =\r
+               container_of(led_cdev, struct led_newton_pwm_data, cdev);\r
+       \r
+       ssize_t ret = -EINVAL;\r
+       char *after;\r
+       unsigned long state = simple_strtoul(buf, &after, 10);\r
+       size_t count = after - buf;\r
+\r
+       if (*after && isspace(*after))\r
+               count++;\r
+\r
+       if (count == size) {\r
+               ret = count;\r
+               led_dat->period = state;\r
+               led_newton_pwm_set( led_cdev, led_cdev->brightness);\r
+       }\r
+\r
+       return ret;\r
+}\r
+\r
+static DEVICE_ATTR(freq, 0644, led_newton_freq_show, led_newton_freq_store);\r
+static DEVICE_ATTR(period, 0644, led_newton_period_show, led_newton_period_store);\r
+\r
+\r
+static int led_newton_pwm_probe(struct platform_device *pdev)\r
+{\r
+       struct led_newton_pwm_platform_data *pdata = pdev->dev.platform_data;\r
+       struct led_newton_pwm *cur_led;\r
+       struct led_newton_pwm_data *leds_data, *led_dat;\r
+       int i, ret = 0;\r
+\r
+       if (!pdata)\r
+               return -EBUSY;\r
+\r
+       leds_data = kzalloc(sizeof(struct led_newton_pwm_data) * pdata->num_leds,\r
+                               GFP_KERNEL);\r
+       if (!leds_data)\r
+               return -ENOMEM;\r
+\r
+       for (i = 0; i < pdata->num_leds; i++) {\r
+               cur_led = &pdata->leds[i];\r
+               led_dat = &leds_data[i];\r
+               \r
+                ret = gpio_request(cur_led->pwm_gpio,"pwm");\r
+               \r
+               if (ret) {\r
+                       dev_err(&pdev->dev,"failed to request pwm gpio\n");\r
+                       goto err;\r
+               }\r
+\r
+\r
+               if (cur_led->pwm_id >2) {\r
+                       dev_err(&pdev->dev, "unable to request PWM %d\n",\r
+                                       cur_led->pwm_id);\r
+                       goto err;\r
+               }\r
+\r
+               led_dat->cdev.name = cur_led->name;\r
+               led_dat->pwm_id = cur_led->pwm_id;\r
+               led_dat->pwm_gpio = cur_led->pwm_gpio;\r
+               led_dat->pwm_iomux_name = cur_led->pwm_iomux_name;\r
+               led_dat->pwm_iomux_pwm = cur_led->pwm_iomux_pwm;\r
+               led_dat->pwm_iomux_gpio = cur_led->pwm_iomux_gpio;\r
+               if(cur_led->freq)\r
+                       led_dat->freq = cur_led->freq;\r
+               else\r
+                       led_dat->freq = 1;\r
+               led_dat->period = cur_led->period;\r
+               led_dat->cdev.brightness_set = led_newton_pwm_set;\r
+               led_dat->cdev.brightness = LED_FULL;\r
+               led_dat->cdev.flags     = 0;\r
+\r
+               ret = led_classdev_register(&pdev->dev, &led_dat->cdev);\r
+               if (ret < 0) {\r
+                       goto err;\r
+               }\r
+\r
+               ret = device_create_file(led_dat->cdev.dev, &dev_attr_freq);\r
+               if (ret)\r
+                       goto err;\r
+               \r
+               ret = device_create_file(led_dat->cdev.dev, &dev_attr_period);\r
+               if(ret)\r
+               {\r
+                       device_remove_file(led_dat->cdev.dev, &dev_attr_freq);\r
+                       goto err;\r
+               }\r
+       }\r
+       \r
+       pwm_clk = clk_get(NULL, "pwm");\r
+       clk_enable(pwm_clk);\r
+       platform_set_drvdata(pdev, leds_data);\r
+\r
+       return 0;\r
+\r
+err:\r
+       if (i > 0) {\r
+               for (i = i - 1; i >= 0; i--) {\r
+                       led_classdev_unregister(&leds_data[i].cdev);\r
+                       gpio_free(leds_data[i].pwm_gpio);\r
+               }\r
+       }\r
+\r
+       kfree(leds_data);\r
+\r
+       return ret;\r
+}\r
+\r
+static int __devexit led_newton_pwm_remove(struct platform_device *pdev)\r
+{\r
+       int i;\r
+       struct led_newton_pwm_platform_data *pdata = pdev->dev.platform_data;\r
+       struct led_newton_pwm_data *leds_data;\r
+\r
+       leds_data = platform_get_drvdata(pdev);\r
+\r
+       for (i = 0; i < pdata->num_leds; i++) {\r
+               led_classdev_unregister(&leds_data[i].cdev);\r
+               gpio_free(leds_data[i].pwm_gpio);\r
+       }\r
+\r
+       kfree(leds_data);\r
+\r
+       return 0;\r
+}\r
+int led_newton_pwm_suspend(struct platform_device *pdev, pm_message_t state)\r
+{\r
+       return 1;\r
+}\r
+\r
+int led_newton_pwm_resume(struct platform_device *pdev)\r
+{\r
+       return 1;\r
+}\r
+\r
+static struct platform_driver led_newton_pwm_driver = {\r
+       .probe          = led_newton_pwm_probe,\r
+       .remove         = __devexit_p(led_newton_pwm_remove),\r
+       .driver         = {\r
+               .name   = "leds_newton_pwm",\r
+               .owner  = THIS_MODULE,\r
+       },\r
+};\r
+\r
+static int __init led_newton_pwm_init(void)\r
+{\r
+       return platform_driver_register(&led_newton_pwm_driver);\r
+}\r
+\r
+static void __exit led_newton_pwm_exit(void)\r
+{\r
+       platform_driver_unregister(&led_newton_pwm_driver);\r
+}\r
+\r
+module_init(led_newton_pwm_init);\r
+module_exit(led_newton_pwm_exit);\r
+\r
+MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");\r
+MODULE_DESCRIPTION("PWM LED driver for PXA");\r
+MODULE_LICENSE("GPL");\r
+MODULE_ALIAS("platform:leds-pwm");\r
+\r