目录
一、简介
二、解决方法
A、底层驱动
B、上层调用
C、验证
一、简介
1、需求:这里是用2个gpio口来控制LED灯,开机时默认亮蓝灯,按开机键,休眠亮红灯,唤醒亮蓝灯。
原理图:
这里由于主板上电阻R635未贴,所以led_sleep不启用。
2、分析:
a.一开始是想将这2个gpio口的控制写在背光pwm驱动中,但是该设备是不接屏幕(mipi/edp/lvds)的,直接由cpu输出信号到hdmi屏,所以无法控制背光pwm。
同理,想写在和屏启动相关的驱动里面,也是无法控制的。例如由i2c控制的gm8775c。
b.所以想到在底层驱动写一个文件节点,由上层应用去控制。
二、解决方法
A、底层驱动
这里写了一个c文件,gpio_led.c
/*
* Driver for keys on GPIO lines capable of generating interrupts.
*
* Copyright (C) 2015, Fuzhou Rockchip Electronics Co., Ltd
* Copyright 2005 Phil Blundell
*
* 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/init.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/wakelock.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
struct vanzeak_gpio_drvdata {
struct gpio_desc *power_gpio;
struct gpio_desc *sleep_gpio;
};
static const struct of_device_id vanzeak_gpio_match[] = {
{ .compatible = "vanzeak,gpio", .data = NULL},
{},
};
MODULE_DEVICE_TABLE(of, vanzeak_gpio_match);
static ssize_t led_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
struct vanzeak_gpio_drvdata *ddata = dev_get_drvdata(dev);
int val = val = simple_strtol(buf, NULL, 8);
if(val){
gpiod_direction_output(ddata->power_gpio, 1);
gpiod_direction_output(ddata->sleep_gpio, 0);
}else{
gpiod_direction_output(ddata->power_gpio, 0);
gpiod_direction_output(ddata->sleep_gpio, 1);
}
return size;
}
static ssize_t led_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return 0;
}
static DEVICE_ATTR(led_enable, 0644, led_enable_show, led_enable_store);
static struct attribute *led_enable_attrs[] = {
&dev_attr_led_enable.attr,
NULL,
};
static struct attribute_group led_enable_attr_group = {
.name = "led_enable",
.attrs = led_enable_attrs,
};
static int vanzeak_gpio_probe(struct platform_device *pdev)
{
struct vanzeak_gpio_drvdata *ddata = NULL;
struct device *dev = &pdev->dev;
int ret;
ddata = devm_kzalloc(dev, sizeof(struct vanzeak_gpio_drvdata),
GFP_KERNEL);
// if(ddata = NULL)
// return -1;
platform_set_drvdata(pdev, ddata);
dev_set_drvdata(&pdev->dev, ddata);
ddata->power_gpio = devm_gpiod_get_optional(dev, "enable", 0);
if (IS_ERR(ddata->power_gpio)) {
ret = PTR_ERR(ddata->power_gpio);
dev_err(dev, "failed to request power GPIO: %d\n", ret);
goto fail0;
}
ddata->sleep_gpio = devm_gpiod_get_optional(dev, "sleep", 0);
if (IS_ERR(ddata->sleep_gpio)) {
ret = PTR_ERR(ddata->sleep_gpio);
dev_err(dev, "failed to request sleep GPIO: %d\n", ret);
goto fail0;
}
gpiod_direction_output(ddata->power_gpio, 1);
gpiod_direction_output(ddata->sleep_gpio, 0);
ret = sysfs_create_group(&pdev->dev.kobj, &led_enable_attr_group);
if (ret) {
pr_err("failed to create attr group\n");
}
return 0;
fail0:
platform_set_drvdata(pdev, NULL);
return -1;
}
static int vanzeak_gpio_remove(struct platform_device *pdev)
{
return 0;
}
#ifdef CONFIG_PM
static int vanzeak_gpio_suspend(struct device *dev)
{
struct vanzeak_gpio_drvdata *ddata = dev_get_drvdata(dev);
printk("DICKE printk %s : %d\n", __func__, __LINE__);
gpiod_direction_output(ddata->power_gpio, 0);
return 0;
}
static int vanzeak_gpio_resume(struct device *dev)
{
struct vanzeak_gpio_drvdata *ddata = dev_get_drvdata(dev);
printk("DICKE printk %s : %d\n", __func__, __LINE__);
gpiod_direction_output(ddata->power_gpio, 1);
return 0;
}
static const struct dev_pm_ops vanzeak_gpio_pm_ops = {
.suspend = vanzeak_gpio_suspend,
.resume = vanzeak_gpio_resume,
};
#endif
static struct platform_driver vanzeak_gpio_device_driver = {
.probe = vanzeak_gpio_probe,
.remove = vanzeak_gpio_remove,
.driver = {
.name = "vanzeak-gpio",
.owner = THIS_MODULE,
.of_match_table = vanzeak_gpio_match,
#ifdef CONFIG_PM
.pm = &vanzeak_gpio_pm_ops,
#endif
}
};
static int __init vanzeak_gpio_driver_init(void)
{
return platform_driver_register(&vanzeak_gpio_device_driver);
}
static void __exit vanzeak_gpio_driver_exit(void)
{
platform_driver_unregister(&vanzeak_gpio_device_driver);
}
module_init(vanzeak_gpio_driver_init);
module_exit(vanzeak_gpio_driver_exit);
B、上层调用
由上层的休眠唤醒来控制LED的亮灭。
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index af7d91cf7ba6..1bbc51a9ed91 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -119,6 +119,14 @@ import java.util.Arrays;
import java.util.List;
import java.util.Objects;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.io.BufferedWriter;
+
/**
* The power manager service is responsible for coordinating power management
* functions on the device.
@@ -1598,6 +1606,46 @@ public final class PowerManagerService extends SystemService
}
}
+ private void closeLed(int i){
+ String path = "/sys/devices/platform/vanzeak-gpio/led_enable/led_enable";
+ String value;
+ if(i == 1)
+ value = "1";
+ else if(i == 0)
+ value = "0";
+ else{
+ Slog.e(TAG, "data error");
+ return;
+ }
+ // Log.i(TAG,"setGpioValue, path = [" + path + "] value = [" + value + "]");
+ File file = new File(path);
+ if (!file.exists()) {
+ Slog.i("dxb","initOpenGpio , file is not exist!!!!");
+ return;
+ }
+ FileOutputStream fileOutputStream = null;
+ BufferedWriter bufferedWriter = null;
+ try {
+ fileOutputStream = new FileOutputStream(file);
+ bufferedWriter = new BufferedWriter(new OutputStreamWriter(fileOutputStream, "utf-8"));
+ bufferedWriter.write(value);
+ bufferedWriter.flush();
+ bufferedWriter.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ Slog.i("dxb","input data error " + e.getMessage());
+ } finally {
+ if (bufferedWriter != null) {
+ try {
+ bufferedWriter.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ }
+
private boolean userActivityNoUpdateLocked(long eventTime, int event, int flags, int uid) {
if (DEBUG_SPEW) {
Slog.d(TAG, "userActivityNoUpdateLocked: eventTime=" + eventTime
@@ -1690,6 +1738,8 @@ public final class PowerManagerService extends SystemService
Trace.traceBegin(Trace.TRACE_TAG_POWER, "wakeUp");
try {
+ Slog.i(TAG, "ctrol led to working mode");
+ closeLed(1);
Slog.i(TAG, "Waking up from "
+ PowerManagerInternal.wakefulnessToString(getWakefulnessLocked())
+ " (uid=" + reasonUid
@@ -1748,6 +1798,8 @@ public final class PowerManagerService extends SystemService
try {
reason = Math.min(PowerManager.GO_TO_SLEEP_REASON_MAX,
Math.max(reason, PowerManager.GO_TO_SLEEP_REASON_MIN));
+ Slog.i(TAG, "ctrol led to sleeping mode");
+ closeLed(0);
Slog.i(TAG, "Going to sleep due to " + PowerManager.sleepReasonToString(reason)
+ " (uid " + uid + ")...");
C、验证
按开机键,休眠亮红灯,唤醒亮蓝灯。