Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/drivers/rtc/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 5 kB image not shown  

Quelle  rtc-ftrtc010.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 *  Faraday Technology FTRTC010 driver
 *
 *  Copyright (C) 2009 Janos Laube <janos.dev@gmail.com>
 *
 * Original code for older kernel 2.6.15 are from Stormlinksemi
 * first update from Janos Laube for > 2.6.29 kernels
 *
 * checkpatch fixes and usage of rtc-lib code
 * Hans Ulli Kroll <ulli.kroll@googlemail.com>
 */


#include <linux/rtc.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/clk.h>

#define DRV_NAME        "rtc-ftrtc010"

MODULE_AUTHOR("Hans Ulli Kroll ");
MODULE_DESCRIPTION("RTC driver for Gemini SoC");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:" DRV_NAME);

struct ftrtc010_rtc {
 void __iomem  *rtc_base;
 int   rtc_irq;
 struct clk  *pclk;
 struct clk  *extclk;
};

enum ftrtc010_rtc_offsets {
 FTRTC010_RTC_SECOND  = 0x00,
 FTRTC010_RTC_MINUTE  = 0x04,
 FTRTC010_RTC_HOUR  = 0x08,
 FTRTC010_RTC_DAYS  = 0x0C,
 FTRTC010_RTC_ALARM_SECOND = 0x10,
 FTRTC010_RTC_ALARM_MINUTE = 0x14,
 FTRTC010_RTC_ALARM_HOUR  = 0x18,
 FTRTC010_RTC_RECORD  = 0x1C,
 FTRTC010_RTC_CR   = 0x20,
};

static irqreturn_t ftrtc010_rtc_interrupt(int irq, void *dev)
{
 return IRQ_HANDLED;
}

/*
 * Looks like the RTC in the Gemini SoC is (totaly) broken
 * We can't read/write directly the time from RTC registers.
 * We must do some "offset" calculation to get the real time
 *
 * This FIX works pretty fine and Stormlinksemi aka Cortina-Networks does
 * the same thing, without the rtc-lib.c calls.
 */


static int ftrtc010_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
 struct ftrtc010_rtc *rtc = dev_get_drvdata(dev);

 u32 days, hour, min, sec, offset;
 timeu64_t time;

 sec  = readl(rtc->rtc_base + FTRTC010_RTC_SECOND);
 min  = readl(rtc->rtc_base + FTRTC010_RTC_MINUTE);
 hour = readl(rtc->rtc_base + FTRTC010_RTC_HOUR);
 days = readl(rtc->rtc_base + FTRTC010_RTC_DAYS);
 offset = readl(rtc->rtc_base + FTRTC010_RTC_RECORD);

 time = offset + days * 86400 + hour * 3600 + min * 60 + sec;

 rtc_time64_to_tm(time, tm);

 return 0;
}

static int ftrtc010_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
 struct ftrtc010_rtc *rtc = dev_get_drvdata(dev);
 u32 sec, min, hour, day, offset;
 timeu64_t time;

 time = rtc_tm_to_time64(tm);

 sec = readl(rtc->rtc_base + FTRTC010_RTC_SECOND);
 min = readl(rtc->rtc_base + FTRTC010_RTC_MINUTE);
 hour = readl(rtc->rtc_base + FTRTC010_RTC_HOUR);
 day = readl(rtc->rtc_base + FTRTC010_RTC_DAYS);

 offset = time - (day * 86400 + hour * 3600 + min * 60 + sec);

 writel(offset, rtc->rtc_base + FTRTC010_RTC_RECORD);
 writel(0x01, rtc->rtc_base + FTRTC010_RTC_CR);

 return 0;
}

static const struct rtc_class_ops ftrtc010_rtc_ops = {
 .read_time     = ftrtc010_rtc_read_time,
 .set_time      = ftrtc010_rtc_set_time,
};

