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和设备树即可

 

posted @ 2023-02-23 15:17  白菜没我白  阅读(519)  评论(0编辑  收藏  举报