高通LCD的pwm背光驱动

发生异常的现象:

msm8953 lcd在快速亮灭的情况下背光概率性休眠不灭;测量高通pwm,发现正常的时候pwm的管脚LCM_BL_PWM为低电平,失败的时候为高电平;

根据原理图:
811006-20180612150932701-1981328986.png

mpp是什么?
mpp是基于电源pmic的管脚,也叫做多功能管脚;MPP的全称是Multi Purpose Pin;可以做电源、gpio、ADC、PWM、SINK等功能。

背光的控制方式:

  1. LCD控制IC支持动态背光控制功能(CABC)通过解析图像的直方图动态改变输出PWM的占空比从而动态调节LCD的背光,在不改变图像显示效果的情况下降低功耗,PMIC根据CABC的占空比控制背光输出电压;
  2. 背光控制部分不经过PMIC而是通过一颗单独的带有boost转换功能的LED驱动器如LM3630A,该芯片通过PWM调节亮度。

我们使用的就是第一种方式;

通过soc->pmi8950(内部pwm)->mpp3的方式去控制。

lcd背光控制调用流程:

首先,我们用的是mipi接口,所以lcd显示驱动是在mdss_dsi.c中,pwm驱动控制是在pwm-qpnp.c文件中(kernel\msm-3.18\drivers\pwm);

mdss_dsi.c文件中,具体在哪里调用到背光函数呢?

根据打印log,可以知道背光控制函数mdss_dsi_panel_bl_ctrl

mdss_dsi_panel_bl_ctrl这个函数是在mdss_dsi_panel.c文件中;

调用顺序如下:
mdss_dsi_ctrl_probe -- >
  mdss_dsi_config_panel -- >
    mdss_dsi_panel_init -- >
     ctrl_pdata->panel_data.set_backlight = mdss_dsi_panel_bl_ctrl;

根据mdss_dsi_panel_bl_ctrl函数:

static void mdss_dsi_panel_bl_ctrl(struct mdss_panel_data *pdata,u32 bl_level)
{....../** Some backlight controllers specify a minimum duty cycle* for the backlight brightness. If the brightness is less* than it, the controller can malfunction.*/if ((bl_level < pdata->panel_info.bl_min) && (bl_level != 0))bl_level = pdata->panel_info.bl_min;switch (ctrl_pdata->bklt_ctrl) {case BL_WLED:led_trigger_event(bl_led_trigger, bl_level);break;case BL_PWM:mdss_dsi_panel_bklt_pwm(ctrl_pdata, bl_level);break;case BL_DCS_CMD:if (!mdss_dsi_sync_wait_enable(ctrl_pdata)) {mdss_dsi_panel_bklt_dcs(ctrl_pdata, bl_level);break;}/** DCS commands to update backlight are usually sent at* the same time to both the controllers. However, if* sync_wait is enabled, we need to ensure that the* dcs commands are first sent to the non-trigger* controller so that when the commands are triggered,* both controllers receive it at the same time.*/sctrl = mdss_dsi_get_other_ctrl(ctrl_pdata);if (mdss_dsi_sync_wait_trigger(ctrl_pdata)) {if (sctrl)mdss_dsi_panel_bklt_dcs(sctrl, bl_level);mdss_dsi_panel_bklt_dcs(ctrl_pdata, bl_level);} else {mdss_dsi_panel_bklt_dcs(ctrl_pdata, bl_level);if (sctrl)mdss_dsi_panel_bklt_dcs(sctrl, bl_level);}break;default:pr_err("%s: Unknown bl_ctrl configuration\n",__func__);break;}
}

我们进入mdss_dsi_panel_bklt_pwm函数来看看:

static void mdss_dsi_panel_bklt_pwm(struct mdss_dsi_ctrl_pdata *ctrl, int level)
{int ret;u32 duty;u32 period_ns;if (ctrl->pwm_bl == NULL) {pr_err("%s: no PWM\n", __func__);return;}if (level == 0) {if (ctrl->pwm_enabled) {ret = pwm_config_us(ctrl->pwm_bl, level,ctrl->pwm_period);if (ret)pr_err("%s: pwm_config_us() failed err=%d.\n",__func__, ret);pwm_disable(ctrl->pwm_bl);}ctrl->pwm_enabled = 0;return;}....
}

进入pwm_disable函数,这里有调用了一个回调函数:

/*** pwm_disable() - stop a PWM output toggling* @pwm: PWM device*/
void pwm_disable(struct pwm_device *pwm)
{if (pwm && test_and_clear_bit(PWMF_ENABLED, &pwm->flags)) {pwm->chip->ops->disable(pwm->chip, pwm);}
}

