kernel添加RTC驱动
kernel5.18 添加 hym8563 的 RTC 驱动:
1. 执行make menuconfig ,选择打开 hym8563 的 RTC 驱动,保存退出;
注意:这里要把PMIC和CPU的RTC拿掉,否则会优先使用PMCI和CPU的RTC,这里用RK平台就把RK805/RK809...RTC 拿掉。
2. 根据你的电路原理图,确认硬件上它连接着哪个 I2C 节点,我这里是 I2C3 ,然后在你的设备树文件上,添加该节点的 RTC 描述;
3. 编译你的 kernel 即可。
注意:如果是低版本的kernel,可能要修改驱动文件,下面以 IMX6 kernel4.1.15为例
kernel4.1.15 添加 RTC hym8563 驱动:
1.硬件电路
2. menuconfig 配置
3. 修改设备树,我这里RTC是挂载在 I2C3 上
vim arch/arm/boot/dts/imx6qdl-sabresd.dtsi
4. 添加 hym8563 的驱动 patch
--- rtc-hym8563_back.c 2023-03-02 11:29:14.461615632 +0800 +++ rtc-hym8563.c 2023-03-02 10:28:35.728248272 +0800 @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Haoyu HYM8563 RTC driver * @@ -6,15 +7,6 @@ * * based on rtc-HYM8563 * Copyright (C) 2010 ROCKCHIP, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/module.h> @@ -86,7 +78,6 @@ struct hym8563 { struct i2c_client *client; struct rtc_device *rtc; - bool valid; #ifdef CONFIG_COMMON_CLK struct clk_hw clkout_hw; #endif @@ -99,16 +90,18 @@ static int hym8563_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct i2c_client *client = to_i2c_client(dev); - struct hym8563 *hym8563 = i2c_get_clientdata(client); u8 buf[7]; int ret; - if (!hym8563->valid) { - dev_warn(&client->dev, "no valid clock/calendar values available\n"); - return -EPERM; - } - ret = i2c_smbus_read_i2c_block_data(client, HYM8563_SEC, 7, buf); + if (ret < 0) + return ret; + + if (buf[0] & HYM8563_SEC_VL) { + dev_warn(&client->dev, + "no valid clock/calendar values available\n"); + return -EINVAL; + } tm->tm_sec = bcd2bin(buf[0] & HYM8563_SEC_MASK); tm->tm_min = bcd2bin(buf[1] & HYM8563_MIN_MASK); @@ -124,7 +117,6 @@ static int hym8563_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct i2c_client *client = to_i2c_client(dev); - struct hym8563 *hym8563 = i2c_get_clientdata(client); u8 buf[7]; int ret; @@ -144,7 +136,7 @@ * it does not seem to carry it over a subsequent write/read. * So we'll limit ourself to 100 years, starting at 2000 for now. */ - buf[6] = tm->tm_year - 100; + buf[6] = bin2bcd(tm->tm_year - 100); /* * CTL1 only contains TEST-mode bits apart from stop, @@ -163,8 +155,6 @@ if (ret < 0) return ret; - hym8563->valid = true; - return 0; } @@ -198,7 +188,7 @@ return ret; /* The alarm only has a minute accuracy */ - alm_tm->tm_sec = -1; + alm_tm->tm_sec = 0; alm_tm->tm_min = (buf[0] & HYM8563_ALM_BIT_DISABLE) ? -1 : @@ -213,9 +203,6 @@ -1 : bcd2bin(buf[3] & HYM8563_WEEKDAY_MASK); - alm_tm->tm_mon = -1; - alm_tm->tm_year = -1; - ret = i2c_smbus_read_byte_data(client, HYM8563_CTL2); if (ret < 0) return ret; @@ -413,7 +400,7 @@ init.name = "hym8563-clkout"; init.ops = &hym8563_clkout_ops; - init.flags = CLK_IS_ROOT; + init.flags = 0; init.parent_names = NULL; init.num_parents = 0; hym8563->clkout_hw.init = &init; @@ -441,10 +428,9 @@ { struct hym8563 *hym8563 = (struct hym8563 *)dev_id; struct i2c_client *client = hym8563->client; - struct mutex *lock = &hym8563->rtc->ops_lock; int data, ret; - mutex_lock(lock); + //rtc_lock(hym8563->rtc); /* Clear the alarm flag */ @@ -464,7 +450,7 @@ } out: - mutex_unlock(lock); + //rtc_unlock(hym8563->rtc); return IRQ_HANDLED; } @@ -540,22 +526,27 @@ hym8563->client = client; i2c_set_clientdata(client, hym8563); - device_set_wakeup_capable(&client->dev, true); - ret = hym8563_init_device(client); if (ret) { dev_err(&client->dev, "could not init device, %d\n", ret); return ret; } - ret = devm_request_threaded_irq(&client->dev, client->irq, - NULL, hym8563_irq, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, - client->name, hym8563); - if (ret < 0) { - dev_err(&client->dev, "irq %d request failed, %d\n", - client->irq, ret); - return ret; + if (client->irq > 0) { + ret = devm_request_threaded_irq(&client->dev, client->irq, + NULL, hym8563_irq, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + client->name, hym8563); + if (ret < 0) { + dev_err(&client->dev, "irq %d request failed, %d\n", + client->irq, ret); + return ret; + } + } + + if (client->irq > 0 || + device_property_read_bool(&client->dev, "wakeup-source")) { + device_init_wakeup(&client->dev, true); } /* check state of calendar information */ @@ -563,9 +554,8 @@ if (ret < 0) return ret; - hym8563->valid = !(ret & HYM8563_SEC_VL); dev_dbg(&client->dev, "rtc information is %s\n", - hym8563->valid ? "valid" : "invalid"); + (ret & HYM8563_SEC_VL) ? "invalid" : "valid"); hym8563->rtc = devm_rtc_device_register(&client->dev, client->name, &hym8563_rtc_ops, THIS_MODULE); @@ -597,7 +587,6 @@ static struct i2c_driver hym8563_driver = { .driver = { .name = "rtc-hym8563", - .owner = THIS_MODULE, .pm = &hym8563_pm_ops, .of_match_table = hym8563_dt_idtable, },
5. 重新编译kernel和设备树即可
本文来自博客园,作者:白菜没我白,转载请注明原文链接:https://www.cnblogs.com/xingboy/p/17148108.html