Platform: RK3288
OS: Android 6.0
Kernel: 3.10.92
背光的亮暗通过pwm控制,驱动在文件pwm-rockchip.c中,这里不做描述.
dts各个配置参数意义:
backlight {
/*设备名,会和驱动匹配.*/
compatible = "pwm-backlight";
/*使用哪个pwm channal, period*/
pwms = <&pwm0 0 25000>;
/*背光可调等级,比如这里是255级,实际反应到占空比就是当前值和数组中最大值的比值,
例如当前是200,那么最终duty cycle就是200/255.*/
brightness-levels = <255 254 253 252 251 250 249 248 247 246 245 244 243 242 241 240
239 238 237 236 235 234 233 232 231 230 229 228 227 226 225 224 223 222 221 220
219 218 217 216 215 214 213 212 211 210 209 208 207 206 205 204 203 202 201 200
199 198 197 196 195 194 193 192 191 190 189 188 187 186 185 184 183 182 181 180
179 178 177 176 175 174 173 172 171 170 169 168 167 166 165 164 163 162 161 160
159 158 157 156 155 154 153 152 151 150 149 148 147 146 145 144 143 142 141 140
139 138 137 136 135 134 133 132 131 130 129 128 127 126 125 124 123 122 121 120
119 118 117 116 115 114 113 112 111 110 109 108 107 106 105 104 103 102 101 100
99 98 97 96 95 94 93 92 91 90 89 88 87 86 85 84 83 82 81 80 79 78 77 76 75 74 73 72 71 70
69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40
39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10
9 8 7 6 5 4 3 2 1 0>;
/*开机初始化默认等级,Android起来之后会改变它.*/
default-brightness-level = <200>;
/*backlight使能控制pin.*/
enable-gpios = <&gpio7 GPIO_A2 GPIO_ACTIVE_HIGH>;
};
驱动流程:
pwm_backlight_probe -> pwm_bl.c
pwm_backlight_parse_dt //读取上面dts中的brightness-levels, default-brightness-level以及enable-gpios,而pwms后面标准接口会解析.
gpio_request_one //申请背光使能gpio
devm_pwm_get -> core.c//获得一个pwm
pwm_get ->
of_pwm_get ->
of_parse_phandle_with_args 解析上面dts中的pwms属性.
of_node_to_pwmchip
pwm = pc->of_xlate //最终生成struct pwm_device类型.
pwm_get_period //获取period.
dev_set_name(&pdev->dev, "rk28_bl"); //name不能改,用户空间会被用到:/sys/class/backlight/rk28_bl
backlight_device_register -> //注册标准背光设备
device_register
backlight_register_fb ->
fb_register_client //callback是fb_notifier_callback.
backlight_update_status -> //用默认值更新.
bd->ops->update_status ->
pwm_backlight_update_status ->
compute_duty_cycle //计算占空比,下面会分析.
pwm_config //配置pwm
pwm_backlight_power_on //enable背光
compute_duty_cycle:
static int compute_duty_cycle(struct pwm_bl_data *pb, int brightness)
{
/*一般情况下这个值都为0*/
unsigned int lth = pb->lth_brightness;
int duty_cycle;
/*pb->levels这个表格就是从dts节点brightness-levels中获取的,
假设进来的参数brightness是254,那么得到的duty_cycle就是1,
如果没有这个表格,那么就直接是进来的亮度值.*/
if (pb->levels)
duty_cycle = pb->levels[brightness];
else
duty_cycle = brightness;
/*假设这里lth是0,那么公式就是duty_cycle * pb->period / pb->scale
pb->scale为pb->levels数组中的最大值. pb->period也就是dts节点pwms
的第三个参数周期值为25000, 所以这个公式就是按照将android的纯数值转换
成事件周期值对应的占空比.*/
return (duty_cycle * (pb->period - lth) / pb->scale) + lth;
}
小结:
其实不管用哪种方式都是调用backlight_update_status来改变背光,syfs也是,看下backlight.c
backlight_class_init -> backlight.c
class_create //创建class,名字是backlight.
backlight_class->dev_attrs = bl_device_attributes;
static struct device_attribute bl_device_attributes[] = {
__ATTR(bl_power, 0644, backlight_show_power, backlight_store_power),
__ATTR(brightness, 0644, backlight_show_brightness,
backlight_store_brightness),
__ATTR(actual_brightness, 0444, backlight_show_actual_brightness,
NULL),
__ATTR(max_brightness, 0444, backlight_show_max_brightness, NULL),
__ATTR(type, 0444, backlight_show_type, NULL),
__ATTR_NULL,
};
其中backlight_store_brightness() 最终调用backlight_update_status().
还有一种情况是亮屏/灭屏时调用,记得前面有注册一个fb notify callback.
static int fb_notifier_callback(struct notifier_block *self,
unsigned long event, void *data)
{
...
/*只处理亮屏和灭屏事件.*/
/* If we aren't interested in this event, skip it immediately ... */
if (event != FB_EVENT_BLANK && event != FB_EVENT_CONBLANK)
return 0;
...
if (bd->ops)
if (!bd->ops->check_fb ||
bd->ops->check_fb(bd, evdata->info)) {
bd->props.fb_blank = *(int *)evdata->data;
//亮屏情况
if (bd->props.fb_blank == FB_BLANK_UNBLANK)
bd->props.state &= ~BL_CORE_FBBLANK;
//灭屏时
else
bd->props.state |= BL_CORE_FBBLANK;
backlight_update_status(bd);
}
...
}
可以看到最后也是调用backlight_update_status().