brintos

brintos / linux-shallow public Read only

0
0
Text · 8.8 KiB · 59b627f Raw
361 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2//3// Copyright (C) 2018 ROHM Semiconductors4//5// RTC driver for ROHM BD71828 and BD71815 PMIC6 7#include <linux/bcd.h>8#include <linux/mfd/rohm-bd71815.h>9#include <linux/mfd/rohm-bd71828.h>10#include <linux/module.h>11#include <linux/of.h>12#include <linux/platform_device.h>13#include <linux/regmap.h>14#include <linux/rtc.h>15 16/*17 * On BD71828 and BD71815 the ALM0 MASK is 14 bytes after the ALM018 * block start19 */20#define BD718XX_ALM_EN_OFFSET 1421 22/*23 * We read regs RTC_SEC => RTC_YEAR24 * this struct is ordered according to chip registers.25 * Keep it u8 only (or packed) to avoid padding issues.26 */27struct bd70528_rtc_day {28	u8 sec;29	u8 min;30	u8 hour;31} __packed;32 33struct bd70528_rtc_data {34	struct bd70528_rtc_day time;35	u8 week;36	u8 day;37	u8 month;38	u8 year;39} __packed;40 41struct bd71828_rtc_alm {42	struct bd70528_rtc_data alm0;43	struct bd70528_rtc_data alm1;44	u8 alm_mask;45	u8 alm1_mask;46} __packed;47 48struct bd70528_rtc {49	struct rohm_regmap_dev *parent;50	struct regmap *regmap;51	struct device *dev;52	u8 reg_time_start;53	u8 bd718xx_alm_block_start;54};55 56static inline void tmday2rtc(struct rtc_time *t, struct bd70528_rtc_day *d)57{58	d->sec &= ~BD70528_MASK_RTC_SEC;59	d->min &= ~BD70528_MASK_RTC_MINUTE;60	d->hour &= ~BD70528_MASK_RTC_HOUR;61	d->sec |= bin2bcd(t->tm_sec);62	d->min |= bin2bcd(t->tm_min);63	d->hour |= bin2bcd(t->tm_hour);64}65 66static inline void tm2rtc(struct rtc_time *t, struct bd70528_rtc_data *r)67{68	r->day &= ~BD70528_MASK_RTC_DAY;69	r->week &= ~BD70528_MASK_RTC_WEEK;70	r->month &= ~BD70528_MASK_RTC_MONTH;71	/*72	 * PM and 24H bits are not used by Wake - thus we clear them73	 * here and not in tmday2rtc() which is also used by wake.74	 */75	r->time.hour &= ~(BD70528_MASK_RTC_HOUR_PM | BD70528_MASK_RTC_HOUR_24H);76 77	tmday2rtc(t, &r->time);78	/*79	 * We do always set time in 24H mode.80	 */81	r->time.hour |= BD70528_MASK_RTC_HOUR_24H;82	r->day |= bin2bcd(t->tm_mday);83	r->week |= bin2bcd(t->tm_wday);84	r->month |= bin2bcd(t->tm_mon + 1);85	r->year = bin2bcd(t->tm_year - 100);86}87 88static inline void rtc2tm(struct bd70528_rtc_data *r, struct rtc_time *t)89{90	t->tm_sec = bcd2bin(r->time.sec & BD70528_MASK_RTC_SEC);91	t->tm_min = bcd2bin(r->time.min & BD70528_MASK_RTC_MINUTE);92	t->tm_hour = bcd2bin(r->time.hour & BD70528_MASK_RTC_HOUR);93	/*94	 * If RTC is in 12H mode, then bit BD70528_MASK_RTC_HOUR_PM95	 * is not BCD value but tells whether it is AM or PM96	 */97	if (!(r->time.hour & BD70528_MASK_RTC_HOUR_24H)) {98		t->tm_hour %= 12;99		if (r->time.hour & BD70528_MASK_RTC_HOUR_PM)100			t->tm_hour += 12;101	}102	t->tm_mday = bcd2bin(r->day & BD70528_MASK_RTC_DAY);103	t->tm_mon = bcd2bin(r->month & BD70528_MASK_RTC_MONTH) - 1;104	t->tm_year = 100 + bcd2bin(r->year & BD70528_MASK_RTC_YEAR);105	t->tm_wday = bcd2bin(r->week & BD70528_MASK_RTC_WEEK);106}107 108static int bd71828_set_alarm(struct device *dev, struct rtc_wkalrm *a)109{110	int ret;111	struct bd71828_rtc_alm alm;112	struct bd70528_rtc *r = dev_get_drvdata(dev);113 114	ret = regmap_bulk_read(r->regmap, r->bd718xx_alm_block_start, &alm,115			       sizeof(alm));116	if (ret) {117		dev_err(dev, "Failed to read alarm regs\n");118		return ret;119	}120 121	tm2rtc(&a->time, &alm.alm0);122 123	if (!a->enabled)124		alm.alm_mask &= ~BD70528_MASK_ALM_EN;125	else126		alm.alm_mask |= BD70528_MASK_ALM_EN;127 128	ret = regmap_bulk_write(r->regmap, r->bd718xx_alm_block_start, &alm,129				sizeof(alm));130	if (ret)131		dev_err(dev, "Failed to set alarm time\n");132 133	return ret;134 135}136 137static int bd71828_read_alarm(struct device *dev, struct rtc_wkalrm *a)138{139	int ret;140	struct bd71828_rtc_alm alm;141	struct bd70528_rtc *r = dev_get_drvdata(dev);142 143	ret = regmap_bulk_read(r->regmap, r->bd718xx_alm_block_start, &alm,144			       sizeof(alm));145	if (ret) {146		dev_err(dev, "Failed to read alarm regs\n");147		return ret;148	}149 150	rtc2tm(&alm.alm0, &a->time);151	a->time.tm_mday = -1;152	a->time.tm_mon = -1;153	a->time.tm_year = -1;154	a->enabled = !!(alm.alm_mask & BD70528_MASK_ALM_EN);155	a->pending = 0;156 157	return 0;158}159 160static int bd71828_set_time(struct device *dev, struct rtc_time *t)161{162	int ret;163	struct bd70528_rtc_data rtc_data;164	struct bd70528_rtc *r = dev_get_drvdata(dev);165 166	ret = regmap_bulk_read(r->regmap, r->reg_time_start, &rtc_data,167			       sizeof(rtc_data));168	if (ret) {169		dev_err(dev, "Failed to read RTC time registers\n");170		return ret;171	}172	tm2rtc(t, &rtc_data);173 174	ret = regmap_bulk_write(r->regmap, r->reg_time_start, &rtc_data,175				sizeof(rtc_data));176	if (ret)177		dev_err(dev, "Failed to set RTC time\n");178 179	return ret;180}181 182static int bd70528_get_time(struct device *dev, struct rtc_time *t)183{184	struct bd70528_rtc *r = dev_get_drvdata(dev);185	struct bd70528_rtc_data rtc_data;186	int ret;187 188	/* read the RTC date and time registers all at once */189	ret = regmap_bulk_read(r->regmap, r->reg_time_start, &rtc_data,190			       sizeof(rtc_data));191	if (ret) {192		dev_err(dev, "Failed to read RTC time (err %d)\n", ret);193		return ret;194	}195 196	rtc2tm(&rtc_data, t);197 198	return 0;199}200 201static int bd71828_alm_enable(struct device *dev, unsigned int enabled)202{203	int ret;204	struct bd70528_rtc *r = dev_get_drvdata(dev);205	unsigned int enableval = BD70528_MASK_ALM_EN;206 207	if (!enabled)208		enableval = 0;209 210	ret = regmap_update_bits(r->regmap, r->bd718xx_alm_block_start +211				 BD718XX_ALM_EN_OFFSET, BD70528_MASK_ALM_EN,212				 enableval);213	if (ret)214		dev_err(dev, "Failed to change alarm state\n");215 216	return ret;217}218 219static const struct rtc_class_ops bd71828_rtc_ops = {220	.read_time		= bd70528_get_time,221	.set_time		= bd71828_set_time,222	.read_alarm		= bd71828_read_alarm,223	.set_alarm		= bd71828_set_alarm,224	.alarm_irq_enable	= bd71828_alm_enable,225};226 227static irqreturn_t alm_hndlr(int irq, void *data)228{229	struct rtc_device *rtc = data;230 231	rtc_update_irq(rtc, 1, RTC_IRQF | RTC_AF | RTC_PF);232	return IRQ_HANDLED;233}234 235static int bd70528_probe(struct platform_device *pdev)236{237	struct bd70528_rtc *bd_rtc;238	const struct rtc_class_ops *rtc_ops;239	const char *irq_name;240	int ret;241	struct rtc_device *rtc;242	int irq;243	unsigned int hr;244	u8 hour_reg;245	enum rohm_chip_type chip = platform_get_device_id(pdev)->driver_data;246 247	bd_rtc = devm_kzalloc(&pdev->dev, sizeof(*bd_rtc), GFP_KERNEL);248	if (!bd_rtc)249		return -ENOMEM;250 251	bd_rtc->regmap = dev_get_regmap(pdev->dev.parent, NULL);252	if (!bd_rtc->regmap) {253		dev_err(&pdev->dev, "No regmap\n");254		return -EINVAL;255	}256 257	bd_rtc->dev = &pdev->dev;258	rtc_ops = &bd71828_rtc_ops;259 260	switch (chip) {261	case ROHM_CHIP_TYPE_BD71815:262		irq_name = "bd71815-rtc-alm-0";263		bd_rtc->reg_time_start = BD71815_REG_RTC_START;264 265		/*266		 * See also BD718XX_ALM_EN_OFFSET:267		 * This works for BD71828 and BD71815 as they have same offset268		 * between ALM0 start and ALM0_MASK. If new ICs are to be269		 * added this requires proper check as ALM0_MASK is not located270		 * at the end of ALM0 block - but after all ALM blocks so if271		 * amount of ALMs differ the offset to enable/disable is likely272		 * to be incorrect and enable/disable must be given as own273		 * reg address here.274		 */275		bd_rtc->bd718xx_alm_block_start = BD71815_REG_RTC_ALM_START;276		hour_reg = BD71815_REG_HOUR;277		break;278	case ROHM_CHIP_TYPE_BD71828:279		irq_name = "bd71828-rtc-alm-0";280		bd_rtc->reg_time_start = BD71828_REG_RTC_START;281		bd_rtc->bd718xx_alm_block_start = BD71828_REG_RTC_ALM_START;282		hour_reg = BD71828_REG_RTC_HOUR;283		break;284	default:285		dev_err(&pdev->dev, "Unknown chip\n");286		return -ENOENT;287	}288 289	irq = platform_get_irq_byname(pdev, irq_name);290 291	if (irq < 0)292		return irq;293 294	platform_set_drvdata(pdev, bd_rtc);295 296	ret = regmap_read(bd_rtc->regmap, hour_reg, &hr);297 298	if (ret) {299		dev_err(&pdev->dev, "Failed to reag RTC clock\n");300		return ret;301	}302 303	if (!(hr & BD70528_MASK_RTC_HOUR_24H)) {304		struct rtc_time t;305 306		ret = rtc_ops->read_time(&pdev->dev, &t);307 308		if (!ret)309			ret = rtc_ops->set_time(&pdev->dev, &t);310 311		if (ret) {312			dev_err(&pdev->dev,313				"Setting 24H clock for RTC failed\n");314			return ret;315		}316	}317 318	device_set_wakeup_capable(&pdev->dev, true);319	device_wakeup_enable(&pdev->dev);320 321	rtc = devm_rtc_allocate_device(&pdev->dev);322	if (IS_ERR(rtc)) {323		dev_err(&pdev->dev, "RTC device creation failed\n");324		return PTR_ERR(rtc);325	}326 327	rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;328	rtc->range_max = RTC_TIMESTAMP_END_2099;329	rtc->ops = rtc_ops;330 331	/* Request alarm IRQ prior to registerig the RTC */332	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, &alm_hndlr,333					IRQF_ONESHOT, "bd70528-rtc", rtc);334	if (ret)335		return ret;336 337	return devm_rtc_register_device(rtc);338}339 340static const struct platform_device_id bd718x7_rtc_id[] = {341	{ "bd71828-rtc", ROHM_CHIP_TYPE_BD71828 },342	{ "bd71815-rtc", ROHM_CHIP_TYPE_BD71815 },343	{ },344};345MODULE_DEVICE_TABLE(platform, bd718x7_rtc_id);346 347static struct platform_driver bd70528_rtc = {348	.driver = {349		.name = "bd70528-rtc"350	},351	.probe = bd70528_probe,352	.id_table = bd718x7_rtc_id,353};354 355module_platform_driver(bd70528_rtc);356 357MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");358MODULE_DESCRIPTION("ROHM BD71828 and BD71815 PMIC RTC driver");359MODULE_LICENSE("GPL");360MODULE_ALIAS("platform:bd70528-rtc");361