2026-01-21 18:59:54 +08:00

199 lines
4.9 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Driver for pwm demo on Firefly board.
*
* Copyright (C) 2016, Zhongshan T-chip Intelligent Technology Co.,ltd.
* Copyright 2006 Tek.Leung
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/pwm.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <dt-bindings/pwm/pwm.h>
#include <linux/platform_device.h>
#include <asm/io.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/init.h>
#define SYS_DEV_CONFIG 1
static int gval = 0;
struct firefly_pwm_data {
int pwm_id;
struct pwm_device *pwm;
unsigned int period;
unsigned int pwm_period_ns;
unsigned int duty_ns;
bool enabled;
};
struct firefly_pwm_data g_firefly_pdata;
#ifdef SYS_DEV_CONFIG
static ssize_t firefly_pwm_store(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t count)
{
unsigned long state;
int c, ret;
ret = kstrtoul(buf, 10, &state);
if (state > g_firefly_pdata.pwm_period_ns)
state = g_firefly_pdata.pwm_period_ns;
else if (state < 0)
state = 0;
c = state;
if (ret)
return ret;
g_firefly_pdata.enabled = true;
pwm_config(g_firefly_pdata.pwm, c, g_firefly_pdata.pwm_period_ns);
pwm_enable(g_firefly_pdata.pwm);
gval = c;
return count;
}
static ssize_t firefly_pwm_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%u\n", gval);
}
static struct kobject *pwm_kobj;
static DEVICE_ATTR(firefly_pwm, (S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP),
firefly_pwm_show, firefly_pwm_store);
#endif
static int firefly_pwm_status_update(struct firefly_pwm_data *pdata)
{
if (pdata->enabled)
return 0;
pwm_enable(pdata->pwm);
pwm_config(pdata->pwm, pdata->duty_ns, g_firefly_pdata.pwm_period_ns);
pdata->enabled = true;
gval = pdata->duty_ns;
return 0;
}
ssize_t firefly_pwm_parse_dt(struct firefly_pwm_data *firefly_pdata,
struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
const __be32 *duty_ns;
int len;
duty_ns = of_get_property(np, "duty_ns", &len);
if (duty_ns)
firefly_pdata->duty_ns = be32_to_cpu(*duty_ns);
return 0;
}
static int firefly_pwm_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct firefly_pwm_data *firefly_pdata = pdev->dev.platform_data;
int ret;
struct pwm_args pargs;
printk("firefly pwm probe start \n");
if (!np) {
dev_err(&pdev->dev, "Device Tree node missing\n");
return -EINVAL;
}
firefly_pdata =
devm_kzalloc(&pdev->dev, sizeof(*firefly_pdata), GFP_KERNEL);
if (!firefly_pdata)
return -ENOMEM;
firefly_pdata->enabled = false;
firefly_pdata->pwm = devm_pwm_get(&(pdev->dev), NULL);
if (IS_ERR(firefly_pdata->pwm)) {
dev_err(&pdev->dev, "unable to request legacy PWM\n");
ret = PTR_ERR(firefly_pdata->pwm);
goto err;
}
if (np)
ret = firefly_pwm_parse_dt(firefly_pdata, pdev);
pwm_get_args(firefly_pdata->pwm, &pargs);
firefly_pdata->pwm_period_ns = pargs.period;
printk("firefly pwm firefly_pdata->pwm_period_ns : %d \n",
firefly_pdata->pwm_period_ns);
if (firefly_pdata->pwm_period_ns > 0)
pwm_set_period(firefly_pdata->pwm,
firefly_pdata->pwm_period_ns);
firefly_pdata->period = pwm_get_period(firefly_pdata->pwm);
printk("firefly pwm firefly_pdata->period : %d \n",
firefly_pdata->period);
g_firefly_pdata = *firefly_pdata;
firefly_pwm_status_update(firefly_pdata);
printk("%s: Firefly PWM Demo !\n", __func__);
#ifdef SYS_DEV_CONFIG
pwm_kobj = kobject_create_and_add("pwm", NULL);
if (pwm_kobj == NULL) {
printk("create kobject fail \n");
ret = -ENOMEM;
goto err;
}
ret = sysfs_create_file(pwm_kobj, &dev_attr_firefly_pwm.attr);
if (ret) {
printk("pwm firefly_sysfs_init: sysfs_create_group failed\n");
goto err;
}
#endif
return 0;
err:
#ifdef SYS_DEV_CONFIG
kobject_del(pwm_kobj);
#endif
devm_kfree(&pdev->dev, firefly_pdata);
return ret;
}
static int firefly_pwm_remove(struct platform_device *pdev)
{
struct firefly_pwm_data *firefly_pdata = pdev->dev.platform_data;
#ifdef SYS_DEV_CONFIG
kobject_del(pwm_kobj);
#endif
devm_kfree(&pdev->dev, firefly_pdata);
return 0;
}
static const struct of_device_id firefly_pwm_dt_ids[] = {
{ .compatible = "firefly,rk3588-pwm" },
{}
};
MODULE_DEVICE_TABLE(of, firefly_pwm_dt_ids);
static struct platform_driver firefly_pwm_driver = {
.driver = {
.name = "firefly-pwm",
.of_match_table = firefly_pwm_dt_ids,
},
.probe = firefly_pwm_probe,
.remove = firefly_pwm_remove,
};
module_platform_driver(firefly_pwm_driver);
MODULE_AUTHOR("maocl <service@t-firefly.com>");
MODULE_DESCRIPTION("Firefly PWM driver");
MODULE_ALIAS("platform:firefly-pwm");
MODULE_LICENSE("GPL");