drivers/rtc/rtc-sd3078.c

Source file repositories/reference/linux-study-clean/drivers/rtc/rtc-sd3078.c

File Facts

System
Linux kernel
Corpus path
drivers/rtc/rtc-sd3078.c
Extension
.c
Size
5582 bytes
Lines
214
Domain
Driver Families
Bucket
drivers/rtc
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
/*
 * Real Time Clock (RTC) Driver for sd3078
 * Copyright (C) 2018 Zoro Li
 */

#include <linux/bcd.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/rtc.h>
#include <linux/slab.h>

#define SD3078_REG_SC			0x00
#define SD3078_REG_MN			0x01
#define SD3078_REG_HR			0x02
#define SD3078_REG_DW			0x03
#define SD3078_REG_DM			0x04
#define SD3078_REG_MO			0x05
#define SD3078_REG_YR			0x06

#define SD3078_REG_CTRL1		0x0f
#define SD3078_REG_CTRL2		0x10
#define SD3078_REG_CTRL3		0x11

#define KEY_WRITE1		0x80
#define KEY_WRITE2		0x04
#define KEY_WRITE3		0x80

#define NUM_TIME_REGS   (SD3078_REG_YR - SD3078_REG_SC + 1)

/*
 * The sd3078 has write protection
 * and we can choose whether or not to use it.
 * Write protection is turned off by default.
 */
#define WRITE_PROTECT_EN	0

/*
 * In order to prevent arbitrary modification of the time register,
 * when modification of the register,
 * the "write" bit needs to be written in a certain order.
 * 1. set WRITE1 bit
 * 2. set WRITE2 bit
 * 3. set WRITE3 bit
 */
static void sd3078_enable_reg_write(struct regmap *regmap)
{
	regmap_update_bits(regmap, SD3078_REG_CTRL2, KEY_WRITE1, KEY_WRITE1);
	regmap_update_bits(regmap, SD3078_REG_CTRL1, KEY_WRITE2, KEY_WRITE2);
	regmap_update_bits(regmap, SD3078_REG_CTRL1, KEY_WRITE3, KEY_WRITE3);
}

#if WRITE_PROTECT_EN
/*
 * In order to prevent arbitrary modification of the time register,
 * we should disable the write function.
 * when disable write,
 * the "write" bit needs to be clear in a certain order.
 * 1. clear WRITE2 bit
 * 2. clear WRITE3 bit
 * 3. clear WRITE1 bit
 */
static void sd3078_disable_reg_write(struct regmap *regmap)
{
	regmap_update_bits(regmap, SD3078_REG_CTRL1, KEY_WRITE2, 0);
	regmap_update_bits(regmap, SD3078_REG_CTRL1, KEY_WRITE3, 0);
	regmap_update_bits(regmap, SD3078_REG_CTRL2, KEY_WRITE1, 0);
}
#endif

static int sd3078_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
	unsigned char hour;
	unsigned char rtc_data[NUM_TIME_REGS] = {0};
	struct i2c_client *client = to_i2c_client(dev);
	struct regmap *regmap = i2c_get_clientdata(client);
	int ret;

	ret = regmap_bulk_read(regmap, SD3078_REG_SC, rtc_data, NUM_TIME_REGS);
	if (ret < 0) {
		dev_err(dev, "reading from RTC failed with err:%d\n", ret);
		return ret;
	}

	tm->tm_sec	= bcd2bin(rtc_data[SD3078_REG_SC] & 0x7F);
	tm->tm_min	= bcd2bin(rtc_data[SD3078_REG_MN] & 0x7F);

	/*
	 * The sd3078 supports 12/24 hour mode.

Annotation

Implementation Notes