搜索之后,可以在qpnp_pwm_disablepwm-qpnp.c文件中找到相应的函数和函数集):

static struct pwm_ops qpnp_pwm_ops = {.enable = qpnp_pwm_enable,.disable = qpnp_pwm_disable,.config = qpnp_pwm_config,.free = qpnp_pwm_free,.owner = THIS_MODULE,
};/*** qpnp_pwm_disable - stop a PWM output toggling* @pwm_chip: the PWM chip* @pwm: the PWM device*/
static void qpnp_pwm_disable(struct pwm_chip *pwm_chip,struct pwm_device *pwm)
{struct qpnp_pwm_chip    *chip = qpnp_pwm_from_pwm_chip(pwm_chip);unsigned long       flags;int rc = 0;spin_lock_irqsave(&chip->lpg_lock, flags);if (QPNP_IS_PWM_CONFIG_SELECTED(chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL]) ||chip->flags & QPNP_PWM_LUT_NOT_SUPPORTED)rc = qpnp_lpg_configure_pwm_state(chip,QPNP_PWM_DISABLE);else if (!(chip->flags & QPNP_PWM_LUT_NOT_SUPPORTED))rc = qpnp_lpg_configure_lut_state(chip,QPNP_LUT_DISABLE);if (!rc)chip->enabled = false;spin_unlock_irqrestore(&chip->lpg_lock, flags);if (rc)pr_err("Failed to disable PWM channel: %d\n",chip->channel_id);
}

来到qpnp_lpg_configure_pwm_state(chip, QPNP_PWM_DISABLE);这个函数中来:

static int qpnp_lpg_configure_pwm_state(struct qpnp_pwm_chip *chip,enum qpnp_pwm_state state)
{struct qpnp_lpg_config  *lpg_config = &chip->lpg_config;u8          value, mask;int         rc;bool            test_enable;if (chip->sub_type == QPNP_PWM_MODE_ONLY_SUB_TYPE) {if (state == QPNP_PWM_ENABLE)value = QPNP_ENABLE_PWM_MODE_ONLY_SUB_TYPE;elsevalue = QPNP_DISABLE_PWM_MODE_ONLY_SUB_TYPE;mask = QPNP_PWM_MODE_ONLY_ENABLE_DISABLE_MASK_SUB_TYPE;} else {if (state == QPNP_PWM_ENABLE)value = qpnp_enable_pwm_mode(chip);elsevalue = QPNP_DISABLE_PWM_MODE(chip);mask = QPNP_EN_PWM_HIGH_MASK | QPNP_EN_PWM_LO_MASK |QPNP_PWM_SRC_SELECT_MASK | QPNP_PWM_EN_RAMP_GEN_MASK;if (chip->sub_type != QPNP_LPG_S_CHAN_SUB_TYPE)mask |= QPNP_EN_PWM_OUTPUT_MASK;}if (chip->in_test_mode) {test_enable = (state == QPNP_PWM_ENABLE) ? 1 : 0;rc = qpnp_dtest_config(chip, test_enable);if (rc)pr_err("Failed to configure TEST mode\n");}pr_debug("pwm_enable_control: %d\n", value);rc = qpnp_lpg_save_and_write(value, mask,&chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL],SPMI_LPG_REG_ADDR(lpg_config->base_addr,QPNP_ENABLE_CONTROL), 1, chip);if (rc)goto out;/** Due to LPG hardware bug, in the PWM mode, having enabled PWM,* We have to write PWM values one more time.*/if (state == QPNP_PWM_ENABLE)return qpnp_lpg_save_pwm_value(chip);
out:return rc;
}

qpnp_lpg_save_pwm_value会保存着上一次pwm的高低电平的值,

rc = qpnp_lpg_save_and_write(value, mask,&chip->qpnp_lpg_registers[QPNP_PWM_VALUE_LSB],SPMI_LPG_REG_ADDR(lpg_config->base_addr,QPNP_PWM_VALUE_LSB), 1, chip);

保存了上一次亮屏的时候的电平值;所以只要把这段语句去掉,在快速闪灭屏的时候,灭屏就不会出现背光不灭的情况,这是因为寄存器没有写好前,就保存亮屏的高电平值;

LCD背光驱动

qpnp_lpg_init进入probe函数中,spmi驱动是什么呢?参考这篇文章:
SPMI理解
其实简单理解spmi就是一个通讯协议;

