Linux Audio

Check our new training course

Loading...
v6.8
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * Copyright (C) 2016 Oleksij Rempel <linux@rempel-privat.de>
  4 */
  5
  6#include <linux/clk.h>
  7#include <linux/interrupt.h>
  8#include <linux/io.h>
  9#include <linux/module.h>
 10#include <linux/of.h>
 11#include <linux/platform_device.h>
 12#include <linux/rtc.h>
 13
 14/* Miscellaneous registers */
 15/* Interrupt Location Register */
 16#define HW_ILR			0x00
 17#define BM_RTCALF		BIT(1)
 18#define BM_RTCCIF		BIT(0)
 19
 20/* Clock Control Register */
 21#define HW_CCR			0x08
 22/* Calibration counter disable */
 23#define BM_CCALOFF		BIT(4)
 24/* Reset internal oscillator divider */
 25#define BM_CTCRST		BIT(1)
 26/* Clock Enable */
 27#define BM_CLKEN		BIT(0)
 28
 29/* Counter Increment Interrupt Register */
 30#define HW_CIIR			0x0C
 31#define BM_CIIR_IMYEAR		BIT(7)
 32#define BM_CIIR_IMMON		BIT(6)
 33#define BM_CIIR_IMDOY		BIT(5)
 34#define BM_CIIR_IMDOW		BIT(4)
 35#define BM_CIIR_IMDOM		BIT(3)
 36#define BM_CIIR_IMHOUR		BIT(2)
 37#define BM_CIIR_IMMIN		BIT(1)
 38#define BM_CIIR_IMSEC		BIT(0)
 39
 40/* Alarm Mask Register */
 41#define HW_AMR			0x10
 42#define BM_AMR_IMYEAR		BIT(7)
 43#define BM_AMR_IMMON		BIT(6)
 44#define BM_AMR_IMDOY		BIT(5)
 45#define BM_AMR_IMDOW		BIT(4)
 46#define BM_AMR_IMDOM		BIT(3)
 47#define BM_AMR_IMHOUR		BIT(2)
 48#define BM_AMR_IMMIN		BIT(1)
 49#define BM_AMR_IMSEC		BIT(0)
 50#define BM_AMR_OFF		0xff
 51
 52/* Consolidated time registers */
 53#define HW_CTIME0		0x14
 54#define BM_CTIME0_DOW_S		24
 55#define BM_CTIME0_DOW_M		0x7
 56#define BM_CTIME0_HOUR_S	16
 57#define BM_CTIME0_HOUR_M	0x1f
 58#define BM_CTIME0_MIN_S		8
 59#define BM_CTIME0_MIN_M		0x3f
 60#define BM_CTIME0_SEC_S		0
 61#define BM_CTIME0_SEC_M		0x3f
 62
 63#define HW_CTIME1		0x18
 64#define BM_CTIME1_YEAR_S	16
 65#define BM_CTIME1_YEAR_M	0xfff
 66#define BM_CTIME1_MON_S		8
 67#define BM_CTIME1_MON_M		0xf
 68#define BM_CTIME1_DOM_S		0
 69#define BM_CTIME1_DOM_M		0x1f
 70
 71#define HW_CTIME2		0x1C
 72#define BM_CTIME2_DOY_S		0
 73#define BM_CTIME2_DOY_M		0xfff
 74
 75/* Time counter registers */
 76#define HW_SEC			0x20
 77#define HW_MIN			0x24
 78#define HW_HOUR			0x28
 79#define HW_DOM			0x2C
 80#define HW_DOW			0x30
 81#define HW_DOY			0x34
 82#define HW_MONTH		0x38
 83#define HW_YEAR			0x3C
 84
 85#define HW_CALIBRATION		0x40
 86#define BM_CALDIR_BACK		BIT(17)
 87#define BM_CALVAL_M		0x1ffff
 88
 89/* General purpose registers */
 90#define HW_GPREG0		0x44
 91#define HW_GPREG1		0x48
 92#define HW_GPREG2		0x4C
 93#define HW_GPREG3		0x50
 94#define HW_GPREG4		0x54
 95
 96/* Alarm register group */
 97#define HW_ALSEC		0x60
 98#define HW_ALMIN		0x64
 99#define HW_ALHOUR		0x68
