Android Prevent system suspend

To prevent the system from suspending while the screen is off, temporary partial wake_lock can be used.

below command enables partial wake_lock and prevents system suspend:

adb shell "echo temporary > /sys/power/wake_lock"

While in wake_lock, the screen off state does not trigger a system suspend. Below command disables partial wake_lock and enables system suspend again:

adb shell "echo temporary > /sys/power/wake_unlock"
Reference:
Advertisements

git: How to find merge commit which include a specific commit

git-whence tool can help to easily find merge commit which include given commit.

# gem install git-whence
# git-whence 6d37485
Merge pull request #10486 from foo/bar

Reference:

Linux kernel MFD driver resources

In Linux Multi Function Device (MFD) driver example, we created simple MFD core and function devices drivers. This example shows how to pass memory and IRQ resources to MFD child device drivers.

In example below core driver passes one memory and one IRQ reosurces. misc device driver, gets those resources in its platform device data structure and use the same way as those are provided in its own device tree.

Example sources

drivers/mfd/example-core.c:

// SPDX-License-Identifier: GPL-2.0
/*
 * Example MFD core driver
 *
 * Rajan Vaja 
 */
#include 
#include 
#include 

static struct resource example_clk_resources[] = {
	{
		.name = "mem1_base",
		.start = 0x80000000,
		.end   = 0x8FFFFFFF,
		.flags = IORESOURCE_MEM,
	},
	{
		.name = "irq1_base",
		.start = 67,
		.end   = 67,
		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
	},
};

static const struct mfd_cell example_func_devs[] = {
	{
		.name = "example-clk",
		.of_compatible = "test,example-clk",
	},
	{
		.name = "example-misc",
		.of_compatible = "test,example-misc",
		.num_resources = ARRAY_SIZE(example_clk_resources),
		.resources = example_clk_resources,
	},
};

static int example_core_probe(struct platform_device *pdev)
{
	int ret;

	dev_info(&pdev->dev, "#### %s() Adding MFD devices ####\n", __func__);
	ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
				   example_func_devs,
				   ARRAY_SIZE(example_func_devs),
				   NULL, 0, NULL);
	dev_info(&pdev->dev, "#### %s() MFD probed ####\n", __func__);

	return ret;
}

static int example_core_remove(struct platform_device *pdev)
{
	pr_info("#### %s() ####\n", __func__);
	return 0;
}

static const struct of_device_id example_core_of_id_table[] = {
	{ .compatible = "test,example-core" },
	{ }
};
MODULE_DEVICE_TABLE(of, example_core_of_id_table);

static struct platform_driver example_core_driver = {
	.driver = {
		.name           = "example-core-drv",
		.of_match_table = example_core_of_id_table,
	},
	.probe                  = example_core_probe,
	.remove                 = example_core_remove,
};

module_platform_driver(example_core_driver);

MODULE_AUTHOR("Rajan Vaja");
MODULE_DESCRIPTION("Example core platform driver");
MODULE_LICENSE("GPL v2");

drivers/misc/example-misc.c:

// SPDX-License-Identifier: GPL-2.0
/*
 * Example misc function driver
 *
 * Rajan Vaja 
 */
#include 
#include 
#include 

static int example_misc_probe(struct platform_device *pdev)
{
	struct device_node *np = pdev->dev.of_node;
	struct resource *res;
	u32 val;
	int ret;

	dev_info(&pdev->dev, "#### %s() ####\n", __func__);

	ret = of_property_read_u32(np, "example-u32", &val);
	if (ret dev, "%s() sample-u32 property read fail %d\n",
			 __func__, ret);
		return ret;
	}
	dev_info(&pdev->dev, "%s() val = 0x%08x\n", __func__, val);

	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem1_base");
	if (!res) {
		dev_err(&pdev->dev, "%s() get mem1 resource failed\n",
				__func__);
		return ret;
	};
	dev_info(&pdev->dev, "%s() name = %s start = 0x%08llx end = 0x%08llx\n",
		 __func__, res->name, res->start, res->end);

	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq1_base");
	if (!res) {
		dev_err(&pdev->dev, "%s() get irq1 resource failed\n",
				__func__);
		return ret;
	};

	dev_info(&pdev->dev, "%s() name = %s start = 0x%08llx end = 0x%08llx\n",
		 __func__, res->name, res->start, res->end);

	return ret;
}

static int example_misc_remove(struct platform_device *pdev)
{
	pr_info("#### %s() ####\n", __func__);

	return 0;
}

static const struct of_device_id example_misc_of_id_table[] = {
	{ .compatible = "test,example-misc" },
	{ }
};
MODULE_DEVICE_TABLE(of, example_misc_of_id_table);

