打印
[i.MX]

关于imx6中linux的pwm使用问题 用来驱动电机

[复制链接]
4441|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Saintxpaul|  楼主 | 2015-12-28 16:29 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
在内核源码的drivers文件夹里应该有pwm的文件吗?看说明写的在arch/arm/plat-mxc里的pwm.c文件就是驱动文件,这个文件应该怎么使用呢?或者说如果自己写了一个测试程序,如何在板子里运行呢?是直接调用pwm.c里面的函数就可以吗?对这部分不太懂,希望大神能够给解答一下 谢谢!

相关帖子

沙发
kris_fei| | 2015-12-28 16:36 | 只看该作者
先看看硬件文档和驱动再说呗

使用特权

评论回复
板凳
mini1986| | 2015-12-30 15:00 | 只看该作者
pwm.c是驱动层面的东西,你直接调用不了......把pwm驱动搞好,用应用层的接口去操作......

使用特权

评论回复
地板
Saintxpaul|  楼主 | 2015-12-30 15:54 | 只看该作者
mini1986 发表于 2015-12-30 15:00
pwm.c是驱动层面的东西,你直接调用不了......把pwm驱动搞好,用应用层的接口去操作...... ...

我看pwm.c里有很多看起来给用户直接调用的函数,所以觉得应该是直接用就可以的
/*
* simple driver for PWM (Pulse Width Modulator) controller
*
* 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.
*
* Derived from pxa PWM driver by eric miao <eric.miao@marvell.com>
* Copyright 2009-2013 Freescale Semiconductor, Inc. All Rights Reserved.
*/

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/pwm.h>
#include <linux/fsl_devices.h>
#include <mach/hardware.h>


/* i.MX1 and i.MX21 share the same PWM function block: */

#define MX1_PWMC    0x00   /* PWM Control Register */
#define MX1_PWMS    0x04   /* PWM Sample Register */
#define MX1_PWMP    0x08   /* PWM Period Register */


/* i.MX27, i.MX31, i.MX35 share the same PWM function block: */

#define MX3_PWMCR                 0x00    /* PWM Control Register */
#define MX3_PWMSAR                0x0C    /* PWM Sample Register */
#define MX3_PWMPR                 0x10    /* PWM Period Register */
#define MX3_PWMCR_PRESCALER(x)    (((x - 1) & 0xFFF) << 4)
#define MX3_PWMCR_DOZEEN                (1 << 24)
#define MX3_PWMCR_WAITEN                (1 << 23)
#define MX3_PWMCR_DBGEN                        (1 << 22)
#define MX3_PWMCR_CLKSRC_IPG_HIGH (2 << 16)
#define MX3_PWMCR_CLKSRC_IPG      (1 << 16)
#define MX3_PWMCR_SWR             (1 << 3)
#define MX3_PWMCR_EN              (1 << 0)

#define MX3_PWMCR_STOPEN                (1 << 25)
#define MX3_PWMCR_DOZEEN                (1 << 24)
#define MX3_PWMCR_WAITEN                (1 << 23)
#define MX3_PWMCR_DBGEN                        (1 << 22)
#define MX3_PWMCR_CLKSRC_IPG                (1 << 16)
#define MX3_PWMCR_CLKSRC_IPG_32k        (3 << 16)

struct pwm_device {
        struct list_head        node;
        struct platform_device *pdev;

        const char        *label;
        struct clk        *clk;

        int                clk_enabled;
        void __iomem        *mmio_base;