static int qpnp_pwm_probe(struct spmi_device *spmi)
{struct qpnp_pwm_chip    *pwm_chip;int         rc;pwm_chip = kzalloc(sizeof(*pwm_chip), GFP_KERNEL);if (pwm_chip == NULL) {pr_err("kzalloc() failed.\n");return -ENOMEM;}spin_lock_init(&pwm_chip->lpg_lock);pwm_chip->spmi_dev = spmi;dev_set_drvdata(&spmi->dev, pwm_chip);rc = qpnp_parse_dt_config(spmi, pwm_chip);if (rc) {pr_err("Failed parsing DT parameters, rc=%d\n", rc);goto failed_config;}pwm_chip->chip.dev = &spmi->dev;pwm_chip->chip.ops = &qpnp_pwm_ops;    pwm_chip->chip.base = -1;pwm_chip->chip.npwm = 1;rc = pwmchip_add(&pwm_chip->chip);if (rc < 0) {pr_err("pwmchip_add() failed: %d\n", rc);goto failed_insert;}if (pwm_chip->channel_owner)pwm_chip->chip.pwms[0].label = pwm_chip->channel_owner;pr_debug("PWM device sid:%d channel:%d probed successfully\n",spmi->sid, pwm_chip->channel_id);return 0;failed_insert:kfree(pwm_chip->lpg_config.lut_config.duty_pct_list);
failed_config:dev_set_drvdata(&spmi->dev, NULL);kfree(pwm_chip);return rc;
}

pwm_chip->chip.ops = &qpnp_pwm_ops;注册相应的回调函数;

patch地址

patch地址

转载于:https://www.cnblogs.com/linhaostudy/p/9173117.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/465737.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

为什么一个字节定义成8位?

今天给大家分享一个小小知识点&#xff0c;为什么一个字节定义成8位呢&#xff1f;一些人没有回答到点子上。这件事得追溯计算机历史&#xff0c;源于IBM360操作系统和图灵奖得主&#xff08;Fred&#xff09;Brooks Jr。布鲁克斯被问到“您认为自己最大的技术成就是什么&#…

硬件基础 —— 光耦

光耦1、工作原理以光为媒介传递电信号。对输入和输出信号有良好的隔离作用&#xff08;光耦隔离&#xff09;。光耦一般由三个部分组成&#xff1a;光的发射、光的接收和信号放大。输入的电信号驱动发光二极管&#xff0c;被光探测器接收而产生光电流&#xff0c;再经过进一步放…

红外感应自动出水水龙头的电路原理

红外感应自动出水的水龙头&#xff0c;生活中很常见&#xff1a;可以用以下的电路方案实现&#xff0c;供电采用USB的5V&#xff1a;只要手靠近“红外线靠近检测模块”&#xff0c;直流水泵就会开启供水&#xff1a;其中这种直流水泵长这样&#xff1a;当“红外线靠近检测模块”…

Linux面试最高频的5个基本问题

CPU利用率和CPU负载的区别是什么提到CPU利用率&#xff0c;就必须理解时间片。什么是CPU时间片&#xff1f;我们现在所使用的Windows、Linux、Mac OS都是“多任务操作系统”&#xff0c;就是说他们可以“同时”运行多个程序&#xff0c;比如一边打开Chrome浏览器浏览网页还能一…

用iptables实现G1手机cmwap代理上http网站[转]

2019独角兽企业重金招聘Python工程师标准>>> 折腾了几天&#xff0c;总算有点阶段性成果&#xff1a; 证实可以用iptables实现通过cmwap的代理上HTTP协议的网站。 首先&#xff0c;android系统的实现是有缺陷的。在接入apn中指定的proxy并不会被系统所用。好似只有浏…

初识Buildroot

转自CSDN &#xff0c;记录是为了作者小编学习需要作者&#xff1a;xixihaha331什么是buildrootBuildroot是Linux平台上一个构建嵌入式Linux系统的框架。整个Buildroot是由Makefile脚本和Kconfig配置文件构成的。你可以和编译Linux内核一样&#xff0c;通过buildroot配置&#…

Python3安装(Windows)

Windows下Python3环境搭建 目录 Windows下Python3环境搭建 安装Python 启动终端会话 IDE —— Geany 安装Python 访问https://www.python.org/downloads 点击上图红色区域按钮&#xff0c;下载Python。下载完成后开始安装&#xff1a; 勾选“Add Python 3.7 to PATH”&…

Runtime消息动态解析与转发流程

先上图&#xff1a; 下面根据具体代码看这张图。 一、创建一个Person类&#xff0c; Person.h #import <Foundation/Foundation.h>interface Person : NSObject-(void)sendMessage:(NSString *)message;end Person.m #import "Person.h" #import <objc/runt…

编写优美的GTest测试案例

