.gpio = RK29_PIN4_PB2,
.default_trigger = "timer",
.active_low = 0,
+ .retain_state_suspended = 1,
.default_state = LEDS_GPIO_DEFSTATE_OFF,
},
{
.gpio = RK29_PIN4_PB1,
.default_trigger = "timer",
.active_low = 0,
+ .retain_state_suspended = 1,
.default_state = LEDS_GPIO_DEFSTATE_OFF,
},
{
.gpio = RK29_PIN4_PB0,
.default_trigger = "timer",
.active_low = 0,
+ .retain_state_suspended = 1,
.default_state = LEDS_GPIO_DEFSTATE_OFF,
},
};
},
};
#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,
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 = {
#ifdef CONFIG_LEDS_GPIO_PLATFORM
&rk29_device_gpio_leds,
#endif
+#ifdef CONFIG_LEDS_NEWTON_PWM
+ &rk29_device_pwm_leds,
+#endif
};
/*****************************************************************************************
--- /dev/null
+/*\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