lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <502BEC1D.5040406@metafoo.de>
Date:	Wed, 15 Aug 2012 20:36:13 +0200
From:	Lars-Peter Clausen <lars@...afoo.de>
To:	Anthony Olech <anthony.olech.opensource@...semi.com>
CC:	Andrew Morton <akpm@...ux-foundation.org>,
	Mark Brown <broonie@...nsource.wolfsonmicro.com>,
	Paul Gortmaker <p_gortmaker@...oo.com>,
	Samuel Ortiz <sameo@...ux.intel.com>,
	Alessandro Zummo <a.zummo@...ertech.it>,
	rtc-linux@...glegroups.com, LKML <linux-kernel@...r.kernel.org>,
	David Dajun Chen <david.chen@...semi.com>
Subject: Re: [NEW DRIVER V3 5/8] DA9058 RTC driver

On 08/15/2012 05:05 PM, Anthony Olech wrote:
> This is the RTC component driver of the Dialog DA9058 PMIC.
> This driver is just one component of the whole DA9058 PMIC driver.
> It depends on the CORE component driver of the DA9058 MFD.

How much is this one actually different from the da9052 rtc core? I just had a
quick glance at them, but they seem rather similar.

> 
> Signed-off-by: Anthony Olech <anthony.olech.opensource@...semi.com>
> Signed-off-by: David Dajun Chen <david.chen@...semi.com>
> ---
>  drivers/rtc/Kconfig      |   10 +
>  drivers/rtc/Makefile     |    1 +
>  drivers/rtc/rtc-da9058.c |  458 ++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 469 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/rtc/rtc-da9058.c
> 
> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> index 08cbdb9..21f5630 100644
> --- a/drivers/rtc/Kconfig
> +++ b/drivers/rtc/Kconfig
> @@ -135,6 +135,16 @@ config RTC_DRV_88PM860X
>  	  This driver can also be built as a module. If so, the module
>  	  will be called rtc-88pm860x.
>  
> +config RTC_DRV_DA9058
> +	tristate "Dialog DA9058"
> +	depends on MFD_DA9058
> +	help
> +	  If you say yes here you will get support for the
> +	  RTC of the Dialog DA9058 PMIC.
> +
> +	  This driver can also be built as a module. If so, the module
> +	  will be called rtc-da9058.
> +
>  config RTC_DRV_DS1307
>  	tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00, EPSON RX-8025"
>  	help
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index 2973921..b772f05 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -29,6 +29,7 @@ obj-$(CONFIG_RTC_DRV_CMOS)	+= rtc-cmos.o
>  obj-$(CONFIG_RTC_DRV_COH901331)	+= rtc-coh901331.o
>  obj-$(CONFIG_RTC_DRV_DA9052)	+= rtc-da9052.o
>  obj-$(CONFIG_RTC_DRV_DAVINCI)	+= rtc-davinci.o
> +obj-$(CONFIG_RTC_DRV_DA9058)	+= rtc-da9058.o
>  obj-$(CONFIG_RTC_DRV_DM355EVM)	+= rtc-dm355evm.o
>  obj-$(CONFIG_RTC_DRV_VRTC)	+= rtc-mrst.o
>  obj-$(CONFIG_RTC_DRV_DS1216)	+= rtc-ds1216.o
> diff --git a/drivers/rtc/rtc-da9058.c b/drivers/rtc/rtc-da9058.c
> new file mode 100644
> index 0000000..1b4e05b
> --- /dev/null
> +++ b/drivers/rtc/rtc-da9058.c
> @@ -0,0 +1,458 @@
> +/*
> + *  Copyright (C) 2012 Dialog Semiconductor Ltd.
> + *
> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation; either version 2 of the License, or
> + *  (at your option) any later version.
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/rtc.h>
> +#include <linux/regmap.h>
> +#include <linux/mfd/core.h>
> +
> +#include <linux/mfd/da9058/version.h>
> +#include <linux/mfd/da9058/registers.h>
> +#include <linux/mfd/da9058/core.h>
> +#include <linux/mfd/da9058/irq.h>
> +#include <linux/mfd/da9058/rtc.h>
> +
> +/*
> + *  Limit values
> + */
> +#define DA9058_RTC_SECONDS_LIMIT		59
> +#define DA9058_RTC_MINUTES_LIMIT		59
> +#define DA9058_RTC_HOURS_LIMIT			23
> +#define DA9058_RTC_DAYS_LIMIT			31
> +#define DA9058_RTC_MONTHS_LIMIT			12
> +#define DA9058_RTC_YEARS_LIMIT			63
> +
> +struct da9058_rtc {
> +	struct da9058 *da9058;
> +	struct platform_device *pdev;
> +	struct rtc_device *rtc_dev;
> +	int alarm_irq;
> +	int tick_irq;
> +	int alarm_enabled;	/* used over suspend/resume */
> +};
> +
> +static int da9058_rtc_check_param(struct rtc_time *rtc_tm)
> +{
> +	if ((rtc_tm->tm_sec > DA9058_RTC_SECONDS_LIMIT) || (rtc_tm->tm_sec < 0))
> +		return -EIO;
> +
> +	if ((rtc_tm->tm_min > DA9058_RTC_MINUTES_LIMIT) || (rtc_tm->tm_min < 0))
> +		return -EIO;
> +
> +	if ((rtc_tm->tm_hour > DA9058_RTC_HOURS_LIMIT) || (rtc_tm->tm_hour < 0))
> +		return -EIO;
> +
> +	if ((rtc_tm->tm_mday > DA9058_RTC_DAYS_LIMIT) || (rtc_tm->tm_mday <= 0))
> +		return -EIO;
> +
> +	if ((rtc_tm->tm_mon > DA9058_RTC_MONTHS_LIMIT) || (rtc_tm->tm_mon <= 0))
> +		return -EIO;
> +
> +	if ((rtc_tm->tm_year > DA9058_RTC_YEARS_LIMIT) || (rtc_tm->tm_year < 0))
> +		return -EIO;
> +
> +	return 0;
> +}
> +
> +static int da9058_rtc_readtime(struct device *dev, struct rtc_time *tm)
> +{
> +	struct da9058_rtc *rtc = dev_get_drvdata(dev);
> +	struct da9058 *da9058 = rtc->da9058;
> +	u8 rtc_time[6];
> +	int ret;
> +
> +	ret = da9058_bulk_read(da9058, DA9058_COUNTS_REG, rtc_time, 6);
> +	if (ret)
> +		return ret;
> +
> +	tm->tm_sec = rtc_time[0] & DA9058_RTC_SECS_MASK;
> +
> +	tm->tm_min = rtc_time[1] & DA9058_RTC_MINS_MASK;
> +
> +	tm->tm_hour = rtc_time[2] & DA9058_RTC_HRS_MASK;
> +
> +	tm->tm_mday = (rtc_time[3] & DA9058_RTC_DAY_MASK);
> +
> +	tm->tm_mon = (rtc_time[4] & DA9058_RTC_MTH_MASK);
> +
> +	tm->tm_year = (rtc_time[5] & DA9058_RTC_YRS_MASK);
> +
> +	ret = da9058_rtc_check_param(tm);
> +
> +	if (ret)
> +		return ret;
> +
> +	tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon,
> +						tm->tm_year);
> +	tm->tm_year += 100;
> +	tm->tm_mon -= 1;
> +
> +	return 0;
> +}
> +
> +static int da9058_rtc_settime(struct device *dev, struct rtc_time *tm)
> +{
> +	struct da9058_rtc *rtc = dev_get_drvdata(dev);
> +	struct da9058 *da9058 = rtc->da9058;
> +	unsigned int rtc_ctrl, val;
> +	u8 rtc_time[6];
> +	int ret;
> +
> +	tm->tm_year -= 100;
> +	tm->tm_mon += 1;
> +
> +	ret = da9058_rtc_check_param(tm);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = da9058_reg_read(da9058, DA9058_COUNTS_REG, &rtc_ctrl);
> +	if (ret)
> +		return ret;
> +	rtc_ctrl &= ~DA9058_RTC_SECS_MASK;
> +
> +	rtc_time[0] = rtc_ctrl | tm->tm_sec;
> +	rtc_time[1] = tm->tm_min;
> +	rtc_time[2] = tm->tm_hour;
> +	rtc_time[3] = tm->tm_mday;
> +	rtc_time[4] = tm->tm_mon;
> +	rtc_time[5] = tm->tm_year;
> +
> +	ret = da9058_bulk_write(da9058, DA9058_COUNTS_REG, rtc_time, 6);
> +	if (ret) {
> +		dev_dbg(dev, "failed %d to write to RTC\n", ret);
> +		return ret;
> +	}
> +	ret = da9058_reg_read(da9058, DA9058_COUNTY_REG, &val);
> +	if (ret)
> +		return ret;
> +
> +	val &= DA9058_COUNTY_MONITOR;
> +	if (val)
> +		return 0;
> +
> +	ret = da9058_set_bits(da9058, DA9058_COUNTY_REG, DA9058_COUNTY_MONITOR);
> +
> +	return ret;
> +}
> +
> +static int da9058_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> +	struct da9058_rtc *rtc = dev_get_drvdata(dev);
> +	struct da9058 *da9058 = rtc->da9058;
> +	struct rtc_time *tm = &alrm->time;
> +	unsigned int val;
> +	u8 alm_time[6];
> +	int ret;
> +
> +	ret = da9058_bulk_read(da9058, DA9058_ALARMS_REG, alm_time, 6);
> +	if (ret)
> +		return ret;
> +
> +	tm->tm_min = alm_time[0] & DA9058_RTC_ALMSECS_MASK;
> +
> +	tm->tm_min = alm_time[1] & DA9058_RTC_ALMMINS_MASK;
> +
> +	tm->tm_hour = alm_time[2] & DA9058_RTC_ALMHRS_MASK;
> +
> +	tm->tm_mday = alm_time[3] & DA9058_RTC_ALMDAY_MASK;
> +
> +	tm->tm_mon = alm_time[4] & DA9058_RTC_ALMMTH_MASK;
> +
> +	tm->tm_year = alm_time[5] & DA9058_RTC_ALMYRS_MASK;
> +
> +	ret = da9058_rtc_check_param(tm);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = da9058_reg_read(da9058, DA9058_ALARMY_REG, &val);
> +	if (ret)
> +		return ret;
> +
> +	alrm->enabled = val & DA9058_ALARMY_ALARMON;
> +
> +	tm->tm_year += 100;
> +	tm->tm_mon -= 1;
> +
> +	return 0;
> +}
> +
> +static int da9058_rtc_stop_alarm(struct da9058_rtc *rtc)
> +{
> +	return da9058_clear_bits(rtc->da9058, DA9058_ALARMY_REG,
> +						DA9058_ALARMY_ALARMON);
> +}
> +
> +static int da9058_rtc_start_alarm(struct da9058_rtc *rtc)
> +{
> +	return da9058_set_bits(rtc->da9058, DA9058_ALARMY_REG,
> +						DA9058_ALARMY_ALARMON);
> +}
> +
> +static int da9058_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> +	struct da9058_rtc *rtc = dev_get_drvdata(dev);
> +	struct da9058 *da9058 = rtc->da9058;
> +	struct rtc_time *tm = &alrm->time;
> +	unsigned int rtc_ctrl;
> +	u8 alm_time[6];
> +	int ret;
> +
> +	tm->tm_year -= 100;
> +	tm->tm_mon += 1;
> +
> +	ret = da9058_rtc_check_param(tm);
> +	if (ret < 0)
> +		return ret;
> +
> +	memset(alm_time, 0, sizeof(alm_time));
> +
> +	if (tm->tm_sec != -1)
> +		alm_time[0] |= tm->tm_sec;
> +	else
> +		alm_time[0] |= DA9058_RTC_ALMSECS_MASK;
> +
> +	ret = da9058_reg_read(da9058, DA9058_ALARMMI_REG, &rtc_ctrl);
> +	if (ret)
> +		return ret;
> +	rtc_ctrl &= ~DA9058_RTC_ALMMINS_MASK;
> +
> +	if (tm->tm_min != -1)
> +		alm_time[1] = rtc_ctrl | tm->tm_min;
> +	else
> +		alm_time[1] = rtc_ctrl | DA9058_RTC_ALMMINS_MASK;
> +
> +	if (tm->tm_hour != -1)
> +		alm_time[2] |= tm->tm_hour;
> +	else
> +		alm_time[2] |= DA9058_RTC_ALMHRS_MASK;
> +
> +	if (tm->tm_mday != -1)
> +		alm_time[3] |= tm->tm_mday;
> +	else
> +		alm_time[3] |= DA9058_RTC_ALMDAY_MASK;
> +
> +	if (tm->tm_mon != -1)
> +		alm_time[4] |= tm->tm_mon;
> +	else
> +		alm_time[4] |= DA9058_RTC_ALMMTH_MASK;
> +
> +	ret = da9058_reg_read(da9058, DA9058_ALARMY_REG, &rtc_ctrl);
> +	if (ret)
> +		return ret;
> +
> +	rtc_ctrl &= ~DA9058_RTC_ALMYRS_MASK;
> +
> +	if (tm->tm_year != -1)
> +		alm_time[5] = rtc_ctrl | tm->tm_year;
> +	else
> +		alm_time[5] = rtc_ctrl | DA9058_RTC_ALMYRS_MASK;
> +
> +	ret = da9058_rtc_stop_alarm(rtc);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = da9058_bulk_write(da9058, DA9058_ALARMS_REG, alm_time, 6);
> +	if (ret)
> +		return ret;
> +
> +	if (alrm->enabled)
> +		ret = da9058_rtc_start_alarm(rtc);
> +
> +	return ret;
> +}
> +
> +static int da9058_rtc_alarm_irq_enable(struct device *dev,
> +						unsigned int enabled)
> +{
> +	struct da9058_rtc *rtc = dev_get_drvdata(dev);
> +
> +	if (enabled)
> +		return da9058_rtc_start_alarm(rtc);
> +	else
> +		return da9058_rtc_stop_alarm(rtc);
> +}
> +
> +static irqreturn_t da9058_rtc_timer_alarm_handler(int irq, void *data)
> +{
> +	struct da9058_rtc *rtc = data;
> +
> +	da9058_rtc_stop_alarm(rtc);
> +	rtc_update_irq(rtc->rtc_dev, 1, RTC_IRQF | RTC_AF);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static irqreturn_t da9058_rtc_tick_alarm_handler(int irq, void *data)
> +{
> +	struct da9058_rtc *rtc = data;
> +
> +	rtc_update_irq(rtc->rtc_dev, 1, RTC_PF | RTC_IRQF);
> +
> +	return IRQ_HANDLED;
> +}
> +static int da9058_rtc_proc(struct device *dev, struct seq_file *seq)
> +{
> +	struct da9058_rtc *rtc = dev_get_drvdata(dev);
> +	struct da9058 *da9058 = rtc->da9058;
> +	unsigned int rtc_ctrl;
> +	int ret;
> +
> +	ret = da9058_reg_read(da9058, DA9058_ALARMY_REG, &rtc_ctrl);
> +
> +	seq_printf(seq, rtc_ctrl & DA9058_ALARMY_ALARMON ?
> +		"ALRM is running\n" : "ALRM is not running\n");
> +
> +	return 0;
> +}
> +
> +static const struct rtc_class_ops da9058_rtc_ops = {
> +	.read_time = da9058_rtc_readtime,
> +	.set_time = da9058_rtc_settime,
> +	.read_alarm = da9058_rtc_readalarm,
> +	.set_alarm = da9058_rtc_setalarm,
> +	.proc = da9058_rtc_proc,
> +	.alarm_irq_enable = da9058_rtc_alarm_irq_enable,
> +};
> +
> +static int da9058_rtc_probe(struct platform_device *pdev)
> +{
> +	struct da9058 *da9058 = dev_get_drvdata(pdev->dev.parent);
> +	const struct mfd_cell *cell = mfd_get_cell(pdev);
> +	struct da9058_rtc_pdata *rtc_pdata;
> +	struct da9058_rtc *rtc;
> +	int ret;
> +
> +	if (cell == NULL) {
> +		ret = -ENODEV;
> +		goto exit;
> +	}
> +
> +	rtc_pdata = cell->platform_data;
> +
> +	if (rtc_pdata == NULL) {
> +		ret = -EINVAL;
> +		goto exit;
> +	}
> +
> +	rtc = devm_kzalloc(&pdev->dev, sizeof(struct da9058_rtc), GFP_KERNEL);
> +	if (!rtc) {
> +		ret = -ENOMEM;
> +		goto exit;
> +	}
> +
> +	platform_set_drvdata(pdev, rtc);
> +
> +	rtc->da9058 = da9058;
> +	rtc->pdev = pdev;
> +	ret = da9058_clear_bits(da9058, DA9058_WAITCONT_REG,
> +						DA9058_WAITCONT_RTCCLOCK);
> +	if (ret) {
> +		dev_err(&pdev->dev, "Failed to set RTC running: %d\n", ret);
> +		goto unable_to_init_device;
> +	}
> +
> +	ret = da9058_set_bits(da9058, DA9058_COUNTY_REG, DA9058_COUNTY_MONITOR);
> +	if (ret) {
> +		dev_err(&pdev->dev, "Failed No gating RTC: %d\n", ret);
> +		goto unable_to_init_device;
> +	}
> +
> +	device_init_wakeup(&pdev->dev, 1);
> +
> +	rtc->rtc_dev = rtc_device_register("da9058", &pdev->dev,
> +						&da9058_rtc_ops, THIS_MODULE);
> +	if (IS_ERR(rtc->rtc_dev)) {
> +		ret = PTR_ERR(rtc->rtc_dev);
> +		dev_err(&pdev->dev, "failed to register RTC: %d\n", ret);
> +		goto unable_to_register_device;
> +	}
> +
> +	rtc->alarm_irq = platform_get_irq(pdev, 0);
> +	if (rtc->alarm_irq < 0) {
> +		dev_err(&pdev->dev, "can not get RTC ALARM IRQ error=%d\n",
> +				rtc->alarm_irq);
> +		ret = -ENODEV;
> +		goto failed_to_get_alarm_irq;
> +	}
> +
> +	ret = request_threaded_irq(da9058_to_virt_irq_num(da9058,
> +							rtc->alarm_irq),
> +				NULL, da9058_rtc_timer_alarm_handler,
> +				IRQF_TRIGGER_RISING | IRQF_ONESHOT,
> +				"DA9058 RTC Timer Alarm", rtc);
> +
> +	if (ret) {
> +		dev_err(&pdev->dev,
> +			"Failed to get rtc timer alarm IRQ %d: %d\n",
> +			rtc->alarm_irq, ret);
> +		goto unable_to_setup_timer_irq;
> +	}
> +
> +	rtc->tick_irq = platform_get_irq(pdev, 1);
> +	if (rtc->tick_irq < 0) {
> +		dev_err(&pdev->dev, "can not get RTC TICK IRQ error=%d\n",
> +				rtc->tick_irq);
> +		ret = -ENODEV;
> +		goto failed_to_get_tick_irq;
> +	}
> +	ret = request_threaded_irq(da9058_to_virt_irq_num(da9058,
> +							rtc->tick_irq),
> +				NULL, da9058_rtc_tick_alarm_handler,
> +				IRQF_TRIGGER_RISING | IRQF_ONESHOT,
> +				"DA9058 RTC Tick Alarm", rtc);
> +	if (ret) {
> +		dev_err(&pdev->dev,
> +			"Failed to get rtc timer alarm IRQ %d: %d\n",
> +			DA9058_IRQ_ETICK, ret);
> +		goto unable_to_setup_alarm_irq;
> +	}
> +	goto exit;
> +
> +failed_to_get_tick_irq:
> +unable_to_setup_alarm_irq:
> +	free_irq(da9058_to_virt_irq_num(da9058, rtc->alarm_irq), rtc);
> +failed_to_get_alarm_irq:
> +unable_to_setup_timer_irq:
> +	rtc_device_unregister(rtc->rtc_dev);
> +unable_to_register_device:
> +unable_to_init_device:
> +	platform_set_drvdata(pdev, NULL);
> +exit:
> +	return ret;
> +}
> +
> +static int __devexit da9058_rtc_remove(struct platform_device *pdev)
> +{
> +	struct da9058_rtc *rtc = platform_get_drvdata(pdev);
> +	struct da9058 *da9058 = rtc->da9058;
> +
> +	free_irq(da9058_to_virt_irq_num(da9058, rtc->alarm_irq), rtc);
> +	free_irq(da9058_to_virt_irq_num(da9058, rtc->tick_irq), rtc);
> +
> +	rtc_device_unregister(rtc->rtc_dev);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver da9058_rtc_driver = {
> +	.probe = da9058_rtc_probe,
> +	.remove = __devexit_p(da9058_rtc_remove),
> +	.driver = {
> +		.name = "da9058-rtc",
> +		.owner = THIS_MODULE,
> +	},
> +};
> +
> +module_platform_driver(da9058_rtc_driver);
> +
> +MODULE_DESCRIPTION("Dialog DA9058 PMIC Real Time Clock Driver");
> +MODULE_AUTHOR("Anthony Olech <Anthony.Olech@...semi.com>");
> +MODULE_LICENSE("GPL v2");
> +MODULE_ALIAS("platform:da9058-rtc");

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