使用gtest也有很长一段时间了&#xff0c;这期间也积累了一些经验&#xff0c;所以分享一下。GTest为我们提供了便捷的测试框架&#xff0c;让我们只需要关注案例本身。如何在GTest框架下写出优美的测试案例&#xff0c;我觉得必须要做到&#xff1a; 案例的层次结构一定要清晰…

评分9.3,你想要的那本书,来了!

还记得那天晚上我发的朋友圈吗&#xff1f;经过不完全统计&#xff0c;更多的人喜欢C语言这本书&#xff0c;所以这次先安排抽奖这本书籍&#xff0c;属于出版社赞助&#xff0c;也是给大家一个获奖的机会。不吹牛啊&#xff0c;我们办公室一个大神&#xff0c;写算法的&#x…

Python3安装(Linux)

Linux下Python3环境搭建 目录 Linux下Python3环境搭建 检查Python版本&#xff08;ubuntu16.04&#xff09; Helloworld IDE —— Geany 检查Python版本&#xff08;ubuntu16.04&#xff09; Linux默认已经安装了Python。CtrlAltT调出终端&#xff0c;输入python&#xff…

create-react-app 创建react项目 多页面应用

1:npm install -g create-react-app 2:创建一个应用 create-react-app my-app cd my-app 3:提取配置文件 npm run eject 4:允许文件 npm start create-react-app 默认是创建单页面应用&#xff0c;但是也可以创建多页面应用&#xff0c;需要手动配置一下webpack 第一步&…

c语言指针用法详解,通俗易懂超详细!

文章转自&#xff1a;无际单片机大家好&#xff0c;我是无际。今天给大家来讲解一下指针。我会由浅到深&#xff0c;最后结合实际应用讲解&#xff0c;让大家学会指针的同时&#xff0c;知道大佬们都用指针来干嘛&#xff01;长文预警&#xff01;全文大约5200多字&#xff0c;…

Python3 —— 变量和简单数据类型

Python3 —— 变量和简单数据类型 目录 python3 —— 变量和简单数据类型 一、变量 1、变量&#xff08;每个变量都存储了一个值——与变量相关联的信息&#xff09; 2、变量命名 二、简单数据类型&#xff08;整型&#xff0c;浮点型&#xff0c;字符串等&#xff09; 1…

Linux C Socket编程,这篇文章让我耳目一新

目录1. 什么是TCP/IP、UDP&#xff1f;2. Socket在哪里呢&#xff1f;3. Socket是什么呢&#xff1f;4. 有很多的框架&#xff0c;为什么还在从Socket开始&#xff1f;5. Linux C Socket简单示例1.什么是TCP/IP、UDP&#xff1f;TCP/IP&#xff08;Transmission Cont…

视频下载比想象中容易

两周前搞定了56.com的视频独立播放和视频下载后&#xff0c;很得意是吹嘘了一把&#xff0c;有一些朋友也就试着用了&#xff08;有朋友笑称我在为56.com做广告&#xff0c;因为他以前是不知道56.com的&#xff0c;我这么一搞&#xff0c;他竟也喜欢上56.com看视频了&#xff0…

微处理器:50岁了!

编排 | strongerHuang微信公众号 | 嵌入式专栏50年前&#xff08;1971年&#xff09;&#xff0c;英特尔推出了第一款商用的通用型微处理器 4004&#xff0c;4004拥有2300多个晶体管&#xff0c;与当今芯片中的几十上百亿个晶体管相比&#xff0c;这个数字相形见绌&#xff0c;…

Python3 —— 列表

Python3 —— 列表 目录 Python3 —— 列表 1.访问列表元素&#xff08;索引&#xff09; 2.修改列表元素 3.添加列表元素 4.删除列表元素 5.组织列表 6.遍历整个列表&#xff08;for循环&#xff0c;缩进部分都在for范围之内&#xff09; 7.创建数值列表 8.列表简单…

当卷烟厂也那么卷后……

过年回家&#xff0c;跟几个同学一起吃饭&#xff0c;聊到当时班上读书厉害的一个同学。同学嘴巴瞪得很大&#xff0c;说了一句&#xff0c;他在烟厂企业上班&#xff0c;现在开的什么什么车&#xff0c;待遇好得不得了。中学时候&#xff0c;那个同学读书真的厉害&#xff0c;…

Python3 —— if/while/input

Python3 —— if/while/input 目录 Python3 —— if/while/input 1.条件测试 2.if语句 3.input()函数 4.while循环 5.break与continue 1.条件测试 等于 ! 不等于 < 小于 < 小于等于 > 大于 > 大于等于 and 与 or 或 not in 不在 2…