static struct platform_driver example_misc_driver = {
	.driver = {
		.name           = "example-misc-drv",
		.of_match_table = example_misc_of_id_table,
	},
	.probe                  = example_misc_probe,
	.remove                 = example_misc_remove,
};

module_platform_driver(example_misc_driver);

MODULE_AUTHOR("Rajan Vaja");
MODULE_DESCRIPTION("Example misc function driver");
MODULE_LICENSE("GPL v2");

 

Linux Multi Function Device (MFD) driver example

In Create a simple platform driver, we created simple platform device driver. If there is device which can provide multiple functionalities, its driver may not go in particular subsystems. For an example, lets say there is chip which can also work as codec & sensors, its full driver can neither go in sound/soc/codec or in sensors subsystem. In this case, MFD provides way to register multiple functionalities through MFD core.

For this, MFD provides way to divide functionalities into core and specific function drivers. Generic functionalities(e.g. register access, generic initialisation, common functionalities, etc), can go in mfd while device specific functionalities(e.g. codec specific functionalities) can go in their specific driver.

devm_mfd_add_devices() in core, registers MFD functionalities which populates individual function devices and invokes probe for those drivers.

Functional driver may use parent device data/DT properties if needed. MFD core can pass resources(memory or IRQ) to MFD devices while registering  MFD devices.

Example

e.g. in below example, I have created three separate drivers:

  1. core driver(drivers/mfd/example-core.c) – common code & functional devices registration
  2. drivers/clk/clk-example.c – Clock function driver
  3. drivers/misc/example-misc.c – Some other miscellaneous function driver

Example source files:

drivers/mfd/example-core.c:

// SPDX-License-Identifier: GPL-2.0
/*
 * Example MFD core driver
 *
 * Rajan Vaja <rajan.vaja@gmail.com>
 */
#include <linux/mfd/core.h>
#include <linux/module.h>
#include <linux/platform_device.h>

static const struct mfd_cell example_func_devs[] = {
	{
		.name = "example-clk",
		.of_compatible = "test,example-clk",
	},
	{
		.name = "example-misc",
		.of_compatible = "test,example-misc",
	},
};

static int example_core_probe(struct platform_device *pdev)
{
	int ret;

	dev_info(&pdev->dev, "#### %s() Adding MFD devices ####\n", __func__);
	ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
				   example_func_devs,
				   ARRAY_SIZE(example_func_devs),
				   NULL, 0, NULL);
	dev_info(&pdev->dev, "#### %s() MFD probed ####\n", __func__);

	return ret;
}

static int example_core_remove(struct platform_device *pdev)
{
	pr_info("#### %s() ####\n", __func__);
	return 0;
}

static const struct of_device_id example_core_of_id_table[] = {
	{ .compatible = "test,example-core" },
	{ }
};
MODULE_DEVICE_TABLE(of, example_core_of_id_table);

static struct platform_driver example_core_driver = {
	.driver = {
		.name           = "example-core-drv",
		.of_match_table = example_core_of_id_table,
	},
	.probe                  = example_core_probe,
	.remove                 = example_core_remove,
};

module_platform_driver(example_core_driver);

MODULE_AUTHOR("Rajan Vaja");
MODULE_DESCRIPTION("Example core platform driver");
MODULE_LICENSE("GPL v2");

drivers/clk/clk-example.c

// SPDX-License-Identifier: GPL-2.0
/*
 * Example clock function driver
 *
 * Rajan Vaja <rajan.vaja@gmail.com>
 */
#include <linux/module.h>
#include <linux/platform_device.h>

static int example_clk_probe(struct platform_device *pdev)
{
	dev_info(&pdev->dev, "#### %s() ####\n", __func__);

	return 0;
}

static int example_clk_remove(struct platform_device *pdev)
{
	pr_info("#### %s() ####\n", __func__);

	return 0;
}

static const struct of_device_id example_clk_of_id_table[] = {
	{ .compatible = "test,example-clk" },
	{ }
};
MODULE_DEVICE_TABLE(of, example_clk_of_id_table);

static struct platform_driver example_clk_driver = {
	.driver = {
		.name           = "example-clk-drv",
		.of_match_table = example_clk_of_id_table,
	},
	.probe                  = example_clk_probe,
	.remove                 = example_clk_remove,
};

module_platform_driver(example_clk_driver);

MODULE_AUTHOR("Rajan Vaja");
MODULE_DESCRIPTION("Example clock function driver");
MODULE_LICENSE("GPL v2");

drivers/misc/example-misc.c

// SPDX-License-Identifier: GPL-2.0
/*
 * Example misc function driver
 *
 * Rajan Vaja <rajan.vaja@gmail.com>
 */
#include <linux/module.h>
#include <linux/platform_device.h>

static int example_misc_probe(struct platform_device *pdev)
{
	dev_info(&pdev->dev, "#### %s() ####\n", __func__);

	return 0;
}

