drivers/mfd/ntxec.c

Source file repositories/reference/linux-study-clean/drivers/mfd/ntxec.c

File Facts

System
Linux kernel
Corpus path
drivers/mfd/ntxec.c
Extension
.c
Size
6820 bytes
Lines
271
Domain
Driver Families
Bucket
drivers/mfd
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * The Netronix embedded controller is a microcontroller found in some
 * e-book readers designed by the original design manufacturer Netronix, Inc.
 * It contains RTC, battery monitoring, system power management, and PWM
 * functionality.
 *
 * This driver implements register access, version detection, and system
 * power-off/reset.
 *
 * Copyright 2020 Jonathan Neuschäfer <j.neuschaefer@gmx.net>
 */

#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/i2c.h>
#include <linux/mfd/core.h>
#include <linux/mfd/ntxec.h>
#include <linux/module.h>
#include <linux/pm.h>
#include <linux/reboot.h>
#include <linux/regmap.h>
#include <linux/types.h>
#include <linux/unaligned.h>

#define NTXEC_REG_VERSION	0x00
#define NTXEC_REG_POWEROFF	0x50
#define NTXEC_REG_POWERKEEP	0x70
#define NTXEC_REG_RESET		0x90

#define NTXEC_POWEROFF_VALUE	0x0100
#define NTXEC_POWERKEEP_VALUE	0x0800
#define NTXEC_RESET_VALUE	0xff00

static struct i2c_client *poweroff_restart_client;

static void ntxec_poweroff(void)
{
	int res;
	u8 buf[3] = { NTXEC_REG_POWEROFF };
	struct i2c_msg msgs[] = {
		{
			.addr = poweroff_restart_client->addr,
			.flags = 0,
			.len = sizeof(buf),
			.buf = buf,
		},
	};

	put_unaligned_be16(NTXEC_POWEROFF_VALUE, buf + 1);

	res = i2c_transfer(poweroff_restart_client->adapter, msgs, ARRAY_SIZE(msgs));
	if (res < 0)
		dev_warn(&poweroff_restart_client->dev,
			 "Failed to power off (err = %d)\n", res);

	/*
	 * The time from the register write until the host CPU is powered off
	 * has been observed to be about 2.5 to 3 seconds. Sleep long enough to
	 * safely avoid returning from the poweroff handler.
	 */
	msleep(5000);
}

static int ntxec_restart(struct notifier_block *nb,
			 unsigned long action, void *data)
{
	int res;
	u8 buf[3] = { NTXEC_REG_RESET };
	/*
	 * NOTE: The lower half of the reset value is not sent, because sending
	 * it causes an I2C error. (The reset handler in the downstream driver
	 * does send the full two-byte value, but doesn't check the result).
	 */
	struct i2c_msg msgs[] = {
		{
			.addr = poweroff_restart_client->addr,
			.flags = 0,
			.len = sizeof(buf) - 1,
			.buf = buf,
		},
	};

	put_unaligned_be16(NTXEC_RESET_VALUE, buf + 1);

	res = i2c_transfer(poweroff_restart_client->adapter, msgs, ARRAY_SIZE(msgs));
	if (res < 0)
		dev_warn(&poweroff_restart_client->dev,
			 "Failed to restart (err = %d)\n", res);

Annotation

Implementation Notes