100#define HW_ALDOM		0x6C
101#define HW_ALDOW		0x70
102#define HW_ALDOY		0x74
103#define HW_ALMON		0x78
104#define HW_ALYEAR		0x7C
105
106struct asm9260_rtc_priv {
107	struct device		*dev;
108	void __iomem		*iobase;
109	struct rtc_device	*rtc;
110	struct clk		*clk;
111};
112
113static irqreturn_t asm9260_rtc_irq(int irq, void *dev_id)
114{
115	struct asm9260_rtc_priv *priv = dev_id;
116	u32 isr;
117	unsigned long events = 0;
118
119	rtc_lock(priv->rtc);
120	isr = ioread32(priv->iobase + HW_CIIR);
121	if (!isr) {
122		rtc_unlock(priv->rtc);
123		return IRQ_NONE;
124	}
125
126	iowrite32(0, priv->iobase + HW_CIIR);
127	rtc_unlock(priv->rtc);
128
129	events |= RTC_AF | RTC_IRQF;
130
131	rtc_update_irq(priv->rtc, 1, events);
132
133	return IRQ_HANDLED;
134}
135
136static int asm9260_rtc_read_time(struct device *dev, struct rtc_time *tm)
137{
138	struct asm9260_rtc_priv *priv = dev_get_drvdata(dev);
139	u32 ctime0, ctime1, ctime2;
140
141	ctime0 = ioread32(priv->iobase + HW_CTIME0);
142	ctime1 = ioread32(priv->iobase + HW_CTIME1);
143	ctime2 = ioread32(priv->iobase + HW_CTIME2);
144
145	if (ctime1 != ioread32(priv->iobase + HW_CTIME1)) {
146		/*
147		 * woops, counter flipped right now. Now we are safe
148		 * to reread.
149		 */
150		ctime0 = ioread32(priv->iobase + HW_CTIME0);
151		ctime1 = ioread32(priv->iobase + HW_CTIME1);
152		ctime2 = ioread32(priv->iobase + HW_CTIME2);
153	}
154
155	tm->tm_sec  = (ctime0 >> BM_CTIME0_SEC_S)  & BM_CTIME0_SEC_M;
156	tm->tm_min  = (ctime0 >> BM_CTIME0_MIN_S)  & BM_CTIME0_MIN_M;
157	tm->tm_hour = (ctime0 >> BM_CTIME0_HOUR_S) & BM_CTIME0_HOUR_M;
158	tm->tm_wday = (ctime0 >> BM_CTIME0_DOW_S)  & BM_CTIME0_DOW_M;
159
160	tm->tm_mday = (ctime1 >> BM_CTIME1_DOM_S)  & BM_CTIME1_DOM_M;
161	tm->tm_mon  = (ctime1 >> BM_CTIME1_MON_S)  & BM_CTIME1_MON_M;
162	tm->tm_year = (ctime1 >> BM_CTIME1_YEAR_S) & BM_CTIME1_YEAR_M;
163
164	tm->tm_yday = (ctime2 >> BM_CTIME2_DOY_S)  & BM_CTIME2_DOY_M;
165
166	return 0;
167}
168
169static int asm9260_rtc_set_time(struct device *dev, struct rtc_time *tm)
170{
171	struct asm9260_rtc_priv *priv = dev_get_drvdata(dev);
172
173	/*
174	 * make sure SEC counter will not flip other counter on write time,
175	 * real value will be written at the enf of sequence.
176	 */
177	iowrite32(0, priv->iobase + HW_SEC);
178
179	iowrite32(tm->tm_year, priv->iobase + HW_YEAR);
180	iowrite32(tm->tm_mon,  priv->iobase + HW_MONTH);
181	iowrite32(tm->tm_mday, priv->iobase + HW_DOM);
182	iowrite32(tm->tm_wday, priv->iobase + HW_DOW);
183	iowrite32(tm->tm_yday, priv->iobase + HW_DOY);
184	iowrite32(tm->tm_hour, priv->iobase + HW_HOUR);
185	iowrite32(tm->tm_min,  priv->iobase + HW_MIN);
186	iowrite32(tm->tm_sec,  priv->iobase + HW_SEC);
187
188	return 0;
189}
190
191static int asm9260_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
192{
193	struct asm9260_rtc_priv *priv = dev_get_drvdata(dev);
194
195	alrm->time.tm_year = ioread32(priv->iobase + HW_ALYEAR);
196	alrm->time.tm_mon  = ioread32(priv->iobase + HW_ALMON);
197	alrm->time.tm_mday = ioread32(priv->iobase + HW_ALDOM);
198	alrm->time.tm_wday = ioread32(priv->iobase + HW_ALDOW);
199	alrm->time.tm_yday = ioread32(priv->iobase + HW_ALDOY);
200	alrm->time.tm_hour = ioread32(priv->iobase + HW_ALHOUR);
201	alrm->time.tm_min  = ioread32(priv->iobase + HW_ALMIN);
202	alrm->time.tm_sec  = ioread32(priv->iobase + HW_ALSEC);
203
204	alrm->enabled = ioread32(priv->iobase + HW_AMR) ? 1 : 0;
205	alrm->pending = ioread32(priv->iobase + HW_CIIR) ? 1 : 0;
206
207	return rtc_valid_tm(&alrm->time);
208}
209
210static int asm9260_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
211{
212	struct asm9260_rtc_priv *priv = dev_get_drvdata(dev);
213
214	iowrite32(alrm->time.tm_year, priv->iobase + HW_ALYEAR);
215	iowrite32(alrm->time.tm_mon,  priv->iobase + HW_ALMON);
216	iowrite32(alrm->time.tm_mday, priv->iobase + HW_ALDOM);
217	iowrite32(alrm->time.tm_wday, priv->iobase + HW_ALDOW);
218	iowrite32(alrm->time.tm_yday, priv->iobase + HW_ALDOY);
219	iowrite32(alrm->time.tm_hour, priv->iobase + HW_ALHOUR);
220	iowrite32(alrm->time.tm_min,  priv->iobase + HW_ALMIN);
221	iowrite32(alrm->time.tm_sec,  priv->iobase + HW_ALSEC);
222
223	iowrite32(alrm->enabled ? 0 : BM_AMR_OFF, priv->iobase + HW_AMR);
224
225	return 0;
226}
227
228static int asm9260_alarm_irq_enable(struct device *dev, unsigned int enabled)
229{
230	struct asm9260_rtc_priv *priv = dev_get_drvdata(dev);
231
232	iowrite32(enabled ? 0 : BM_AMR_OFF, priv->iobase + HW_AMR);
233	return 0;
234}
235
236static const struct rtc_class_ops asm9260_rtc_ops = {
237	.read_time		= asm9260_rtc_read_time,
238	.set_time		= asm9260_rtc_set_time,
239	.read_alarm		= asm9260_rtc_read_alarm,
240	.set_alarm		= asm9260_rtc_set_alarm,
241	.alarm_irq_enable	= asm9260_alarm_irq_enable,
242};
243
244static int asm9260_rtc_probe(struct platform_device *pdev)
245{
246	struct asm9260_rtc_priv *priv;
247	struct device *dev = &pdev->dev;
248	int irq_alarm, ret;
249	u32 ccr;
250
251	priv = devm_kzalloc(dev, sizeof(struct asm9260_rtc_priv), GFP_KERNEL);
252	if (!priv)
253		return -ENOMEM;
254
255	priv->dev = &pdev->dev;
256	platform_set_drvdata(pdev, priv);
257
258	irq_alarm = platform_get_irq(pdev, 0);
259	if (irq_alarm < 0)
260		return irq_alarm;
261
262	priv->iobase = devm_platform_ioremap_resource(pdev, 0);
263	if (IS_ERR(priv->iobase))
264		return PTR_ERR(priv->iobase);
265
266	priv->clk = devm_clk_get(dev, "ahb");
267	if (IS_ERR(priv->clk))
268		return PTR_ERR(priv->clk);
269
270	ret = clk_prepare_enable(priv->clk);
271	if (ret) {
272		dev_err(dev, "Failed to enable clk!\n");
273		return ret;
274	}
275
276	ccr = ioread32(priv->iobase + HW_CCR);
277	/* if dev is not enabled, reset it */
278	if ((ccr & (BM_CLKEN | BM_CTCRST)) != BM_CLKEN) {
279		iowrite32(BM_CTCRST, priv->iobase + HW_CCR);
280		ccr = 0;
281	}
282
283	iowrite32(BM_CLKEN | ccr, priv->iobase + HW_CCR);
284	iowrite32(0, priv->iobase + HW_CIIR);
285	iowrite32(BM_AMR_OFF, priv->iobase + HW_AMR);
286
287	priv->rtc = devm_rtc_device_register(dev, dev_name(dev),
288					     &asm9260_rtc_ops, THIS_MODULE);
289	if (IS_ERR(priv->rtc)) {
290		ret = PTR_ERR(priv->rtc);
291		dev_err(dev, "Failed to register RTC device: %d\n", ret);
292		goto err_return;
293	}
294
295	ret = devm_request_threaded_irq(dev, irq_alarm, NULL,
296					asm9260_rtc_irq, IRQF_ONESHOT,
297					dev_name(dev), priv);
298	if (ret < 0) {
299		dev_err(dev, "can't get irq %i, err %d\n",
300			irq_alarm, ret);
301		goto err_return;
302	}
303
304	return 0;
305
306err_return:
307	clk_disable_unprepare(priv->clk);
308	return ret;
309}
310
311static void asm9260_rtc_remove(struct platform_device *pdev)
312{
313	struct asm9260_rtc_priv *priv = platform_get_drvdata(pdev);
314
315	/* Disable alarm matching */
316	iowrite32(BM_AMR_OFF, priv->iobase + HW_AMR);
317	clk_disable_unprepare(priv->clk);
 
318}
319
320static const struct of_device_id asm9260_dt_ids[] = {
321	{ .compatible = "alphascale,asm9260-rtc", },
322	{}
323};
324MODULE_DEVICE_TABLE(of, asm9260_dt_ids);
325
326static struct platform_driver asm9260_rtc_driver = {
327	.probe		= asm9260_rtc_probe,
328	.remove_new	= asm9260_rtc_remove,
329	.driver		= {
330		.name	= "asm9260-rtc",
331		.of_match_table = asm9260_dt_ids,
332	},
333};
334
335module_platform_driver(asm9260_rtc_driver);
336
337MODULE_AUTHOR("Oleksij Rempel <linux@rempel-privat.de>");
338MODULE_DESCRIPTION("Alphascale asm9260 SoC Realtime Clock Driver (RTC)");
339MODULE_LICENSE("GPL");
v5.9
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * Copyright (C) 2016 Oleksij Rempel <linux@rempel-privat.de>
  4 */
  5
  6#include <linux/clk.h>
  7#include <linux/interrupt.h>
  8#include <linux/io.h>
  9#include <linux/module.h>
 10#include <linux/of.h>
 11#include <linux/platform_device.h>
 12#include <linux/rtc.h>
 13
 14/* Miscellaneous registers */
 15/* Interrupt Location Register */
 16#define HW_ILR			0x00
 17#define BM_RTCALF		BIT(1)
 18#define BM_RTCCIF		BIT(0)
 19
 20/* Clock Control Register */
 21#define HW_CCR			0x08
 22/* Calibration counter disable */
 23#define BM_CCALOFF		BIT(4)
 24/* Reset internal oscillator divider */
 25#define BM_CTCRST		BIT(1)
 26/* Clock Enable */
 27#define BM_CLKEN		BIT(0)
 28
 29/* Counter Increment Interrupt Register */
 30#define HW_CIIR			0x0C
 31#define BM_CIIR_IMYEAR		BIT(7)
 32#define BM_CIIR_IMMON		BIT(6)
 33#define BM_CIIR_IMDOY		BIT(5)
 34#define BM_CIIR_IMDOW		BIT(4)
 35#define BM_CIIR_IMDOM		BIT(3)
 36#define BM_CIIR_IMHOUR		BIT(2)
 37#define BM_CIIR_IMMIN		BIT(1)
 38#define BM_CIIR_IMSEC		BIT(0)
 39
 40/* Alarm Mask Register */
 41#define HW_AMR			0x10
 42#define BM_AMR_IMYEAR		BIT(7)
 43#define BM_AMR_IMMON		BIT(6)
 44#define BM_AMR_IMDOY		BIT(5)
 45#define BM_AMR_IMDOW		BIT(4)
 46#define BM_AMR_IMDOM		BIT(3)
 47#define BM_AMR_IMHOUR		BIT(2)
 48#define BM_AMR_IMMIN		BIT(1)
 49#define BM_AMR_IMSEC		BIT(0)
 50#define BM_AMR_OFF		0xff
 51
 52/* Consolidated time registers */
 53#define HW_CTIME0		0x14
 54#define BM_CTIME0_DOW_S		24
 55#define BM_CTIME0_DOW_M		0x7
 56#define BM_CTIME0_HOUR_S	16
 57#define BM_CTIME0_HOUR_M	0x1f
 58#define BM_CTIME0_MIN_S		8
 59#define BM_CTIME0_MIN_M		0x3f
 60#define BM_CTIME0_SEC_S		0
 61#define BM_CTIME0_SEC_M		0x3f
 62
 63#define HW_CTIME1		0x18
 64#define BM_CTIME1_YEAR_S	16
 65#define BM_CTIME1_YEAR_M	0xfff
 66#define BM_CTIME1_MON_S		8
 67#define BM_CTIME1_MON_M		0xf
 68#define BM_CTIME1_DOM_S		0
 69#define BM_CTIME1_DOM_M		0x1f
 70
 71#define HW_CTIME2		0x1C
 72#define BM_CTIME2_DOY_S		0
 73#define BM_CTIME2_DOY_M		0xfff
 74
 75/* Time counter registers */
 76#define HW_SEC			0x20
 77#define HW_MIN			0x24
 78#define HW_HOUR			0x28
 79#define HW_DOM			0x2C
 80#define HW_DOW			0x30
 81#define HW_DOY			0x34
 82#define HW_MONTH		0x38
 83#define HW_YEAR			0x3C
 84
 85#define HW_CALIBRATION		0x40
 86#define BM_CALDIR_BACK		BIT(17)
 87#define BM_CALVAL_M		0x1ffff
 88
 89/* General purpose registers */
 90#define HW_GPREG0		0x44
 91#define HW_GPREG1		0x48
 92#define HW_GPREG2		0x4C
 93#define HW_GPREG3		0x50
 94#define HW_GPREG4		0x54
 95
 96/* Alarm register group */
 97#define HW_ALSEC		0x60
 98#define HW_ALMIN		0x64
 99#define HW_ALHOUR		0x68