        unsigned int        use_count;
        unsigned int        pwm_id;
        int                pwmo_invert;
        void (*enable_pwm_pad)(void);
        void (*disable_pwm_pad)(void);
};

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;

        if (!(cpu_is_mx1() || cpu_is_mx21())) {
                unsigned long long c;
                unsigned long period_cycles, duty_cycles, prescale;
                u32 cr;

                if (pwm->pwmo_invert)
                        duty_ns = period_ns - duty_ns;

                c = clk_get_rate(pwm->clk);
                c = c * period_ns;
                do_div(c, 1000000000);
                period_cycles = c;

                prescale = period_cycles / 0x10000 + 1;

                period_cycles /= prescale;
                c = (unsigned long long)period_cycles * duty_ns;
                do_div(c, period_ns);
                duty_cycles = c;

                /*
                 * according to imx pwm RM, the real period value should be
                 * PERIOD value in PWMPR plus 2.
                 */
                if (period_cycles > 2)
                        period_cycles -= 2;
                else
                        period_cycles = 0;

                writel(duty_cycles, pwm->mmio_base + MX3_PWMSAR);
                writel(period_cycles, pwm->mmio_base + MX3_PWMPR);

                cr = MX3_PWMCR_PRESCALER(prescale) |
                        MX3_PWMCR_STOPEN | MX3_PWMCR_DOZEEN |
                        MX3_PWMCR_WAITEN | MX3_PWMCR_DBGEN;

                if (cpu_is_mx25())
                        cr |= MX3_PWMCR_CLKSRC_IPG;
                else
                        cr |= MX3_PWMCR_CLKSRC_IPG_HIGH;

                writel(cr, pwm->mmio_base + MX3_PWMCR);
        } else if (cpu_is_mx1() || cpu_is_mx21()) {
                /* The PWM subsystem allows for exact frequencies. However,
                 * I cannot connect a scope on my device to the PWM line and
                 * thus cannot provide the program the PWM controller
                 * exactly. Instead, I'm relying on the fact that the
                 * Bootloader (u-boot or WinCE+haret) has programmed the PWM
                 * function group already. So I'll just modify the PWM sample
                 * register to follow the ratio of duty_ns vs. period_ns
                 * accordingly.
                 *
                 * This is good enough for programming the brightness of
                 * the LCD backlight.
                 *
                 * The real implementation would divide PERCLK[0] first by
                 * both the prescaler (/1 .. /128) and then by CLKSEL
                 * (/2 .. /16).
                 */
                u32 max = readl(pwm->mmio_base + MX1_PWMP);
                u32 p;
                if (pwm->pwmo_invert)
                        duty_ns = period_ns - duty_ns;
                p = max * duty_ns / period_ns;
                writel(max - p, pwm->mmio_base + MX1_PWMS);
        } else {
                BUG();
        }

        return 0;
}
EXPORT_SYMBOL(pwm_config);

int pwm_enable(struct pwm_device *pwm)
{
        unsigned long reg;
        int rc = 0;

        if (!pwm->clk_enabled) {
                rc = clk_enable(pwm->clk);
                if (!rc)
                        pwm->clk_enabled = 1;
        }

        reg = readl(pwm->mmio_base + MX3_PWMCR);
        reg |= MX3_PWMCR_EN;
        writel(reg, pwm->mmio_base + MX3_PWMCR);

        if (pwm->enable_pwm_pad)
                pwm->enable_pwm_pad();

        return rc;
}
EXPORT_SYMBOL(pwm_enable);

void pwm_disable(struct pwm_device *pwm)
{
        if (pwm->disable_pwm_pad)
                pwm->disable_pwm_pad();

        writel(MX3_PWMCR_SWR, pwm->mmio_base + MX3_PWMCR);
        while (readl(pwm->mmio_base + MX3_PWMCR) & MX3_PWMCR_SWR)
                ;

        if (pwm->clk_enabled) {
                clk_disable(pwm->clk);
                pwm->clk_enabled = 0;
        }
}
EXPORT_SYMBOL(pwm_disable);

static DEFINE_MUTEX(pwm_lock);
static LIST_HEAD(pwm_list);

struct pwm_device *pwm_request(int pwm_id, const char *label)
{
        struct pwm_device *pwm;
        int found = 0;

        mutex_lock(&pwm_lock);

        list_for_each_entry(pwm, &pwm_list, node) {
                if (pwm->pwm_id == pwm_id) {
                        found = 1;
                        break;
                }
        }