static int ftrtc010_rtc_probe(struct platform_device *pdev)
{
 u32 days, hour, min, sec;
 struct ftrtc010_rtc *rtc;
 struct device *dev = &pdev->dev;
 struct resource *res;
 struct rtc_device *rtc_dev;
 int ret;

 rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
 if (unlikely(!rtc))
  return -ENOMEM;
 platform_set_drvdata(pdev, rtc);

 rtc->pclk = devm_clk_get(dev, "PCLK");
 if (IS_ERR(rtc->pclk)) {
  dev_err(dev, "could not get PCLK\n");
 } else {
  ret = clk_prepare_enable(rtc->pclk);
  if (ret) {
   dev_err(dev, "failed to enable PCLK\n");
   return ret;
  }
 }
 rtc->extclk = devm_clk_get(dev, "EXTCLK");
 if (IS_ERR(rtc->extclk)) {
  dev_err(dev, "could not get EXTCLK\n");
 } else {
  ret = clk_prepare_enable(rtc->extclk);
  if (ret) {
   dev_err(dev, "failed to enable EXTCLK\n");
   goto err_disable_pclk;
  }
 }

 rtc->rtc_irq = platform_get_irq(pdev, 0);
 if (rtc->rtc_irq < 0) {
  ret = rtc->rtc_irq;
  goto err_disable_extclk;
 }

 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 if (!res) {
  ret = -ENODEV;
  goto err_disable_extclk;
 }

 rtc->rtc_base = devm_ioremap(dev, res->start,
         resource_size(res));
 if (!rtc->rtc_base) {
  ret = -ENOMEM;
  goto err_disable_extclk;
 }

 rtc_dev = devm_rtc_allocate_device(dev);
 if (IS_ERR(rtc_dev)) {
  ret = PTR_ERR(rtc_dev);
  goto err_disable_extclk;
 }

 rtc_dev->ops = &ftrtc010_rtc_ops;

 sec  = readl(rtc->rtc_base + FTRTC010_RTC_SECOND);
 min  = readl(rtc->rtc_base + FTRTC010_RTC_MINUTE);
 hour = readl(rtc->rtc_base + FTRTC010_RTC_HOUR);
 days = readl(rtc->rtc_base + FTRTC010_RTC_DAYS);

 rtc_dev->range_min = (u64)days * 86400 + hour * 3600 + min * 60 + sec;
 rtc_dev->range_max = U32_MAX + rtc_dev->range_min;

 ret = devm_request_irq(dev, rtc->rtc_irq, ftrtc010_rtc_interrupt,
          IRQF_SHARED, pdev->name, dev);
 if (unlikely(ret))
  goto err_disable_extclk;

 return devm_rtc_register_device(rtc_dev);

err_disable_extclk:
 clk_disable_unprepare(rtc->extclk);
err_disable_pclk:
 clk_disable_unprepare(rtc->pclk);
 return ret;
}

static void ftrtc010_rtc_remove(struct platform_device *pdev)
{
 struct ftrtc010_rtc *rtc = platform_get_drvdata(pdev);

 if (!IS_ERR(rtc->extclk))
  clk_disable_unprepare(rtc->extclk);
 if (!IS_ERR(rtc->pclk))
  clk_disable_unprepare(rtc->pclk);
}

static const struct of_device_id ftrtc010_rtc_dt_match[] = {
 { .compatible = "cortina,gemini-rtc" },
 { .compatible = "faraday,ftrtc010" },
 { }
};
MODULE_DEVICE_TABLE(of, ftrtc010_rtc_dt_match);

static struct platform_driver ftrtc010_rtc_driver = {
 .driver  = {
  .name = DRV_NAME,
  .of_match_table = ftrtc010_rtc_dt_match,
 },
 .probe  = ftrtc010_rtc_probe,
 .remove  = ftrtc010_rtc_remove,
};

module_platform_driver_probe(ftrtc010_rtc_driver, ftrtc010_rtc_probe);

Messung V0.5
C=99 H=83 G=91

¤ Dauer der Verarbeitung: 0.9 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.