xref: /openbmc/linux/drivers/rtc/rtc-max6916.c (revision 22652ba72453d35c8a637d5c0f06b3dc29ff9eb0)
106776c89SVenkat Prashanth B U /* rtc-max6916.c
206776c89SVenkat Prashanth B U  *
306776c89SVenkat Prashanth B U  * Driver for MAXIM  max6916 Low Current, SPI Compatible
406776c89SVenkat Prashanth B U  * Real Time Clock
506776c89SVenkat Prashanth B U  *
606776c89SVenkat Prashanth B U  * Author : Venkat Prashanth B U <venkat.prashanth2498@gmail.com>
706776c89SVenkat Prashanth B U  *
806776c89SVenkat Prashanth B U  * This program is free software; you can redistribute it and/or modify
906776c89SVenkat Prashanth B U  * it under the terms of the GNU General Public License version 2 as
1006776c89SVenkat Prashanth B U  * published by the Free Software Foundation.
1106776c89SVenkat Prashanth B U  *
1206776c89SVenkat Prashanth B U  */
1306776c89SVenkat Prashanth B U 
1406776c89SVenkat Prashanth B U #include <linux/init.h>
1506776c89SVenkat Prashanth B U #include <linux/module.h>
1606776c89SVenkat Prashanth B U #include <linux/device.h>
1706776c89SVenkat Prashanth B U #include <linux/platform_device.h>
1806776c89SVenkat Prashanth B U #include <linux/rtc.h>
1906776c89SVenkat Prashanth B U #include <linux/spi/spi.h>
2006776c89SVenkat Prashanth B U #include <linux/bcd.h>
2106776c89SVenkat Prashanth B U 
2206776c89SVenkat Prashanth B U /* Registers in max6916 rtc */
2306776c89SVenkat Prashanth B U 
2406776c89SVenkat Prashanth B U #define MAX6916_SECONDS_REG	0x01
2506776c89SVenkat Prashanth B U #define MAX6916_MINUTES_REG	0x02
2606776c89SVenkat Prashanth B U #define MAX6916_HOURS_REG	0x03
2706776c89SVenkat Prashanth B U #define MAX6916_DATE_REG	0x04
2806776c89SVenkat Prashanth B U #define MAX6916_MONTH_REG	0x05
2906776c89SVenkat Prashanth B U #define MAX6916_DAY_REG	0x06
3006776c89SVenkat Prashanth B U #define MAX6916_YEAR_REG	0x07
3106776c89SVenkat Prashanth B U #define MAX6916_CONTROL_REG	0x08
3206776c89SVenkat Prashanth B U #define MAX6916_STATUS_REG	0x0C
3306776c89SVenkat Prashanth B U #define MAX6916_CLOCK_BURST	0x3F
3406776c89SVenkat Prashanth B U 
3506776c89SVenkat Prashanth B U static int max6916_read_reg(struct device *dev, unsigned char address,
3606776c89SVenkat Prashanth B U 			    unsigned char *data)
3706776c89SVenkat Prashanth B U {
3806776c89SVenkat Prashanth B U 	struct spi_device *spi = to_spi_device(dev);
3906776c89SVenkat Prashanth B U 
4006776c89SVenkat Prashanth B U 	*data = address | 0x80;
4106776c89SVenkat Prashanth B U 
4206776c89SVenkat Prashanth B U 	return spi_write_then_read(spi, data, 1, data, 1);
4306776c89SVenkat Prashanth B U }
4406776c89SVenkat Prashanth B U 
4506776c89SVenkat Prashanth B U static int max6916_write_reg(struct device *dev, unsigned char address,
4606776c89SVenkat Prashanth B U 			     unsigned char data)
4706776c89SVenkat Prashanth B U {
4806776c89SVenkat Prashanth B U 	struct spi_device *spi = to_spi_device(dev);
4906776c89SVenkat Prashanth B U 	unsigned char buf[2];
5006776c89SVenkat Prashanth B U 
5106776c89SVenkat Prashanth B U 	buf[0] = address & 0x7F;
5206776c89SVenkat Prashanth B U 	buf[1] = data;
5306776c89SVenkat Prashanth B U 
5406776c89SVenkat Prashanth B U 	return spi_write_then_read(spi, buf, 2, NULL, 0);
5506776c89SVenkat Prashanth B U }
5606776c89SVenkat Prashanth B U 
5706776c89SVenkat Prashanth B U static int max6916_read_time(struct device *dev, struct rtc_time *dt)
5806776c89SVenkat Prashanth B U {
5906776c89SVenkat Prashanth B U 	struct spi_device *spi = to_spi_device(dev);
6006776c89SVenkat Prashanth B U 	int err;
6106776c89SVenkat Prashanth B U 	unsigned char buf[8];
6206776c89SVenkat Prashanth B U 
6306776c89SVenkat Prashanth B U 	buf[0] = MAX6916_CLOCK_BURST | 0x80;
6406776c89SVenkat Prashanth B U 
6506776c89SVenkat Prashanth B U 	err = spi_write_then_read(spi, buf, 1, buf, 8);
6606776c89SVenkat Prashanth B U 
6706776c89SVenkat Prashanth B U 	if (err)
6806776c89SVenkat Prashanth B U 		return err;
6906776c89SVenkat Prashanth B U 
7006776c89SVenkat Prashanth B U 	dt->tm_sec = bcd2bin(buf[0]);
7106776c89SVenkat Prashanth B U 	dt->tm_min = bcd2bin(buf[1]);
7206776c89SVenkat Prashanth B U 	dt->tm_hour = bcd2bin(buf[2] & 0x3F);
7306776c89SVenkat Prashanth B U 	dt->tm_mday = bcd2bin(buf[3]);
7406776c89SVenkat Prashanth B U 	dt->tm_mon = bcd2bin(buf[4]) - 1;
7506776c89SVenkat Prashanth B U 	dt->tm_wday = bcd2bin(buf[5]) - 1;
7606776c89SVenkat Prashanth B U 	dt->tm_year = bcd2bin(buf[6]) + 100;
7706776c89SVenkat Prashanth B U 
78*22652ba7SAlexandre Belloni 	return 0;
7906776c89SVenkat Prashanth B U }
8006776c89SVenkat Prashanth B U 
8106776c89SVenkat Prashanth B U static int max6916_set_time(struct device *dev, struct rtc_time *dt)
8206776c89SVenkat Prashanth B U {
8306776c89SVenkat Prashanth B U 	struct spi_device *spi = to_spi_device(dev);
8406776c89SVenkat Prashanth B U 	unsigned char buf[9];
8506776c89SVenkat Prashanth B U 
8606776c89SVenkat Prashanth B U 	if (dt->tm_year < 100 || dt->tm_year > 199) {
8706776c89SVenkat Prashanth B U 		dev_err(&spi->dev, "Year must be between 2000 and 2099. It's %d.\n",
8806776c89SVenkat Prashanth B U 			dt->tm_year + 1900);
8906776c89SVenkat Prashanth B U 	return -EINVAL;
9006776c89SVenkat Prashanth B U 	}
9106776c89SVenkat Prashanth B U 
9206776c89SVenkat Prashanth B U 	buf[0] = MAX6916_CLOCK_BURST & 0x7F;
9306776c89SVenkat Prashanth B U 	buf[1] = bin2bcd(dt->tm_sec);
9406776c89SVenkat Prashanth B U 	buf[2] = bin2bcd(dt->tm_min);
9506776c89SVenkat Prashanth B U 	buf[3] = (bin2bcd(dt->tm_hour) & 0X3F);
9606776c89SVenkat Prashanth B U 	buf[4] = bin2bcd(dt->tm_mday);
9706776c89SVenkat Prashanth B U 	buf[5] = bin2bcd(dt->tm_mon + 1);
9806776c89SVenkat Prashanth B U 	buf[6] = bin2bcd(dt->tm_wday + 1);
9906776c89SVenkat Prashanth B U 	buf[7] = bin2bcd(dt->tm_year % 100);
10006776c89SVenkat Prashanth B U 	buf[8] = bin2bcd(0x00);
10106776c89SVenkat Prashanth B U 
10206776c89SVenkat Prashanth B U 	/* write the rtc settings */
10306776c89SVenkat Prashanth B U 	return spi_write_then_read(spi, buf, 9, NULL, 0);
10406776c89SVenkat Prashanth B U }
10506776c89SVenkat Prashanth B U 
10606776c89SVenkat Prashanth B U static const struct rtc_class_ops max6916_rtc_ops = {
10706776c89SVenkat Prashanth B U 	.read_time = max6916_read_time,
10806776c89SVenkat Prashanth B U 	.set_time = max6916_set_time,
10906776c89SVenkat Prashanth B U };
11006776c89SVenkat Prashanth B U 
11106776c89SVenkat Prashanth B U static int max6916_probe(struct spi_device *spi)
11206776c89SVenkat Prashanth B U {
11306776c89SVenkat Prashanth B U 	struct rtc_device *rtc;
11406776c89SVenkat Prashanth B U 	unsigned char data;
11506776c89SVenkat Prashanth B U 	int res;
11606776c89SVenkat Prashanth B U 
11706776c89SVenkat Prashanth B U 	/* spi setup with max6916 in mode 3 and bits per word as 8 */
11806776c89SVenkat Prashanth B U 	spi->mode = SPI_MODE_3;
11906776c89SVenkat Prashanth B U 	spi->bits_per_word = 8;
12006776c89SVenkat Prashanth B U 	spi_setup(spi);
12106776c89SVenkat Prashanth B U 
12206776c89SVenkat Prashanth B U 	/* RTC Settings */
12306776c89SVenkat Prashanth B U 	res = max6916_read_reg(&spi->dev, MAX6916_SECONDS_REG, &data);
12406776c89SVenkat Prashanth B U 	if (res)
12506776c89SVenkat Prashanth B U 		return res;
12606776c89SVenkat Prashanth B U 
12706776c89SVenkat Prashanth B U 	/* Disable the write protect of rtc */
12806776c89SVenkat Prashanth B U 	max6916_read_reg(&spi->dev, MAX6916_CONTROL_REG, &data);
12906776c89SVenkat Prashanth B U 	data = data & ~(1 << 7);
13006776c89SVenkat Prashanth B U 	max6916_write_reg(&spi->dev, MAX6916_CONTROL_REG, data);
13106776c89SVenkat Prashanth B U 
13206776c89SVenkat Prashanth B U 	/*Enable oscillator,disable oscillator stop flag, glitch filter*/
13306776c89SVenkat Prashanth B U 	max6916_read_reg(&spi->dev, MAX6916_STATUS_REG, &data);
13406776c89SVenkat Prashanth B U 	data = data & 0x1B;
13506776c89SVenkat Prashanth B U 	max6916_write_reg(&spi->dev, MAX6916_STATUS_REG, data);
13606776c89SVenkat Prashanth B U 
13706776c89SVenkat Prashanth B U 	/* display the settings */
13806776c89SVenkat Prashanth B U 	max6916_read_reg(&spi->dev, MAX6916_CONTROL_REG, &data);
13906776c89SVenkat Prashanth B U 	dev_info(&spi->dev, "MAX6916 RTC CTRL Reg = 0x%02x\n", data);
14006776c89SVenkat Prashanth B U 
14106776c89SVenkat Prashanth B U 	max6916_read_reg(&spi->dev, MAX6916_STATUS_REG, &data);
14206776c89SVenkat Prashanth B U 	dev_info(&spi->dev, "MAX6916 RTC Status Reg = 0x%02x\n", data);
14306776c89SVenkat Prashanth B U 
14406776c89SVenkat Prashanth B U 	rtc = devm_rtc_device_register(&spi->dev, "max6916",
14506776c89SVenkat Prashanth B U 				       &max6916_rtc_ops, THIS_MODULE);
14606776c89SVenkat Prashanth B U 	if (IS_ERR(rtc))
14706776c89SVenkat Prashanth B U 		return PTR_ERR(rtc);
14806776c89SVenkat Prashanth B U 
14906776c89SVenkat Prashanth B U 	spi_set_drvdata(spi, rtc);
15006776c89SVenkat Prashanth B U 
15106776c89SVenkat Prashanth B U 	return 0;
15206776c89SVenkat Prashanth B U }
15306776c89SVenkat Prashanth B U 
15406776c89SVenkat Prashanth B U static struct spi_driver max6916_driver = {
15506776c89SVenkat Prashanth B U 	.driver = {
15606776c89SVenkat Prashanth B U 		.name = "max6916",
15706776c89SVenkat Prashanth B U 	},
15806776c89SVenkat Prashanth B U 	.probe = max6916_probe,
15906776c89SVenkat Prashanth B U };
16006776c89SVenkat Prashanth B U module_spi_driver(max6916_driver);
16106776c89SVenkat Prashanth B U 
16206776c89SVenkat Prashanth B U MODULE_DESCRIPTION("MAX6916 SPI RTC DRIVER");
16306776c89SVenkat Prashanth B U MODULE_AUTHOR("Venkat Prashanth B U <venkat.prashanth2498@gmail.com>");
16406776c89SVenkat Prashanth B U MODULE_LICENSE("GPL v2");
165