brintos

brintos / linux-shallow public Read only

0
0
Text · 9.2 KiB · f40cc06 Raw
341 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Real Time Clock driver for Marvell 88PM80x PMIC4 *5 * Copyright (c) 2012 Marvell International Ltd.6 *  Wenzeng Chen<wzch@marvell.com>7 *  Qiao Zhou <zhouqiao@marvell.com>8 */9 10#include <linux/kernel.h>11#include <linux/module.h>12#include <linux/slab.h>13#include <linux/regmap.h>14#include <linux/mfd/core.h>15#include <linux/mfd/88pm80x.h>16#include <linux/rtc.h>17 18#define PM800_RTC_COUNTER1		(0xD1)19#define PM800_RTC_COUNTER2		(0xD2)20#define PM800_RTC_COUNTER3		(0xD3)21#define PM800_RTC_COUNTER4		(0xD4)22#define PM800_RTC_EXPIRE1_1		(0xD5)23#define PM800_RTC_EXPIRE1_2		(0xD6)24#define PM800_RTC_EXPIRE1_3		(0xD7)25#define PM800_RTC_EXPIRE1_4		(0xD8)26#define PM800_RTC_TRIM1			(0xD9)27#define PM800_RTC_TRIM2			(0xDA)28#define PM800_RTC_TRIM3			(0xDB)29#define PM800_RTC_TRIM4			(0xDC)30#define PM800_RTC_EXPIRE2_1		(0xDD)31#define PM800_RTC_EXPIRE2_2		(0xDE)32#define PM800_RTC_EXPIRE2_3		(0xDF)33#define PM800_RTC_EXPIRE2_4		(0xE0)34 35#define PM800_POWER_DOWN_LOG1	(0xE5)36#define PM800_POWER_DOWN_LOG2	(0xE6)37 38struct pm80x_rtc_info {39	struct pm80x_chip *chip;40	struct regmap *map;41	struct rtc_device *rtc_dev;42	struct device *dev;43 44	int irq;45};46 47static irqreturn_t rtc_update_handler(int irq, void *data)48{49	struct pm80x_rtc_info *info = (struct pm80x_rtc_info *)data;50	int mask;51 52	mask = PM800_ALARM | PM800_ALARM_WAKEUP;53	regmap_update_bits(info->map, PM800_RTC_CONTROL, mask | PM800_ALARM1_EN,54			   mask);55	rtc_update_irq(info->rtc_dev, 1, RTC_AF);56	return IRQ_HANDLED;57}58 59static int pm80x_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)60{61	struct pm80x_rtc_info *info = dev_get_drvdata(dev);62 63	if (enabled)64		regmap_update_bits(info->map, PM800_RTC_CONTROL,65				   PM800_ALARM1_EN, PM800_ALARM1_EN);66	else67		regmap_update_bits(info->map, PM800_RTC_CONTROL,68				   PM800_ALARM1_EN, 0);69	return 0;70}71 72/*73 * Calculate the next alarm time given the requested alarm time mask74 * and the current time.75 */76static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now,77				struct rtc_time *alrm)78{79	unsigned long next_time;80	unsigned long now_time;81 82	next->tm_year = now->tm_year;83	next->tm_mon = now->tm_mon;84	next->tm_mday = now->tm_mday;85	next->tm_hour = alrm->tm_hour;86	next->tm_min = alrm->tm_min;87	next->tm_sec = alrm->tm_sec;88 89	now_time = rtc_tm_to_time64(now);90	next_time = rtc_tm_to_time64(next);91 92	if (next_time < now_time) {93		/* Advance one day */94		next_time += 60 * 60 * 24;95		rtc_time64_to_tm(next_time, next);96	}97}98 99static int pm80x_rtc_read_time(struct device *dev, struct rtc_time *tm)100{101	struct pm80x_rtc_info *info = dev_get_drvdata(dev);102	unsigned char buf[4];103	unsigned long ticks, base, data;104	regmap_raw_read(info->map, PM800_RTC_EXPIRE2_1, buf, 4);105	base = ((unsigned long)buf[3] << 24) | (buf[2] << 16) |106		(buf[1] << 8) | buf[0];107	dev_dbg(info->dev, "%x-%x-%x-%x\n", buf[0], buf[1], buf[2], buf[3]);108 109	/* load 32-bit read-only counter */110	regmap_raw_read(info->map, PM800_RTC_COUNTER1, buf, 4);111	data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) |112		(buf[1] << 8) | buf[0];113	ticks = base + data;114	dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",115		base, data, ticks);116	rtc_time64_to_tm(ticks, tm);117	return 0;118}119 120static int pm80x_rtc_set_time(struct device *dev, struct rtc_time *tm)121{122	struct pm80x_rtc_info *info = dev_get_drvdata(dev);123	unsigned char buf[4];124	unsigned long ticks, base, data;125 126	ticks = rtc_tm_to_time64(tm);127 128	/* load 32-bit read-only counter */129	regmap_raw_read(info->map, PM800_RTC_COUNTER1, buf, 4);130	data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) |131		(buf[1] << 8) | buf[0];132	base = ticks - data;133	dev_dbg(info->dev, "set base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",134		base, data, ticks);135	buf[0] = base & 0xFF;136	buf[1] = (base >> 8) & 0xFF;137	buf[2] = (base >> 16) & 0xFF;138	buf[3] = (base >> 24) & 0xFF;139	regmap_raw_write(info->map, PM800_RTC_EXPIRE2_1, buf, 4);140 141	return 0;142}143 144static int pm80x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)145{146	struct pm80x_rtc_info *info = dev_get_drvdata(dev);147	unsigned char buf[4];148	unsigned long ticks, base, data;149	int ret;150 151	regmap_raw_read(info->map, PM800_RTC_EXPIRE2_1, buf, 4);152	base = ((unsigned long)buf[3] << 24) | (buf[2] << 16) |153		(buf[1] << 8) | buf[0];154	dev_dbg(info->dev, "%x-%x-%x-%x\n", buf[0], buf[1], buf[2], buf[3]);155 156	regmap_raw_read(info->map, PM800_RTC_EXPIRE1_1, buf, 4);157	data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) |158		(buf[1] << 8) | buf[0];159	ticks = base + data;160	dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",161		base, data, ticks);162 163	rtc_time64_to_tm(ticks, &alrm->time);164	regmap_read(info->map, PM800_RTC_CONTROL, &ret);165	alrm->enabled = (ret & PM800_ALARM1_EN) ? 1 : 0;166	alrm->pending = (ret & (PM800_ALARM | PM800_ALARM_WAKEUP)) ? 1 : 0;167	return 0;168}169 170static int pm80x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)171{172	struct pm80x_rtc_info *info = dev_get_drvdata(dev);173	struct rtc_time now_tm, alarm_tm;174	unsigned long ticks, base, data;175	unsigned char buf[4];176	int mask;177 178	regmap_update_bits(info->map, PM800_RTC_CONTROL, PM800_ALARM1_EN, 0);179 180	regmap_raw_read(info->map, PM800_RTC_EXPIRE2_1, buf, 4);181	base = ((unsigned long)buf[3] << 24) | (buf[2] << 16) |182		(buf[1] << 8) | buf[0];183	dev_dbg(info->dev, "%x-%x-%x-%x\n", buf[0], buf[1], buf[2], buf[3]);184 185	/* load 32-bit read-only counter */186	regmap_raw_read(info->map, PM800_RTC_COUNTER1, buf, 4);187	data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) |188		(buf[1] << 8) | buf[0];189	ticks = base + data;190	dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",191		base, data, ticks);192 193	rtc_time64_to_tm(ticks, &now_tm);194	dev_dbg(info->dev, "%s, now time : %lu\n", __func__, ticks);195	rtc_next_alarm_time(&alarm_tm, &now_tm, &alrm->time);196	/* get new ticks for alarm in 24 hours */197	ticks = rtc_tm_to_time64(&alarm_tm);198	dev_dbg(info->dev, "%s, alarm time: %lu\n", __func__, ticks);199	data = ticks - base;200 201	buf[0] = data & 0xff;202	buf[1] = (data >> 8) & 0xff;203	buf[2] = (data >> 16) & 0xff;204	buf[3] = (data >> 24) & 0xff;205	regmap_raw_write(info->map, PM800_RTC_EXPIRE1_1, buf, 4);206	if (alrm->enabled) {207		mask = PM800_ALARM | PM800_ALARM_WAKEUP | PM800_ALARM1_EN;208		regmap_update_bits(info->map, PM800_RTC_CONTROL, mask, mask);209	} else {210		mask = PM800_ALARM | PM800_ALARM_WAKEUP | PM800_ALARM1_EN;211		regmap_update_bits(info->map, PM800_RTC_CONTROL, mask,212				   PM800_ALARM | PM800_ALARM_WAKEUP);213	}214	return 0;215}216 217static const struct rtc_class_ops pm80x_rtc_ops = {218	.read_time = pm80x_rtc_read_time,219	.set_time = pm80x_rtc_set_time,220	.read_alarm = pm80x_rtc_read_alarm,221	.set_alarm = pm80x_rtc_set_alarm,222	.alarm_irq_enable = pm80x_rtc_alarm_irq_enable,223};224 225#ifdef CONFIG_PM_SLEEP226static int pm80x_rtc_suspend(struct device *dev)227{228	return pm80x_dev_suspend(dev);229}230 231static int pm80x_rtc_resume(struct device *dev)232{233	return pm80x_dev_resume(dev);234}235#endif236 237static SIMPLE_DEV_PM_OPS(pm80x_rtc_pm_ops, pm80x_rtc_suspend, pm80x_rtc_resume);238 239static int pm80x_rtc_probe(struct platform_device *pdev)240{241	struct pm80x_chip *chip = dev_get_drvdata(pdev->dev.parent);242	struct pm80x_rtc_pdata *pdata = dev_get_platdata(&pdev->dev);243	struct pm80x_rtc_info *info;244	struct device_node *node = pdev->dev.of_node;245	int ret;246 247	if (!pdata && !node) {248		dev_err(&pdev->dev,249			"pm80x-rtc requires platform data or of_node\n");250		return -EINVAL;251	}252 253	if (!pdata) {254		pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);255		if (!pdata) {256			dev_err(&pdev->dev, "failed to allocate memory\n");257			return -ENOMEM;258		}259	}260 261	info =262	    devm_kzalloc(&pdev->dev, sizeof(struct pm80x_rtc_info), GFP_KERNEL);263	if (!info)264		return -ENOMEM;265	info->irq = platform_get_irq(pdev, 0);266	if (info->irq < 0) {267		ret = -EINVAL;268		goto out;269	}270 271	info->chip = chip;272	info->map = chip->regmap;273	if (!info->map) {274		dev_err(&pdev->dev, "no regmap!\n");275		ret = -EINVAL;276		goto out;277	}278 279	info->dev = &pdev->dev;280	dev_set_drvdata(&pdev->dev, info);281 282	info->rtc_dev = devm_rtc_allocate_device(&pdev->dev);283	if (IS_ERR(info->rtc_dev))284		return PTR_ERR(info->rtc_dev);285 286	ret = pm80x_request_irq(chip, info->irq, rtc_update_handler,287				IRQF_ONESHOT, "rtc", info);288	if (ret < 0) {289		dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",290			info->irq, ret);291		goto out;292	}293 294	info->rtc_dev->ops = &pm80x_rtc_ops;295	info->rtc_dev->range_max = U32_MAX;296 297	ret = devm_rtc_register_device(info->rtc_dev);298	if (ret)299		goto out_rtc;300 301	/*302	 * enable internal XO instead of internal 3.25MHz clock since it can303	 * free running in PMIC power-down state.304	 */305	regmap_update_bits(info->map, PM800_RTC_CONTROL, PM800_RTC1_USE_XO,306			   PM800_RTC1_USE_XO);307 308	/* remember whether this power up is caused by PMIC RTC or not */309	info->rtc_dev->dev.platform_data = &pdata->rtc_wakeup;310 311	device_init_wakeup(&pdev->dev, 1);312 313	return 0;314out_rtc:315	pm80x_free_irq(chip, info->irq, info);316out:317	return ret;318}319 320static void pm80x_rtc_remove(struct platform_device *pdev)321{322	struct pm80x_rtc_info *info = platform_get_drvdata(pdev);323	pm80x_free_irq(info->chip, info->irq, info);324}325 326static struct platform_driver pm80x_rtc_driver = {327	.driver = {328		   .name = "88pm80x-rtc",329		   .pm = &pm80x_rtc_pm_ops,330		   },331	.probe = pm80x_rtc_probe,332	.remove_new = pm80x_rtc_remove,333};334 335module_platform_driver(pm80x_rtc_driver);336 337MODULE_LICENSE("GPL");338MODULE_DESCRIPTION("Marvell 88PM80x RTC driver");339MODULE_AUTHOR("Qiao Zhou <zhouqiao@marvell.com>");340MODULE_ALIAS("platform:88pm80x-rtc");341