diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index f16c278..8c08120 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -85,6 +85,17 @@ config ATMEL_PWM
 	  purposes including software controlled power-efficient backlights
 	  on LCD displays, motor control, and waveform generation.
 
+config SUNXI_PWM 
+        tristate "Sunxi PWM Driver (pwm-sunxi)" 
+        help 
+          Say Y here if you want Hardware PWM Support 
+ 
+          To compile this driver as a module, choose M here: the 
+          module will be called pwm-sunxi.  This driver supports 
+          a sysfs interface at /sys/class/pwm-sunxi as well as the 
+          kernel pwm interface. 
+ 
+
 config AB8500_PWM
 	bool "AB8500 PWM support"
 	depends on AB8500_CORE && ARCH_U8500
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index f49d878..24a9408 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -55,3 +55,4 @@ obj-$(CONFIG_SENSORS_AK8975)	+= akm8975.o
 obj-$(CONFIG_SUN4I_VIBRATOR)	+= sun4i-vibrator.o
 obj-$(CONFIG_SUN4I_GPIO_UGLY)	+= sun4i-gpio.o
 obj-$(CONFIG_SUNXI_DBGREG)		+= sunxi-dbgreg.o
+obj-$(CONFIG_SUNXI_PWM)                += pwm-sunxi.o 
diff --git a/drivers/misc/pwm-sunxi.c b/drivers/misc/pwm-sunxi.c
new file mode 100644
index 0000000..1b2fc65
--- /dev/null
+++ b/drivers/misc/pwm-sunxi.c
@@ -0,0 +1,928 @@
+/* pwm-sunxi.c 
+ * 
+ * pwm module for sun4i (and others) like cubieboard and pcduino 
+ * 
+ * (C) Copyright 2013 
+ * David H. Wilkins  <dwil...@conecuh.com> 
+ * 
+ * CHANGELOG:
+ * 10.08.2013 - Stefan Voit <stefan.voit@voit-consulting.com>
+ * - Added script.bin support for [pwm0_para] and [pwm1_para]: pwm_used, pwm_period, pwm_duty_percent
+ * - Added initial setup based on script.bin settings
+ * - Removed bug that caused the PWM to pause quickly when changing parameters
+ * - Dropped debug/dump functions
+ *
+ * TODO:
+ * - Implement duty_percent=0 to set pwm line to 0 - right now it goes to 100%
+ * - Change the script_bin settings loader for pwm_period to allow text based values (100ms, 10hz,...)
+ * - Merge h & c file
+ * - 
+ *
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License as 
+ * published by the Free Software Foundation; either version 2 of 
+ * the License, or (at your option) any later version. 
+ * 
+ * This program is distributed in the hope that it will be useful, 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the 
+ * GNU General Public License for more details. 
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+ * MA 02111-1307 USA 
+ */ 
+ 
+#include <linux/kobject.h> 
+#include <linux/slab.h> 
+#include <linux/device.h> 
+#include <linux/sysfs.h> 
+#include <linux/module.h> 
+#include <linux/kernel.h> 
+#include <linux/platform_device.h> 
+#include <linux/err.h> 
+#include <asm/io.h> 
+#include <asm/delay.h> 
+#include <mach/platform.h> 
+#include <linux/pwm.h> 
+#include <linux/ctype.h> 
+#include <linux/limits.h> 
+#include <pwm-sunxi.h> 
+#include <linux/pwm.h> 
+#include <linux/kdev_t.h> 
+#include <plat/sys_config.h>
+/* 
+ * Forward Declarations 
+ */ 
+
+
+#define SUNXI_PWM_DEBUG
+
+//comment to get debug messages
+#undef SUNXI_PWM_DEBUG
+ 
+void release_pwm_sunxi(struct kobject *kobj); 
+void pwm_setup_available_channels(void ); 
+ssize_t pwm_set_mode(unsigned int enable, struct sun4i_pwm_available_channel *chan); 
+enum sun4i_pwm_prescale  pwm_get_best_prescale(unsigned long long period); 
+unsigned int get_entire_cycles(struct sun4i_pwm_available_channel *chan); 
+unsigned int get_active_cycles(struct sun4i_pwm_available_channel *chan); 
+unsigned long convert_string_to_microseconds(const char *buf); 
+int pwm_set_period_and_duty(struct sun4i_pwm_available_channel *chan); 
+void fixup_duty(struct sun4i_pwm_available_channel *chan); 
+ 
+ 
+static DEFINE_MUTEX(sysfs_lock); 
+static struct class pwm_class; 
+ 
+struct kobject *pwm0_kobj; 
+struct kobject *pwm1_kobj; 
+ 
+void *PWM_CTRL_REG_BASE = NULL; 
+ 
+ 
+static struct class_attribute pwm_class_attrs[] = { 
+        __ATTR_NULL 
+}; 
+ 
+ 
+static struct class pwm_class = { 
+        .name =         "pwm-sunxi", 
+        .owner =        THIS_MODULE, 
+        .class_attrs =  pwm_class_attrs, 
+}; 
+ 
+ 
+/* 
+ * sysfs store / show functions 
+ */ 
+ 
+static ssize_t pwm_polarity_show(struct device *dev, struct device_attribute *attr, char *buf); 
+static ssize_t pwm_period_show(struct device *dev, struct device_attribute *attr, char *buf); 
+static ssize_t pwm_duty_show(struct device *dev, struct device_attribute *attr, char *buf); 
+static ssize_t pwm_run_show(struct device *dev,struct device_attribute *attr, char *buf); 
+static ssize_t pwm_duty_percent_show(struct device *dev,struct device_attribute *attr, char *buf); 
+static ssize_t pwm_pulse_show(struct device *dev,struct device_attribute *attr, char *buf); 
+static ssize_t pwm_pin_show(struct device *dev,struct device_attribute *attr, char *buf); 
+ 
+static ssize_t pwm_polarity_store(struct device *dev,struct device_attribute *attr, const char *buf, size_t size); 
+static ssize_t pwm_period_store(struct device *dev,struct device_attribute *attr, const char *buf, size_t size); 
+static ssize_t pwm_duty_store(struct device *dev,struct device_attribute *attr, const char *buf, size_t size); 
+static ssize_t pwm_run_store(struct device *dev,struct device_attribute *attr, const char *buf, size_t size); 
+static ssize_t pwm_duty_percent_store(struct device *dev,struct device_attribute *attr, const char *buf, size_t size); 
+static ssize_t pwm_pulse_store(struct device *dev,struct device_attribute *attr, const char *buf, size_t size); 
+ 
+static DEVICE_ATTR(polarity, 0644,pwm_polarity_show, pwm_polarity_store); 
+static DEVICE_ATTR(period, 0644, pwm_period_show, pwm_period_store); 
+static DEVICE_ATTR(duty, 0644,pwm_duty_show, pwm_duty_store); 
+static DEVICE_ATTR(run, 0644, pwm_run_show, pwm_run_store); 
+static DEVICE_ATTR(duty_percent, 0644, pwm_duty_percent_show, pwm_duty_percent_store); 
+static DEVICE_ATTR(pulse, 0644, pwm_pulse_show, pwm_pulse_store); 
+static DEVICE_ATTR(pin, 0644, pwm_pin_show, NULL); 
+ 
+static const struct attribute *pwm_attrs[] = { 
+        &dev_attr_polarity.attr, 
+        &dev_attr_period.attr, 
+        &dev_attr_duty.attr, 
+        &dev_attr_run.attr, 
+        &dev_attr_duty_percent.attr, 
+        &dev_attr_pulse.attr, 
+        &dev_attr_pin.attr, 
+        NULL, 
+}; 
+ 
+static const struct attribute_group pwm_attr_group = { 
+        .attrs = (struct attribute **) pwm_attrs 
+}; 
+ 
+struct device *pwm0; 
+struct device *pwm1; 
+ 
+ 
+static struct sun4i_pwm_available_channel pwm_available_chan[SUN4I_MAX_HARDWARE_PWM_CHANNELS]; 
+ 
+static int __init sunxi_pwm_init(void) 
+{ 
+        int return_val,init_enable,init_duty_percent;
+	int init_period; 
+	struct sun4i_pwm_available_channel *chan;
+	int err = 0;
+
+        pwm_setup_available_channels(); 
+ 
+        return_val = class_register(&pwm_class); 
+        if(return_val) { 
+                class_unregister(&pwm_class); 
+        } 
+#ifdef SUNXI_PWM_DEBUG
+	else { 
+                printk("pwm-sunxi: pwm_class.dev_kobj = %p\n",pwm_class.dev_kobj); 
+        } 
+#endif
+/* 
+        platform_device_register(&sun4i_pwm_device); 
+        platform_driver_register(&sun4i_pwm_driver); 
+*/ 
+ 
+        pwm0 = device_create(&pwm_class,NULL,MKDEV(0,0),&pwm_available_chan[0],"pwm0"); 
+        pwm1 = device_create(&pwm_class,NULL,MKDEV(0,0),&pwm_available_chan[1],"pwm1"); 
+ 
+        pwm0_kobj = &pwm0->kobj; 
+        pwm1_kobj = &pwm1->kobj; 
+        return_val = sysfs_create_group(pwm0_kobj,&pwm_attr_group); 
+        if(return_val) { 
+                printk("pwm-sunxi: return from sysfs_create_group(pwm0) was %d\n",return_val); 
+        } 
+ 
+        return_val = sysfs_create_group(pwm1_kobj,&pwm_attr_group); 
+        if(return_val) { 
+                printk("pwm-sunxi: return from sysfs_create_group(pwm1) was %d\n",return_val); 
+        } 
+
+
+	//PWM 0
+	//printk("pwm-sunxi: configuring pwm0...\n");
+	chan = &pwm_available_chan[0];
+ 	
+	init_enable=0;
+	init_period=0;
+	init_duty_percent=100;
+
+	
+
+	err = script_parser_fetch("pwm0_para", "pwm_used", &init_enable,sizeof(init_enable)/sizeof(int));
+	if (err) {
+		pr_err("%s script_parser_fetch '[pwm0_para]' 'pwm_used' err - disabling pwm0\n",	__func__);
+	}
+
+	if(init_enable) {
+	
+		err = script_parser_fetch("pwm0_para", "pwm_period", &init_period,sizeof(init_period)/sizeof(int));
+		if (err) {
+			pr_err("%s script_parser_fetch '[pwm0_para]' 'pwm_period' err - using 10000\n",	__func__);
+			init_period=10000;
+		}
+
+		err = script_parser_fetch("pwm0_para", "pwm_duty_percent", &init_duty_percent,sizeof(init_duty_percent)/sizeof(int));
+		if (err) {
+			pr_err("%s script_parser_fetch '[pwm0_para]' 'pwm_duty_percent' err - using 100\n",	__func__);
+			init_duty_percent=100;
+		}
+
+		chan->duty_percent=init_duty_percent;
+		chan->period = init_period; 
+		chan->prescale = pwm_get_best_prescale(init_period); 
+		fixup_duty(chan); 
+#ifdef SUNXI_PWM_DEBUG
+		printk("pwm-sunxi: pwm0 set initial values\n");
+#endif
+		pwm_set_mode(init_enable,chan); 
+	}
+ 
+        printk("pwm-sunxi: pwm0 configured - enable: %d, period: %ld, duty_percent: %d, duty: %ld\n",init_enable,chan->period,chan->duty_percent,chan->duty);
+
+
+
+	//PWM 1
+	//printk("pwm-sunxi: configuring pwm1...\n");
+	chan = &pwm_available_chan[1];
+		
+ 	
+	init_enable=0;
+	init_period=0;
+	init_duty_percent=100;
+
+	
+
+	err = script_parser_fetch("pwm1_para", "pwm_used", &init_enable,sizeof(init_enable)/sizeof(int));
+	if (err) {
+		pr_err("%s script_parser_fetch '[pwm1_para]' 'pwm_used' err - disabling pwm1\n",	__func__);
+	}
+
+	if(init_enable) {
+	
+		err = script_parser_fetch("pwm1_para", "pwm_period", &init_period,sizeof(init_period)/sizeof(int));
+		if (err) {
+			pr_err("%s script_parser_fetch '[pwm1_para]' 'pwm_period' err - using 10000\n",	__func__);
+			init_period=10000;
+		}
+
+		err = script_parser_fetch("pwm1_para", "pwm_duty_percent", &init_duty_percent,sizeof(init_duty_percent)/sizeof(int));
+		if (err) {
+			pr_err("%s script_parser_fetch '[pwm1_para]' 'pwm_duty_percent' err - using 100\n",	__func__);
+			init_duty_percent=100;
+		}
+
+		chan->duty_percent=init_duty_percent;
+		chan->period = init_period; 
+		chan->prescale = pwm_get_best_prescale(init_period); 
+		fixup_duty(chan); 
+#ifdef SUNXI_PWM_DEBUG
+		printk("pwm-sunxi: pwm0 set initial values\n");
+#endif
+		pwm_set_mode(init_enable,chan); 
+	}
+ 
+        printk("pwm-sunxi: pwm1 configured - enable: %d, period: %ld, duty_percent: %d, duty: %ld\n",init_enable,chan->period,chan->duty_percent,chan->duty);
+
+
+
+ 
+	printk("pwm-sunxi: Initialized\n");
+        return return_val; 
+} 
+ 
+void sunxi_pwm_exit(void) 
+{ 
+        void *timer_base = ioremap(SW_PA_TIMERC_IO_BASE, 0x400); 
+        void *PWM_CTRL_REG_BASE = timer_base + 0x200; 
+ 
+        device_destroy(&pwm_class,pwm0->devt); 
+        device_destroy(&pwm_class,pwm1->devt); 
+        writel(0, PWM_CTRL_REG_BASE + 0); 
+        writel(pwm_available_chan[0].pin_backup.initializer, pwm_available_chan[0].pin_addr); 
+        writel(pwm_available_chan[1].pin_backup.initializer, pwm_available_chan[1].pin_addr); 
+ 
+        class_unregister(&pwm_class); 
+} 
+ 
+/* 
+ * Functions to display the pwm variables currently set 
+ */ 
+ 
+static ssize_t pwm_polarity_show(struct device *dev, struct device_attribute *attr, char *buf) { 
+        const struct sun4i_pwm_available_channel *chan = dev_get_drvdata(dev); 
+        ssize_t status; 
+        switch (chan->channel) { 
+        case 0: 
+                status = scnprintf(buf,PAGE_SIZE,"%d",chan->ctrl_current.s.ch0_act_state); 
+                break; 
+        case 1: 
+                status = scnprintf(buf,PAGE_SIZE,"%d",chan->ctrl_current.s.ch1_act_state); 
+                break; 
+        default: 
+                status = -EINVAL; 
+                break; 
+        } 
+        return status; 
+} 
+static ssize_t pwm_period_show(struct device *dev, struct device_attribute *attr, char *buf) { 
+        const struct sun4i_pwm_available_channel *chan = dev_get_drvdata(dev); 
+        ssize_t status; 
+        status = sprintf(buf,"%lu",chan->period); 
+        return status; 
+} 
+static ssize_t pwm_duty_show(struct device *dev, struct device_attribute *attr, char *buf) { 
+        const struct sun4i_pwm_available_channel *chan = dev_get_drvdata(dev); 
+        ssize_t status; 
+        status = sprintf(buf,"%lu",chan->duty); 
+        return status; 
+} 
+static ssize_t pwm_run_show(struct device *dev,struct device_attribute *attr, char *buf) { 
+        const struct sun4i_pwm_available_channel *chan = dev_get_drvdata(dev); 
+        ssize_t status; 
+        switch (chan->channel) { 
+        case 0: 
+                status = sprintf(buf,"%d",chan->ctrl_current.s.ch0_en); 
+                break; 
+        case 1: 
+                status = sprintf(buf,"%d",chan->ctrl_current.s.ch1_en); 
+                break; 
+        default: 
+                status = -EINVAL; 
+                break; 
+        } 
+ 
+        return status; 
+} 
+static ssize_t pwm_duty_percent_show(struct device *dev,struct device_attribute *attr, char *buf) { 
+        const struct sun4i_pwm_available_channel *chan = dev_get_drvdata(dev); 
+        return sprintf(buf,"%u",chan->duty_percent); 
+} 
+static ssize_t pwm_pulse_show(struct device *dev,struct device_attribute *attr, char *buf) { 
+        const struct sun4i_pwm_available_channel *chan = dev_get_drvdata(dev); 
+        ssize_t status; 
+        switch (chan->channel) { 
+        case 0: 
+                status = sprintf(buf,"%d",chan->ctrl_current.s.ch0_pulse_start); 
+                break; 
+        case 1: 
+                status = sprintf(buf,"%d",chan->ctrl_current.s.ch1_pulse_start); 
+                break; 
+        default: 
+                status = -EINVAL; 
+                break; 
+        } 
+        return status; 
+} 
+ 
+static ssize_t pwm_pin_show(struct device *dev,struct device_attribute *attr, char *buf) { 
+        const struct sun4i_pwm_available_channel *chan = dev_get_drvdata(dev); 
+        ssize_t status; 
+        status = sprintf(buf,"%s",chan->pin_name); 
+ 
+        return status; 
+} 
+ 
+/* 
+ * Functions to store values for pwm 
+ */ 
+ 
+static ssize_t pwm_polarity_store(struct device *dev,struct device_attribute *attr, const char *buf, size_t size) { 
+        struct sun4i_pwm_available_channel *chan = dev_get_drvdata(dev); 
+        ssize_t status = -EINVAL; 
+        int act_state = 0; 
+ 
+        sscanf(buf,"%d",&act_state); 
+        if(act_state < 2) { 
+                switch (chan->channel) { 
+                case 0: 
+                        chan->ctrl_current.s.ch0_act_state = act_state; 
+                        break; 
+                case 1: 
+                        chan->ctrl_current.s.ch1_act_state = act_state; 
+                        break; 
+                default: 
+                        status = -EINVAL; 
+                        break; 
+                } 
+                status = size; 
+        } 
+        return status; 
+} 
+static ssize_t pwm_period_store(struct device *dev,struct device_attribute *attr, const char *buf, size_t size) { 
+        unsigned long long period = 0; 
+        struct sun4i_pwm_available_channel *chan = dev_get_drvdata(dev); 
+ 
+        period = convert_string_to_microseconds(buf); 
+        if(!period || period > ULONG_MAX) { 
+                size = -EINVAL; 
+        } else { 
+                if(period <= chan->duty) { 
+                        chan->duty = period; 
+                } 
+                chan->period = period; 
+                chan->prescale = pwm_get_best_prescale(period); 
+                fixup_duty(chan); 
+                if(chan->duty) { 
+                        pwm_set_mode(NO_ENABLE_CHANGE,chan); 
+                } 
+        } 
+        return size; 
+} 
+static ssize_t pwm_duty_store(struct device *dev,struct device_attribute *attr, const char *buf, size_t size) { 
+        unsigned long long duty = 0; 
+        struct sun4i_pwm_available_channel *chan = dev_get_drvdata(dev); 
+ 
+        /* sscanf(buf,"%Lu",&duty); */ /* L means long long pointer */ 
+        duty = convert_string_to_microseconds(buf); 
+        duty = duty > ULONG_MAX ? ULONG_MAX : duty; 
+        duty = duty > chan->period ? chan->period : duty; 
+        chan->duty_percent = -1; /* disable duty_percent if duty is set by hand */ 
+        chan->duty = duty; 
+        pwm_set_mode(NO_ENABLE_CHANGE,chan); 
+        return size; 
+} 
+ 
+struct time_suffix suffixes[] = { 
+        [0] = { .suffix = "hz",  .multiplier =          1, .freq = true  }, /* f = 1/T */ 
+        [1] = { .suffix = "khz", .multiplier =       1000, .freq = true  }, 
+        [2] = { .suffix = "mhz", .multiplier =    1000000, .freq = true  }, 
+        [3] = { .suffix = "ghz", .multiplier = 1000000000, .freq = true  }, 
+        [4] = { .suffix = "ms",  .multiplier =       1000, .freq = false }, /* T = 1/f */ 
+        [5] = { .suffix = "us",  .multiplier =          1, .freq = false }, 
+        [6] = { .suffix = "ns",  .multiplier =          1, .freq = false }, 
+        [7] = { .suffix = NULL,  .multiplier =          0, .freq = false }, 
+}; 
+ 
+ 
+unsigned long convert_string_to_microseconds(const char *buf) { 
+        unsigned char ch = 0; 
+        char numbers[10]; 
+        char letters[4]; 
+        const char *bufptr = buf; 
+        int i = 0; 
+        unsigned long microseconds = 0; 
+        unsigned long numeric_part = 0; 
+        int found_suffix = -1; 
+        int numbers_index = 0, letters_index = 0; 
+        while(bufptr && *bufptr && (ch = *bufptr)  && isdigit(ch) && numbers_index < (sizeof(numbers)-1)) { 
+                numbers[numbers_index++] = *bufptr++; 
+        } 
+        numbers[numbers_index] = 0; 
+        while(bufptr && *bufptr && (ch = *bufptr)  && strchr("usmhznhzkg",tolower(ch)) && letters_index < (sizeof(letters)-1)) { 
+                letters[letters_index++] = tolower(*bufptr); 
+                bufptr++; 
+        } 
+        letters[letters_index] = 0; 
+        sscanf(numbers,"%lu",&numeric_part); 
+        while(suffixes[i].suffix) { 
+                if(!strcmp(suffixes[i].suffix,letters)) { 
+                        found_suffix = i; 
+                        break; 
+                } 
+                i++; 
+        } 
+        if(found_suffix > -1) { 
+                if(suffixes[found_suffix].freq) { 
+                        microseconds = 1000000 / (numeric_part * suffixes[found_suffix].multiplier); 
+                } else { 
+                        microseconds = suffixes[found_suffix].multiplier * numeric_part; 
+                } 
+        } 
+        return microseconds; 
+} 
+ 
+ 
+ 
+ 
+static const unsigned int prescale_divisor[13] = {120, 
+                                                  180, 
+                                                  240, 
+                                                  360, 
+                                                  480, 
+                                                  480, /* Invalid Option */ 
+                                                  480, /* Invalid Option */ 
+                                                  480, /* Invalid Option */ 
+                                                  12000, 
+                                                  24000, 
+                                                  36000, 
+                                                  48000, 
+                                                  72000}; 
+ 
+/* 
+ * Find the best prescale value for the period 
+ * We want to get the highest period cycle count possible, so we look 
+ * make a run through the prescale values looking for numbers over 
+ * min_optimal_period_cycles.  If none are found then root though again 
+ * taking anything that works 
+ */ 
+enum sun4i_pwm_prescale  pwm_get_best_prescale(unsigned long long period_in) { 
+        int i; 
+        unsigned long period = period_in; 
+        const unsigned long min_optimal_period_cycles = MAX_CYCLES / 2; 
+        const unsigned long min_period_cycles = 0x02; 
+        enum sun4i_pwm_prescale best_prescale = 0; 
+ 
+        best_prescale = -1; 
+        for(i = 0 ; i < 13 ; i++) { 
+                unsigned long int check_value = (prescale_divisor[i] /24); 
+                if(check_value < 1 || check_value > period) { 
+                        break; 
+                } 
+                if(((period / check_value) >= min_optimal_period_cycles) && 
+                        ((period / check_value) <= MAX_CYCLES)) { 
+                        best_prescale = i; 
+                        break; 
+                } 
+        } 
+ 
+        if(best_prescale > 13) { 
+                for(i = 0 ; i < 13 ; i++) { 
+                        unsigned long int check_value = (prescale_divisor[i] /24); 
+                        if(check_value < 1 || check_value > period) { 
+                                break; 
+                        } 
+                        if(((period / check_value) >= min_period_cycles) && 
+                                ((period / check_value) <= MAX_CYCLES)) { 
+                                best_prescale = i; 
+                                break; 
+                        } 
+                } 
+        } 
+        if(best_prescale > 13) { 
+                best_prescale = PRESCALE_DIV480;  /* Something that's not zero - use invalid prescale value */ 
+        } 
+ 
+        return best_prescale; 
+} 
+ 
+/* 
+ * return the number of cycles for the channel period computed from the microseconds 
+ * for the period.  Allwinner docs call this "entire" cycles 
+ */ 
+unsigned int get_entire_cycles(struct sun4i_pwm_available_channel *chan) { 
+        unsigned int entire_cycles = 0x01; 
+        if ((2 * prescale_divisor[chan->prescale] * MAX_CYCLES) > 0) { 
+                entire_cycles = chan->period / (prescale_divisor[chan->prescale] /24); 
+        } 
+        if(entire_cycles == 0) {entire_cycles = MAX_CYCLES;} 
+        if(entire_cycles > MAX_CYCLES) {entire_cycles = MAX_CYCLES;} 
+#ifdef SUNXI_PWM_DEBUG
+        printk("Best prescale was %d, entire cycles was %u\n",chan->prescale, entire_cycles); 
+#endif
+ 
+        return entire_cycles; 
+} 
+ 
+/* 
+ * return the number of cycles for the channel duty computed from the microseconds 
+ * for the duty.  Allwinner docs call this "active" cycles 
+ */ 
+unsigned int get_active_cycles(struct sun4i_pwm_available_channel *chan) { 
+        unsigned int active_cycles = 0x01; 
+        unsigned int entire_cycles = get_entire_cycles(chan); 
+        if(chan->duty < 0 && chan->period) { 
+       		active_cycles = entire_cycles-1; 
+        } else if ((2 * prescale_divisor[chan->prescale] * MAX_CYCLES) > 0) { 
+                active_cycles = chan->duty / (prescale_divisor[chan->prescale] /24); 
+        } 
+/*        if(active_cycles == 0) {active_cycles = 0x0ff;} */ 
+#ifdef SUNXI_PWM_DEBUG
+        printk("Best prescale was %d, active cycles was %u (before entire check)\n",chan->prescale, active_cycles); 
+#endif
+        if(active_cycles > MAX_CYCLES) {active_cycles = entire_cycles-1;} 
+#ifdef SUNXI_PWM_DEBUG
+        printk("Best prescale was %d, active cycles was %u (after  entire check)\n",chan->prescale, active_cycles); 
+#endif
+        return active_cycles; 
+} 
+ 
+/* 
+ * When the duty is set, compute the number of microseconds 
+ * based on the period. 
+ */ 
+ 
+void fixup_duty(struct sun4i_pwm_available_channel *chan) { 
+        if(chan->duty_percent >= 0) { 
+                chan->duty = chan->period * chan->duty_percent / 100; 
+        } 
+} 
+ 
+/* 
+ * Stores the run (enable) bit. 
+ */ 
+ 
+static ssize_t pwm_run_store(struct device *dev,struct device_attribute *attr, const char *buf, size_t size) { 
+        struct sun4i_pwm_available_channel *chan = dev_get_drvdata(dev); 
+        ssize_t status = -EINVAL; 
+        int enable = 0; 
+ 
+        sscanf(buf,"%d",&enable); 
+        if(enable < 2) { 
+                status = pwm_set_mode(enable, chan); 
+        } 
+        return size; 
+} 
+ 
+static ssize_t pwm_duty_percent_store(struct device *dev,struct device_attribute *attr, const char *buf, size_t size) { 
+        unsigned int duty_percent = 0; 
+        struct sun4i_pwm_available_channel *chan = dev_get_drvdata(dev); 
+ 
+        sscanf(buf,"%u",&duty_percent); 
+        if(duty_percent > 100) { 
+                size = -EINVAL; 
+        } else { 
+                chan->duty_percent = duty_percent; 
+                if(chan->period) { 
+                        fixup_duty(chan); 
+                        pwm_set_mode(NO_ENABLE_CHANGE,chan); 
+                } 
+        } 
+ 
+        return size; 
+} 
+static ssize_t pwm_pulse_store(struct device *dev,struct device_attribute *attr, const char *buf, size_t size) { 
+        struct sun4i_pwm_available_channel *chan = dev_get_drvdata(dev); 
+        ssize_t status = -EINVAL; 
+        int pulse = 0; 
+        sscanf(buf,"%d",&pulse); 
+        if(pulse < 2) { 
+                switch (chan->channel) { 
+                case 0: 
+                        chan->ctrl_current.s.ch0_pulse_start = pulse; 
+                        break; 
+                case 1: 
+                        chan->ctrl_current.s.ch1_pulse_start = pulse; 
+                        break; 
+                default: 
+                        status = -EINVAL; 
+                        break; 
+                } 
+                status = size; 
+        } 
+        return status; 
+} 
+ 
+int pwm_set_period_and_duty(struct sun4i_pwm_available_channel *chan) { 
+        int return_val = -EINVAL; 
+        unsigned int entire_cycles = get_entire_cycles(chan); 
+        unsigned int active_cycles = get_active_cycles(chan); 
+        chan->period_reg.initializer = 0; 
+        if(entire_cycles >= active_cycles && active_cycles) { 
+                chan->period_reg.s.pwm_entire_cycles = entire_cycles; 
+                chan->period_reg.s.pwm_active_cycles = active_cycles; 
+        } else { 
+                chan->period_reg.s.pwm_entire_cycles = MAX_CYCLES; 
+                chan->period_reg.s.pwm_active_cycles = MAX_CYCLES; 
+        } 
+        writel(chan->period_reg.initializer, chan->period_reg_addr); 
+        return return_val; 
+} 
+ 
+ 
+ssize_t pwm_set_mode(unsigned int enable, struct sun4i_pwm_available_channel *chan) { 
+        ssize_t status = 0; 
+        if(enable == NO_ENABLE_CHANGE) { 
+                switch (chan->channel) { 
+                case 0: 
+                        enable = chan->ctrl_current.s.ch0_en; 
+                        break; 
+                case 1: 
+                        enable = chan->ctrl_current.s.ch1_en; 
+                        break; 
+                default: 
+                        status = -EINVAL; 
+                        break; 
+                } 
+        } 
+        chan->ctrl_current.initializer = readl(chan->ctrl_addr); 
+        if(enable == 1) { 
+                switch (chan->channel) { 
+                case 0: 
+                        chan->ctrl_current.s.ch0_prescaler = 0; 
+                        chan->ctrl_current.s.ch0_act_state = 0; 
+                        chan->ctrl_current.s.ch0_mode = 0; 
+                        chan->ctrl_current.s.ch0_pulse_start = 0; 
+                        chan->ctrl_current.s.ch0_en = 0; 
+                        chan->ctrl_current.s.ch0_clk_gating = 0; 
+                        break; 
+                case 1: 
+                        chan->ctrl_current.s.ch1_prescaler = 0; 
+                        chan->ctrl_current.s.ch1_act_state = 0; 
+                        chan->ctrl_current.s.ch1_mode = 0; 
+                        chan->ctrl_current.s.ch1_pulse_start = 0; 
+                        chan->ctrl_current.s.ch1_en = 1; 
+                        chan->ctrl_current.s.ch1_clk_gating = 0; 
+                        break; 
+                default: 
+                        status = -EINVAL; 
+                        break; 
+                } 
+                if(status) { 
+                        return status; 
+                } 
+                //writel(chan->ctrl_current.initializer,chan->ctrl_addr); 
+                chan->pin_current.initializer = readl(chan->pin_addr); 
+                if(chan->pin_mask.s0.pin0_select) { 
+                        chan->pin_current.s0.pin0_select = SELECT_PWM; 
+                } 
+                if(chan->pin_mask.s0.pin1_select) { 
+                        chan->pin_current.s0.pin1_select = SELECT_PWM; 
+                } 
+                if(chan->pin_mask.s0.pin2_select) { 
+                        chan->pin_current.s0.pin2_select = SELECT_PWM; 
+                } 
+                if(chan->pin_mask.s0.pin3_select) { 
+                        chan->pin_current.s0.pin3_select = SELECT_PWM; 
+                } 
+                if(chan->pin_mask.s0.pin4_select) { 
+                        chan->pin_current.s0.pin4_select = SELECT_PWM; 
+                } 
+                if(chan->pin_mask.s0.pin5_select) { 
+                        chan->pin_current.s0.pin5_select = SELECT_PWM; 
+                } 
+                if(chan->pin_mask.s0.pin6_select) { 
+                        chan->pin_current.s0.pin6_select = SELECT_PWM; 
+                } 
+                if(chan->pin_mask.s0.pin7_select) { 
+                        chan->pin_current.s0.pin7_select = SELECT_PWM; 
+                } 
+                if(chan->channel == 0) { 
+                        chan->ctrl_current.s.ch0_prescaler = chan->prescale; 
+                } else { 
+                        chan->ctrl_current.s.ch1_prescaler = chan->prescale; 
+                } 
+                pwm_set_period_and_duty(chan); 
+ 
+                writel(chan->pin_current.initializer,chan->pin_addr); 
+                //writel(chan->ctrl_current.initializer,chan->ctrl_addr); 
+                switch (chan->channel) { 
+                case 0: 
+                        chan->ctrl_current.s.ch0_en = 1; 
+                        chan->ctrl_current.s.ch0_clk_gating = 1; 
+                        break; 
+                case 1: 
+                        chan->ctrl_current.s.ch1_en = 1; 
+                        chan->ctrl_current.s.ch1_clk_gating = 1; 
+                        break; 
+                } 
+                writel(chan->ctrl_current.initializer,chan->ctrl_addr); 
+ 
+        } else if (enable == 0) { 
+                switch (chan->channel) { 
+                case 0: 
+                        chan->ctrl_current.s.ch0_clk_gating = 0; 
+                        chan->ctrl_current.s.ch0_en = enable; 
+                        break; 
+                case 1: 
+                        chan->ctrl_current.s.ch1_clk_gating = 0; 
+                        chan->ctrl_current.s.ch1_en = enable; 
+                        break; 
+                default: 
+                        status = -EINVAL; 
+                        break; 
+                } 
+                if(!status) { 
+                        chan->pin_current.initializer &= ~chan->pin_mask.initializer; 
+                        chan->pin_current.initializer |= readl(chan->pin_addr) & chan->pin_mask.initializer; 
+                        writel(chan->pin_current.initializer,chan->pin_addr); 
+                        writel(chan->ctrl_current.initializer,chan->ctrl_addr); 
+                } 
+        } 
+        return status; 
+} 
+ 
+ 
+ 
+void pwm_setup_available_channels( void ) { 
+        void * timer_base = ioremap(SW_PA_TIMERC_IO_BASE, 0x400);  /* 0x01c20c00 */ 
+        void * PWM_CTRL_REG_BASE = timer_base + 0x200;             /* 0x01c20e00 */ 
+        void * portc_io_base = ioremap(SW_PA_PORTC_IO_BASE,0x400); /* 0x01c20800 */ 
+        void * PB_CFG0_REG = (portc_io_base + 0x24);               /* 0x01C20824 */ 
+        void * PI_CFG0_REG = (portc_io_base + 0x120);              /* 0x01c20920 */ 
+ 
+        /*void * PB_PULL0_REG = (portc_io_base + 0x040);*/             /* 0x01c20840 */ 
+        /*void * PI_PULL0_REG = (portc_io_base + 0x13c);*/             /* 0x01c2091c */ 
+        /*void * PH_CFG0_REG = (portc_io_base + 0xfc);*/               /* 0x01c208fc */ 
+        /*void * PH_CFG1_REG = (portc_io_base + 0x100);*/              /* 0x01c20900 */ 
+        /*void * PH_PULL0_REG = (portc_io_base + 0x118);*/             /* 0x01c20918 */ 
+ 
+        pwm_available_chan[0].use_count = 0; 
+        pwm_available_chan[0].ctrl_addr = PWM_CTRL_REG_BASE; 
+        pwm_available_chan[0].pin_addr = PB_CFG0_REG; 
+        pwm_available_chan[0].period_reg_addr = pwm_available_chan[0].ctrl_addr + 0x04; 
+        pwm_available_chan[0].channel = 0; 
+        pwm_available_chan[0].ctrl_backup.initializer = readl(pwm_available_chan[0].ctrl_addr); 
+        pwm_available_chan[0].ctrl_mask.initializer = 0; 
+        pwm_available_chan[0].ctrl_mask.s.ch0_prescaler = 0x0f; 
+        pwm_available_chan[0].ctrl_mask.s.ch0_en = 0x01; 
+        pwm_available_chan[0].ctrl_mask.s.ch0_act_state = 0x01; 
+        pwm_available_chan[0].ctrl_mask.s.ch0_clk_gating = 0x00; 
+        pwm_available_chan[0].ctrl_mask.s.ch0_mode = 0x01; 
+        pwm_available_chan[0].ctrl_mask.s.ch0_pulse_start = 0x01; 
+        pwm_available_chan[0].ctrl_current.initializer = 0; 
+        pwm_available_chan[0].pin_backup.initializer = readl(pwm_available_chan[0].pin_addr); 
+/*        pwm_available_chan[0].pin_mask.initializer = 0xffffffff; */ 
+        pwm_available_chan[0].pin_mask.s0.pin2_select = 0x07; 
+        pwm_available_chan[0].pin_current.s0.pin2_select = 0x02; 
+ 
+        pwm_available_chan[0].pin_name = "PB2"; 
+        pwm_available_chan[0].period = 10000; 
+        pwm_available_chan[0].duty_percent = 100; 
+        *(unsigned int *)&pwm_available_chan[0].period_reg = 0; 
+        pwm_available_chan[0].prescale = 0; 
+ 
+ 
+        pwm_available_chan[1].use_count = 0; 
+        pwm_available_chan[1].ctrl_addr = PWM_CTRL_REG_BASE; 
+        pwm_available_chan[1].pin_addr = PI_CFG0_REG; 
+        pwm_available_chan[1].period_reg_addr = pwm_available_chan[1].ctrl_addr + 0x08; 
+        pwm_available_chan[1].channel = 1; 
+        pwm_available_chan[1].ctrl_backup.initializer = readl(pwm_available_chan[1].ctrl_addr); 
+        pwm_available_chan[1].ctrl_mask.initializer = 0; 
+        pwm_available_chan[1].ctrl_mask.s.ch1_prescaler = 0x0f; 
+        pwm_available_chan[1].ctrl_mask.s.ch1_en = 0x01; 
+        pwm_available_chan[1].ctrl_mask.s.ch1_act_state = 0x01; 
+        pwm_available_chan[1].ctrl_mask.s.ch1_clk_gating = 0x00; 
+        pwm_available_chan[1].ctrl_mask.s.ch1_mode = 0x01; 
+        pwm_available_chan[1].ctrl_mask.s.ch1_pulse_start = 0x01; 
+        pwm_available_chan[1].ctrl_current.initializer = 0; 
+        pwm_available_chan[1].pin_backup.initializer = readl(pwm_available_chan[1].pin_addr); 
+        pwm_available_chan[1].pin_mask.initializer = 0; 
+        pwm_available_chan[1].pin_mask.s0.pin3_select = 0x07; 
+        pwm_available_chan[1].pin_current.s0.pin3_select = 0x02; 
+        pwm_available_chan[1].pin_name = "PI3"; 
+        pwm_available_chan[1].period = 10000; 
+        pwm_available_chan[1].duty_percent = 50; 
+        *(unsigned int *)&pwm_available_chan[1].period_reg = 0; 
+        pwm_available_chan[1].prescale = 0; 
+ 
+ 
+} 
+ 
+struct pwm_device { 
+        struct sun4i_pwm_available_channel *chan; 
+}; 
+ 
+struct pwm_device pwm_devices[2] = { 
+        [0] = {.chan = &pwm_available_chan[0]}, 
+        [1] = {.chan = &pwm_available_chan[1]} 
+}; 
+ 
+struct pwm_device *pwm_request(int pwm_id, const char *label) 
+{ 
+        struct pwm_device *pwm; 
+        int found = 0; 
+ 
+        if(pwm_id < 2 && pwm_id >= 0) { 
+                pwm = &pwm_devices[pwm_id]; 
+                found = 1; 
+        } 
+        if (found) { 
+                if (pwm->chan->use_count == 0) { 
+                        pwm->chan->use_count++; 
+                        pwm->chan->name = label; 
+                } else 
+                        pwm = ERR_PTR(-EBUSY); 
+        } else 
+                pwm = ERR_PTR(-ENOENT); 
+ 
+        return pwm; 
+} 
+EXPORT_SYMBOL(pwm_request); 
+ 
+ 
+int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) 
+{ 
+        if (pwm == NULL || period_ns == 0 || duty_ns > period_ns) 
+                return -EINVAL; 
+ 
+        pwm->chan->period = period_ns / 1000; 
+        pwm->chan->prescale = pwm_get_best_prescale(pwm->chan->period); 
+        pwm->chan->duty = duty_ns / 1000; 
+        fixup_duty(pwm->chan); 
+        pwm_set_mode(NO_ENABLE_CHANGE,pwm->chan); 
+        return 0; 
+} 
+EXPORT_SYMBOL(pwm_config); 
+ 
+ 
+int pwm_enable(struct pwm_device *pwm) 
+{ 
+        if (pwm == NULL) { 
+                return -EINVAL; 
+        } 
+        pwm_set_mode(PWM_CTRL_ENABLE,pwm->chan); 
+        return 0; 
+} 
+EXPORT_SYMBOL(pwm_enable); 
+ 
+void pwm_disable(struct pwm_device *pwm) 
+{ 
+        if (pwm == NULL) { 
+                return; 
+        } 
+        pwm_set_mode(PWM_CTRL_DISABLE,pwm->chan); 
+} 
+EXPORT_SYMBOL(pwm_disable); 
+ 
+void pwm_free(struct pwm_device *pwm) 
+{ 
+        if (pwm->chan->use_count) { 
+                pwm->chan->use_count--; 
+        } else 
+                pr_warning("PWM device already freed\n"); 
+} 
+EXPORT_SYMBOL(pwm_free); 
+ 
+ 
+module_init(sunxi_pwm_init); 
+module_exit(sunxi_pwm_exit); 
+ 
+ 
+ 
+ 
+MODULE_LICENSE("GPL"); 
+MODULE_AUTHOR("David H. Wilkins <dwil...@conecuh.com>"); 
diff --git a/drivers/misc/pwm-sunxi.h b/drivers/misc/pwm-sunxi.h
new file mode 100644
index 0000000..0a65606
--- /dev/null
+++ b/drivers/misc/pwm-sunxi.h
@@ -0,0 +1,198 @@
+/* 
+ * pwm-sunxi.h 
+ * 
+ * (C) Copyright 2013 
+ * David H. Wilkins  <dwil...@conecuh.com> 
+ * 
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License as 
+ * published by the Free Software Foundation; either version 2 of 
+ * the License, or (at your option) any later version. 
+ * 
+ * This program is distributed in the hope that it will be useful, 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the 
+ * GNU General Public License for more details. 
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+ * MA 02111-1307 USA 
+ */ 
+ 
+ 
+#define SUN4I_PWM_IOREG_MAX 10 
+#define SUN4I_MAX_HARDWARE_PWM_CHANNELS 2 
+ 
+/* 
+ * structure that defines the pwm control register 
+ */ 
+ 
+enum sun4i_pwm_prescale { 
+        PRESCALE_DIV120  = 0x00,  /* Divide 24mhz clock by 120 */ 
+        PRESCALE_DIV180  = 0x01, 
+        PRESCALE_DIV240  = 0x02, 
+        PRESCALE_DIV360  = 0x03, 
+        PRESCALE_DIV480  = 0x04, 
+        PRESCALE_INVx05  = 0x05, 
+        PRESCALE_INVx06  = 0x06, 
+        PRESCALE_INVx07  = 0x07, 
+        PRESCALE_DIV12k  = 0x08, 
+        PRESCALE_DIV24k  = 0x09, 
+        PRESCALE_DIV36k  = 0x0a, 
+        PRESCALE_DIV48k  = 0x0b, 
+        PRESCALE_DIV72k  = 0x0c 
+}; 
+ 
+ 
+ 
+ 
+struct sun4i_pwm_ctrl { 
+        enum sun4i_pwm_prescale ch0_prescaler:4; /* ch0 Prescale register - values above */ 
+        unsigned int ch0_en:1;                  /* chan 0 enable */ 
+        unsigned int ch0_act_state:1;           /* chan 0 polarity 0=low, 1=high */ 
+        unsigned int ch0_clk_gating:1;          /* Allow clock to run for chan 0 */ 
+        unsigned int ch0_mode:1;                /* Mode - 0 = cycle(running), 1=only 1 pulse */ 
+        unsigned int ch0_pulse_start:1;         /* Write 1 for mode pulse above to start */ 
+        unsigned int unused1:6;                 /* The bit skip count is 6 */ 
+        enum sun4i_pwm_prescale ch1_prescaler:4; /* ch1 Prescale register - values above*/ 
+        unsigned int ch1_en:1;                  /* chan 1 enable */ 
+        unsigned int ch1_act_state:1;           /* chan 1 polarity 0=low, 1=high */ 
+        unsigned int ch1_clk_gating:1;          /* Allow clock to run for chan 1 */ 
+        unsigned int ch1_mode:1;                /* Mode - 0 = cycle(running), 1=only 1 pulse */ 
+        unsigned int ch1_pulse_start:1;         /* Write 1 for mode pulse above to start */ 
+        unsigned int unused2:6;                 /* The bit skip count is 6 */ 
+}; 
+ 
+ 
+#define A10CLK 24000000  /* Speed of the clock - 24mhz */ 
+ 
+#define NO_ENABLE_CHANGE 2  /* Signal to set_pwm_mode to keep the same chan enable bit */ 
+ 
+#define PWM_CTRL_ENABLE 1 
+#define PWM_CTRL_DISABLE 0 
+ 
+#define MAX_CYCLES 0x0ffff /* max cycle count possible for period active and entire */ 
+struct sun4i_pwm_period { 
+#if MAX_CYCLES > 0x0ff 
+        unsigned int pwm_active_cycles:16;        /* duty cycle */ 
+        unsigned int pwm_entire_cycles:16;        /* period */ 
+#else 
+        unsigned int pwm_active_cycles:8;        /* duty cycle */ 
+        unsigned int unused1:8; 
+        unsigned int pwm_entire_cycles:8;        /* period */ 
+        unsigned int unused2:8; 
+#endif 
+}; 
+ 
+ 
+enum sun4i_ioreg_pin_select { 
+        SELECT_INPUT      = 0x00,                /* bits for the config registers */ 
+        SELECT_OUTPUT     = 0x01, 
+        SELECT_PWM        = 0x02, 
+        SELECT_SPI2_CLK   = 0x02, 
+        SELECT_I2S_LRCK   = 0x02, 
+        SELECT_I2S_BCLK   = 0x02 
+}; 
+ 
+ 
+struct sun4i_ioreg_cfg0 { 
+        enum sun4i_ioreg_pin_select pin0_select:4; 
+        enum sun4i_ioreg_pin_select pin1_select:4; 
+        enum sun4i_ioreg_pin_select pin2_select:4; 
+        enum sun4i_ioreg_pin_select pin3_select:4; 
+        enum sun4i_ioreg_pin_select pin4_select:4; 
+        enum sun4i_ioreg_pin_select pin5_select:4; 
+        enum sun4i_ioreg_pin_select pin6_select:4; 
+        enum sun4i_ioreg_pin_select pin7_select:4; 
+}; 
+ 
+/* 
+ * another duplicate struct to make the pin names 
+ * look right 
+ */ 
+struct sun4i_ioreg_cfg1 { 
+        enum  sun4i_ioreg_pin_select pin8_select:4; 
+        enum  sun4i_ioreg_pin_select pin9_select:4; 
+        enum  sun4i_ioreg_pin_select pin10_select:4; 
+        enum  sun4i_ioreg_pin_select pin11_select:4; 
+        enum  sun4i_ioreg_pin_select pin12_select:4; 
+        enum  sun4i_ioreg_pin_select pin13_select:4; 
+        enum  sun4i_ioreg_pin_select pin14_select:4; 
+        enum  sun4i_ioreg_pin_select pin15_select:4; 
+}; 
+ 
+ 
+struct ioreg_pull { 
+        unsigned int pin0:2; 
+        unsigned int pin1:2; 
+        unsigned int pin2:2; 
+        unsigned int pin3:2; 
+        unsigned int pin4:2; 
+        unsigned int pin5:2; 
+        unsigned int pin6:2; 
+        unsigned int pin7:2; 
+        unsigned int pin8:2; 
+        unsigned int pin9:2; 
+        unsigned int pin10:2; 
+        unsigned int pin11:2; 
+        unsigned int pin12:2; 
+        unsigned int pin13:2; 
+        unsigned int pin14:2; 
+        unsigned int pin15:2; 
+}; 
+ 
+union ioreg_pull_u { 
+        struct ioreg_pull s; 
+        unsigned int initializer; 
+}; 
+ 
+ 
+union sun4i_pwm_ctrl_u { 
+        struct sun4i_pwm_ctrl s; 
+        unsigned int initializer; 
+}; 
+ 
+union sun4i_pwm_period_u { 
+        struct sun4i_pwm_period s; 
+        unsigned int initializer; 
+}; 
+ 
+union sun4i_ioreg_cfg_u { 
+        struct sun4i_ioreg_cfg0 s0; /* io register config 0 */ 
+        struct sun4i_ioreg_cfg1 s1; /* io register config 1 (just to make pin names look nice) */ 
+        unsigned int initializer; 
+}; 
+ 
+ 
+ 
+struct sun4i_pwm_available_channel{ 
+        unsigned int use_count; 
+        void *ctrl_addr;                           /* Address of the control register */ 
+        void *pin_addr;                            /* Address of the pin register to change to PWM mode */ 
+        void *period_reg_addr;                     /* Address of the period register for this chan */ 
+        unsigned int channel;                      /* Channel number */ 
+        unsigned long period;                      /* Period in microseconds */ 
+        unsigned long duty;                        /* duty cycle in microseconds */ 
+        unsigned int duty_percent;                 /* percentage (drives duty microseconds if set) */ 
+        enum sun4i_pwm_prescale prescale;           /* best prescale value computed for period */ 
+        union sun4i_pwm_period_u period_reg;       /* period register */ 
+        union sun4i_pwm_ctrl_u ctrl_backup;        /* control register backup at init */ 
+        union sun4i_pwm_ctrl_u ctrl_mask;          /* mask for ctrl register bit we can change */ 
+        union sun4i_pwm_ctrl_u ctrl_current;       /* current control register settings */ 
+        union sun4i_ioreg_cfg_u pin_backup;        /* pin backup at init */ 
+        union sun4i_ioreg_cfg_u pin_mask;          /* mask of pin settings we can change */ 
+        union sun4i_ioreg_cfg_u pin_current;       /* current pin register */ 
+        const char *pin_name;                      /* name of the pin */ 
+        const char *name;                          /* name of the pwm device from the pwm i/f */ 
+}; 
+ 
+/* 
+ * struct used to implement the hz/khz/ms/us etc for period and duty 
+ */ 
+struct time_suffix { 
+        char * suffix;                             /* text suffix */ 
+        unsigned long multiplier;                  /* multiplier for the entered value */ 
+        bool freq;                                 /* true if a frequency, otherwise a time */ 
+                                                   /* T = 1/f and f = 1/T */ 
+}; 
diff --git a/drivers/video/sunxi/disp/disp_lcd.c b/drivers/video/sunxi/disp/disp_lcd.c
index 31e69bb..8040fb9 100644
--- a/drivers/video/sunxi/disp/disp_lcd.c
+++ b/drivers/video/sunxi/disp/disp_lcd.c
@@ -769,7 +769,6 @@ pwm_enable(__u32 channel, __bool b_en)
 
 	return 0;
 }
-EXPORT_SYMBOL(pwm_enable);
 
 #ifdef CONFIG_ARCH_SUN4I
 /*