100#define HW_ALDOM		0x6C
101#define HW_ALDOW		0x70
102#define HW_ALDOY		0x74
103#define HW_ALMON		0x78
104#define HW_ALYEAR		0x7C
105
106struct asm9260_rtc_priv {
107	struct device		*dev;
108	void __iomem		*iobase;
109	struct rtc_device	*rtc;
110	struct clk		*clk;
111};
112
113static irqreturn_t asm9260_rtc_irq(int irq, void *dev_id)
114{
115	struct asm9260_rtc_priv *priv = dev_id;
116	u32 isr;
117	unsigned long events = 0;
118
119	mutex_lock(&priv->rtc->ops_lock);
120	isr = ioread32(priv->iobase + HW_CIIR);
121	if (!isr) {
122		mutex_unlock(&priv->rtc->ops_lock);
123		return IRQ_NONE;
124	}
125
126	iowrite32(0, priv->iobase + HW_CIIR);
127	mutex_unlock(&priv->rtc->ops_lock);
128
129	events |= RTC_AF | RTC_IRQF;
130
131	rtc_update_irq(priv->rtc, 1, events);
132
133	return IRQ_HANDLED;
134}
135
136static int asm9260_rtc_read_time(struct device *dev, struct rtc_time *tm)
137{
138	struct asm9260_rtc_priv *priv = dev_get_drvdata(dev);
139	u32 ctime0, ctime1, ctime2;
140
141	ctime0 = ioread32(priv->iobase + HW_CTIME0);
142	ctime1 = ioread32(priv->iobase + HW_CTIME1);
143	ctime2 = ioread32(priv->iobase + HW_CTIME2);
144
145	if (ctime1 != ioread32(priv->iobase + HW_CTIME1)) {
146		/*
147		 * woops, counter flipped right now. Now we are safe
148		 * to reread.
149		 */
150		ctime0 = ioread32(priv->iobase + HW_CTIME0);
151		ctime1 = ioread32(priv->iobase + HW_CTIME1);
152		ctime2 = ioread32(priv->iobase + HW_CTIME2);
153	}
154
155	tm->tm_sec  = (ctime0 >> BM_CTIME0_SEC_S)  & BM_CTIME0_SEC_M;
156	tm->tm_min  = (ctime0 >> BM_CTIME0_MIN_S)  & BM_CTIME0_MIN_M;
157	tm->tm_hour = (ctime0 >> BM_CTIME0_HOUR_S) & BM_CTIME0_HOUR_M;
158	tm->tm_wday = (ctime0 >> BM_CTIME0_DOW_S)  & BM_CTIME0_DOW_M;
159
160	tm->tm_mday = (ctime1 >> BM_CTIME1_DOM_S)  & BM_CTIME1_DOM_M;
161	tm->tm_mon  = (ctime1 >> BM_CTIME1_MON_S)  & BM_CTIME1_MON_M;
162	tm->tm_year = (ctime1 >> BM_CTIME1_YEAR_S) & BM_CTIME1_YEAR_M;
163
164	tm->tm_yday = (ctime2 >> BM_CTIME2_DOY_S)  & BM_CTIME2_DOY_M;
165
166	return 0;
167}
168
169static int asm9260_rtc_set_time(struct device *dev, struct rtc_time *tm)
170{
171	struct asm9260_rtc_priv *priv = dev_get_drvdata(dev);
172
173	/*
174	 * make sure SEC counter will not flip other counter on write time,
175	 * real value will be written at the enf of sequence.
176	 */
177	iowrite32(0, priv->iobase + HW_SEC);
178
179	iowrite32(tm->tm_year, priv->iobase + HW_YEAR);
180	iowrite32(tm->tm_mon,  priv->iobase + HW_MONTH);
181	iowrite32(tm->tm_mday, priv->iobase + HW_DOM);
182	iowrite32(tm->tm_wday, priv->iobase + HW_DOW);
183	iowrite32(tm->tm_yday, priv->iobase + HW_DOY);
184	iowrite32(tm->tm_hour, priv->iobase + HW_HOUR);
185	iowrite32(tm->tm_min,  priv->iobase + HW_MIN);
186	iowrite32(tm->tm_sec,  priv->iobase + HW_SEC);
187
188	return 0;
189}
190
191static int asm9260_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
192{
193	struct asm9260_rtc_priv *priv = dev_get_drvdata(dev);
194
195	alrm->time.tm_year = ioread32(priv->iobase + HW_ALYEAR);
196	alrm->time.tm_mon  = ioread32(priv->iobase + HW_ALMON);
197	alrm->time.tm_mday = ioread32(priv->iobase + HW_ALDOM);
198	alrm->time.tm_wday = ioread32(priv->iobase + HW_ALDOW);
199	alrm->time.tm_yday = ioread32(priv->iobase + HW_ALDOY);
200	alrm->time.tm_hour = ioread32(priv->iobase + HW_ALHOUR);
201	alrm->time.tm_min  = ioread32(priv->iobase + HW_ALMIN);
202	alrm->time.tm_sec  = ioread32(priv->iobase + HW_ALSEC);
203
204	alrm->enabled = ioread32(priv->iobase + HW_AMR) ? 1 : 0;
205	alrm->pending = ioread32(priv->iobase + HW_CIIR) ? 1 : 0;
206
207	return rtc_valid_tm(&alrm->time);
208}
209
210static int asm9260_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
211{
212	struct asm9260_rtc_priv *priv = dev_get_drvdata(dev);
213
214	iowrite32(alrm->time.tm_year, priv->iobase + HW_ALYEAR);
215	iowrite32(alrm->time.tm_mon,  priv->iobase + HW_ALMON);
216	iowrite32(alrm->time.tm_mday, priv->iobase + HW_ALDOM);
217	iowrite32(alrm->time.tm_wday, priv->iobase + HW_ALDOW);
218	iowrite32(alrm->time.tm_yday, priv->iobase + HW_ALDOY);
219	iowrite32(alrm->time.tm_hour, priv->iobase + HW_ALHOUR);
220	iowrite32(alrm->time.tm_min,  priv->iobase + HW_ALMIN);
221	iowrite32(alrm->time.tm_sec,  priv->iobase + HW_ALSEC);
222
223	iowrite32(alrm->enabled ? 0 : BM_AMR_OFF, priv->iobase + HW_AMR);
224
225	return 0;
226}
227
228static int asm9260_alarm_irq_enable(struct device *dev, unsigned int enabled)
229{
230	struct asm9260_rtc_priv *priv = dev_get_drvdata(dev);
231
232	iowrite32(enabled ? 0 : BM_AMR_OFF, priv->iobase + HW_AMR);
233	return 0;
234}
235
236static const struct rtc_class_ops asm9260_rtc_ops = {
237	.read_time		= asm9260_rtc_read_time,
238	.set_time		= asm9260_rtc_set_time,
239	.read_alarm		= asm9260_rtc_read_alarm,
240	.set_alarm		= asm9260_rtc_set_alarm,
241	.alarm_irq_enable	= asm9260_alarm_irq_enable,
242};
243
244static int asm9260_rtc_probe(struct platform_device *pdev)
245{
246	struct asm9260_rtc_priv *priv;
247	struct device *dev = &pdev->dev;
248	int irq_alarm, ret;
249	u32 ccr;
250
251	priv = devm_kzalloc(dev, sizeof(struct asm9260_rtc_priv), GFP_KERNEL);
252	if (!priv)
253		return -ENOMEM;
254
255	priv->dev = &pdev->dev;
256	platform_set_drvdata(pdev, priv);
257
258	irq_alarm = platform_get_irq(pdev, 0);
259	if (irq_alarm < 0)
260		return irq_alarm;
261
262	priv->iobase = devm_platform_ioremap_resource(pdev, 0);
263	if (IS_ERR(priv->iobase))
264		return PTR_ERR(priv->iobase);
265
266	priv->clk = devm_clk_get(dev, "ahb");
267	if (IS_ERR(priv->clk))
268		return PTR_ERR(priv->clk);
269
270	ret = clk_prepare_enable(priv->clk);
271	if (ret) {
272		dev_err(dev, "Failed to enable clk!\n");
273		return ret;
274	}
275
276	ccr = ioread32(priv->iobase + HW_CCR);
277	/* if dev is not enabled, reset it */
278	if ((ccr & (BM_CLKEN | BM_CTCRST)) != BM_CLKEN) {
279		iowrite32(BM_CTCRST, priv->iobase + HW_CCR);
280		ccr = 0;
281	}
282
283	iowrite32(BM_CLKEN | ccr, priv->iobase + HW_CCR);
284	iowrite32(0, priv->iobase + HW_CIIR);
285	iowrite32(BM_AMR_OFF, priv->iobase + HW_AMR);
286
287	priv->rtc = devm_rtc_device_register(dev, dev_name(dev),
288					     &asm9260_rtc_ops, THIS_MODULE);
289	if (IS_ERR(priv->rtc)) {
290		ret = PTR_ERR(priv->rtc);
291		dev_err(dev, "Failed to register RTC device: %d\n", ret);
292		goto err_return;
293	}
294
295	ret = devm_request_threaded_irq(dev, irq_alarm, NULL,
296					asm9260_rtc_irq, IRQF_ONESHOT,
297					dev_name(dev), priv);
298	if (ret < 0) {
299		dev_err(dev, "can't get irq %i, err %d\n",
300			irq_alarm, ret);
301		goto err_return;
302	}
303
304	return 0;
305
306err_return:
307	clk_disable_unprepare(priv->clk);
308	return ret;
309}
310
311static int asm9260_rtc_remove(struct platform_device *pdev)
312{
313	struct asm9260_rtc_priv *priv = platform_get_drvdata(pdev);
314
315	/* Disable alarm matching */
316	iowrite32(BM_AMR_OFF, priv->iobase + HW_AMR);
317	clk_disable_unprepare(priv->clk);
318	return 0;
319}
320
321static const struct of_device_id asm9260_dt_ids[] = {
322	{ .compatible = "alphascale,asm9260-rtc", },
323	{}
324};
325MODULE_DEVICE_TABLE(of, asm9260_dt_ids);
326
327static struct platform_driver asm9260_rtc_driver = {
328	.probe		= asm9260_rtc_probe,
329	.remove		= asm9260_rtc_remove,
330	.driver		= {
331		.name	= "asm9260-rtc",
332		.of_match_table = asm9260_dt_ids,
333	},
334};
335
336module_platform_driver(asm9260_rtc_driver);
337
338MODULE_AUTHOR("Oleksij Rempel <linux@rempel-privat.de>");
339MODULE_DESCRIPTION("Alphascale asm9260 SoC Realtime Clock Driver (RTC)");
340MODULE_LICENSE("GPL");