static int example_misc_remove(struct platform_device *pdev)
{
	pr_info("#### %s() ####\n", __func__);

	return 0;
}

static const struct of_device_id example_misc_of_id_table[] = {
	{ .compatible = "test,example-misc" },
	{ }
};
MODULE_DEVICE_TABLE(of, example_misc_of_id_table);

static struct platform_driver example_misc_driver = {
	.driver = {
		.name           = "example-misc-drv",
		.of_match_table = example_misc_of_id_table,
	},
	.probe                  = example_misc_probe,
	.remove                 = example_misc_remove,
};

module_platform_driver(example_misc_driver);

MODULE_AUTHOR("Rajan Vaja");
MODULE_DESCRIPTION("Example misc function driver");
MODULE_LICENSE("GPL v2");

 

Mirror external repository on github

If we want to fork repository from any github repository, it is possible through github fork utility. However if we want to get some external repository with all branches, tags and commit history, following steps can be useful:

    1. Create an empty repository on github
      • Go to https://github.com/new
      • Provide repository name, access type
      • Click on “Create repository” button
    2. Clone remote repository (original one on your local system using below command:
      git clone --mirror <git-repo>
      e.g.
      git clone --miror https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/
    3. Go to cloned repository directory and push all refs to your empty repository
      cd <remote-git-directory>
      git push --mirror <your-empty-repo>
      e.g.
      cd linux.git
      git push --mirror https://github.com/rajanvaja/linux/

 

Linux kernel debug print custom identifier

Sometimes it is easier to have our own identifier in print messages to easily filter/grep messages from the dmesg. It is also useful when we want to have some fixed data (e.g. __func__ or __LINE__). This also helps in debugging.

We can format pr_messages by defining pr_fmt macro.

#define pr_fmt(fmt) "<custom-fmt>" fmt, <custom-param-for-custom-fmt>

e.g. you can print kernel module name using below:

    #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

Example

I generally define it like  below format for my debug messages. It prints out “rmv” and function name before any pr_* messages.

#define pr_fmt(fmt) " rmv: %s() %d " fmt, __func__, __LINE__

Below is print statement at line 25 in my_func()

pr_info("Hello World\n");

Its output would like below after timestamp:

rmv: my_func()  25 Hello World

 

 

Create a simple platform driver

This post explains how to create simple platform driver and get its probe called. The driver can be compiled as module or inbuilt in kernel. When driver’s compatible string matches with any device’s compatible string, driver’s probe is called. Creating simple platform driver would help to:

  • Get into Linux kernel world
  • Device tree basic concept

There are things needs to be done for this:

  • Add Kconfig option for driver option in kernel menuconfig
  • Add Makefile entry to build driver file(s)
  • Add driver source file
  • Add device node in DTS with compatible string matching with driver

As our driver doesn’t fall into any category, I have created as misc driver(drivers/misc/simple_misc_drv.c).

Add Kconfig option

Add below lines in drivers/misc/Kconfig:

config SIMPLE_MISC_DRIVER
	tristate "Simple misc driver"
	default n
	help
	  Simple misc platform driver. This driver is designed to demonstrate
	  platform driver and DTS compatible string scenarios.

Add Makefile entry to build driver file(s)

Add below lines in drivers/misc/Makefile:

obj-$(CONFIG_SIMPLE_MISC_DRIVER)	+= simple_misc_drv.o

Add driver source file

#include <linux/module.h>
#include <linux/platform_device.h>

static int simple_misc_probe(struct platform_device *pdev)
{
pr_info("#### %s() ####\n", __func__);
return 0;
}

static int simple_misc_remove(struct platform_device *pdev)
{
pr_info("#### %s() ####\n", __func__);
return 0;
}

static const struct of_device_id simple_misc_of_id_table[] = {
{ .compatible = "test,simple-misc-dev" },
{ }
};
MODULE_DEVICE_TABLE(of, simple_misc_of_id_table);

static struct platform_driver simple_misc_driver = {
.driver = {
.name = "simple-misc-drv",
.of_match_table = simple_misc_of_id_table,
},
.probe = simple_misc_probe,
.remove = simple_misc_remove,
};

module_platform_driver(simple_misc_driver);

MODULE_AUTHOR("Rajan Vaja");
MODULE_DESCRIPTION("Simple misc platform driver");
MODULE_LICENSE("GPL v2");

 

Add device node in DTS

Add below node in device tree.

	simple_misc_device: simple-misc-device {
		compatible = "test,simple-misc-dev";
	};

 

Debugging

What to do if your probe is not called. Here is some checklist which I know:

  1. Driver is not getting compiled
  2. Driver registration is failing. This can be due to:
    1. Driver name duplication with any other driver
  3. Device is not registered due to:
    1. Device node “status” property is set to “disabled” in DTS. If so change it to “okay”.