gpio模拟pwm用于控制led灯亮度

android设备中可以使用gpio去模拟pwm对外接led灯进行亮度控制。

下面是一个gpio模拟pwm的内核驱动:

#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/pwm.h>
#include <linux/slab.h>
#include <linux/clk.h>
 
// #include <linux/adc.h>
#include <linux/iio/iio.h>
#include <linux/iio/machine.h>
#include <linux/iio/driver.h>
#include <linux/iio/consumer.h>
#include <linux/delay.h>
#include <linux/time.h>
#include <linux/timer.h>
#include <linux/input.h>
#include <linux/interrupt.h>
// #include <linux/io.h>
#include <linux/of_platform.h>
#include <linux/of_device.h>
#include <linux/types.h>
#include <linux/ioport.h>
#include <asm/irq.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/pm_wakeirq.h>
#include <linux/reset.h>
struct gpio_pwm_dev {
	int value;
	unsigned gpio;
	struct gpio_desc * gpiod;
	struct mutex mtx;
	const char* name;
	int gpioled_pwm_level;
	struct device *dev;
	int high_time;
	int low_time;
	unsigned long flags;
	unsigned active_low;
	struct timer_list pwm_timer;	
	void __iomem *reg_base;
};
static int gpioled_gpio = 0;

static int frequency = 1000; //频率,单位:Hz
static int high_cnt = 50;//占空比,gpio拉高的时间百分比,当前将一个周期分为period_cnt(100)个时间段
static int period_cnt = 100;//一个周期分为100个时间段。

static struct hrtimer pwm_timer1;
static int pwm_period = 10000;//一个周期的时间,纳秒
ktime_t kt;
 
static ssize_t gpioled_pwm_level_show(struct device *dev, struct device_attribute *attr, char *buf)
{
	return sprintf(buf, "%d\n", high_cnt);
}
		
 
static ssize_t gpioled_pwm_level_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
	long gpioled_pwm_level_val;
	int ret;

	ret = kstrtoul(buf, 10, &gpioled_pwm_level_val);
	if(ret < 0){
		printk("%s kstrtoul failed!\n",__func__);
		return -1;
	}
	high_cnt = gpioled_pwm_level_val;
	return count;
}
static struct device_attribute gpioled_pwm_level = {
	.attr = {
		.name = "gpioled_pwm_level",
		.mode = S_IRUGO | S_IWUGO | S_IXUGO ,
	},
	.show = gpioled_pwm_level_show,
	.store = gpioled_pwm_level_store,
};
 
 /*************************************************************************/
static enum hrtimer_restart pwm_timer_callback(struct hrtimer *timer) {
 	if (gpio_get_value(gpioled_gpio) == 1) {
		/* There is no need to pull down when the duty cycle is 100% */
		if (high_cnt >= 0 && high_cnt < period_cnt) {
			gpio_set_value(gpioled_gpio, 0);
			kt = ktime_set(0, (period_cnt - high_cnt)*pwm_period);
		}
		/* timer overflow */
		hrtimer_forward_now(&pwm_timer1, kt);
	} else {
		/* There is no need to pull up when the duty cycle is 0 */
		if (high_cnt > 0) {
			gpio_set_value(gpioled_gpio, 1);
			kt = ktime_set(0, high_cnt * pwm_period);
		}
		/* timer overflow */
		hrtimer_forward_now(&pwm_timer1, kt);
	}

    return HRTIMER_RESTART;
}
 
