如何在qualcomm 8960和8921上使用PWM功能 (GPIO24)

发布时间:2014-10-22 14:02:05编辑:www.fx114.net 分享查询网我要评论
本篇文章主要介绍了"如何在qualcomm 8960和8921上使用PWM功能 (GPIO24)",主要涉及到如何在qualcomm 8960和8921上使用PWM功能 (GPIO24)方面的内容,对于如何在qualcomm 8960和8921上使用PWM功能 (GPIO24)感兴趣的同学可以参考一下。

一、PWM 分析 1. PWM: Pulse Width Modulator; LPG: Light Pulse Generator; 两者指的是同一东西。  2. PWM driver: /kernel/drivers/mfd/pm8xxx-pwm.c 3. 手机中注册路径: /sys/devices/platform/msm_ssbi.0/pm8921-core/pm8xxx-pwm 4. 利用debugfs调试     a. #mkdir /data/debugfs     b. #mount -t debugfs none /data/debugfs     c. #cd /data/debugfs/pmx8xxx-pwm-dbg     d. #ls 可以看到共有8路pwm可用     e. #cd 0; ls         duty-cycle    //占宽比 (0,100)之间         enable         period        //输出波周期 [7, 327*1000000L]微秒之间     f. 需要先设置period, #echo 50 > period     g. #echo 50 > duty-cycle     h. #echo 1 > enable         二、调查完成,所需要修改的代码 1. @kernel/arch/arm/mach-msm/board-semc_blue_cdb.c, 设置PM8921的GPIO工作在PWM function     static struct pm8xxx_gpio_init pm8921_gpios[] __initdata = {         ...         //PM8XXX_GPIO_DISABLE(24),         PM8XXX_GPIO_INIT(    24,                      PM_GPIO_DIR_OUT,                     PM_GPIO_OUT_BUF_CMOS,                     1,                     PM_GPIO_PULL_NO,                     PMIC_GPIO_VIN0,                     PM_GPIO_STRENGTH_HIGH,                     PM_GPIO_FUNC_2,                     1,                     0                 ),             ...     } 2. @kernel/arch/arm/mach-msm/board-semc_blue.c, 设置PWM/LPG 的bank1 可用,该bank1 对应的是GPIO24     static struct pm8xxx_pwm_platform_data pm8xxx_pwm_pdata = {         //.dtest_channel    = PM8XXX_PWM_DTEST_CHANNEL_NONE,         .dtest_channel    = 0,       }; 3. 进入手机adb shell     a. #mount -t debugfs none /data/debugfs     b. #cd data/debugfs/ pm8xxx-pwm-dbg/0     c. #echo 2000 > period //必须先设置period, 单位为usecond, 区间为[7, 327*1000000L]us     d. #echo 50 > duty-cycle //占空比 (0,100)之间     e. #echo 1 > enable //现在有LPG 方波输出         f. #echo 1 > enable //取消 LPG 方波输出     三、如何检测PM8921 GPIO 的状态 1. 利用手机系统中 已有 /sys/kernel/debug/pm8921-dbg ,gpio检测接口     a. #echo 0x??? > addr //输入GPIO register addrress     b. #echo 0x??? > data //输入控制GPIO,写入register 的值     c. #cat data //查看当前bank输入的值 2. 查看PM8921 register information 文档     a. Function,Sub funtion,Register name,Register Address,Type,Reset code,default value,comments         GPIO,   GPIO_24,     GPIO_CNTRL,    0x167,        8B_WR, 5,    00865A01,    Power-off and Power-on default state is Hi-Z     b. 所以GPIO24的 Register Address 是0x167 3. 检测GPIO24的配置状态,先设置 bank0-7,再读取在该bank设置的参数     #echo 0x167 > addr      echo 0x0 > data //选择bank0     cat data --> 0x01 //得到在bank0 设置的参数     echo 0x10 > data      cat data -->0x18     echo 0x20> data      cat data -->0x2A     echo 0x30 > data      cat data -->0x34     echo 0x40 > data      cat data -->0x46     echo 0x50 > data      cat data      echo 0x60 > data      cat data      echo 0x70 > data      cat data      直接设置某个bank的参数     #echo 0x167 > addr      #echo 0xc6 > data //各bit含义: [7]->(1W,0R),[6:4]->Bank Select, [3:0]->各bank含义不一样     所以0xC6表示0b11000110, 写入,bank4,写入的参数为0110 四,如何用GPIO24模拟 PWM 输出,主要修改kernel/drivers/mfd/pm8xxx-pwm.c #define TEST_PWM #ifdef TEST_PWM #include <linux/mfd/pm8xxx/gpio.h> #include <linux/delay.h> #endif struct pm8xxx_pwm_dbg_device {     struct mutex        dbg_mutex;     struct device        *dev;     struct dentry        *dent;     struct pm8xxx_pwm_user    *user; #ifdef TEST_PWM     struct work_struct pwm_work;     struct workqueue_struct *pwm_wq;     bool pwm_run; #endif     }; #ifdef TEST_PWM static int dbg_pwm_value_set(void *data, u64 val) {     struct pm8xxx_pwm_user      *puser = data;     struct pm8xxx_pwm_dbg_device    *dbgdev = puser->dbgdev;     int gpio_sys = 175;//PM8921_GPIO_PM_TO_SYS(24);     mutex_lock(&dbgdev->dbg_mutex);     gpio_set_value_cansleep(gpio_sys, val);              mutex_unlock(&dbgdev->dbg_mutex);     pr_debug("#### value = %d\n",(int)val);          return 0; } static int dbg_pwm_value_get(void *data, u64 *val) {     struct pm8xxx_pwm_user      *puser = data;     struct pm8xxx_pwm_dbg_device    *dbgdev = puser->dbgdev;     int gpio_sys = 175;//PM8921_GPIO_PM_TO_SYS(24);     mutex_lock(&dbgdev->dbg_mutex);          *val =gpio_get_value_cansleep(gpio_sys);     mutex_unlock(&dbgdev->dbg_mutex);     pr_debug("#### value = %d\n",(int)*val);     return 0; } DEFINE_SIMPLE_ATTRIBUTE(dbg_pwm_value_fops,             dbg_pwm_value_get, dbg_pwm_value_set, "%lld\n"); static void pwm_instant_work(struct work_struct *work) {     int gpio_sys = 175;//PM8921_GPIO_PM_TO_SYS(24);     struct pm8xxx_pwm_dbg_device  *dbgdev= container_of(work, struct pm8xxx_pwm_dbg_device, pwm_work);     struct pm8xxx_pwm_user      *puser;     int  period;     int  duty_cycle;     int  high_us, low_us;          pr_debug(" ### start output signal\n");     puser = dbgdev->user;     period = puser->period;     duty_cycle = puser->duty_cycle;     if( !period || !duty_cycle )         return;          high_us = period * duty_cycle /100;     low_us = period - high_us;     pr_debug("### hight_us = %d, low_us = %d \n ", high_us, low_us);          while(dbgdev->pwm_run)     {         gpio_set_value_cansleep(gpio_sys, 1);         //usleep(high_us);          udelay(high_us);                  gpio_set_value_cansleep(gpio_sys, 0);         //usleep(low_us);         udelay(low_us);     } } static int dbg_pwm_output_set(void *data, u64 val) {     struct pm8xxx_pwm_user      *puser = data;     struct pm8xxx_pwm_dbg_device    *dbgdev = puser->dbgdev;     mutex_lock(&dbgdev->dbg_mutex);     pr_debug("#### value = %d\n",(int)val);     if( val )     {         dbgdev->pwm_run = true;         queue_work(dbgdev->pwm_wq, &dbgdev->pwm_work);     }     else     {         dbgdev->pwm_run = false;     }     mutex_unlock(&dbgdev->dbg_mutex);     return 0; } static int dbg_pwm_output_get(void *data, u64 *val) {     struct pm8xxx_pwm_user      *puser = data;     struct pm8xxx_pwm_dbg_device    *dbgdev = puser->dbgdev;     mutex_lock(&dbgdev->dbg_mutex);          *val = dbgdev->pwm_run;     mutex_unlock(&dbgdev->dbg_mutex);     return 0; } DEFINE_SIMPLE_ATTRIBUTE(dbg_pwm_output_fops,             dbg_pwm_output_get, dbg_pwm_output_set, "%lld\n"); #endif static int __devinit pm8xxx_pwm_dbg_probe(struct device *dev) {      ....         if (temp == NULL || IS_ERR(temp)) {             pr_err("ERR: pwm=%d: enable: dent=%p\n", i, dent);             rc = -ENOMEM;             goto debug_error;         } #ifdef TEST_PWM         temp = debugfs_create_file("value", S_IRUGO | S_IWUSR,                         dent, puser, &dbg_pwm_value_fops);         if (temp == NULL || IS_ERR(temp)) {             pr_err("ERR: pwm=%d: enable: dent=%p\n", i, dent);             rc = -ENOMEM;             goto debug_error;         }         temp = debugfs_create_file("output", S_IRUGO | S_IWUSR,                         dent, puser, &dbg_pwm_output_fops);         if (temp == NULL || IS_ERR(temp)) {             pr_err("ERR: pwm=%d: enable: dent=%p\n", i, dent);             rc = -ENOMEM;             goto debug_error;         } #endif     ....     pmic_dbg_device = dbgdev; #ifdef TEST_PWM     dbgdev->pwm_wq = create_singlethread_workqueue("pwm_wq");     INIT_WORK(&dbgdev->pwm_work, pwm_instant_work); #endif         return 0;    .... }


上一篇:Kendo UI开发教程(27): 移动应用开发简介
下一篇:[转载] 老码农教你学英语

相关文章

相关评论

本站评论功能暂时取消,后续此功能例行通知。

一、不得利用本站危害国家安全、泄露国家秘密,不得侵犯国家社会集体的和公民的合法权益,不得利用本站制作、复制和传播不法有害信息!

二、互相尊重,对自己的言论和行为负责。

好贷网好贷款