        if (found) {
                if (pwm->use_count == 0) {
                        pwm->use_count++;
                        pwm->label = label;
                } else
                        pwm = ERR_PTR(-EBUSY);
        } else
                pwm = ERR_PTR(-ENOENT);

        mutex_unlock(&pwm_lock);
        return pwm;
}
EXPORT_SYMBOL(pwm_request);

void pwm_free(struct pwm_device *pwm)
{
        mutex_lock(&pwm_lock);

        if (pwm->use_count) {
                pwm->use_count--;
                pwm->label = NULL;
        } else
                pr_warning("PWM device already freed\n");

        mutex_unlock(&pwm_lock);
}
EXPORT_SYMBOL(pwm_free);

static int __devinit mxc_pwm_probe(struct platform_device *pdev)
{
        struct pwm_device *pwm;
        struct resource *r;
        struct mxc_pwm_platform_data *plat_data = pdev->dev.platform_data;
        int ret = 0;

        pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
        if (pwm == NULL) {
                dev_err(&pdev->dev, "failed to allocate memory\n");
                return -ENOMEM;
        }

        pwm->clk = clk_get(&pdev->dev, "pwm");

        if (IS_ERR(pwm->clk)) {
                ret = PTR_ERR(pwm->clk);
                goto err_free;
        }

        pwm->clk_enabled = 0;

        pwm->use_count = 0;
        pwm->pwm_id = pdev->id;
        pwm->pdev = pdev;
        if (plat_data != NULL) {
                pwm->pwmo_invert = plat_data->pwmo_invert;
                pwm->enable_pwm_pad = plat_data->enable_pwm_pad;
                pwm->disable_pwm_pad = plat_data->disable_pwm_pad;
        }

        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (r == NULL) {
                dev_err(&pdev->dev, "no memory resource defined\n");
                ret = -ENODEV;
                goto err_free_clk;
        }

        r = request_mem_region(r->start, r->end - r->start + 1, pdev->name);
        if (r == NULL) {
                dev_err(&pdev->dev, "failed to request memory resource\n");
                ret = -EBUSY;
                goto err_free_clk;
        }

        pwm->mmio_base = ioremap(r->start, r->end - r->start + 1);
        if (pwm->mmio_base == NULL) {
                dev_err(&pdev->dev, "failed to ioremap() registers\n");
                ret = -ENODEV;
                goto err_free_mem;
        }

        mutex_lock(&pwm_lock);
        list_add_tail(&pwm->node, &pwm_list);
        mutex_unlock(&pwm_lock);

        platform_set_drvdata(pdev, pwm);
        return 0;

err_free_mem:
        release_mem_region(r->start, r->end - r->start + 1);
err_free_clk:
        clk_put(pwm->clk);
err_free:
        kfree(pwm);
        return ret;
}

static int __devexit mxc_pwm_remove(struct platform_device *pdev)
{
        struct pwm_device *pwm;
        struct resource *r;

        pwm = platform_get_drvdata(pdev);
        if (pwm == NULL)
                return -ENODEV;

        mutex_lock(&pwm_lock);
        list_del(&pwm->node);
        mutex_unlock(&pwm_lock);

        iounmap(pwm->mmio_base);

        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        release_mem_region(r->start, r->end - r->start + 1);

        clk_put(pwm->clk);

        kfree(pwm);
        return 0;
}

static struct platform_driver mxc_pwm_driver = {
        .driver                = {
                .name        = "mxc_pwm",
        },
        .probe                = mxc_pwm_probe,
        .remove                = __devexit_p(mxc_pwm_remove),
};

static int __init mxc_pwm_init(void)
{
        return platform_driver_register(&mxc_pwm_driver);
}
arch_initcall(mxc_pwm_init);

static void __exit mxc_pwm_exit(void)
{
        platform_driver_unregister(&mxc_pwm_driver);
}
module_exit(mxc_pwm_exit);

MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

10

主题

27

帖子

1

粉丝