static int io_to_pwm_init(void) {
    //计算PWM周期为pwm_period*period_cnt=pwm_period*100=1*10^(-6)
	pwm_period = 1000000000/frequency/period_cnt;
    kt = ktime_set(0, high_cnt * pwm_period); 
 
    // 初始化定时器
    hrtimer_init(&pwm_timer1, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
    pwm_timer1.function = pwm_timer_callback;//回调函数操作GPIO
 
    // 启动高精度定时器
    hrtimer_start(&pwm_timer1, kt, HRTIMER_MODE_REL);
 
    printk(KERN_INFO "PWM Timer Module Loaded\n");
	printk("%s\n",__func__);
 
    return 0;
}
/*************************************************************************/
 
static int gpio_pwm_probe(struct platform_device *pdev)
{
	
	int ret = 0;
	
	struct device *dev = &pdev->dev;
	struct gpio_pwm_dev *gblacklight_dev;		
	
	printk("%s\n",__func__);
	gblacklight_dev = devm_kzalloc(dev, sizeof(struct gpio_pwm_dev), GFP_KERNEL);
	memset(gblacklight_dev, 0, sizeof(*gblacklight_dev));
	if (!gblacklight_dev)
	{
		printk("devm_kzalloc gblacklight_dev fail \n");
		return -1;
	}
	gblacklight_dev->reg_base = of_iomap(pdev->dev.of_node, 0);
	if (gblacklight_dev->reg_base == 0)
	{
		printk("%s:Failed to ioremap() io memory region.\n", __func__);
		ret = -EBUSY;
	}
	else
		printk("xxkey base: %p !\n", gblacklight_dev->reg_base);
 
	gpioled_gpio = of_get_named_gpio_flags(pdev->dev.of_node, "gpioled-gpio", 0, NULL);
	if (gpioled_gpio < 0)
	{
		printk("%s() Can not read property gpioled-gpio\n", __func__);
		gpioled_gpio = 0;
		return -1;
	}
	ret = gpio_request(gpioled_gpio, "gpioled-gpio");
	if (ret < 0)
	{
		printk("gpio request gpioled-gpio error!\n");
	}
	else
	{
		printk("%s get gpioled-gpio:%d success!\n",__func__, gpioled_gpio);
		gpio_direction_output(gpioled_gpio, 1);
	}

	io_to_pwm_init();
	if(device_create_file(&pdev->dev, &gpioled_pwm_level))
		printk("%s create gpioled_pwm_level file fail because of erorr\n",__func__);
	platform_set_drvdata(pdev, gblacklight_dev);

	
	return ret;
}

static int gpio_pwm_remove(struct platform_device *pdev)
{
	struct gpio_pwm_dev *gblacklight_dev = (struct gpio_pwm_dev *)dev_get_drvdata(&pdev->dev);
	del_timer(&gblacklight_dev->pwm_timer);
	device_remove_file(gblacklight_dev->dev, &gpioled_pwm_level);	
	dev_set_drvdata(gblacklight_dev->dev, NULL);
	hrtimer_cancel(&pwm_timer1);
	return 0;
}

static const struct of_device_id of_gpio_pwms_match[] = {
	{ .compatible = "gpioled,gpiopwm" },
	{},
};

 static struct platform_driver gpio_pwm_driver = {
	.probe		= gpio_pwm_probe,
	.remove		= gpio_pwm_remove,
	.driver		= {
		.name	= "gpio_pwm",
		.of_match_table = of_gpio_pwms_match,
	},
};

static int __init gpio_pwm_init(void)
{
	printk("%s\n",__func__);
	platform_driver_register(&gpio_pwm_driver);
	return 0;
}

static void __exit gpio_pwm_exit(void)
{
	printk("%s\n",__func__);
	platform_driver_unregister(&gpio_pwm_driver);
	return;
}

module_init(gpio_pwm_init);
module_exit(gpio_pwm_exit);

MODULE_LICENSE("GPL");		
MODULE_AUTHOR("hedalei");	

对应系统dts添加如下配置:

	gpioled {
		status = "okay";
		compatible = "gpioled,gpiopwm";
		gpioled-gpio = <&pio PI 6 GPIO_ACTIVE_HIGH>;
	};

上面驱动添加以后,会生成/sys/devices/platform/gpioled/gpioled_pwm_level节点,对节点写0~100的数值就可以进行亮度调节了。设置0的时候是一直拉低,亮度为0,设置为100的时候一直拉高,亮度为100.

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值