RTC for 4.6

Core:
  - New sysfs interface to set and read clock offset
  - Drivers can now be both I2C and SPI (see pcf2127 and ds3232)
 
 New drivers:
  - Alphascale ASM9260
  - Epson RX6110SA
  - Maxim max20024 and max77620 (in max77686)
  - Microchip PIC32
  - NXP pcf2129 (in pcf2127)
 
 Subsystem wide cleanups:
  - remove IRQF_EARLY_RESUME when unecessary
 
 Drivers:
  - ds1307: clock output, temperature sensor and wakeup-source support
  - ds1685: actually spin forever in poweroff error path
  - ds3232: many cleanups
  - ds3234: merged in ds3232
  - hym8563: fix invalid year calculation
  - max77686: many cleanups
  - max77802 merged in max77686
  - pcf2123: cleanups and offset support
  - pcf85063: cleanups
  - pcf8523: propely handle oscillator stop bit
  - rv3029: many cleanups, trickle charger and temperature sensor support
  - rv8803: convert spin_lock to mutex_lock
  - rx8025: many fixes
  - vr41xx: restore alarm_irq_enable
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABCAAGBQJW5uWTAAoJEKbNnwlvZCyzUmAP/3/bxOtQ9QUq4nLIVb/dR9G0
 yNY5L/RmgQ/x3CJqMkGQImyj4rSEmwdHJSWakv/hGh5iTINtZrw4sl79YKNoTQlB
 LaXAse1sXzhyfLzH8jYrrzpq14z1kv/LlUPtgFf1arcaRMdjw1kabdIqHnsv0nH2
 fvyj3O0qW/KWWYongViiXW94dr8uQXoMVR4M/M8OmG6j6Lw1Kd7gKDZx02dqbo8+
 NNQQYAswSxzHCZirIv5Xyjdrz1gIuaWghEdbaVY6BW+CuT8NcC2if1BoYo6xR/Qe
 KC6M5MGY4xogOxP8+EkH1/GycXx1mwrisJSTxJh9YKMDnLgi9YnTjXnO4t9kQyoK
 HOspgaHhGHRONNc2dADJqm55SbLUKBEXVTk/Tzq6BJvTKmZmrisAUhWxISLscHwP
 QPU//fLxyerC/tMKoFyuG7yDtd5VofWThLQV8sF0wcX8AKfLaUIEnN69euCk9mVj
 +eCwkYyOly0UeYdeXkrnHczIFffzMTENpz9Q8TkrLF1UOMI7nCOb/jCo6hKidEEB
 ymgHHzhhGeppfEQgU+MsXOxG0E9Ku4gXGOaVk/q7zxyiBhXOmMpoHk6nshKq0A0S
 eBKmd0BWS0GwXJ+dABfHuI6MSay3A7Bn+fLLoD8LTPMJEONyvOGxDNSH3DymD9JR
 LpDO4HnalG1ao+eXcD+U
 =+x1Q
 -----END PGP SIGNATURE-----

Merge tag 'rtc-4.6' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux

Pull RTC updates from Alexandre Belloni:
 "Core:
   - New sysfs interface to set and read clock offset
   - Drivers can now be both I2C and SPI (see pcf2127 and ds3232)

  New drivers:
   - Alphascale ASM9260
   - Epson RX6110SA
   - Maxim max20024 and max77620 (in max77686)
   - Microchip PIC32
   - NXP pcf2129 (in pcf2127)

  Subsystem wide cleanups:
   - remove IRQF_EARLY_RESUME when unecessary

  Drivers:
   - ds1307: clock output, temperature sensor and wakeup-source support
   - ds1685: actually spin forever in poweroff error path
   - ds3232: many cleanups
   - ds3234: merged in ds3232
   - hym8563: fix invalid year calculation
   - max77686: many cleanups
   - max77802 merged in max77686
   - pcf2123: cleanups and offset support
   - pcf85063: cleanups
   - pcf8523: propely handle oscillator stop bit
   - rv3029: many cleanups, trickle charger and temperature sensor support
   - rv8803: convert spin_lock to mutex_lock
   - rx8025: many fixes
   - vr41xx: restore alarm_irq_enable"

* tag 'rtc-4.6' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (86 commits)
  rtc: pcf2127: add pcf2129 device id
  rtc: pcf2127: add support for spi interface
  rtc: pcf2127: convert to use regmap
  rtc: rv3029: Add thermometer hwmon support
  rtc: rv3029: Add update_bits helper for eeprom access
  rtc: ds1685: actually spin forever in poweroff error path
  rtc: hym8563: fix invalid year calculation
  rtc: ds3232: use rtc->ops_lock to protect alarm operations
  rtc: ds3232: fix issue when irq is shared several devices
  rtc: ds3232: remove unused UIE code
  rtc: ds3232: add register access error checks
  rtc: ds3232: fix read on /dev/rtc after RTC_AIE_ON
  rtc: merge ds3232 and ds3234
  rtc: ds3232: convert to use regmap
  rtc: pxa: fix Kconfig indentation
  rtc: rv3029: Add device tree property for trickle charger
  rtc: rv3029: Add functions for EEPROM access
  rtc: rv3029: Add i2c register update-bits helper
  rtc: rv3029: Add missing register definitions
  rtc: rv3029: Add "rv3029" I2C device id
  ...
This commit is contained in:
Linus Torvalds 2016-03-15 21:58:58 -07:00
commit 13f6f62f61
40 changed files with 3855 additions and 1654 deletions

View File

@ -0,0 +1,19 @@
* Alphascale asm9260 SoC Real Time Clock
Required properties:
- compatible: Should be "alphascale,asm9260-rtc"
- reg: Physical base address of the controller and length
of memory mapped region.
- interrupts: IRQ line for the RTC.
- clocks: Reference to the clock entry.
- clock-names: should contain:
* "ahb" for the SoC RTC clock
Example:
rtc0: rtc@800a0000 {
compatible = "alphascale,asm9260-rtc";
reg = <0x800a0000 0x100>;
clocks = <&acc CLKID_AHB_RTC>;
clock-names = "ahb";
interrupts = <2>;
};

View File

@ -0,0 +1,39 @@
Epson RX6110 Real Time Clock
============================
The Epson RX6110 can be used with SPI or I2C busses. The kind of
bus depends on the SPISEL pin and can not be configured via software.
I2C mode
--------
Required properties:
- compatible: should be: "epson,rx6110"
- reg : the I2C address of the device for I2C
Example:
rtc: rtc@32 {
compatible = "epson,rx6110"
reg = <0x32>;
};
SPI mode
--------
Required properties:
- compatible: should be: "epson,rx6110"
- reg: chip select number
- spi-cs-high: RX6110 needs chipselect high
- spi-cpha: RX6110 works with SPI shifted clock phase
- spi-cpol: RX6110 works with SPI inverse clock polarity
Example:
rtc: rtc@3 {
compatible = "epson,rx6110"
reg = <3>
spi-cs-high;
spi-cpha;
spi-cpol;
};

View File

@ -0,0 +1,37 @@
* Maxim DS3231 Real Time Clock
Required properties:
see: Documentation/devicetree/bindings/i2c/trivial-devices.txt
Optional property:
- #clock-cells: Should be 1.
- clock-output-names:
overwrite the default clock names "ds3231_clk_sqw" and "ds3231_clk_32khz".
Each clock is assigned an identifier and client nodes can use this identifier
to specify the clock which they consume. Following indices are allowed:
- 0: square-wave output on the SQW pin
- 1: square-wave output on the 32kHz pin
- interrupts: rtc alarm/event interrupt. When this property is selected,
clock on the SQW pin cannot be used.
Example:
ds3231: ds3231@51 {
compatible = "maxim,ds3231";
reg = <0x68>;
#clock-cells = <1>;
};
device1 {
...
clocks = <&ds3231 0>;
...
};
device2 {
...
clocks = <&ds3231 1>;
...
};

View File

@ -0,0 +1,21 @@
* Microchip PIC32 Real Time Clock and Calendar
The RTCC keeps time in hours, minutes, and seconds, and one half second. It
provides a calendar in weekday, date, month, and year. It also provides a
configurable alarm.
Required properties:
- compatible: should be: "microchip,pic32mzda-rtc"
- reg: physical base address of the controller and length of memory mapped
region.
- interrupts: RTC alarm/event interrupt
- clocks: clock phandle
Example:
rtc: rtc@1f8c0000 {
compatible = "microchip,pic32mzda-rtc";
reg = <0x1f8c0000 0x60>;
interrupts = <166 IRQ_TYPE_EDGE_RISING>;
clocks = <&PBCLK6>;
};

View File

@ -157,6 +157,12 @@ wakealarm: The time at which the clock will generate a system wakeup
the epoch by default, or if there's a leading +, seconds in the
future, or if there is a leading +=, seconds ahead of the current
alarm.
offset: The amount which the rtc clock has been adjusted in firmware.
Visible only if the driver supports clock offset adjustment.
The unit is parts per billion, i.e. The number of clock ticks
which are added to or removed from the rtc's base clock per
billion ticks. A positive value makes a day pass more slowly,
longer, and a negative value makes a day pass more quickly.
IOCTL INTERFACE
---------------

View File

@ -35,8 +35,6 @@
#include <linux/err.h>
#include <linux/of.h>
#define I2C_ADDR_RTC (0x0C >> 1)
static const struct mfd_cell max77686_devs[] = {
{ .name = "max77686-pmic", },
{ .name = "max77686-rtc", },
@ -116,11 +114,6 @@ static const struct regmap_config max77686_regmap_config = {
.val_bits = 8,
};
static const struct regmap_config max77686_rtc_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
static const struct regmap_config max77802_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
@ -156,25 +149,6 @@ static const struct regmap_irq_chip max77686_irq_chip = {
.num_irqs = ARRAY_SIZE(max77686_irqs),
};
static const struct regmap_irq max77686_rtc_irqs[] = {
/* RTC interrupts */
{ .reg_offset = 0, .mask = MAX77686_RTCINT_RTC60S_MSK, },
{ .reg_offset = 0, .mask = MAX77686_RTCINT_RTCA1_MSK, },
{ .reg_offset = 0, .mask = MAX77686_RTCINT_RTCA2_MSK, },
{ .reg_offset = 0, .mask = MAX77686_RTCINT_SMPL_MSK, },
{ .reg_offset = 0, .mask = MAX77686_RTCINT_RTC1S_MSK, },
{ .reg_offset = 0, .mask = MAX77686_RTCINT_WTSR_MSK, },
};
static const struct regmap_irq_chip max77686_rtc_irq_chip = {
.name = "max77686-rtc",
.status_base = MAX77686_RTC_INT,
.mask_base = MAX77686_RTC_INTM,
.num_regs = 1,
.irqs = max77686_rtc_irqs,
.num_irqs = ARRAY_SIZE(max77686_rtc_irqs),
};
static const struct regmap_irq_chip max77802_irq_chip = {
.name = "max77802-pmic",
.status_base = MAX77802_REG_INT1,
@ -184,15 +158,6 @@ static const struct regmap_irq_chip max77802_irq_chip = {
.num_irqs = ARRAY_SIZE(max77686_irqs),
};
static const struct regmap_irq_chip max77802_rtc_irq_chip = {
.name = "max77802-rtc",
.status_base = MAX77802_RTC_INT,
.mask_base = MAX77802_RTC_INTM,
.num_regs = 1,
.irqs = max77686_rtc_irqs, /* same masks as 77686 */
.num_irqs = ARRAY_SIZE(max77686_rtc_irqs),
};
static const struct of_device_id max77686_pmic_dt_match[] = {
{
.compatible = "maxim,max77686",
@ -214,8 +179,6 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
int ret = 0;
const struct regmap_config *config;
const struct regmap_irq_chip *irq_chip;
const struct regmap_irq_chip *rtc_irq_chip;
struct regmap **rtc_regmap;
const struct mfd_cell *cells;
int n_devs;
@ -242,15 +205,11 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
if (max77686->type == TYPE_MAX77686) {
config = &max77686_regmap_config;
irq_chip = &max77686_irq_chip;
rtc_irq_chip = &max77686_rtc_irq_chip;
rtc_regmap = &max77686->rtc_regmap;
cells = max77686_devs;
n_devs = ARRAY_SIZE(max77686_devs);
} else {
config = &max77802_regmap_config;
irq_chip = &max77802_irq_chip;
rtc_irq_chip = &max77802_rtc_irq_chip;
rtc_regmap = &max77686->regmap;
cells = max77802_devs;
n_devs = ARRAY_SIZE(max77802_devs);
}
@ -270,60 +229,25 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
return -ENODEV;
}
if (max77686->type == TYPE_MAX77686) {
max77686->rtc = i2c_new_dummy(i2c->adapter, I2C_ADDR_RTC);
if (!max77686->rtc) {
dev_err(max77686->dev,
"Failed to allocate I2C device for RTC\n");
return -ENODEV;
}
i2c_set_clientdata(max77686->rtc, max77686);
max77686->rtc_regmap =
devm_regmap_init_i2c(max77686->rtc,
&max77686_rtc_regmap_config);
if (IS_ERR(max77686->rtc_regmap)) {
ret = PTR_ERR(max77686->rtc_regmap);
dev_err(max77686->dev,
"failed to allocate RTC regmap: %d\n",
ret);
goto err_unregister_i2c;
}
}
ret = regmap_add_irq_chip(max77686->regmap, max77686->irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT |
IRQF_SHARED, 0, irq_chip,
&max77686->irq_data);
if (ret) {
if (ret < 0) {
dev_err(&i2c->dev, "failed to add PMIC irq chip: %d\n", ret);
goto err_unregister_i2c;
}
ret = regmap_add_irq_chip(*rtc_regmap, max77686->irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT |
IRQF_SHARED, 0, rtc_irq_chip,
&max77686->rtc_irq_data);
if (ret) {
dev_err(&i2c->dev, "failed to add RTC irq chip: %d\n", ret);
goto err_del_irqc;
return ret;
}
ret = mfd_add_devices(max77686->dev, -1, cells, n_devs, NULL, 0, NULL);
if (ret < 0) {
dev_err(&i2c->dev, "failed to add MFD devices: %d\n", ret);
goto err_del_rtc_irqc;
goto err_del_irqc;
}
return 0;
err_del_rtc_irqc:
regmap_del_irq_chip(max77686->irq, max77686->rtc_irq_data);
err_del_irqc:
regmap_del_irq_chip(max77686->irq, max77686->irq_data);
err_unregister_i2c:
if (max77686->type == TYPE_MAX77686)
i2c_unregister_device(max77686->rtc);
return ret;
}
@ -334,12 +258,8 @@ static int max77686_i2c_remove(struct i2c_client *i2c)
mfd_remove_devices(max77686->dev);
regmap_del_irq_chip(max77686->irq, max77686->rtc_irq_data);
regmap_del_irq_chip(max77686->irq, max77686->irq_data);
if (max77686->type == TYPE_MAX77686)
i2c_unregister_device(max77686->rtc);
return 0;
}

View File

@ -140,7 +140,6 @@ config RTC_DRV_TEST
will be called rtc-test.
comment "I2C RTC drivers"
depends on I2C
if I2C
@ -212,6 +211,15 @@ config RTC_DRV_DS1307
This driver can also be built as a module. If so, the module
will be called rtc-ds1307.
config RTC_DRV_DS1307_HWMON
bool "HWMON support for rtc-ds1307"
depends on RTC_DRV_DS1307 && HWMON
depends on !(RTC_DRV_DS1307=y && HWMON=m)
default y
help
Say Y here if you want to expose temperature sensor data on
rtc-ds1307 (only DS3231)
config RTC_DRV_DS1374
tristate "Dallas/Maxim DS1374"
help
@ -239,16 +247,6 @@ config RTC_DRV_DS1672
This driver can also be built as a module. If so, the module
will be called rtc-ds1672.
config RTC_DRV_DS3232
tristate "Dallas/Maxim DS3232"
help
If you say yes here you get support for Dallas Semiconductor
DS3232 real-time clock chips. If an interrupt is associated
with the device, the alarm functionality is supported.
This driver can also be built as a module. If so, the module
will be called rtc-ds3232.
config RTC_DRV_HYM8563
tristate "Haoyu Microelectronics HYM8563"
depends on OF
@ -317,10 +315,10 @@ config RTC_DRV_MAX8997
config RTC_DRV_MAX77686
tristate "Maxim MAX77686"
depends on MFD_MAX77686
depends on MFD_MAX77686 || MFD_MAX77620
help
If you say yes here you will get support for the
RTC of Maxim MAX77686 PMIC.
RTC of Maxim MAX77686/MAX77620/MAX77802 PMIC.
This driver can also be built as a module. If so, the module
will be called rtc-max77686.
@ -335,16 +333,6 @@ config RTC_DRV_RK808
This driver can also be built as a module. If so, the module
will be called rk808-rtc.
config RTC_DRV_MAX77802
tristate "Maxim 77802 RTC"
depends on MFD_MAX77686
help
If you say yes here you will get support for the
RTC of Maxim MAX77802 PMIC.
This driver can also be built as a module. If so, the module
will be called rtc-max77802.
config RTC_DRV_RS5C372
tristate "Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A"
help
@ -391,25 +379,6 @@ config RTC_DRV_X1205
This driver can also be built as a module. If so, the module
will be called rtc-x1205.
config RTC_DRV_PALMAS
tristate "TI Palmas RTC driver"
depends on MFD_PALMAS
help
If you say yes here you get support for the RTC of TI PALMA series PMIC
chips.
This driver can also be built as a module. If so, the module
will be called rtc-palma.
config RTC_DRV_PCF2127
tristate "NXP PCF2127"
help
If you say yes here you get support for the NXP PCF2127/29 RTC
chips.
This driver can also be built as a module. If so, the module
will be called rtc-pcf2127.
config RTC_DRV_PCF8523
tristate "NXP PCF8523"
help
@ -419,6 +388,14 @@ config RTC_DRV_PCF8523
This driver can also be built as a module. If so, the module
will be called rtc-pcf8523.
config RTC_DRV_PCF85063
tristate "NXP PCF85063"
help
If you say yes here you get support for the PCF85063 RTC chip
This driver can also be built as a module. If so, the module
will be called rtc-pcf85063.
config RTC_DRV_PCF8563
tristate "Philips PCF8563/Epson RTC8564"
help
@ -429,14 +406,6 @@ config RTC_DRV_PCF8563
This driver can also be built as a module. If so, the module
will be called rtc-pcf8563.
config RTC_DRV_PCF85063
tristate "nxp PCF85063"
help
If you say yes here you get support for the PCF85063 RTC chip
This driver can also be built as a module. If so, the module
will be called rtc-pcf85063.
config RTC_DRV_PCF8583
tristate "Philips PCF8583"
help
@ -501,6 +470,16 @@ config RTC_DRV_TWL4030
This driver can also be built as a module. If so, the module
will be called rtc-twl.
config RTC_DRV_PALMAS
tristate "TI Palmas RTC driver"
depends on MFD_PALMAS
help
If you say yes here you get support for the RTC of TI PALMA series PMIC
chips.
This driver can also be built as a module. If so, the module
will be called rtc-palma.
config RTC_DRV_TPS6586X
tristate "TI TPS6586X RTC driver"
depends on MFD_TPS6586X
@ -595,14 +574,23 @@ config RTC_DRV_EM3027
will be called rtc-em3027.
config RTC_DRV_RV3029C2
tristate "Micro Crystal RTC"
tristate "Micro Crystal RV3029"
help
If you say yes here you get support for the Micro Crystal
RV3029-C2 RTC chips.
RV3029 RTC chips.
This driver can also be built as a module. If so, the module
will be called rtc-rv3029c2.
config RTC_DRV_RV3029_HWMON
bool "HWMON support for RV3029"
depends on RTC_DRV_RV3029C2 && HWMON
depends on !(RTC_DRV_RV3029C2=y && HWMON=m)
default y
help
Say Y here if you want to expose temperature sensor data on
rtc-rv3029c2.
config RTC_DRV_RV8803
tristate "Micro Crystal RV8803"
help
@ -691,15 +679,6 @@ config RTC_DRV_DS1390
This driver can also be built as a module. If so, the module
will be called rtc-ds1390.
config RTC_DRV_MAX6902
tristate "Maxim MAX6902"
help
If you say yes here you will get support for the
Maxim MAX6902 SPI RTC chip.
This driver can also be built as a module. If so, the module
will be called rtc-max6902.
config RTC_DRV_R9701
tristate "Epson RTC-9701JE"
help
@ -709,6 +688,23 @@ config RTC_DRV_R9701
This driver can also be built as a module. If so, the module
will be called rtc-r9701.
config RTC_DRV_RX4581
tristate "Epson RX-4581"
help
If you say yes here you will get support for the Epson RX-4581.
This driver can also be built as a module. If so the module
will be called rtc-rx4581.
config RTC_DRV_RX6110
tristate "Epson RX-6110"
select REGMAP_SPI
help
If you say yes here you will get support for the Epson RX-6610.
This driver can also be built as a module. If so the module
will be called rtc-rx6110.
config RTC_DRV_RS5C348
tristate "Ricoh RS5C348A/B"
help
@ -718,14 +714,14 @@ config RTC_DRV_RS5C348
This driver can also be built as a module. If so, the module
will be called rtc-rs5c348.
config RTC_DRV_DS3234
tristate "Maxim/Dallas DS3234"
config RTC_DRV_MAX6902
tristate "Maxim MAX6902"
help
If you say yes here you get support for the
Maxim/Dallas DS3234 SPI RTC chip.
If you say yes here you will get support for the
Maxim MAX6902 SPI RTC chip.
This driver can also be built as a module. If so, the module
will be called rtc-ds3234.
will be called rtc-max6902.
config RTC_DRV_PCF2123
tristate "NXP PCF2123"
@ -736,14 +732,6 @@ config RTC_DRV_PCF2123
This driver can also be built as a module. If so, the module
will be called rtc-pcf2123.
config RTC_DRV_RX4581
tristate "Epson RX-4581"
help
If you say yes here you will get support for the Epson RX-4581.
This driver can also be built as a module. If so the module
will be called rtc-rx4581.
config RTC_DRV_MCP795
tristate "Microchip MCP795"
help
@ -754,6 +742,41 @@ config RTC_DRV_MCP795
endif # SPI_MASTER
#
# Helper to resolve issues with configs that have SPI enabled but I2C
# modular. See SND_SOC_I2C_AND_SPI for more information
#
config RTC_I2C_AND_SPI
tristate
default m if I2C=m
default y if I2C=y
default y if SPI_MASTER=y
select REGMAP_I2C if I2C
select REGMAP_SPI if SPI_MASTER
comment "SPI and I2C RTC drivers"
config RTC_DRV_DS3232
tristate "Dallas/Maxim DS3232/DS3234"
depends on RTC_I2C_AND_SPI
help
If you say yes here you get support for Dallas Semiconductor
DS3232 and DS3234 real-time clock chips. If an interrupt is associated
with the device, the alarm functionality is supported.
This driver can also be built as a module. If so, the module
will be called rtc-ds3232.
config RTC_DRV_PCF2127
tristate "NXP PCF2127"
depends on RTC_I2C_AND_SPI
help
If you say yes here you get support for the NXP PCF2127/29 RTC
chips.
This driver can also be built as a module. If so, the module
will be called rtc-pcf2127.
comment "Platform RTC drivers"
# this 'CMOS' RTC driver is arch dependent because <asm-generic/rtc.h>
@ -1087,7 +1110,7 @@ config RTC_DRV_WM8350
config RTC_DRV_SPEAR
tristate "SPEAR ST RTC"
depends on PLAT_SPEAR
depends on PLAT_SPEAR || COMPILE_TEST
default y
help
If you say Y here you will get support for the RTC found on
@ -1119,7 +1142,7 @@ config RTC_DRV_AB8500
config RTC_DRV_NUC900
tristate "NUC910/NUC920 RTC driver"
depends on ARCH_W90X900
depends on ARCH_W90X900 || COMPILE_TEST
help
If you say yes here you get support for the RTC subsystem of the
NUC910/NUC920 used in embedded systems.
@ -1144,9 +1167,19 @@ config RTC_DRV_ZYNQMP
comment "on-CPU RTC drivers"
config RTC_DRV_ASM9260
tristate "Alphascale asm9260 RTC"
depends on MACH_ASM9260
help
If you say yes here you get support for the RTC on the
Alphascale asm9260 SoC.
This driver can also be built as a module. If so, the module
will be called rtc-asm9260.
config RTC_DRV_DAVINCI
tristate "TI DaVinci RTC"
depends on ARCH_DAVINCI_DM365
depends on ARCH_DAVINCI_DM365 || COMPILE_TEST
help
If you say yes here you get support for the RTC on the
DaVinci platforms (DM365).
@ -1156,7 +1189,7 @@ config RTC_DRV_DAVINCI
config RTC_DRV_DIGICOLOR
tristate "Conexant Digicolor RTC"
depends on ARCH_DIGICOLOR
depends on ARCH_DIGICOLOR || COMPILE_TEST
help
If you say yes here you get support for the RTC on Conexant
Digicolor platforms. This currently includes the CX92755 SoC.
@ -1175,7 +1208,7 @@ config RTC_DRV_IMXDI
config RTC_DRV_OMAP
tristate "TI OMAP Real Time Clock"
depends on ARCH_OMAP || ARCH_DAVINCI
depends on ARCH_OMAP || ARCH_DAVINCI || COMPILE_TEST
help
Say "yes" here to support the on chip real time clock
present on TI OMAP1, AM33xx, DA8xx/OMAP-L13x, AM43xx and DRA7xx.
@ -1192,7 +1225,7 @@ config HAVE_S3C_RTC
config RTC_DRV_S3C
tristate "Samsung S3C series SoC RTC"
depends on ARCH_S3C64XX || HAVE_S3C_RTC
depends on ARCH_S3C64XX || HAVE_S3C_RTC || COMPILE_TEST
help
RTC (Realtime Clock) driver for the clock inbuilt into the
Samsung S3C24XX series of SoCs. This can provide periodic
@ -1208,7 +1241,7 @@ config RTC_DRV_S3C
config RTC_DRV_EP93XX
tristate "Cirrus Logic EP93XX"
depends on ARCH_EP93XX
depends on ARCH_EP93XX || COMPILE_TEST
help
If you say yes here you get support for the
RTC embedded in the Cirrus Logic EP93XX processors.
@ -1238,7 +1271,7 @@ config RTC_DRV_SH
config RTC_DRV_VR41XX
tristate "NEC VR41XX"
depends on CPU_VR41XX
depends on CPU_VR41XX || COMPILE_TEST
help
If you say Y here you will get access to the real time clock
built into your NEC VR41XX CPU.
@ -1268,14 +1301,14 @@ config RTC_DRV_PL031
config RTC_DRV_AT32AP700X
tristate "AT32AP700X series RTC"
depends on PLATFORM_AT32AP
depends on PLATFORM_AT32AP || COMPILE_TEST
help
Driver for the internal RTC (Realtime Clock) on Atmel AVR32
AT32AP700x family processors.
config RTC_DRV_AT91RM9200
tristate "AT91RM9200 or some AT91SAM9 RTC"
depends on ARCH_AT91
depends on ARCH_AT91 || COMPILE_TEST
help
Driver for the internal RTC (Realtime Clock) module found on
Atmel AT91RM9200's and some AT91SAM9 chips. On AT91SAM9 chips
@ -1283,7 +1316,7 @@ config RTC_DRV_AT91RM9200
config RTC_DRV_AT91SAM9
tristate "AT91SAM9 RTT as RTC"
depends on ARCH_AT91
depends on ARCH_AT91 || COMPILE_TEST
select MFD_SYSCON
help
Some AT91SAM9 SoCs provide an RTT (Real Time Timer) block which
@ -1325,17 +1358,17 @@ config RTC_DRV_GENERIC
tristate "Generic RTC support"
# Please consider writing a new RTC driver instead of using the generic
# RTC abstraction
depends on PARISC || M68K || PPC || SUPERH32
depends on PARISC || M68K || PPC || SUPERH32 || COMPILE_TEST
help
Say Y or M here to enable RTC support on systems using the generic
RTC abstraction. If you do not know what you are doing, you should
just say Y.
config RTC_DRV_PXA
tristate "PXA27x/PXA3xx"
depends on ARCH_PXA
select RTC_DRV_SA1100
help
tristate "PXA27x/PXA3xx"
depends on ARCH_PXA
select RTC_DRV_SA1100
help
If you say Y here you will get access to the real time clock
built into your PXA27x or PXA3xx CPU. This RTC is actually 2 RTCs
consisting of an SA1100 compatible RTC and the extended PXA RTC.
@ -1345,7 +1378,7 @@ config RTC_DRV_PXA
config RTC_DRV_VT8500
tristate "VIA/WonderMedia 85xx SoC RTC"
depends on ARCH_VT8500
depends on ARCH_VT8500 || COMPILE_TEST
help
If you say Y here you will get access to the real time clock
built into your VIA VT8500 SoC or its relatives.
@ -1360,14 +1393,15 @@ config RTC_DRV_SUN4V
config RTC_DRV_SUN6I
tristate "Allwinner A31 RTC"
depends on MACH_SUN6I || MACH_SUN8I
default MACH_SUN6I || MACH_SUN8I || COMPILE_TEST
depends on ARCH_SUNXI
help
If you say Y here you will get support for the RTC found on
Allwinner A31.
If you say Y here you will get support for the RTC found in
some Allwinner SoCs like the A31 or the A64.
config RTC_DRV_SUNXI
tristate "Allwinner sun4i/sun7i RTC"
depends on MACH_SUN4I || MACH_SUN7I
depends on MACH_SUN4I || MACH_SUN7I || COMPILE_TEST
help
If you say Y here you will get support for the RTC found on
Allwinner A10/A20.
@ -1388,7 +1422,7 @@ config RTC_DRV_TX4939
config RTC_DRV_MV
tristate "Marvell SoC RTC"
depends on ARCH_DOVE || ARCH_MVEBU
depends on ARCH_DOVE || ARCH_MVEBU || COMPILE_TEST
help
If you say yes here you will get support for the in-chip RTC
that can be found in some of Marvell's SoC devices, such as
@ -1399,7 +1433,7 @@ config RTC_DRV_MV
config RTC_DRV_ARMADA38X
tristate "Armada 38x Marvell SoC RTC"
depends on ARCH_MVEBU
depends on ARCH_MVEBU || COMPILE_TEST
help
If you say yes here you will get support for the in-chip RTC
that can be found in the Armada 38x Marvell's SoC device
@ -1429,7 +1463,7 @@ config RTC_DRV_PS3
config RTC_DRV_COH901331
tristate "ST-Ericsson COH 901 331 RTC"
depends on ARCH_U300
depends on ARCH_U300 || COMPILE_TEST
help
If you say Y here you will get access to ST-Ericsson
COH 901 331 RTC clock found in some ST-Ericsson Mobile
@ -1441,7 +1475,7 @@ config RTC_DRV_COH901331
config RTC_DRV_STMP
tristate "Freescale STMP3xxx/i.MX23/i.MX28 RTC"
depends on ARCH_MXS
depends on ARCH_MXS || COMPILE_TEST
select STMP_DEVICE
help
If you say yes here you will get support for the onboard
@ -1476,7 +1510,7 @@ config RTC_DRV_MPC5121
config RTC_DRV_JZ4740
tristate "Ingenic JZ4740 SoC"
depends on MACH_JZ4740
depends on MACH_JZ4740 || COMPILE_TEST
help
If you say yes here you get support for the Ingenic JZ4740 SoC RTC
controller.
@ -1497,7 +1531,7 @@ config RTC_DRV_LPC24XX
so, the module will be called rtc-lpc24xx.
config RTC_DRV_LPC32XX
depends on ARCH_LPC32XX
depends on ARCH_LPC32XX || COMPILE_TEST
tristate "NXP LPC32XX RTC"
help
This enables support for the NXP RTC in the LPC32XX
@ -1507,7 +1541,7 @@ config RTC_DRV_LPC32XX
config RTC_DRV_PM8XXX
tristate "Qualcomm PMIC8XXX RTC"
depends on MFD_PM8XXX || MFD_SPMI_PMIC
depends on MFD_PM8XXX || MFD_SPMI_PMIC || COMPILE_TEST
help
If you say yes here you get support for the
Qualcomm PMIC8XXX RTC.
@ -1517,7 +1551,7 @@ config RTC_DRV_PM8XXX
config RTC_DRV_TEGRA
tristate "NVIDIA Tegra Internal RTC driver"
depends on ARCH_TEGRA
depends on ARCH_TEGRA || COMPILE_TEST
help
If you say yes here you get support for the
Tegra 200 series internal RTC module.
@ -1603,7 +1637,7 @@ config RTC_DRV_MOXART
config RTC_DRV_MT6397
tristate "Mediatek Real Time Clock driver"
depends on MFD_MT6397 || COMPILE_TEST
depends on MFD_MT6397 || (COMPILE_TEST && IRQ_DOMAIN)
help
This selects the Mediatek(R) RTC driver. RTC is part of Mediatek
MT6397 PMIC. You should enable MT6397 PMIC MFD before select
@ -1622,6 +1656,16 @@ config RTC_DRV_XGENE
This driver can also be built as a module, if so, the module
will be called "rtc-xgene".
config RTC_DRV_PIC32
tristate "Microchip PIC32 RTC"
depends on MACH_PIC32
default y
help
If you say yes here you get support for the PIC32 RTC module.
This driver can also be built as a module. If so, the module
will be called rtc-pic32
comment "HID Sensor RTC drivers"
config RTC_DRV_HID_SENSOR_TIME

View File

@ -28,6 +28,7 @@ obj-$(CONFIG_RTC_DRV_ABB5ZES3) += rtc-ab-b5ze-s3.o
obj-$(CONFIG_RTC_DRV_ABX80X) += rtc-abx80x.o
obj-$(CONFIG_RTC_DRV_ARMADA38X) += rtc-armada38x.o
obj-$(CONFIG_RTC_DRV_AS3722) += rtc-as3722.o
obj-$(CONFIG_RTC_DRV_ASM9260) += rtc-asm9260.o
obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o
obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o
@ -59,7 +60,6 @@ obj-$(CONFIG_RTC_DRV_DS1685_FAMILY) += rtc-ds1685.o
obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o
obj-$(CONFIG_RTC_DRV_DS2404) += rtc-ds2404.o
obj-$(CONFIG_RTC_DRV_DS3232) += rtc-ds3232.o
obj-$(CONFIG_RTC_DRV_DS3234) += rtc-ds3234.o
obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o
obj-$(CONFIG_RTC_DRV_EM3027) += rtc-em3027.o
obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
@ -86,7 +86,6 @@ obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o
obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o
obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o
obj-$(CONFIG_RTC_DRV_MAX77686) += rtc-max77686.o
obj-$(CONFIG_RTC_DRV_MAX77802) += rtc-max77802.o
obj-$(CONFIG_RTC_DRV_MAX8907) += rtc-max8907.o
obj-$(CONFIG_RTC_DRV_MAX8925) += rtc-max8925.o
obj-$(CONFIG_RTC_DRV_MAX8997) += rtc-max8997.o
@ -112,6 +111,7 @@ obj-$(CONFIG_RTC_DRV_PCF85063) += rtc-pcf85063.o
obj-$(CONFIG_RTC_DRV_PCF8523) += rtc-pcf8523.o
obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o
obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o
obj-$(CONFIG_RTC_DRV_PIC32) += rtc-pic32.o
obj-$(CONFIG_RTC_DRV_PL030) += rtc-pl030.o
obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o
obj-$(CONFIG_RTC_DRV_PM8XXX) += rtc-pm8xxx.o
@ -128,6 +128,7 @@ obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o
obj-$(CONFIG_RTC_DRV_RV3029C2) += rtc-rv3029c2.o
obj-$(CONFIG_RTC_DRV_RV8803) += rtc-rv8803.o
obj-$(CONFIG_RTC_DRV_RX4581) += rtc-rx4581.o
obj-$(CONFIG_RTC_DRV_RX6110) += rtc-rx6110.o
obj-$(CONFIG_RTC_DRV_RX8010) += rtc-rx8010.o
obj-$(CONFIG_RTC_DRV_RX8025) += rtc-rx8025.o
obj-$(CONFIG_RTC_DRV_RX8581) += rtc-rx8581.o

View File

@ -361,17 +361,4 @@ static int __init rtc_init(void)
rtc_dev_init();
return 0;
}
static void __exit rtc_exit(void)
{
rtc_dev_exit();
class_destroy(rtc_class);
ida_destroy(&rtc_ida);
}
subsys_initcall(rtc_init);
module_exit(rtc_exit);
MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
MODULE_DESCRIPTION("RTC class support");
MODULE_LICENSE("GPL");

View File

@ -939,4 +939,58 @@ void rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer *timer)
mutex_unlock(&rtc->ops_lock);
}
/**
* rtc_read_offset - Read the amount of rtc offset in parts per billion
* @ rtc: rtc device to be used
* @ offset: the offset in parts per billion
*
* see below for details.
*
* Kernel interface to read rtc clock offset
* Returns 0 on success, or a negative number on error.
* If read_offset() is not implemented for the rtc, return -EINVAL
*/
int rtc_read_offset(struct rtc_device *rtc, long *offset)
{
int ret;
if (!rtc->ops)
return -ENODEV;
if (!rtc->ops->read_offset)
return -EINVAL;
mutex_lock(&rtc->ops_lock);
ret = rtc->ops->read_offset(rtc->dev.parent, offset);
mutex_unlock(&rtc->ops_lock);
return ret;
}
/**
* rtc_set_offset - Adjusts the duration of the average second
* @ rtc: rtc device to be used
* @ offset: the offset in parts per billion
*
* Some rtc's allow an adjustment to the average duration of a second
* to compensate for differences in the actual clock rate due to temperature,
* the crystal, capacitor, etc.
*
* Kernel interface to adjust an rtc clock offset.
* Return 0 on success, or a negative number on error.
* If the rtc offset is not setable (or not implemented), return -EINVAL
*/
int rtc_set_offset(struct rtc_device *rtc, long offset)
{
int ret;
if (!rtc->ops)
return -ENODEV;
if (!rtc->ops->set_offset)
return -EINVAL;
mutex_lock(&rtc->ops_lock);
ret = rtc->ops->set_offset(rtc->dev.parent, offset);
mutex_unlock(&rtc->ops_lock);
return ret;
}

View File

@ -210,7 +210,7 @@ static int as3722_rtc_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "RTC interrupt %d\n", as3722_rtc->alarm_irq);
ret = devm_request_threaded_irq(&pdev->dev, as3722_rtc->alarm_irq, NULL,
as3722_alarm_irq, IRQF_ONESHOT | IRQF_EARLY_RESUME,
as3722_alarm_irq, IRQF_ONESHOT,
"rtc-alarm", as3722_rtc);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n",

355
drivers/rtc/rtc-asm9260.c Normal file
View File

@ -0,0 +1,355 @@
/*
* Copyright (C) 2016 Oleksij Rempel <linux@rempel-privat.de>
*
* 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/clk.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
/* Miscellaneous registers */
/* Interrupt Location Register */
#define HW_ILR 0x00
#define BM_RTCALF BIT(1)
#define BM_RTCCIF BIT(0)
/* Clock Control Register */
#define HW_CCR 0x08
/* Calibration counter disable */
#define BM_CCALOFF BIT(4)
/* Reset internal oscillator divider */
#define BM_CTCRST BIT(1)
/* Clock Enable */
#define BM_CLKEN BIT(0)
/* Counter Increment Interrupt Register */
#define HW_CIIR 0x0C
#define BM_CIIR_IMYEAR BIT(7)
#define BM_CIIR_IMMON BIT(6)
#define BM_CIIR_IMDOY BIT(5)
#define BM_CIIR_IMDOW BIT(4)
#define BM_CIIR_IMDOM BIT(3)
#define BM_CIIR_IMHOUR BIT(2)
#define BM_CIIR_IMMIN BIT(1)
#define BM_CIIR_IMSEC BIT(0)
/* Alarm Mask Register */
#define HW_AMR 0x10
#define BM_AMR_IMYEAR BIT(7)
#define BM_AMR_IMMON BIT(6)
#define BM_AMR_IMDOY BIT(5)
#define BM_AMR_IMDOW BIT(4)
#define BM_AMR_IMDOM BIT(3)
#define BM_AMR_IMHOUR BIT(2)
#define BM_AMR_IMMIN BIT(1)
#define BM_AMR_IMSEC BIT(0)
#define BM_AMR_OFF 0xff
/* Consolidated time registers */
#define HW_CTIME0 0x14
#define BM_CTIME0_DOW_S 24
#define BM_CTIME0_DOW_M 0x7
#define BM_CTIME0_HOUR_S 16
#define BM_CTIME0_HOUR_M 0x1f
#define BM_CTIME0_MIN_S 8
#define BM_CTIME0_MIN_M 0x3f
#define BM_CTIME0_SEC_S 0
#define BM_CTIME0_SEC_M 0x3f
#define HW_CTIME1 0x18
#define BM_CTIME1_YEAR_S 16
#define BM_CTIME1_YEAR_M 0xfff
#define BM_CTIME1_MON_S 8
#define BM_CTIME1_MON_M 0xf
#define BM_CTIME1_DOM_S 0
#define BM_CTIME1_DOM_M 0x1f
#define HW_CTIME2 0x1C
#define BM_CTIME2_DOY_S 0
#define BM_CTIME2_DOY_M 0xfff
/* Time counter registers */
#define HW_SEC 0x20
#define HW_MIN 0x24
#define HW_HOUR 0x28
#define HW_DOM 0x2C
#define HW_DOW 0x30
#define HW_DOY 0x34
#define HW_MONTH 0x38
#define HW_YEAR 0x3C
#define HW_CALIBRATION 0x40
#define BM_CALDIR_BACK BIT(17)
#define BM_CALVAL_M 0x1ffff
/* General purpose registers */
#define HW_GPREG0 0x44
#define HW_GPREG1 0x48
#define HW_GPREG2 0x4C
#define HW_GPREG3 0x50
#define HW_GPREG4 0x54
/* Alarm register group */
#define HW_ALSEC 0x60
#define HW_ALMIN 0x64
#define HW_ALHOUR 0x68
#define HW_ALDOM 0x6C
#define HW_ALDOW 0x70
#define HW_ALDOY 0x74
#define HW_ALMON 0x78
#define HW_ALYEAR 0x7C
struct asm9260_rtc_priv {
struct device *dev;
void __iomem *iobase;
struct rtc_device *rtc;
struct clk *clk;
/* io lock */
spinlock_t lock;
};
static irqreturn_t asm9260_rtc_irq(int irq, void *dev_id)
{
struct asm9260_rtc_priv *priv = dev_id;
u32 isr;
unsigned long events = 0;
isr = ioread32(priv->iobase + HW_CIIR);
if (!isr)
return IRQ_NONE;
iowrite32(0, priv->iobase + HW_CIIR);
events |= RTC_AF | RTC_IRQF;
rtc_update_irq(priv->rtc, 1, events);
return IRQ_HANDLED;
}
static int asm9260_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct asm9260_rtc_priv *priv = dev_get_drvdata(dev);
u32 ctime0, ctime1, ctime2;
unsigned long irq_flags;
spin_lock_irqsave(&priv->lock, irq_flags);
ctime0 = ioread32(priv->iobase + HW_CTIME0);
ctime1 = ioread32(priv->iobase + HW_CTIME1);
ctime2 = ioread32(priv->iobase + HW_CTIME2);
if (ctime1 != ioread32(priv->iobase + HW_CTIME1)) {
/*
* woops, counter flipped right now. Now we are safe
* to reread.
*/
ctime0 = ioread32(priv->iobase + HW_CTIME0);
ctime1 = ioread32(priv->iobase + HW_CTIME1);
ctime2 = ioread32(priv->iobase + HW_CTIME2);
}
spin_unlock_irqrestore(&priv->lock, irq_flags);
tm->tm_sec = (ctime0 >> BM_CTIME0_SEC_S) & BM_CTIME0_SEC_M;
tm->tm_min = (ctime0 >> BM_CTIME0_MIN_S) & BM_CTIME0_MIN_M;
tm->tm_hour = (ctime0 >> BM_CTIME0_HOUR_S) & BM_CTIME0_HOUR_M;
tm->tm_wday = (ctime0 >> BM_CTIME0_DOW_S) & BM_CTIME0_DOW_M;
tm->tm_mday = (ctime1 >> BM_CTIME1_DOM_S) & BM_CTIME1_DOM_M;
tm->tm_mon = (ctime1 >> BM_CTIME1_MON_S) & BM_CTIME1_MON_M;
tm->tm_year = (ctime1 >> BM_CTIME1_YEAR_S) & BM_CTIME1_YEAR_M;
tm->tm_yday = (ctime2 >> BM_CTIME2_DOY_S) & BM_CTIME2_DOY_M;
return 0;
}
static int asm9260_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct asm9260_rtc_priv *priv = dev_get_drvdata(dev);
unsigned long irq_flags;
spin_lock_irqsave(&priv->lock, irq_flags);
/*
* make sure SEC counter will not flip other counter on write time,
* real value will be written at the enf of sequence.
*/
iowrite32(0, priv->iobase + HW_SEC);
iowrite32(tm->tm_year, priv->iobase + HW_YEAR);
iowrite32(tm->tm_mon, priv->iobase + HW_MONTH);
iowrite32(tm->tm_mday, priv->iobase + HW_DOM);
iowrite32(tm->tm_wday, priv->iobase + HW_DOW);
iowrite32(tm->tm_yday, priv->iobase + HW_DOY);
iowrite32(tm->tm_hour, priv->iobase + HW_HOUR);
iowrite32(tm->tm_min, priv->iobase + HW_MIN);
iowrite32(tm->tm_sec, priv->iobase + HW_SEC);
spin_unlock_irqrestore(&priv->lock, irq_flags);
return 0;
}
static int asm9260_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct asm9260_rtc_priv *priv = dev_get_drvdata(dev);
unsigned long irq_flags;
spin_lock_irqsave(&priv->lock, irq_flags);
alrm->time.tm_year = ioread32(priv->iobase + HW_ALYEAR);
alrm->time.tm_mon = ioread32(priv->iobase + HW_ALMON);
alrm->time.tm_mday = ioread32(priv->iobase + HW_ALDOM);
alrm->time.tm_wday = ioread32(priv->iobase + HW_ALDOW);
alrm->time.tm_yday = ioread32(priv->iobase + HW_ALDOY);
alrm->time.tm_hour = ioread32(priv->iobase + HW_ALHOUR);
alrm->time.tm_min = ioread32(priv->iobase + HW_ALMIN);
alrm->time.tm_sec = ioread32(priv->iobase + HW_ALSEC);
alrm->enabled = ioread32(priv->iobase + HW_AMR) ? 1 : 0;
alrm->pending = ioread32(priv->iobase + HW_CIIR) ? 1 : 0;
spin_unlock_irqrestore(&priv->lock, irq_flags);
return rtc_valid_tm(&alrm->time);
}
static int asm9260_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct asm9260_rtc_priv *priv = dev_get_drvdata(dev);
unsigned long irq_flags;
spin_lock_irqsave(&priv->lock, irq_flags);
iowrite32(alrm->time.tm_year, priv->iobase + HW_ALYEAR);
iowrite32(alrm->time.tm_mon, priv->iobase + HW_ALMON);
iowrite32(alrm->time.tm_mday, priv->iobase + HW_ALDOM);
iowrite32(alrm->time.tm_wday, priv->iobase + HW_ALDOW);
iowrite32(alrm->time.tm_yday, priv->iobase + HW_ALDOY);
iowrite32(alrm->time.tm_hour, priv->iobase + HW_ALHOUR);
iowrite32(alrm->time.tm_min, priv->iobase + HW_ALMIN);
iowrite32(alrm->time.tm_sec, priv->iobase + HW_ALSEC);
iowrite32(alrm->enabled ? 0 : BM_AMR_OFF, priv->iobase + HW_AMR);
spin_unlock_irqrestore(&priv->lock, irq_flags);
return 0;
}
static int asm9260_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
struct asm9260_rtc_priv *priv = dev_get_drvdata(dev);
iowrite32(enabled ? 0 : BM_AMR_OFF, priv->iobase + HW_AMR);
return 0;
}
static const struct rtc_class_ops asm9260_rtc_ops = {
.read_time = asm9260_rtc_read_time,
.set_time = asm9260_rtc_set_time,
.read_alarm = asm9260_rtc_read_alarm,
.set_alarm = asm9260_rtc_set_alarm,
.alarm_irq_enable = asm9260_alarm_irq_enable,
};
static int __init asm9260_rtc_probe(struct platform_device *pdev)
{
struct asm9260_rtc_priv *priv;
struct device *dev = &pdev->dev;
struct resource *res;
int irq_alarm, ret;
u32 ccr;
priv = devm_kzalloc(dev, sizeof(struct asm9260_rtc_priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->dev = &pdev->dev;
platform_set_drvdata(pdev, priv);
irq_alarm = platform_get_irq(pdev, 0);
if (irq_alarm < 0) {
dev_err(dev, "No alarm IRQ resource defined\n");
return irq_alarm;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->iobase = devm_ioremap_resource(dev, res);
if (IS_ERR(priv->iobase))
return PTR_ERR(priv->iobase);
priv->clk = devm_clk_get(dev, "ahb");
ret = clk_prepare_enable(priv->clk);
if (ret) {
dev_err(dev, "Failed to enable clk!\n");
return ret;
}
ccr = ioread32(priv->iobase + HW_CCR);
/* if dev is not enabled, reset it */
if ((ccr & (BM_CLKEN | BM_CTCRST)) != BM_CLKEN) {
iowrite32(BM_CTCRST, priv->iobase + HW_CCR);
ccr = 0;
}
iowrite32(BM_CLKEN | ccr, priv->iobase + HW_CCR);
iowrite32(0, priv->iobase + HW_CIIR);
iowrite32(BM_AMR_OFF, priv->iobase + HW_AMR);
priv->rtc = devm_rtc_device_register(dev, dev_name(dev),
&asm9260_rtc_ops, THIS_MODULE);
if (IS_ERR(priv->rtc)) {
ret = PTR_ERR(priv->rtc);
dev_err(dev, "Failed to register RTC device: %d\n", ret);
goto err_return;
}
ret = devm_request_threaded_irq(dev, irq_alarm, NULL,
asm9260_rtc_irq, IRQF_ONESHOT,
dev_name(dev), priv);
if (ret < 0) {
dev_err(dev, "can't get irq %i, err %d\n",
irq_alarm, ret);
goto err_return;
}
return 0;
err_return:
clk_disable_unprepare(priv->clk);
return ret;
}
static int __exit asm9260_rtc_remove(struct platform_device *pdev)
{
struct asm9260_rtc_priv *priv = platform_get_drvdata(pdev);
/* Disable alarm matching */
iowrite32(BM_AMR_OFF, priv->iobase + HW_AMR);
clk_disable_unprepare(priv->clk);
return 0;
}
static const struct of_device_id asm9260_dt_ids[] = {
{ .compatible = "alphascale,asm9260-rtc", },
{}
};
static struct platform_driver asm9260_rtc_driver = {
.probe = asm9260_rtc_probe,
.remove = asm9260_rtc_remove,
.driver = {
.name = "asm9260-rtc",
.owner = THIS_MODULE,
.of_match_table = asm9260_dt_ids,
},
};
module_platform_driver(asm9260_rtc_driver);
MODULE_AUTHOR("Oleksij Rempel <linux@rempel-privat.de>");
MODULE_DESCRIPTION("Alphascale asm9260 SoC Realtime Clock Driver (RTC)");
MODULE_LICENSE("GPL");

View File

@ -532,7 +532,7 @@ ds1305_nvram_read(struct file *filp, struct kobject *kobj,
struct spi_transfer x[2];
int status;
spi = container_of(kobj, struct spi_device, dev.kobj);
spi = to_spi_device(kobj_to_dev(kobj));
addr = DS1305_NVRAM + off;
msg_init(&m, x, &addr, count, NULL, buf);
@ -554,7 +554,7 @@ ds1305_nvram_write(struct file *filp, struct kobject *kobj,
struct spi_transfer x[2];
int status;
spi = container_of(kobj, struct spi_device, dev.kobj);
spi = to_spi_device(kobj_to_dev(kobj));
addr = (DS1305_WRITE | DS1305_NVRAM) + off;
msg_init(&m, x, &addr, count, buf, NULL);

View File

@ -19,6 +19,9 @@
#include <linux/rtc.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/clk-provider.h>
/*
* We can't determine type by probing, but if we expect pre-Linux code
@ -89,6 +92,7 @@ enum ds_type {
# define DS1340_BIT_OSF 0x80
#define DS1337_REG_STATUS 0x0f
# define DS1337_BIT_OSF 0x80
# define DS3231_BIT_EN32KHZ 0x08
# define DS1337_BIT_A2I 0x02
# define DS1337_BIT_A1I 0x01
#define DS1339_REG_ALARM1_SECS 0x07
@ -118,6 +122,9 @@ struct ds1307 {
u8 length, u8 *values);
s32 (*write_block_data)(const struct i2c_client *client, u8 command,
u8 length, const u8 *values);
#ifdef CONFIG_COMMON_CLK
struct clk_hw clks[2];
#endif
};
struct chip_desc {
@ -842,6 +849,378 @@ out:
return;
}
/*----------------------------------------------------------------------*/
#ifdef CONFIG_RTC_DRV_DS1307_HWMON
/*
* Temperature sensor support for ds3231 devices.
*/
#define DS3231_REG_TEMPERATURE 0x11
/*
* A user-initiated temperature conversion is not started by this function,
* so the temperature is updated once every 64 seconds.
*/
static int ds3231_hwmon_read_temp(struct device *dev, s16 *mC)
{
struct ds1307 *ds1307 = dev_get_drvdata(dev);
u8 temp_buf[2];
s16 temp;
int ret;
ret = ds1307->read_block_data(ds1307->client, DS3231_REG_TEMPERATURE,
sizeof(temp_buf), temp_buf);
if (ret < 0)
return ret;
if (ret != sizeof(temp_buf))
return -EIO;
/*
* Temperature is represented as a 10-bit code with a resolution of
* 0.25 degree celsius and encoded in two's complement format.
*/
temp = (temp_buf[0] << 8) | temp_buf[1];
temp >>= 6;
*mC = temp * 250;
return 0;
}
static ssize_t ds3231_hwmon_show_temp(struct device *dev,
struct device_attribute *attr, char *buf)
{
int ret;
s16 temp;
ret = ds3231_hwmon_read_temp(dev, &temp);
if (ret)
return ret;
return sprintf(buf, "%d\n", temp);
}
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, ds3231_hwmon_show_temp,
NULL, 0);
static struct attribute *ds3231_hwmon_attrs[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr,
NULL,
};
ATTRIBUTE_GROUPS(ds3231_hwmon);
static void ds1307_hwmon_register(struct ds1307 *ds1307)
{
struct device *dev;
if (ds1307->type != ds_3231)
return;
dev = devm_hwmon_device_register_with_groups(&ds1307->client->dev,
ds1307->client->name,
ds1307, ds3231_hwmon_groups);
if (IS_ERR(dev)) {
dev_warn(&ds1307->client->dev,
"unable to register hwmon device %ld\n", PTR_ERR(dev));
}
}
#else
static void ds1307_hwmon_register(struct ds1307 *ds1307)
{
}
#endif /* CONFIG_RTC_DRV_DS1307_HWMON */
/*----------------------------------------------------------------------*/
/*
* Square-wave output support for DS3231
* Datasheet: https://datasheets.maximintegrated.com/en/ds/DS3231.pdf
*/
#ifdef CONFIG_COMMON_CLK
enum {
DS3231_CLK_SQW = 0,
DS3231_CLK_32KHZ,
};
#define clk_sqw_to_ds1307(clk) \
container_of(clk, struct ds1307, clks[DS3231_CLK_SQW])
#define clk_32khz_to_ds1307(clk) \
container_of(clk, struct ds1307, clks[DS3231_CLK_32KHZ])
static int ds3231_clk_sqw_rates[] = {
1,
1024,
4096,
8192,
};
static int ds1337_write_control(struct ds1307 *ds1307, u8 mask, u8 value)
{
struct i2c_client *client = ds1307->client;
struct mutex *lock = &ds1307->rtc->ops_lock;
int control;
int ret;
mutex_lock(lock);
control = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);
if (control < 0) {
ret = control;
goto out;
}
control &= ~mask;
control |= value;
ret = i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, control);
out:
mutex_unlock(lock);
return ret;
}
static unsigned long ds3231_clk_sqw_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw);
int control;
int rate_sel = 0;
control = i2c_smbus_read_byte_data(ds1307->client, DS1337_REG_CONTROL);
if (control < 0)
return control;
if (control & DS1337_BIT_RS1)
rate_sel += 1;
if (control & DS1337_BIT_RS2)
rate_sel += 2;
return ds3231_clk_sqw_rates[rate_sel];
}
static long ds3231_clk_sqw_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
int i;
for (i = ARRAY_SIZE(ds3231_clk_sqw_rates) - 1; i >= 0; i--) {
if (ds3231_clk_sqw_rates[i] <= rate)
return ds3231_clk_sqw_rates[i];
}
return 0;
}
static int ds3231_clk_sqw_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw);
int control = 0;
int rate_sel;
for (rate_sel = 0; rate_sel < ARRAY_SIZE(ds3231_clk_sqw_rates);
rate_sel++) {
if (ds3231_clk_sqw_rates[rate_sel] == rate)
break;
}
if (rate_sel == ARRAY_SIZE(ds3231_clk_sqw_rates))
return -EINVAL;
if (rate_sel & 1)
control |= DS1337_BIT_RS1;
if (rate_sel & 2)
control |= DS1337_BIT_RS2;
return ds1337_write_control(ds1307, DS1337_BIT_RS1 | DS1337_BIT_RS2,
control);
}
static int ds3231_clk_sqw_prepare(struct clk_hw *hw)
{
struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw);
return ds1337_write_control(ds1307, DS1337_BIT_INTCN, 0);
}
static void ds3231_clk_sqw_unprepare(struct clk_hw *hw)
{
struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw);
ds1337_write_control(ds1307, DS1337_BIT_INTCN, DS1337_BIT_INTCN);
}
static int ds3231_clk_sqw_is_prepared(struct clk_hw *hw)
{
struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw);
int control;
control = i2c_smbus_read_byte_data(ds1307->client, DS1337_REG_CONTROL);
if (control < 0)
return control;
return !(control & DS1337_BIT_INTCN);
}
static const struct clk_ops ds3231_clk_sqw_ops = {
.prepare = ds3231_clk_sqw_prepare,
.unprepare = ds3231_clk_sqw_unprepare,
.is_prepared = ds3231_clk_sqw_is_prepared,
.recalc_rate = ds3231_clk_sqw_recalc_rate,
.round_rate = ds3231_clk_sqw_round_rate,
.set_rate = ds3231_clk_sqw_set_rate,
};
static unsigned long ds3231_clk_32khz_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
return 32768;
}
static int ds3231_clk_32khz_control(struct ds1307 *ds1307, bool enable)
{
struct i2c_client *client = ds1307->client;
struct mutex *lock = &ds1307->rtc->ops_lock;
int status;
int ret;
mutex_lock(lock);
status = i2c_smbus_read_byte_data(client, DS1337_REG_STATUS);
if (status < 0) {
ret = status;
goto out;
}
if (enable)
status |= DS3231_BIT_EN32KHZ;
else
status &= ~DS3231_BIT_EN32KHZ;
ret = i2c_smbus_write_byte_data(client, DS1337_REG_STATUS, status);
out:
mutex_unlock(lock);
return ret;
}
static int ds3231_clk_32khz_prepare(struct clk_hw *hw)
{
struct ds1307 *ds1307 = clk_32khz_to_ds1307(hw);
return ds3231_clk_32khz_control(ds1307, true);
}
static void ds3231_clk_32khz_unprepare(struct clk_hw *hw)
{
struct ds1307 *ds1307 = clk_32khz_to_ds1307(hw);
ds3231_clk_32khz_control(ds1307, false);
}
static int ds3231_clk_32khz_is_prepared(struct clk_hw *hw)
{
struct ds1307 *ds1307 = clk_32khz_to_ds1307(hw);
int status;
status = i2c_smbus_read_byte_data(ds1307->client, DS1337_REG_STATUS);
if (status < 0)
return status;
return !!(status & DS3231_BIT_EN32KHZ);
}
static const struct clk_ops ds3231_clk_32khz_ops = {
.prepare = ds3231_clk_32khz_prepare,
.unprepare = ds3231_clk_32khz_unprepare,
.is_prepared = ds3231_clk_32khz_is_prepared,
.recalc_rate = ds3231_clk_32khz_recalc_rate,
};
static struct clk_init_data ds3231_clks_init[] = {
[DS3231_CLK_SQW] = {
.name = "ds3231_clk_sqw",
.ops = &ds3231_clk_sqw_ops,
.flags = CLK_IS_ROOT,
},
[DS3231_CLK_32KHZ] = {
.name = "ds3231_clk_32khz",
.ops = &ds3231_clk_32khz_ops,
.flags = CLK_IS_ROOT,
},
};
static int ds3231_clks_register(struct ds1307 *ds1307)
{
struct i2c_client *client = ds1307->client;
struct device_node *node = client->dev.of_node;
struct clk_onecell_data *onecell;
int i;
onecell = devm_kzalloc(&client->dev, sizeof(*onecell), GFP_KERNEL);
if (!onecell)
return -ENOMEM;
onecell->clk_num = ARRAY_SIZE(ds3231_clks_init);
onecell->clks = devm_kcalloc(&client->dev, onecell->clk_num,
sizeof(onecell->clks[0]), GFP_KERNEL);
if (!onecell->clks)
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(ds3231_clks_init); i++) {
struct clk_init_data init = ds3231_clks_init[i];
/*
* Interrupt signal due to alarm conditions and square-wave
* output share same pin, so don't initialize both.
*/
if (i == DS3231_CLK_SQW && test_bit(HAS_ALARM, &ds1307->flags))
continue;
/* optional override of the clockname */
of_property_read_string_index(node, "clock-output-names", i,
&init.name);
ds1307->clks[i].init = &init;
onecell->clks[i] = devm_clk_register(&client->dev,
&ds1307->clks[i]);
if (IS_ERR(onecell->clks[i]))
return PTR_ERR(onecell->clks[i]);
}
if (!node)
return 0;
of_clk_add_provider(node, of_clk_src_onecell_get, onecell);
return 0;
}
static void ds1307_clks_register(struct ds1307 *ds1307)
{
int ret;
if (ds1307->type != ds_3231)
return;
ret = ds3231_clks_register(ds1307);
if (ret) {
dev_warn(&ds1307->client->dev,
"unable to register clock device %d\n", ret);
}
}
#else
static void ds1307_clks_register(struct ds1307 *ds1307)
{
}
#endif /* CONFIG_COMMON_CLK */
static int ds1307_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@ -851,6 +1230,7 @@ static int ds1307_probe(struct i2c_client *client,
struct chip_desc *chip = &chips[id->driver_data];
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
bool want_irq = false;
bool ds1307_can_wakeup_device = false;
unsigned char *buf;
struct ds1307_platform_data *pdata = dev_get_platdata(&client->dev);
irq_handler_t irq_handler = ds1307_irq;
@ -898,6 +1278,20 @@ static int ds1307_probe(struct i2c_client *client,
ds1307->write_block_data = ds1307_write_block_data;
}
#ifdef CONFIG_OF
/*
* For devices with no IRQ directly connected to the SoC, the RTC chip
* can be forced as a wakeup source by stating that explicitly in
* the device's .dts file using the "wakeup-source" boolean property.
* If the "wakeup-source" property is set, don't request an IRQ.
* This will guarantee the 'wakealarm' sysfs entry is available on the device,
* if supported by the RTC.
*/
if (of_property_read_bool(client->dev.of_node, "wakeup-source")) {
ds1307_can_wakeup_device = true;
}
#endif
switch (ds1307->type) {
case ds_1337:
case ds_1339:
@ -916,11 +1310,13 @@ static int ds1307_probe(struct i2c_client *client,
ds1307->regs[0] &= ~DS1337_BIT_nEOSC;
/*
* Using IRQ? Disable the square wave and both alarms.
* Using IRQ or defined as wakeup-source?
* Disable the square wave and both alarms.
* For some variants, be sure alarms can trigger when we're
* running on Vbackup (BBSQI/BBSQW)
*/
if (ds1307->client->irq > 0 && chip->alarm) {
if (chip->alarm && (ds1307->client->irq > 0 ||
ds1307_can_wakeup_device)) {
ds1307->regs[0] |= DS1337_BIT_INTCN
| bbsqi_bitpos[ds1307->type];
ds1307->regs[0] &= ~(DS1337_BIT_A2IE | DS1337_BIT_A1IE);
@ -1135,6 +1531,14 @@ read_rtc:
return PTR_ERR(ds1307->rtc);
}
if (ds1307_can_wakeup_device) {
/* Disable request for an IRQ */
want_irq = false;
dev_info(&client->dev, "'wakeup-source' is set, request for an IRQ is disabled!\n");
/* We cannot support UIE mode if we do not have an IRQ line */
ds1307->rtc->uie_unsupported = 1;
}
if (want_irq) {
err = devm_request_threaded_irq(&client->dev,
client->irq, NULL, irq_handler,
@ -1182,6 +1586,9 @@ read_rtc:
}
}
ds1307_hwmon_register(ds1307);
ds1307_clks_register(ds1307);
return 0;
exit:

View File

@ -187,9 +187,9 @@ ds1685_rtc_end_data_access(struct ds1685_priv *rtc)
* Only use this where you are certain another lock will not be held.
*/
static inline void
ds1685_rtc_begin_ctrl_access(struct ds1685_priv *rtc, unsigned long flags)
ds1685_rtc_begin_ctrl_access(struct ds1685_priv *rtc, unsigned long *flags)
{
spin_lock_irqsave(&rtc->lock, flags);
spin_lock_irqsave(&rtc->lock, *flags);
ds1685_rtc_switch_to_bank1(rtc);
}
@ -1300,7 +1300,7 @@ ds1685_rtc_sysfs_ctrl_regs_store(struct device *dev,
{
struct ds1685_priv *rtc = dev_get_drvdata(dev);
u8 reg = 0, bit = 0, tmp;
unsigned long flags = 0;
unsigned long flags;
long int val = 0;
const struct ds1685_rtc_ctrl_regs *reg_info =
ds1685_rtc_sysfs_ctrl_regs_lookup(attr->attr.name);
@ -1321,7 +1321,7 @@ ds1685_rtc_sysfs_ctrl_regs_store(struct device *dev,
bit = reg_info->bit;
/* Safe to spinlock during a write. */
ds1685_rtc_begin_ctrl_access(rtc, flags);
ds1685_rtc_begin_ctrl_access(rtc, &flags);
tmp = rtc->read(rtc, reg);
rtc->write(rtc, reg, (val ? (tmp | bit) : (tmp & ~(bit))));
ds1685_rtc_end_ctrl_access(rtc, flags);
@ -2161,6 +2161,7 @@ ds1685_rtc_poweroff(struct platform_device *pdev)
/* Check for valid RTC data, else, spin forever. */
if (unlikely(!pdev)) {
pr_emerg("platform device data not available, spinning forever ...\n");
while(1);
unreachable();
} else {
/* Get the rtc data. */

View File

@ -1,19 +1,15 @@
/*
* RTC client/driver for the Maxim/Dallas DS3232 Real-Time Clock over I2C
* RTC client/driver for the Maxim/Dallas DS3232/DS3234 Real-Time Clock
*
* Copyright (C) 2009-2011 Freescale Semiconductor.
* Author: Jack Lan <jack.lan@freescale.com>
* Copyright (C) 2008 MIMOMax Wireless 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.
*/
/*
* It would be more efficient to use i2c msgs/i2c_transfer directly but, as
* recommened in .../Documentation/i2c/writing-clients section
* "Sending and receiving", using SMBus level communication is preferred.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@ -21,10 +17,11 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/spi/spi.h>
#include <linux/rtc.h>
#include <linux/bcd.h>
#include <linux/workqueue.h>
#include <linux/slab.h>
#include <linux/regmap.h>
#define DS3232_REG_SECONDS 0x00
#define DS3232_REG_MINUTES 0x01
@ -50,39 +47,33 @@
# define DS3232_REG_SR_A1F 0x01
struct ds3232 {
struct i2c_client *client;
struct device *dev;
struct regmap *regmap;
int irq;
struct rtc_device *rtc;
struct work_struct work;
/* The mutex protects alarm operations, and prevents a race
* between the enable_irq() in the workqueue and the free_irq()
* in the remove function.
*/
struct mutex mutex;
bool suspended;
int exiting;
};
static struct i2c_driver ds3232_driver;
static int ds3232_check_rtc_status(struct i2c_client *client)
static int ds3232_check_rtc_status(struct device *dev)
{
struct ds3232 *ds3232 = dev_get_drvdata(dev);
int ret = 0;
int control, stat;
stat = i2c_smbus_read_byte_data(client, DS3232_REG_SR);
if (stat < 0)
return stat;
ret = regmap_read(ds3232->regmap, DS3232_REG_SR, &stat);
if (ret)
return ret;
if (stat & DS3232_REG_SR_OSF)
dev_warn(&client->dev,
dev_warn(dev,
"oscillator discontinuity flagged, "
"time unreliable\n");
stat &= ~(DS3232_REG_SR_OSF | DS3232_REG_SR_A1F | DS3232_REG_SR_A2F);
ret = i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat);
if (ret < 0)
ret = regmap_write(ds3232->regmap, DS3232_REG_SR, stat);
if (ret)
return ret;
/* If the alarm is pending, clear it before requesting
@ -90,31 +81,28 @@ static int ds3232_check_rtc_status(struct i2c_client *client)
* before everything is initialized.
*/
control = i2c_smbus_read_byte_data(client, DS3232_REG_CR);
if (control < 0)
return control;
ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control);
if (ret)
return ret;
control &= ~(DS3232_REG_CR_A1IE | DS3232_REG_CR_A2IE);
control |= DS3232_REG_CR_INTCN;
return i2c_smbus_write_byte_data(client, DS3232_REG_CR, control);
return regmap_write(ds3232->regmap, DS3232_REG_CR, control);
}
static int ds3232_read_time(struct device *dev, struct rtc_time *time)
{
struct i2c_client *client = to_i2c_client(dev);
struct ds3232 *ds3232 = dev_get_drvdata(dev);
int ret;
u8 buf[7];
unsigned int year, month, day, hour, minute, second;
unsigned int week, twelve_hr, am_pm;
unsigned int century, add_century = 0;
ret = i2c_smbus_read_i2c_block_data(client, DS3232_REG_SECONDS, 7, buf);
if (ret < 0)
ret = regmap_bulk_read(ds3232->regmap, DS3232_REG_SECONDS, buf, 7);
if (ret)
return ret;
if (ret < 7)
return -EIO;
second = buf[0];
minute = buf[1];
@ -159,7 +147,7 @@ static int ds3232_read_time(struct device *dev, struct rtc_time *time)
static int ds3232_set_time(struct device *dev, struct rtc_time *time)
{
struct i2c_client *client = to_i2c_client(dev);
struct ds3232 *ds3232 = dev_get_drvdata(dev);
u8 buf[7];
/* Extract time from rtc_time and load into ds3232*/
@ -179,8 +167,7 @@ static int ds3232_set_time(struct device *dev, struct rtc_time *time)
buf[6] = bin2bcd(time->tm_year);
}
return i2c_smbus_write_i2c_block_data(client,
DS3232_REG_SECONDS, 7, buf);
return regmap_bulk_write(ds3232->regmap, DS3232_REG_SECONDS, buf, 7);
}
/*
@ -190,24 +177,19 @@ static int ds3232_set_time(struct device *dev, struct rtc_time *time)
*/
static int ds3232_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
struct i2c_client *client = to_i2c_client(dev);
struct ds3232 *ds3232 = i2c_get_clientdata(client);
struct ds3232 *ds3232 = dev_get_drvdata(dev);
int control, stat;
int ret;
u8 buf[4];
mutex_lock(&ds3232->mutex);
ret = i2c_smbus_read_byte_data(client, DS3232_REG_SR);
if (ret < 0)
ret = regmap_read(ds3232->regmap, DS3232_REG_SR, &stat);
if (ret)
goto out;
stat = ret;
ret = i2c_smbus_read_byte_data(client, DS3232_REG_CR);
if (ret < 0)
ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control);
if (ret)
goto out;
control = ret;
ret = i2c_smbus_read_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf);
if (ret < 0)
ret = regmap_bulk_read(ds3232->regmap, DS3232_REG_ALARM1, buf, 4);
if (ret)
goto out;
alarm->time.tm_sec = bcd2bin(buf[0] & 0x7F);
@ -226,7 +208,6 @@ static int ds3232_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
ret = 0;
out:
mutex_unlock(&ds3232->mutex);
return ret;
}
@ -236,166 +217,129 @@ out:
*/
static int ds3232_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
struct i2c_client *client = to_i2c_client(dev);
struct ds3232 *ds3232 = i2c_get_clientdata(client);
struct ds3232 *ds3232 = dev_get_drvdata(dev);
int control, stat;
int ret;
u8 buf[4];
if (client->irq <= 0)
if (ds3232->irq <= 0)
return -EINVAL;
mutex_lock(&ds3232->mutex);
buf[0] = bin2bcd(alarm->time.tm_sec);
buf[1] = bin2bcd(alarm->time.tm_min);
buf[2] = bin2bcd(alarm->time.tm_hour);
buf[3] = bin2bcd(alarm->time.tm_mday);
/* clear alarm interrupt enable bit */
ret = i2c_smbus_read_byte_data(client, DS3232_REG_CR);
if (ret < 0)
ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control);
if (ret)
goto out;
control = ret;
control &= ~(DS3232_REG_CR_A1IE | DS3232_REG_CR_A2IE);
ret = i2c_smbus_write_byte_data(client, DS3232_REG_CR, control);
if (ret < 0)
ret = regmap_write(ds3232->regmap, DS3232_REG_CR, control);
if (ret)
goto out;
/* clear any pending alarm flag */
ret = i2c_smbus_read_byte_data(client, DS3232_REG_SR);
if (ret < 0)
ret = regmap_read(ds3232->regmap, DS3232_REG_SR, &stat);
if (ret)
goto out;
stat = ret;
stat &= ~(DS3232_REG_SR_A1F | DS3232_REG_SR_A2F);
ret = i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat);
if (ret < 0)
ret = regmap_write(ds3232->regmap, DS3232_REG_SR, stat);
if (ret)
goto out;
ret = i2c_smbus_write_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf);
ret = regmap_bulk_write(ds3232->regmap, DS3232_REG_ALARM1, buf, 4);
if (ret)
goto out;
if (alarm->enabled) {
control |= DS3232_REG_CR_A1IE;
ret = i2c_smbus_write_byte_data(client, DS3232_REG_CR, control);
ret = regmap_write(ds3232->regmap, DS3232_REG_CR, control);
}
out:
mutex_unlock(&ds3232->mutex);
return ret;
}
static void ds3232_update_alarm(struct i2c_client *client)
static int ds3232_update_alarm(struct device *dev, unsigned int enabled)
{
struct ds3232 *ds3232 = i2c_get_clientdata(client);
struct ds3232 *ds3232 = dev_get_drvdata(dev);
int control;
int ret;
u8 buf[4];
mutex_lock(&ds3232->mutex);
ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control);
if (ret)
return ret;
ret = i2c_smbus_read_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf);
if (ret < 0)
goto unlock;
buf[0] = bcd2bin(buf[0]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ?
0x80 : buf[0];
buf[1] = bcd2bin(buf[1]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ?
0x80 : buf[1];
buf[2] = bcd2bin(buf[2]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ?
0x80 : buf[2];
buf[3] = bcd2bin(buf[3]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ?
0x80 : buf[3];
ret = i2c_smbus_write_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf);
if (ret < 0)
goto unlock;
control = i2c_smbus_read_byte_data(client, DS3232_REG_CR);
if (control < 0)
goto unlock;
if (ds3232->rtc->irq_data & (RTC_AF | RTC_UF))
if (enabled)
/* enable alarm1 interrupt */
control |= DS3232_REG_CR_A1IE;
else
/* disable alarm1 interrupt */
control &= ~(DS3232_REG_CR_A1IE);
i2c_smbus_write_byte_data(client, DS3232_REG_CR, control);
ret = regmap_write(ds3232->regmap, DS3232_REG_CR, control);
unlock:
mutex_unlock(&ds3232->mutex);
return ret;
}
static int ds3232_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
struct i2c_client *client = to_i2c_client(dev);
struct ds3232 *ds3232 = i2c_get_clientdata(client);
struct ds3232 *ds3232 = dev_get_drvdata(dev);
if (client->irq <= 0)
if (ds3232->irq <= 0)
return -EINVAL;
if (enabled)
ds3232->rtc->irq_data |= RTC_AF;
else
ds3232->rtc->irq_data &= ~RTC_AF;
ds3232_update_alarm(client);
return 0;
return ds3232_update_alarm(dev, enabled);
}
static irqreturn_t ds3232_irq(int irq, void *dev_id)
{
struct i2c_client *client = dev_id;
struct ds3232 *ds3232 = i2c_get_clientdata(client);
disable_irq_nosync(irq);
/*
* If rtc as a wakeup source, can't schedule the work
* at system resume flow, because at this time the i2c bus
* has not been resumed.
*/
if (!ds3232->suspended)
schedule_work(&ds3232->work);
return IRQ_HANDLED;
}
static void ds3232_work(struct work_struct *work)
{
struct ds3232 *ds3232 = container_of(work, struct ds3232, work);
struct i2c_client *client = ds3232->client;
struct device *dev = dev_id;
struct ds3232 *ds3232 = dev_get_drvdata(dev);
struct mutex *lock = &ds3232->rtc->ops_lock;
int ret;
int stat, control;
mutex_lock(&ds3232->mutex);
mutex_lock(lock);
stat = i2c_smbus_read_byte_data(client, DS3232_REG_SR);
if (stat < 0)
ret = regmap_read(ds3232->regmap, DS3232_REG_SR, &stat);
if (ret)
goto unlock;
if (stat & DS3232_REG_SR_A1F) {
control = i2c_smbus_read_byte_data(client, DS3232_REG_CR);
if (control < 0) {
pr_warn("Read Control Register error - Disable IRQ%d\n",
client->irq);
ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control);
if (ret) {
dev_warn(ds3232->dev,
"Read Control Register error %d\n", ret);
} else {
/* disable alarm1 interrupt */
control &= ~(DS3232_REG_CR_A1IE);
i2c_smbus_write_byte_data(client, DS3232_REG_CR,
control);
ret = regmap_write(ds3232->regmap, DS3232_REG_CR,
control);
if (ret) {
dev_warn(ds3232->dev,
"Write Control Register error %d\n",
ret);
goto unlock;
}
/* clear the alarm pend flag */
stat &= ~DS3232_REG_SR_A1F;
i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat);
ret = regmap_write(ds3232->regmap, DS3232_REG_SR, stat);
if (ret) {
dev_warn(ds3232->dev,
"Write Status Register error %d\n",
ret);
goto unlock;
}
rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF);
if (!ds3232->exiting)
enable_irq(client->irq);
}
}
unlock:
mutex_unlock(&ds3232->mutex);
mutex_unlock(lock);
return IRQ_HANDLED;
}
static const struct rtc_class_ops ds3232_rtc_ops = {
@ -406,67 +350,50 @@ static const struct rtc_class_ops ds3232_rtc_ops = {
.alarm_irq_enable = ds3232_alarm_irq_enable,
};
static int ds3232_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int ds3232_probe(struct device *dev, struct regmap *regmap, int irq,
const char *name)
{
struct ds3232 *ds3232;
int ret;
ds3232 = devm_kzalloc(&client->dev, sizeof(struct ds3232), GFP_KERNEL);
ds3232 = devm_kzalloc(dev, sizeof(*ds3232), GFP_KERNEL);
if (!ds3232)
return -ENOMEM;
ds3232->client = client;
i2c_set_clientdata(client, ds3232);
ds3232->regmap = regmap;
ds3232->irq = irq;
ds3232->dev = dev;
dev_set_drvdata(dev, ds3232);
INIT_WORK(&ds3232->work, ds3232_work);
mutex_init(&ds3232->mutex);
ret = ds3232_check_rtc_status(client);
ret = ds3232_check_rtc_status(dev);
if (ret)
return ret;
if (client->irq > 0) {
ret = devm_request_irq(&client->dev, client->irq, ds3232_irq,
IRQF_SHARED, "ds3232", client);
if (ds3232->irq > 0) {
ret = devm_request_threaded_irq(dev, ds3232->irq, NULL,
ds3232_irq,
IRQF_SHARED | IRQF_ONESHOT,
name, dev);
if (ret) {
dev_err(&client->dev, "unable to request IRQ\n");
}
device_init_wakeup(&client->dev, 1);
ds3232->irq = 0;
dev_err(dev, "unable to request IRQ\n");
} else
device_init_wakeup(dev, 1);
}
ds3232->rtc = devm_rtc_device_register(&client->dev, client->name,
&ds3232_rtc_ops, THIS_MODULE);
ds3232->rtc = devm_rtc_device_register(dev, name, &ds3232_rtc_ops,
THIS_MODULE);
return PTR_ERR_OR_ZERO(ds3232->rtc);
}
static int ds3232_remove(struct i2c_client *client)
{
struct ds3232 *ds3232 = i2c_get_clientdata(client);
if (client->irq > 0) {
mutex_lock(&ds3232->mutex);
ds3232->exiting = 1;
mutex_unlock(&ds3232->mutex);
devm_free_irq(&client->dev, client->irq, client);
cancel_work_sync(&ds3232->work);
}
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int ds3232_suspend(struct device *dev)
{
struct ds3232 *ds3232 = dev_get_drvdata(dev);
struct i2c_client *client = to_i2c_client(dev);
if (device_can_wakeup(dev)) {
ds3232->suspended = true;
if (irq_set_irq_wake(client->irq, 1)) {
if (device_may_wakeup(dev)) {
if (enable_irq_wake(ds3232->irq))
dev_warn_once(dev, "Cannot set wakeup source\n");
ds3232->suspended = false;
}
}
return 0;
@ -475,16 +402,9 @@ static int ds3232_suspend(struct device *dev)
static int ds3232_resume(struct device *dev)
{
struct ds3232 *ds3232 = dev_get_drvdata(dev);
struct i2c_client *client = to_i2c_client(dev);
if (ds3232->suspended) {
ds3232->suspended = false;
/* Clear the hardware alarm pend flag */
schedule_work(&ds3232->work);
irq_set_irq_wake(client->irq, 0);
}
if (device_may_wakeup(dev))
disable_irq_wake(ds3232->irq);
return 0;
}
@ -494,6 +414,27 @@ static const struct dev_pm_ops ds3232_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(ds3232_suspend, ds3232_resume)
};
#if IS_ENABLED(CONFIG_I2C)
static int ds3232_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct regmap *regmap;
static const struct regmap_config config = {
.reg_bits = 8,
.val_bits = 8,
};
regmap = devm_regmap_init_i2c(client, &config);
if (IS_ERR(regmap)) {
dev_err(&client->dev, "%s: regmap allocation failed: %ld\n",
__func__, PTR_ERR(regmap));
return PTR_ERR(regmap);
}
return ds3232_probe(&client->dev, regmap, client->irq, client->name);
}
static const struct i2c_device_id ds3232_id[] = {
{ "ds3232", 0 },
{ }
@ -505,13 +446,162 @@ static struct i2c_driver ds3232_driver = {
.name = "rtc-ds3232",
.pm = &ds3232_pm_ops,
},
.probe = ds3232_probe,
.remove = ds3232_remove,
.probe = ds3232_i2c_probe,
.id_table = ds3232_id,
};
module_i2c_driver(ds3232_driver);
static int ds3232_register_driver(void)
{
return i2c_add_driver(&ds3232_driver);
}
static void ds3232_unregister_driver(void)
{
i2c_del_driver(&ds3232_driver);
}
#else
static int ds3232_register_driver(void)
{
return 0;
}
static void ds3232_unregister_driver(void)
{
}
#endif
#if IS_ENABLED(CONFIG_SPI_MASTER)
static int ds3234_probe(struct spi_device *spi)
{
int res;
unsigned int tmp;
static const struct regmap_config config = {
.reg_bits = 8,
.val_bits = 8,
.write_flag_mask = 0x80,
};
struct regmap *regmap;
regmap = devm_regmap_init_spi(spi, &config);
if (IS_ERR(regmap)) {
dev_err(&spi->dev, "%s: regmap allocation failed: %ld\n",
__func__, PTR_ERR(regmap));
return PTR_ERR(regmap);
}
spi->mode = SPI_MODE_3;
spi->bits_per_word = 8;
spi_setup(spi);
res = regmap_read(regmap, DS3232_REG_SECONDS, &tmp);
if (res)
return res;
/* Control settings
*
* CONTROL_REG
* BIT 7 6 5 4 3 2 1 0
* EOSC BBSQW CONV RS2 RS1 INTCN A2IE A1IE
*
* 0 0 0 1 1 1 0 0
*
* CONTROL_STAT_REG
* BIT 7 6 5 4 3 2 1 0
* OSF BB32kHz CRATE1 CRATE0 EN32kHz BSY A2F A1F
*
* 1 0 0 0 1 0 0 0
*/
res = regmap_read(regmap, DS3232_REG_CR, &tmp);
if (res)
return res;
res = regmap_write(regmap, DS3232_REG_CR, tmp & 0x1c);
if (res)
return res;
res = regmap_read(regmap, DS3232_REG_SR, &tmp);
if (res)
return res;
res = regmap_write(regmap, DS3232_REG_SR, tmp & 0x88);
if (res)
return res;
/* Print our settings */
res = regmap_read(regmap, DS3232_REG_CR, &tmp);
if (res)
return res;
dev_info(&spi->dev, "Control Reg: 0x%02x\n", tmp);
res = regmap_read(regmap, DS3232_REG_SR, &tmp);
if (res)
return res;
dev_info(&spi->dev, "Ctrl/Stat Reg: 0x%02x\n", tmp);
return ds3232_probe(&spi->dev, regmap, spi->irq, "ds3234");
}
static struct spi_driver ds3234_driver = {
.driver = {
.name = "ds3234",
},
.probe = ds3234_probe,
};
static int ds3234_register_driver(void)
{
return spi_register_driver(&ds3234_driver);
}
static void ds3234_unregister_driver(void)
{
spi_unregister_driver(&ds3234_driver);
}
#else
static int ds3234_register_driver(void)
{
return 0;
}
static void ds3234_unregister_driver(void)
{
}
#endif
static int __init ds323x_init(void)
{
int ret;
ret = ds3232_register_driver();
if (ret) {
pr_err("Failed to register ds3232 driver: %d\n", ret);
return ret;
}
ret = ds3234_register_driver();
if (ret) {
pr_err("Failed to register ds3234 driver: %d\n", ret);
ds3232_unregister_driver();
}
return ret;
}
module_init(ds323x_init)
static void __exit ds323x_exit(void)
{
ds3234_unregister_driver();
ds3232_unregister_driver();
}
module_exit(ds323x_exit)
MODULE_AUTHOR("Srikanth Srinivasan <srikanth.srinivasan@freescale.com>");
MODULE_DESCRIPTION("Maxim/Dallas DS3232 RTC Driver");
MODULE_AUTHOR("Dennis Aberilla <denzzzhome@yahoo.com>");
MODULE_DESCRIPTION("Maxim/Dallas DS3232/DS3234 RTC Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("spi:ds3234");

View File

@ -1,171 +0,0 @@
/* rtc-ds3234.c
*
* Driver for Dallas Semiconductor (DS3234) SPI RTC with Integrated Crystal
* and SRAM.
*
* Copyright (C) 2008 MIMOMax Wireless Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
#include <linux/spi/spi.h>
#include <linux/bcd.h>
#define DS3234_REG_SECONDS 0x00
#define DS3234_REG_MINUTES 0x01
#define DS3234_REG_HOURS 0x02
#define DS3234_REG_DAY 0x03
#define DS3234_REG_DATE 0x04
#define DS3234_REG_MONTH 0x05
#define DS3234_REG_YEAR 0x06
#define DS3234_REG_CENTURY (1 << 7) /* Bit 7 of the Month register */
#define DS3234_REG_CONTROL 0x0E
#define DS3234_REG_CONT_STAT 0x0F
static int ds3234_set_reg(struct device *dev, unsigned char address,
unsigned char data)
{
struct spi_device *spi = to_spi_device(dev);
unsigned char buf[2];
/* MSB must be '1' to indicate write */
buf[0] = address | 0x80;
buf[1] = data;
return spi_write_then_read(spi, buf, 2, NULL, 0);
}
static int ds3234_get_reg(struct device *dev, unsigned char address,
unsigned char *data)
{
struct spi_device *spi = to_spi_device(dev);
*data = address & 0x7f;
return spi_write_then_read(spi, data, 1, data, 1);
}
static int ds3234_read_time(struct device *dev, struct rtc_time *dt)
{
int err;
unsigned char buf[8];
struct spi_device *spi = to_spi_device(dev);
buf[0] = 0x00; /* Start address */
err = spi_write_then_read(spi, buf, 1, buf, 8);
if (err != 0)
return err;
/* Seconds, Minutes, Hours, Day, Date, Month, Year */
dt->tm_sec = bcd2bin(buf[0]);
dt->tm_min = bcd2bin(buf[1]);
dt->tm_hour = bcd2bin(buf[2] & 0x3f);
dt->tm_wday = bcd2bin(buf[3]) - 1; /* 0 = Sun */
dt->tm_mday = bcd2bin(buf[4]);
dt->tm_mon = bcd2bin(buf[5] & 0x1f) - 1; /* 0 = Jan */
dt->tm_year = bcd2bin(buf[6] & 0xff) + 100; /* Assume 20YY */
return rtc_valid_tm(dt);
}
static int ds3234_set_time(struct device *dev, struct rtc_time *dt)
{
ds3234_set_reg(dev, DS3234_REG_SECONDS, bin2bcd(dt->tm_sec));
ds3234_set_reg(dev, DS3234_REG_MINUTES, bin2bcd(dt->tm_min));
ds3234_set_reg(dev, DS3234_REG_HOURS, bin2bcd(dt->tm_hour) & 0x3f);
/* 0 = Sun */
ds3234_set_reg(dev, DS3234_REG_DAY, bin2bcd(dt->tm_wday + 1));
ds3234_set_reg(dev, DS3234_REG_DATE, bin2bcd(dt->tm_mday));
/* 0 = Jan */
ds3234_set_reg(dev, DS3234_REG_MONTH, bin2bcd(dt->tm_mon + 1));
/* Assume 20YY although we just want to make sure not to go negative. */
if (dt->tm_year > 100)
dt->tm_year -= 100;
ds3234_set_reg(dev, DS3234_REG_YEAR, bin2bcd(dt->tm_year));
return 0;
}
static const struct rtc_class_ops ds3234_rtc_ops = {
.read_time = ds3234_read_time,
.set_time = ds3234_set_time,
};
static int ds3234_probe(struct spi_device *spi)
{
struct rtc_device *rtc;
unsigned char tmp;
int res;
spi->mode = SPI_MODE_3;
spi->bits_per_word = 8;
spi_setup(spi);
res = ds3234_get_reg(&spi->dev, DS3234_REG_SECONDS, &tmp);
if (res != 0)
return res;
/* Control settings
*
* CONTROL_REG
* BIT 7 6 5 4 3 2 1 0
* EOSC BBSQW CONV RS2 RS1 INTCN A2IE A1IE
*
* 0 0 0 1 1 1 0 0
*
* CONTROL_STAT_REG
* BIT 7 6 5 4 3 2 1 0
* OSF BB32kHz CRATE1 CRATE0 EN32kHz BSY A2F A1F
*
* 1 0 0 0 1 0 0 0
*/
ds3234_get_reg(&spi->dev, DS3234_REG_CONTROL, &tmp);
ds3234_set_reg(&spi->dev, DS3234_REG_CONTROL, tmp & 0x1c);
ds3234_get_reg(&spi->dev, DS3234_REG_CONT_STAT, &tmp);
ds3234_set_reg(&spi->dev, DS3234_REG_CONT_STAT, tmp & 0x88);
/* Print our settings */
ds3234_get_reg(&spi->dev, DS3234_REG_CONTROL, &tmp);
dev_info(&spi->dev, "Control Reg: 0x%02x\n", tmp);
ds3234_get_reg(&spi->dev, DS3234_REG_CONT_STAT, &tmp);
dev_info(&spi->dev, "Ctrl/Stat Reg: 0x%02x\n", tmp);
rtc = devm_rtc_device_register(&spi->dev, "ds3234",
&ds3234_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
spi_set_drvdata(spi, rtc);
return 0;
}
static struct spi_driver ds3234_driver = {
.driver = {
.name = "ds3234",
},
.probe = ds3234_probe,
};
module_spi_driver(ds3234_driver);
MODULE_DESCRIPTION("DS3234 SPI RTC driver");
MODULE_AUTHOR("Dennis Aberilla <denzzzhome@yahoo.com>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("spi:ds3234");

View File

@ -9,6 +9,8 @@
#include <linux/platform_device.h>
#include <linux/rtc.h>
#if defined(CONFIG_M68K) || defined(CONFIG_PARISC) || \
defined(CONFIG_PPC) || defined(CONFIG_SUPERH32)
#include <asm/rtc.h>
static int generic_get_time(struct device *dev, struct rtc_time *tm)
@ -33,13 +35,21 @@ static const struct rtc_class_ops generic_rtc_ops = {
.read_time = generic_get_time,
.set_time = generic_set_time,
};
#else
#define generic_rtc_ops *(struct rtc_class_ops*)NULL
#endif
static int __init generic_rtc_probe(struct platform_device *dev)
{
struct rtc_device *rtc;
const struct rtc_class_ops *ops;
ops = dev_get_platdata(&dev->dev);
if (!ops)
ops = &generic_rtc_ops;
rtc = devm_rtc_device_register(&dev->dev, "rtc-generic",
&generic_rtc_ops, THIS_MODULE);
ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);

View File

@ -144,7 +144,7 @@ static int hym8563_rtc_set_time(struct device *dev, struct rtc_time *tm)
* it does not seem to carry it over a subsequent write/read.
* So we'll limit ourself to 100 years, starting at 2000 for now.
*/
buf[6] = tm->tm_year - 100;
buf[6] = bin2bcd(tm->tm_year - 100);
/*
* CTL1 only contains TEST-mode bits apart from stop,

View File

@ -1,5 +1,5 @@
/*
* RTC driver for Maxim MAX77686
* RTC driver for Maxim MAX77686 and MAX77802
*
* Copyright (C) 2012 Samsung Electronics Co.Ltd
*
@ -12,8 +12,7 @@
*
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/rtc.h>
#include <linux/delay.h>
@ -24,24 +23,38 @@
#include <linux/irqdomain.h>
#include <linux/regmap.h>
#define MAX77686_I2C_ADDR_RTC (0x0C >> 1)
#define MAX77620_I2C_ADDR_RTC 0x68
#define MAX77686_INVALID_I2C_ADDR (-1)
/* Define non existing register */
#define MAX77686_INVALID_REG (-1)
/* RTC Control Register */
#define BCD_EN_SHIFT 0
#define BCD_EN_MASK (1 << BCD_EN_SHIFT)
#define BCD_EN_MASK BIT(BCD_EN_SHIFT)
#define MODEL24_SHIFT 1
#define MODEL24_MASK (1 << MODEL24_SHIFT)
#define MODEL24_MASK BIT(MODEL24_SHIFT)
/* RTC Update Register1 */
#define RTC_UDR_SHIFT 0
#define RTC_UDR_MASK (1 << RTC_UDR_SHIFT)
#define RTC_UDR_MASK BIT(RTC_UDR_SHIFT)
#define RTC_RBUDR_SHIFT 4
#define RTC_RBUDR_MASK (1 << RTC_RBUDR_SHIFT)
#define RTC_RBUDR_MASK BIT(RTC_RBUDR_SHIFT)
/* RTC Hour register */
#define HOUR_PM_SHIFT 6
#define HOUR_PM_MASK (1 << HOUR_PM_SHIFT)
#define HOUR_PM_MASK BIT(HOUR_PM_SHIFT)
/* RTC Alarm Enable */
#define ALARM_ENABLE_SHIFT 7
#define ALARM_ENABLE_MASK (1 << ALARM_ENABLE_SHIFT)
#define ALARM_ENABLE_MASK BIT(ALARM_ENABLE_SHIFT)
#define MAX77686_RTC_UPDATE_DELAY 16
#define REG_RTC_NONE 0xdeadbeef
/*
* MAX77802 has separate register (RTCAE1) for alarm enable instead
* using 1 bit from registers RTC{SEC,MIN,HOUR,DAY,MONTH,YEAR,DATE}
* as in done in MAX77686.
*/
#define MAX77802_ALARM_ENABLE_VALUE 0x77
enum {
RTC_SEC = 0,
@ -54,15 +67,38 @@ enum {
RTC_NR_TIME
};
struct max77686_rtc_driver_data {
/* Minimum usecs needed for a RTC update */
unsigned long delay;
/* Mask used to read RTC registers value */
u8 mask;
/* Registers offset to I2C addresses map */
const unsigned int *map;
/* Has a separate alarm enable register? */
bool alarm_enable_reg;
/* I2C address for RTC block */
int rtc_i2c_addr;
/* RTC interrupt via platform resource */
bool rtc_irq_from_platform;
/* Pending alarm status register */
int alarm_pending_status_reg;
/* RTC IRQ CHIP for regmap */
const struct regmap_irq_chip *rtc_irq_chip;
};
struct max77686_rtc_info {
struct device *dev;
struct max77686_dev *max77686;
struct i2c_client *rtc;
struct rtc_device *rtc_dev;
struct mutex lock;
struct regmap *regmap;
struct regmap *rtc_regmap;
const struct max77686_rtc_driver_data *drv_data;
struct regmap_irq_chip_data *rtc_irq_data;
int rtc_irq;
int virq;
int rtc_24hr_mode;
};
@ -72,29 +108,190 @@ enum MAX77686_RTC_OP {
MAX77686_RTC_READ,
};
/* These are not registers but just offsets that are mapped to addresses */
enum max77686_rtc_reg_offset {
REG_RTC_CONTROLM = 0,
REG_RTC_CONTROL,
REG_RTC_UPDATE0,
REG_WTSR_SMPL_CNTL,
REG_RTC_SEC,
REG_RTC_MIN,
REG_RTC_HOUR,
REG_RTC_WEEKDAY,
REG_RTC_MONTH,
REG_RTC_YEAR,
REG_RTC_DATE,
REG_ALARM1_SEC,
REG_ALARM1_MIN,
REG_ALARM1_HOUR,
REG_ALARM1_WEEKDAY,
REG_ALARM1_MONTH,
REG_ALARM1_YEAR,
REG_ALARM1_DATE,
REG_ALARM2_SEC,
REG_ALARM2_MIN,
REG_ALARM2_HOUR,
REG_ALARM2_WEEKDAY,
REG_ALARM2_MONTH,
REG_ALARM2_YEAR,
REG_ALARM2_DATE,
REG_RTC_AE1,
REG_RTC_END,
};
/* Maps RTC registers offset to the MAX77686 register addresses */
static const unsigned int max77686_map[REG_RTC_END] = {
[REG_RTC_CONTROLM] = MAX77686_RTC_CONTROLM,
[REG_RTC_CONTROL] = MAX77686_RTC_CONTROL,
[REG_RTC_UPDATE0] = MAX77686_RTC_UPDATE0,
[REG_WTSR_SMPL_CNTL] = MAX77686_WTSR_SMPL_CNTL,
[REG_RTC_SEC] = MAX77686_RTC_SEC,
[REG_RTC_MIN] = MAX77686_RTC_MIN,
[REG_RTC_HOUR] = MAX77686_RTC_HOUR,
[REG_RTC_WEEKDAY] = MAX77686_RTC_WEEKDAY,
[REG_RTC_MONTH] = MAX77686_RTC_MONTH,
[REG_RTC_YEAR] = MAX77686_RTC_YEAR,
[REG_RTC_DATE] = MAX77686_RTC_DATE,
[REG_ALARM1_SEC] = MAX77686_ALARM1_SEC,
[REG_ALARM1_MIN] = MAX77686_ALARM1_MIN,
[REG_ALARM1_HOUR] = MAX77686_ALARM1_HOUR,
[REG_ALARM1_WEEKDAY] = MAX77686_ALARM1_WEEKDAY,
[REG_ALARM1_MONTH] = MAX77686_ALARM1_MONTH,
[REG_ALARM1_YEAR] = MAX77686_ALARM1_YEAR,
[REG_ALARM1_DATE] = MAX77686_ALARM1_DATE,
[REG_ALARM2_SEC] = MAX77686_ALARM2_SEC,
[REG_ALARM2_MIN] = MAX77686_ALARM2_MIN,
[REG_ALARM2_HOUR] = MAX77686_ALARM2_HOUR,
[REG_ALARM2_WEEKDAY] = MAX77686_ALARM2_WEEKDAY,
[REG_ALARM2_MONTH] = MAX77686_ALARM2_MONTH,
[REG_ALARM2_YEAR] = MAX77686_ALARM2_YEAR,
[REG_ALARM2_DATE] = MAX77686_ALARM2_DATE,
[REG_RTC_AE1] = REG_RTC_NONE,
};
static const struct regmap_irq max77686_rtc_irqs[] = {
/* RTC interrupts */
REGMAP_IRQ_REG(0, 0, MAX77686_RTCINT_RTC60S_MSK),
REGMAP_IRQ_REG(1, 0, MAX77686_RTCINT_RTCA1_MSK),
REGMAP_IRQ_REG(2, 0, MAX77686_RTCINT_RTCA2_MSK),
REGMAP_IRQ_REG(3, 0, MAX77686_RTCINT_SMPL_MSK),
REGMAP_IRQ_REG(4, 0, MAX77686_RTCINT_RTC1S_MSK),
REGMAP_IRQ_REG(5, 0, MAX77686_RTCINT_WTSR_MSK),
};
static const struct regmap_irq_chip max77686_rtc_irq_chip = {
.name = "max77686-rtc",
.status_base = MAX77686_RTC_INT,
.mask_base = MAX77686_RTC_INTM,
.num_regs = 1,
.irqs = max77686_rtc_irqs,
.num_irqs = ARRAY_SIZE(max77686_rtc_irqs),
};
static const struct max77686_rtc_driver_data max77686_drv_data = {
.delay = 16000,
.mask = 0x7f,
.map = max77686_map,
.alarm_enable_reg = false,
.rtc_irq_from_platform = false,
.alarm_pending_status_reg = MAX77686_REG_STATUS2,
.rtc_i2c_addr = MAX77686_I2C_ADDR_RTC,
.rtc_irq_chip = &max77686_rtc_irq_chip,
};
static const struct max77686_rtc_driver_data max77620_drv_data = {
.delay = 16000,
.mask = 0x7f,
.map = max77686_map,
.alarm_enable_reg = false,
.rtc_irq_from_platform = true,
.alarm_pending_status_reg = MAX77686_INVALID_REG,
.rtc_i2c_addr = MAX77620_I2C_ADDR_RTC,
.rtc_irq_chip = &max77686_rtc_irq_chip,
};
static const unsigned int max77802_map[REG_RTC_END] = {
[REG_RTC_CONTROLM] = MAX77802_RTC_CONTROLM,
[REG_RTC_CONTROL] = MAX77802_RTC_CONTROL,
[REG_RTC_UPDATE0] = MAX77802_RTC_UPDATE0,
[REG_WTSR_SMPL_CNTL] = MAX77802_WTSR_SMPL_CNTL,
[REG_RTC_SEC] = MAX77802_RTC_SEC,
[REG_RTC_MIN] = MAX77802_RTC_MIN,
[REG_RTC_HOUR] = MAX77802_RTC_HOUR,
[REG_RTC_WEEKDAY] = MAX77802_RTC_WEEKDAY,
[REG_RTC_MONTH] = MAX77802_RTC_MONTH,
[REG_RTC_YEAR] = MAX77802_RTC_YEAR,
[REG_RTC_DATE] = MAX77802_RTC_DATE,
[REG_ALARM1_SEC] = MAX77802_ALARM1_SEC,
[REG_ALARM1_MIN] = MAX77802_ALARM1_MIN,
[REG_ALARM1_HOUR] = MAX77802_ALARM1_HOUR,
[REG_ALARM1_WEEKDAY] = MAX77802_ALARM1_WEEKDAY,
[REG_ALARM1_MONTH] = MAX77802_ALARM1_MONTH,
[REG_ALARM1_YEAR] = MAX77802_ALARM1_YEAR,
[REG_ALARM1_DATE] = MAX77802_ALARM1_DATE,
[REG_ALARM2_SEC] = MAX77802_ALARM2_SEC,
[REG_ALARM2_MIN] = MAX77802_ALARM2_MIN,
[REG_ALARM2_HOUR] = MAX77802_ALARM2_HOUR,
[REG_ALARM2_WEEKDAY] = MAX77802_ALARM2_WEEKDAY,
[REG_ALARM2_MONTH] = MAX77802_ALARM2_MONTH,
[REG_ALARM2_YEAR] = MAX77802_ALARM2_YEAR,
[REG_ALARM2_DATE] = MAX77802_ALARM2_DATE,
[REG_RTC_AE1] = MAX77802_RTC_AE1,
};
static const struct regmap_irq_chip max77802_rtc_irq_chip = {
.name = "max77802-rtc",
.status_base = MAX77802_RTC_INT,
.mask_base = MAX77802_RTC_INTM,
.num_regs = 1,
.irqs = max77686_rtc_irqs, /* same masks as 77686 */
.num_irqs = ARRAY_SIZE(max77686_rtc_irqs),
};
static const struct max77686_rtc_driver_data max77802_drv_data = {
.delay = 200,
.mask = 0xff,
.map = max77802_map,
.alarm_enable_reg = true,
.rtc_irq_from_platform = false,
.alarm_pending_status_reg = MAX77686_REG_STATUS2,
.rtc_i2c_addr = MAX77686_INVALID_I2C_ADDR,
.rtc_irq_chip = &max77802_rtc_irq_chip,
};
static void max77686_rtc_data_to_tm(u8 *data, struct rtc_time *tm,
int rtc_24hr_mode)
struct max77686_rtc_info *info)
{
tm->tm_sec = data[RTC_SEC] & 0x7f;
tm->tm_min = data[RTC_MIN] & 0x7f;
if (rtc_24hr_mode)
u8 mask = info->drv_data->mask;
tm->tm_sec = data[RTC_SEC] & mask;
tm->tm_min = data[RTC_MIN] & mask;
if (info->rtc_24hr_mode) {
tm->tm_hour = data[RTC_HOUR] & 0x1f;
else {
} else {
tm->tm_hour = data[RTC_HOUR] & 0x0f;
if (data[RTC_HOUR] & HOUR_PM_MASK)
tm->tm_hour += 12;
}
/* Only a single bit is set in data[], so fls() would be equivalent */
tm->tm_wday = ffs(data[RTC_WEEKDAY] & 0x7f) - 1;
tm->tm_wday = ffs(data[RTC_WEEKDAY] & mask) - 1;
tm->tm_mday = data[RTC_DATE] & 0x1f;
tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1;
tm->tm_year = (data[RTC_YEAR] & 0x7f) + 100;
tm->tm_year = data[RTC_YEAR] & mask;
tm->tm_yday = 0;
tm->tm_isdst = 0;
/*
* MAX77686 uses 1 bit from sec/min/hour/etc RTC registers and the
* year values are just 0..99 so add 100 to support up to 2099.
*/
if (!info->drv_data->alarm_enable_reg)
tm->tm_year += 100;
}
static int max77686_rtc_tm_to_data(struct rtc_time *tm, u8 *data)
static int max77686_rtc_tm_to_data(struct rtc_time *tm, u8 *data,
struct max77686_rtc_info *info)
{
data[RTC_SEC] = tm->tm_sec;
data[RTC_MIN] = tm->tm_min;
@ -102,35 +299,44 @@ static int max77686_rtc_tm_to_data(struct rtc_time *tm, u8 *data)
data[RTC_WEEKDAY] = 1 << tm->tm_wday;
data[RTC_DATE] = tm->tm_mday;
data[RTC_MONTH] = tm->tm_mon + 1;
if (info->drv_data->alarm_enable_reg) {
data[RTC_YEAR] = tm->tm_year;
return 0;
}
data[RTC_YEAR] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0;
if (tm->tm_year < 100) {
pr_warn("RTC cannot handle the year %d. Assume it's 2000.\n",
dev_err(info->dev, "RTC cannot handle the year %d.\n",
1900 + tm->tm_year);
return -EINVAL;
}
return 0;
}
static int max77686_rtc_update(struct max77686_rtc_info *info,
enum MAX77686_RTC_OP op)
enum MAX77686_RTC_OP op)
{
int ret;
unsigned int data;
unsigned long delay = info->drv_data->delay;
if (op == MAX77686_RTC_WRITE)
data = 1 << RTC_UDR_SHIFT;
else
data = 1 << RTC_RBUDR_SHIFT;
ret = regmap_update_bits(info->max77686->rtc_regmap,
MAX77686_RTC_UPDATE0, data, data);
ret = regmap_update_bits(info->rtc_regmap,
info->drv_data->map[REG_RTC_UPDATE0],
data, data);
if (ret < 0)
dev_err(info->dev, "%s: fail to write update reg(ret=%d, data=0x%x)\n",
__func__, ret, data);
dev_err(info->dev, "Fail to write update reg(ret=%d, data=0x%x)\n",
ret, data);
else {
/* Minimum 16ms delay required before RTC update. */
msleep(MAX77686_RTC_UPDATE_DELAY);
/* Minimum delay required before RTC update. */
usleep_range(delay, delay * 2);
}
return ret;
@ -148,14 +354,15 @@ static int max77686_rtc_read_time(struct device *dev, struct rtc_time *tm)
if (ret < 0)
goto out;
ret = regmap_bulk_read(info->max77686->rtc_regmap,
MAX77686_RTC_SEC, data, RTC_NR_TIME);
ret = regmap_bulk_read(info->rtc_regmap,
info->drv_data->map[REG_RTC_SEC],
data, ARRAY_SIZE(data));
if (ret < 0) {
dev_err(info->dev, "%s: fail to read time reg(%d)\n", __func__, ret);
dev_err(info->dev, "Fail to read time reg(%d)\n", ret);
goto out;
}
max77686_rtc_data_to_tm(data, tm, info->rtc_24hr_mode);
max77686_rtc_data_to_tm(data, tm, info);
ret = rtc_valid_tm(tm);
@ -170,17 +377,17 @@ static int max77686_rtc_set_time(struct device *dev, struct rtc_time *tm)
u8 data[RTC_NR_TIME];
int ret;
ret = max77686_rtc_tm_to_data(tm, data);
ret = max77686_rtc_tm_to_data(tm, data, info);
if (ret < 0)
return ret;
mutex_lock(&info->lock);
ret = regmap_bulk_write(info->max77686->rtc_regmap,
MAX77686_RTC_SEC, data, RTC_NR_TIME);
ret = regmap_bulk_write(info->rtc_regmap,
info->drv_data->map[REG_RTC_SEC],
data, ARRAY_SIZE(data));
if (ret < 0) {
dev_err(info->dev, "%s: fail to write time reg(%d)\n", __func__,
ret);
dev_err(info->dev, "Fail to write time reg(%d)\n", ret);
goto out;
}
@ -196,6 +403,7 @@ static int max77686_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
struct max77686_rtc_info *info = dev_get_drvdata(dev);
u8 data[RTC_NR_TIME];
unsigned int val;
const unsigned int *map = info->drv_data->map;
int i, ret;
mutex_lock(&info->lock);
@ -204,29 +412,53 @@ static int max77686_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
if (ret < 0)
goto out;
ret = regmap_bulk_read(info->max77686->rtc_regmap,
MAX77686_ALARM1_SEC, data, RTC_NR_TIME);
ret = regmap_bulk_read(info->rtc_regmap, map[REG_ALARM1_SEC],
data, ARRAY_SIZE(data));
if (ret < 0) {
dev_err(info->dev, "%s:%d fail to read alarm reg(%d)\n",
__func__, __LINE__, ret);
dev_err(info->dev, "Fail to read alarm reg(%d)\n", ret);
goto out;
}
max77686_rtc_data_to_tm(data, &alrm->time, info->rtc_24hr_mode);
max77686_rtc_data_to_tm(data, &alrm->time, info);
alrm->enabled = 0;
for (i = 0; i < RTC_NR_TIME; i++) {
if (data[i] & ALARM_ENABLE_MASK) {
if (info->drv_data->alarm_enable_reg) {
if (map[REG_RTC_AE1] == REG_RTC_NONE) {
ret = -EINVAL;
dev_err(info->dev,
"alarm enable register not set(%d)\n", ret);
goto out;
}
ret = regmap_read(info->rtc_regmap, map[REG_RTC_AE1], &val);
if (ret < 0) {
dev_err(info->dev,
"fail to read alarm enable(%d)\n", ret);
goto out;
}
if (val)
alrm->enabled = 1;
break;
} else {
for (i = 0; i < ARRAY_SIZE(data); i++) {
if (data[i] & ALARM_ENABLE_MASK) {
alrm->enabled = 1;
break;
}
}
}
alrm->pending = 0;
ret = regmap_read(info->max77686->regmap, MAX77686_REG_STATUS2, &val);
if (info->drv_data->alarm_pending_status_reg == MAX77686_INVALID_REG)
goto out;
ret = regmap_read(info->regmap,
info->drv_data->alarm_pending_status_reg, &val);
if (ret < 0) {
dev_err(info->dev, "%s:%d fail to read status2 reg(%d)\n",
__func__, __LINE__, ret);
dev_err(info->dev,
"Fail to read alarm pending status reg(%d)\n", ret);
goto out;
}
@ -235,7 +467,7 @@ static int max77686_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
out:
mutex_unlock(&info->lock);
return 0;
return ret;
}
static int max77686_rtc_stop_alarm(struct max77686_rtc_info *info)
@ -243,6 +475,7 @@ static int max77686_rtc_stop_alarm(struct max77686_rtc_info *info)
u8 data[RTC_NR_TIME];
int ret, i;
struct rtc_time tm;
const unsigned int *map = info->drv_data->map;
if (!mutex_is_locked(&info->lock))
dev_warn(info->dev, "%s: should have mutex locked\n", __func__);
@ -251,24 +484,34 @@ static int max77686_rtc_stop_alarm(struct max77686_rtc_info *info)
if (ret < 0)
goto out;
ret = regmap_bulk_read(info->max77686->rtc_regmap,
MAX77686_ALARM1_SEC, data, RTC_NR_TIME);
if (ret < 0) {
dev_err(info->dev, "%s: fail to read alarm reg(%d)\n",
__func__, ret);
goto out;
if (info->drv_data->alarm_enable_reg) {
if (map[REG_RTC_AE1] == REG_RTC_NONE) {
ret = -EINVAL;
dev_err(info->dev,
"alarm enable register not set(%d)\n", ret);
goto out;
}
ret = regmap_write(info->rtc_regmap, map[REG_RTC_AE1], 0);
} else {
ret = regmap_bulk_read(info->rtc_regmap, map[REG_ALARM1_SEC],
data, ARRAY_SIZE(data));
if (ret < 0) {
dev_err(info->dev, "Fail to read alarm reg(%d)\n", ret);
goto out;
}
max77686_rtc_data_to_tm(data, &tm, info);
for (i = 0; i < ARRAY_SIZE(data); i++)
data[i] &= ~ALARM_ENABLE_MASK;
ret = regmap_bulk_write(info->rtc_regmap, map[REG_ALARM1_SEC],
data, ARRAY_SIZE(data));
}
max77686_rtc_data_to_tm(data, &tm, info->rtc_24hr_mode);
for (i = 0; i < RTC_NR_TIME; i++)
data[i] &= ~ALARM_ENABLE_MASK;
ret = regmap_bulk_write(info->max77686->rtc_regmap,
MAX77686_ALARM1_SEC, data, RTC_NR_TIME);
if (ret < 0) {
dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
__func__, ret);
dev_err(info->dev, "Fail to write alarm reg(%d)\n", ret);
goto out;
}
@ -282,6 +525,7 @@ static int max77686_rtc_start_alarm(struct max77686_rtc_info *info)
u8 data[RTC_NR_TIME];
int ret;
struct rtc_time tm;
const unsigned int *map = info->drv_data->map;
if (!mutex_is_locked(&info->lock))
dev_warn(info->dev, "%s: should have mutex locked\n", __func__);
@ -290,32 +534,36 @@ static int max77686_rtc_start_alarm(struct max77686_rtc_info *info)
if (ret < 0)
goto out;
ret = regmap_bulk_read(info->max77686->rtc_regmap,
MAX77686_ALARM1_SEC, data, RTC_NR_TIME);
if (ret < 0) {
dev_err(info->dev, "%s: fail to read alarm reg(%d)\n",
__func__, ret);
goto out;
if (info->drv_data->alarm_enable_reg) {
ret = regmap_write(info->rtc_regmap, map[REG_RTC_AE1],
MAX77802_ALARM_ENABLE_VALUE);
} else {
ret = regmap_bulk_read(info->rtc_regmap, map[REG_ALARM1_SEC],
data, ARRAY_SIZE(data));
if (ret < 0) {
dev_err(info->dev, "Fail to read alarm reg(%d)\n", ret);
goto out;
}
max77686_rtc_data_to_tm(data, &tm, info);
data[RTC_SEC] |= (1 << ALARM_ENABLE_SHIFT);
data[RTC_MIN] |= (1 << ALARM_ENABLE_SHIFT);
data[RTC_HOUR] |= (1 << ALARM_ENABLE_SHIFT);
data[RTC_WEEKDAY] &= ~ALARM_ENABLE_MASK;
if (data[RTC_MONTH] & 0xf)
data[RTC_MONTH] |= (1 << ALARM_ENABLE_SHIFT);
if (data[RTC_YEAR] & info->drv_data->mask)
data[RTC_YEAR] |= (1 << ALARM_ENABLE_SHIFT);
if (data[RTC_DATE] & 0x1f)
data[RTC_DATE] |= (1 << ALARM_ENABLE_SHIFT);
ret = regmap_bulk_write(info->rtc_regmap, map[REG_ALARM1_SEC],
data, ARRAY_SIZE(data));
}
max77686_rtc_data_to_tm(data, &tm, info->rtc_24hr_mode);
data[RTC_SEC] |= (1 << ALARM_ENABLE_SHIFT);
data[RTC_MIN] |= (1 << ALARM_ENABLE_SHIFT);
data[RTC_HOUR] |= (1 << ALARM_ENABLE_SHIFT);
data[RTC_WEEKDAY] &= ~ALARM_ENABLE_MASK;
if (data[RTC_MONTH] & 0xf)
data[RTC_MONTH] |= (1 << ALARM_ENABLE_SHIFT);
if (data[RTC_YEAR] & 0x7f)
data[RTC_YEAR] |= (1 << ALARM_ENABLE_SHIFT);
if (data[RTC_DATE] & 0x1f)
data[RTC_DATE] |= (1 << ALARM_ENABLE_SHIFT);
ret = regmap_bulk_write(info->max77686->rtc_regmap,
MAX77686_ALARM1_SEC, data, RTC_NR_TIME);
if (ret < 0) {
dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
__func__, ret);
dev_err(info->dev, "Fail to write alarm reg(%d)\n", ret);
goto out;
}
@ -330,7 +578,7 @@ static int max77686_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
u8 data[RTC_NR_TIME];
int ret;
ret = max77686_rtc_tm_to_data(&alrm->time, data);
ret = max77686_rtc_tm_to_data(&alrm->time, data, info);
if (ret < 0)
return ret;
@ -340,12 +588,12 @@ static int max77686_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
if (ret < 0)
goto out;
ret = regmap_bulk_write(info->max77686->rtc_regmap,
MAX77686_ALARM1_SEC, data, RTC_NR_TIME);
ret = regmap_bulk_write(info->rtc_regmap,
info->drv_data->map[REG_ALARM1_SEC],
data, ARRAY_SIZE(data));
if (ret < 0) {
dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
__func__, ret);
dev_err(info->dev, "Fail to write alarm reg(%d)\n", ret);
goto out;
}
@ -361,7 +609,7 @@ out:
}
static int max77686_rtc_alarm_irq_enable(struct device *dev,
unsigned int enabled)
unsigned int enabled)
{
struct max77686_rtc_info *info = dev_get_drvdata(dev);
int ret;
@ -380,7 +628,7 @@ static irqreturn_t max77686_rtc_alarm_irq(int irq, void *data)
{
struct max77686_rtc_info *info = data;
dev_info(info->dev, "%s:irq(%d)\n", __func__, irq);
dev_dbg(info->dev, "RTC alarm IRQ: %d\n", irq);
rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF);
@ -406,10 +654,11 @@ static int max77686_rtc_init_reg(struct max77686_rtc_info *info)
info->rtc_24hr_mode = 1;
ret = regmap_bulk_write(info->max77686->rtc_regmap, MAX77686_RTC_CONTROLM, data, 2);
ret = regmap_bulk_write(info->rtc_regmap,
info->drv_data->map[REG_RTC_CONTROLM],
data, ARRAY_SIZE(data));
if (ret < 0) {
dev_err(info->dev, "%s: fail to write controlm reg(%d)\n",
__func__, ret);
dev_err(info->dev, "Fail to write controlm reg(%d)\n", ret);
return ret;
}
@ -417,28 +666,97 @@ static int max77686_rtc_init_reg(struct max77686_rtc_info *info)
return ret;
}
static int max77686_rtc_probe(struct platform_device *pdev)
static const struct regmap_config max77686_rtc_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
static int max77686_init_rtc_regmap(struct max77686_rtc_info *info)
{
struct max77686_dev *max77686 = dev_get_drvdata(pdev->dev.parent);
struct max77686_rtc_info *info;
struct device *parent = info->dev->parent;
struct i2c_client *parent_i2c = to_i2c_client(parent);
int ret;
dev_info(&pdev->dev, "%s\n", __func__);
if (info->drv_data->rtc_irq_from_platform) {
struct platform_device *pdev = to_platform_device(info->dev);
info->rtc_irq = platform_get_irq(pdev, 0);
if (info->rtc_irq < 0) {
dev_err(info->dev, "Failed to get rtc interrupts: %d\n",
info->rtc_irq);
return info->rtc_irq;
}
} else {
info->rtc_irq = parent_i2c->irq;
}
info->regmap = dev_get_regmap(parent, NULL);
if (!info->regmap) {
dev_err(info->dev, "Failed to get rtc regmap\n");
return -ENODEV;
}
if (info->drv_data->rtc_i2c_addr == MAX77686_INVALID_I2C_ADDR) {
info->rtc_regmap = info->regmap;
goto add_rtc_irq;
}
info->rtc = i2c_new_dummy(parent_i2c->adapter,
info->drv_data->rtc_i2c_addr);
if (!info->rtc) {
dev_err(info->dev, "Failed to allocate I2C device for RTC\n");
return -ENODEV;
}
info->rtc_regmap = devm_regmap_init_i2c(info->rtc,
&max77686_rtc_regmap_config);
if (IS_ERR(info->rtc_regmap)) {
ret = PTR_ERR(info->rtc_regmap);
dev_err(info->dev, "Failed to allocate RTC regmap: %d\n", ret);
goto err_unregister_i2c;
}
add_rtc_irq:
ret = regmap_add_irq_chip(info->rtc_regmap, info->rtc_irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT |
IRQF_SHARED, 0, info->drv_data->rtc_irq_chip,
&info->rtc_irq_data);
if (ret < 0) {
dev_err(info->dev, "Failed to add RTC irq chip: %d\n", ret);
goto err_unregister_i2c;
}
return 0;
err_unregister_i2c:
if (info->rtc)
i2c_unregister_device(info->rtc);
return ret;
}
static int max77686_rtc_probe(struct platform_device *pdev)
{
struct max77686_rtc_info *info;
const struct platform_device_id *id = platform_get_device_id(pdev);
int ret;
info = devm_kzalloc(&pdev->dev, sizeof(struct max77686_rtc_info),
GFP_KERNEL);
GFP_KERNEL);
if (!info)
return -ENOMEM;
mutex_init(&info->lock);
info->dev = &pdev->dev;
info->max77686 = max77686;
info->rtc = max77686->rtc;
info->drv_data = (const struct max77686_rtc_driver_data *)
id->driver_data;
ret = max77686_init_rtc_regmap(info);
if (ret < 0)
return ret;
platform_set_drvdata(pdev, info);
ret = max77686_rtc_init_reg(info);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to initialize RTC reg:%d\n", ret);
goto err_rtc;
@ -446,7 +764,7 @@ static int max77686_rtc_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 1);
info->rtc_dev = devm_rtc_device_register(&pdev->dev, "max77686-rtc",
info->rtc_dev = devm_rtc_device_register(&pdev->dev, id->name,
&max77686_rtc_ops, THIS_MODULE);
if (IS_ERR(info->rtc_dev)) {
@ -457,29 +775,43 @@ static int max77686_rtc_probe(struct platform_device *pdev)
goto err_rtc;
}
if (!max77686->rtc_irq_data) {
ret = -EINVAL;
dev_err(&pdev->dev, "%s: no RTC regmap IRQ chip\n", __func__);
goto err_rtc;
}
info->virq = regmap_irq_get_virq(max77686->rtc_irq_data,
info->virq = regmap_irq_get_virq(info->rtc_irq_data,
MAX77686_RTCIRQ_RTCA1);
if (!info->virq) {
if (info->virq <= 0) {
ret = -ENXIO;
goto err_rtc;
}
ret = devm_request_threaded_irq(&pdev->dev, info->virq, NULL,
max77686_rtc_alarm_irq, 0, "rtc-alarm1", info);
if (ret < 0)
ret = request_threaded_irq(info->virq, NULL, max77686_rtc_alarm_irq, 0,
"rtc-alarm1", info);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
info->virq, ret);
goto err_rtc;
}
return 0;
err_rtc:
regmap_del_irq_chip(info->rtc_irq, info->rtc_irq_data);
if (info->rtc)
i2c_unregister_device(info->rtc);
return ret;
}
static int max77686_rtc_remove(struct platform_device *pdev)
{
struct max77686_rtc_info *info = platform_get_drvdata(pdev);
free_irq(info->virq, info);
regmap_del_irq_chip(info->rtc_irq, info->rtc_irq_data);
if (info->rtc)
i2c_unregister_device(info->rtc);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int max77686_rtc_suspend(struct device *dev)
{
@ -508,7 +840,9 @@ static SIMPLE_DEV_PM_OPS(max77686_rtc_pm_ops,
max77686_rtc_suspend, max77686_rtc_resume);
static const struct platform_device_id rtc_id[] = {
{ "max77686-rtc", 0 },
{ "max77686-rtc", .driver_data = (kernel_ulong_t)&max77686_drv_data, },
{ "max77802-rtc", .driver_data = (kernel_ulong_t)&max77802_drv_data, },
{ "max77620-rtc", .driver_data = (kernel_ulong_t)&max77620_drv_data, },
{},
};
MODULE_DEVICE_TABLE(platform, rtc_id);
@ -519,6 +853,7 @@ static struct platform_driver max77686_rtc_driver = {
.pm = &max77686_rtc_pm_ops,
},
.probe = max77686_rtc_probe,
.remove = max77686_rtc_remove,
.id_table = rtc_id,
};

View File

@ -1,502 +0,0 @@
/*
* RTC driver for Maxim MAX77802
*
* Copyright (C) 2013 Google, Inc
*
* Copyright (C) 2012 Samsung Electronics Co.Ltd
*
* based on rtc-max8997.c
*
* 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/slab.h>
#include <linux/rtc.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mfd/max77686-private.h>
#include <linux/irqdomain.h>
#include <linux/regmap.h>
/* RTC Control Register */
#define BCD_EN_SHIFT 0
#define BCD_EN_MASK (1 << BCD_EN_SHIFT)
#define MODEL24_SHIFT 1
#define MODEL24_MASK (1 << MODEL24_SHIFT)
/* RTC Update Register1 */
#define RTC_UDR_SHIFT 0
#define RTC_UDR_MASK (1 << RTC_UDR_SHIFT)
#define RTC_RBUDR_SHIFT 4
#define RTC_RBUDR_MASK (1 << RTC_RBUDR_SHIFT)
/* RTC Hour register */
#define HOUR_PM_SHIFT 6
#define HOUR_PM_MASK (1 << HOUR_PM_SHIFT)
/* RTC Alarm Enable */
#define ALARM_ENABLE_SHIFT 7
#define ALARM_ENABLE_MASK (1 << ALARM_ENABLE_SHIFT)
/* For the RTCAE1 register, we write this value to enable the alarm */
#define ALARM_ENABLE_VALUE 0x77
#define MAX77802_RTC_UPDATE_DELAY_US 200
enum {
RTC_SEC = 0,
RTC_MIN,
RTC_HOUR,
RTC_WEEKDAY,
RTC_MONTH,
RTC_YEAR,
RTC_DATE,
RTC_NR_TIME
};
struct max77802_rtc_info {
struct device *dev;
struct max77686_dev *max77802;
struct i2c_client *rtc;
struct rtc_device *rtc_dev;
struct mutex lock;
struct regmap *regmap;
int virq;
int rtc_24hr_mode;
};
enum MAX77802_RTC_OP {
MAX77802_RTC_WRITE,
MAX77802_RTC_READ,
};
static void max77802_rtc_data_to_tm(u8 *data, struct rtc_time *tm,
int rtc_24hr_mode)
{
tm->tm_sec = data[RTC_SEC] & 0xff;
tm->tm_min = data[RTC_MIN] & 0xff;
if (rtc_24hr_mode)
tm->tm_hour = data[RTC_HOUR] & 0x1f;
else {
tm->tm_hour = data[RTC_HOUR] & 0x0f;
if (data[RTC_HOUR] & HOUR_PM_MASK)
tm->tm_hour += 12;
}
/* Only a single bit is set in data[], so fls() would be equivalent */
tm->tm_wday = ffs(data[RTC_WEEKDAY] & 0xff) - 1;
tm->tm_mday = data[RTC_DATE] & 0x1f;
tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1;
tm->tm_year = data[RTC_YEAR] & 0xff;
tm->tm_yday = 0;
tm->tm_isdst = 0;
}
static int max77802_rtc_tm_to_data(struct rtc_time *tm, u8 *data)
{
data[RTC_SEC] = tm->tm_sec;
data[RTC_MIN] = tm->tm_min;
data[RTC_HOUR] = tm->tm_hour;
data[RTC_WEEKDAY] = 1 << tm->tm_wday;
data[RTC_DATE] = tm->tm_mday;
data[RTC_MONTH] = tm->tm_mon + 1;
data[RTC_YEAR] = tm->tm_year;
return 0;
}
static int max77802_rtc_update(struct max77802_rtc_info *info,
enum MAX77802_RTC_OP op)
{
int ret;
unsigned int data;
if (op == MAX77802_RTC_WRITE)
data = 1 << RTC_UDR_SHIFT;
else
data = 1 << RTC_RBUDR_SHIFT;
ret = regmap_update_bits(info->max77802->regmap,
MAX77802_RTC_UPDATE0, data, data);
if (ret < 0)
dev_err(info->dev, "%s: fail to write update reg(ret=%d, data=0x%x)\n",
__func__, ret, data);
else {
/* Minimum delay required before RTC update. */
usleep_range(MAX77802_RTC_UPDATE_DELAY_US,
MAX77802_RTC_UPDATE_DELAY_US * 2);
}
return ret;
}
static int max77802_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct max77802_rtc_info *info = dev_get_drvdata(dev);
u8 data[RTC_NR_TIME];
int ret;
mutex_lock(&info->lock);
ret = max77802_rtc_update(info, MAX77802_RTC_READ);
if (ret < 0)
goto out;
ret = regmap_bulk_read(info->max77802->regmap,
MAX77802_RTC_SEC, data, RTC_NR_TIME);
if (ret < 0) {
dev_err(info->dev, "%s: fail to read time reg(%d)\n", __func__,
ret);
goto out;
}
max77802_rtc_data_to_tm(data, tm, info->rtc_24hr_mode);
ret = rtc_valid_tm(tm);
out:
mutex_unlock(&info->lock);
return ret;
}
static int max77802_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct max77802_rtc_info *info = dev_get_drvdata(dev);
u8 data[RTC_NR_TIME];
int ret;
ret = max77802_rtc_tm_to_data(tm, data);
if (ret < 0)
return ret;
mutex_lock(&info->lock);
ret = regmap_bulk_write(info->max77802->regmap,
MAX77802_RTC_SEC, data, RTC_NR_TIME);
if (ret < 0) {
dev_err(info->dev, "%s: fail to write time reg(%d)\n", __func__,
ret);
goto out;
}
ret = max77802_rtc_update(info, MAX77802_RTC_WRITE);
out:
mutex_unlock(&info->lock);
return ret;
}
static int max77802_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct max77802_rtc_info *info = dev_get_drvdata(dev);
u8 data[RTC_NR_TIME];
unsigned int val;
int ret;
mutex_lock(&info->lock);
ret = max77802_rtc_update(info, MAX77802_RTC_READ);
if (ret < 0)
goto out;
ret = regmap_bulk_read(info->max77802->regmap,
MAX77802_ALARM1_SEC, data, RTC_NR_TIME);
if (ret < 0) {
dev_err(info->dev, "%s:%d fail to read alarm reg(%d)\n",
__func__, __LINE__, ret);
goto out;
}
max77802_rtc_data_to_tm(data, &alrm->time, info->rtc_24hr_mode);
alrm->enabled = 0;
ret = regmap_read(info->max77802->regmap,
MAX77802_RTC_AE1, &val);
if (ret < 0) {
dev_err(info->dev, "%s:%d fail to read alarm enable(%d)\n",
__func__, __LINE__, ret);
goto out;
}
if (val)
alrm->enabled = 1;
alrm->pending = 0;
ret = regmap_read(info->max77802->regmap, MAX77802_REG_STATUS2, &val);
if (ret < 0) {
dev_err(info->dev, "%s:%d fail to read status2 reg(%d)\n",
__func__, __LINE__, ret);
goto out;
}
if (val & (1 << 2)) /* RTCA1 */
alrm->pending = 1;
out:
mutex_unlock(&info->lock);
return 0;
}
static int max77802_rtc_stop_alarm(struct max77802_rtc_info *info)
{
int ret;
if (!mutex_is_locked(&info->lock))
dev_warn(info->dev, "%s: should have mutex locked\n", __func__);
ret = max77802_rtc_update(info, MAX77802_RTC_READ);
if (ret < 0)
goto out;
ret = regmap_write(info->max77802->regmap,
MAX77802_RTC_AE1, 0);
if (ret < 0) {
dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
__func__, ret);
goto out;
}
ret = max77802_rtc_update(info, MAX77802_RTC_WRITE);
out:
return ret;
}
static int max77802_rtc_start_alarm(struct max77802_rtc_info *info)
{
int ret;
if (!mutex_is_locked(&info->lock))
dev_warn(info->dev, "%s: should have mutex locked\n",
__func__);
ret = max77802_rtc_update(info, MAX77802_RTC_READ);
if (ret < 0)
goto out;
ret = regmap_write(info->max77802->regmap,
MAX77802_RTC_AE1,
ALARM_ENABLE_VALUE);
if (ret < 0) {
dev_err(info->dev, "%s: fail to read alarm reg(%d)\n",
__func__, ret);
goto out;
}
ret = max77802_rtc_update(info, MAX77802_RTC_WRITE);
out:
return ret;
}
static int max77802_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct max77802_rtc_info *info = dev_get_drvdata(dev);
u8 data[RTC_NR_TIME];
int ret;
ret = max77802_rtc_tm_to_data(&alrm->time, data);
if (ret < 0)
return ret;
mutex_lock(&info->lock);
ret = max77802_rtc_stop_alarm(info);
if (ret < 0)
goto out;
ret = regmap_bulk_write(info->max77802->regmap,
MAX77802_ALARM1_SEC, data, RTC_NR_TIME);
if (ret < 0) {
dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
__func__, ret);
goto out;
}
ret = max77802_rtc_update(info, MAX77802_RTC_WRITE);
if (ret < 0)
goto out;
if (alrm->enabled)
ret = max77802_rtc_start_alarm(info);
out:
mutex_unlock(&info->lock);
return ret;
}
static int max77802_rtc_alarm_irq_enable(struct device *dev,
unsigned int enabled)
{
struct max77802_rtc_info *info = dev_get_drvdata(dev);
int ret;
mutex_lock(&info->lock);
if (enabled)
ret = max77802_rtc_start_alarm(info);
else
ret = max77802_rtc_stop_alarm(info);
mutex_unlock(&info->lock);
return ret;
}
static irqreturn_t max77802_rtc_alarm_irq(int irq, void *data)
{
struct max77802_rtc_info *info = data;
dev_dbg(info->dev, "%s:irq(%d)\n", __func__, irq);
rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF);
return IRQ_HANDLED;
}
static const struct rtc_class_ops max77802_rtc_ops = {
.read_time = max77802_rtc_read_time,
.set_time = max77802_rtc_set_time,
.read_alarm = max77802_rtc_read_alarm,
.set_alarm = max77802_rtc_set_alarm,
.alarm_irq_enable = max77802_rtc_alarm_irq_enable,
};
static int max77802_rtc_init_reg(struct max77802_rtc_info *info)
{
u8 data[2];
int ret;
max77802_rtc_update(info, MAX77802_RTC_READ);
/* Set RTC control register : Binary mode, 24hour mdoe */
data[0] = (1 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
info->rtc_24hr_mode = 1;
ret = regmap_bulk_write(info->max77802->regmap,
MAX77802_RTC_CONTROLM, data, ARRAY_SIZE(data));
if (ret < 0) {
dev_err(info->dev, "%s: fail to write controlm reg(%d)\n",
__func__, ret);
return ret;
}
ret = max77802_rtc_update(info, MAX77802_RTC_WRITE);
return ret;
}
static int max77802_rtc_probe(struct platform_device *pdev)
{
struct max77686_dev *max77802 = dev_get_drvdata(pdev->dev.parent);
struct max77802_rtc_info *info;
int ret;
dev_dbg(&pdev->dev, "%s\n", __func__);
info = devm_kzalloc(&pdev->dev, sizeof(struct max77802_rtc_info),
GFP_KERNEL);
if (!info)
return -ENOMEM;
mutex_init(&info->lock);
info->dev = &pdev->dev;
info->max77802 = max77802;
info->rtc = max77802->i2c;
platform_set_drvdata(pdev, info);
ret = max77802_rtc_init_reg(info);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to initialize RTC reg:%d\n", ret);
return ret;
}
device_init_wakeup(&pdev->dev, 1);
info->rtc_dev = devm_rtc_device_register(&pdev->dev, "max77802-rtc",
&max77802_rtc_ops, THIS_MODULE);
if (IS_ERR(info->rtc_dev)) {
ret = PTR_ERR(info->rtc_dev);
dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
if (ret == 0)
ret = -EINVAL;
return ret;
}
if (!max77802->rtc_irq_data) {
dev_err(&pdev->dev, "No RTC regmap IRQ chip\n");
return -EINVAL;
}
info->virq = regmap_irq_get_virq(max77802->rtc_irq_data,
MAX77686_RTCIRQ_RTCA1);
if (info->virq <= 0) {
dev_err(&pdev->dev, "Failed to get virtual IRQ %d\n",
MAX77686_RTCIRQ_RTCA1);
return -EINVAL;
}
ret = devm_request_threaded_irq(&pdev->dev, info->virq, NULL,
max77802_rtc_alarm_irq, 0, "rtc-alarm1",
info);
if (ret < 0)
dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
info->virq, ret);
return ret;
}
#ifdef CONFIG_PM_SLEEP
static int max77802_rtc_suspend(struct device *dev)
{
if (device_may_wakeup(dev)) {
struct max77802_rtc_info *info = dev_get_drvdata(dev);
return enable_irq_wake(info->virq);
}
return 0;
}
static int max77802_rtc_resume(struct device *dev)
{
if (device_may_wakeup(dev)) {
struct max77802_rtc_info *info = dev_get_drvdata(dev);
return disable_irq_wake(info->virq);
}
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(max77802_rtc_pm_ops,
max77802_rtc_suspend, max77802_rtc_resume);
static const struct platform_device_id rtc_id[] = {
{ "max77802-rtc", 0 },
{},
};
MODULE_DEVICE_TABLE(platform, rtc_id);
static struct platform_driver max77802_rtc_driver = {
.driver = {
.name = "max77802-rtc",
.pm = &max77802_rtc_pm_ops,
},
.probe = max77802_rtc_probe,
.id_table = rtc_id,
};
module_platform_driver(max77802_rtc_driver);
MODULE_DESCRIPTION("Maxim MAX77802 RTC driver");
MODULE_AUTHOR("Simon Glass <sjg@chromium.org>");
MODULE_LICENSE("GPL");

View File

@ -419,4 +419,3 @@ module_platform_driver(mtk_rtc_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Tianping Fang <tianping.fang@mediatek.com>");
MODULE_DESCRIPTION("RTC Driver for MediaTek MT6397 PMIC");
MODULE_ALIAS("platform:mt6397-rtc");

View File

@ -311,8 +311,7 @@ static int palmas_rtc_probe(struct platform_device *pdev)
ret = devm_request_threaded_irq(&pdev->dev, palmas_rtc->irq, NULL,
palmas_rtc_interrupt,
IRQF_TRIGGER_LOW | IRQF_ONESHOT |
IRQF_EARLY_RESUME,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
dev_name(&pdev->dev), palmas_rtc);
if (ret < 0) {
dev_err(&pdev->dev, "IRQ request failed, err = %d\n", ret);

View File

@ -48,6 +48,7 @@
#define DRV_VERSION "0.6"
/* REGISTERS */
#define PCF2123_REG_CTRL1 (0x00) /* Control Register 1 */
#define PCF2123_REG_CTRL2 (0x01) /* Control Register 2 */
#define PCF2123_REG_SC (0x02) /* datetime */
@ -57,10 +58,54 @@
#define PCF2123_REG_DW (0x06)
#define PCF2123_REG_MO (0x07)
#define PCF2123_REG_YR (0x08)
#define PCF2123_REG_ALRM_MN (0x09) /* Alarm Registers */
#define PCF2123_REG_ALRM_HR (0x0a)
#define PCF2123_REG_ALRM_DM (0x0b)
#define PCF2123_REG_ALRM_DW (0x0c)
#define PCF2123_REG_OFFSET (0x0d) /* Clock Rate Offset Register */
#define PCF2123_REG_TMR_CLKOUT (0x0e) /* Timer Registers */
#define PCF2123_REG_CTDWN_TMR (0x0f)
/* PCF2123_REG_CTRL1 BITS */
#define CTRL1_CLEAR (0) /* Clear */
#define CTRL1_CORR_INT BIT(1) /* Correction irq enable */
#define CTRL1_12_HOUR BIT(2) /* 12 hour time */
#define CTRL1_SW_RESET (BIT(3) | BIT(4) | BIT(6)) /* Software reset */
#define CTRL1_STOP BIT(5) /* Stop the clock */
#define CTRL1_EXT_TEST BIT(7) /* External clock test mode */
/* PCF2123_REG_CTRL2 BITS */
#define CTRL2_TIE BIT(0) /* Countdown timer irq enable */
#define CTRL2_AIE BIT(1) /* Alarm irq enable */
#define CTRL2_TF BIT(2) /* Countdown timer flag */
#define CTRL2_AF BIT(3) /* Alarm flag */
#define CTRL2_TI_TP BIT(4) /* Irq pin generates pulse */
#define CTRL2_MSF BIT(5) /* Minute or second irq flag */
#define CTRL2_SI BIT(6) /* Second irq enable */
#define CTRL2_MI BIT(7) /* Minute irq enable */
/* PCF2123_REG_SC BITS */
#define OSC_HAS_STOPPED BIT(7) /* Clock has been stopped */
/* PCF2123_REG_ALRM_XX BITS */
#define ALRM_ENABLE BIT(7) /* MN, HR, DM, or DW alarm enable */
/* PCF2123_REG_TMR_CLKOUT BITS */
#define CD_TMR_4096KHZ (0) /* 4096 KHz countdown timer */
#define CD_TMR_64HZ (1) /* 64 Hz countdown timer */
#define CD_TMR_1HZ (2) /* 1 Hz countdown timer */
#define CD_TMR_60th_HZ (3) /* 60th Hz countdown timer */
#define CD_TMR_TE BIT(3) /* Countdown timer enable */
/* PCF2123_REG_OFFSET BITS */
#define OFFSET_SIGN_BIT BIT(6) /* 2's complement sign bit */
#define OFFSET_COARSE BIT(7) /* Coarse mode offset */
#define OFFSET_STEP (2170) /* Offset step in parts per billion */
/* READ/WRITE ADDRESS BITS */
#define PCF2123_WRITE BIT(4)
#define PCF2123_READ (BIT(4) | BIT(7))
#define PCF2123_SUBADDR (1 << 4)
#define PCF2123_WRITE ((0 << 7) | PCF2123_SUBADDR)
#define PCF2123_READ ((1 << 7) | PCF2123_SUBADDR)
static struct spi_driver pcf2123_driver;
@ -84,12 +129,44 @@ static inline void pcf2123_delay_trec(void)
ndelay(30);
}
static int pcf2123_read(struct device *dev, u8 reg, u8 *rxbuf, size_t size)
{
struct spi_device *spi = to_spi_device(dev);
int ret;
reg |= PCF2123_READ;
ret = spi_write_then_read(spi, &reg, 1, rxbuf, size);
pcf2123_delay_trec();
return ret;
}
static int pcf2123_write(struct device *dev, u8 *txbuf, size_t size)
{
struct spi_device *spi = to_spi_device(dev);
int ret;
txbuf[0] |= PCF2123_WRITE;
ret = spi_write(spi, txbuf, size);
pcf2123_delay_trec();
return ret;
}
static int pcf2123_write_reg(struct device *dev, u8 reg, u8 val)
{
u8 txbuf[2];
txbuf[0] = reg;
txbuf[1] = val;
return pcf2123_write(dev, txbuf, sizeof(txbuf));
}
static ssize_t pcf2123_show(struct device *dev, struct device_attribute *attr,
char *buffer)
{
struct spi_device *spi = to_spi_device(dev);
struct pcf2123_sysfs_reg *r;
u8 txbuf[1], rxbuf[1];
u8 rxbuf[1];
unsigned long reg;
int ret;
@ -99,19 +176,16 @@ static ssize_t pcf2123_show(struct device *dev, struct device_attribute *attr,
if (ret)
return ret;
txbuf[0] = PCF2123_READ | reg;
ret = spi_write_then_read(spi, txbuf, 1, rxbuf, 1);
ret = pcf2123_read(dev, reg, rxbuf, 1);
if (ret < 0)
return -EIO;
pcf2123_delay_trec();
return sprintf(buffer, "0x%x\n", rxbuf[0]);
}
static ssize_t pcf2123_store(struct device *dev, struct device_attribute *attr,
const char *buffer, size_t count) {
struct spi_device *spi = to_spi_device(dev);
struct pcf2123_sysfs_reg *r;
u8 txbuf[2];
unsigned long reg;
unsigned long val;
@ -127,27 +201,78 @@ static ssize_t pcf2123_store(struct device *dev, struct device_attribute *attr,
if (ret)
return ret;
txbuf[0] = PCF2123_WRITE | reg;
txbuf[1] = val;
ret = spi_write(spi, txbuf, sizeof(txbuf));
pcf2123_write_reg(dev, reg, val);
if (ret < 0)
return -EIO;
pcf2123_delay_trec();
return count;
}
static int pcf2123_read_offset(struct device *dev, long *offset)
{
int ret;
s8 reg;
ret = pcf2123_read(dev, PCF2123_REG_OFFSET, &reg, 1);
if (ret < 0)
return ret;
if (reg & OFFSET_COARSE)
reg <<= 1; /* multiply by 2 and sign extend */
else
reg |= (reg & OFFSET_SIGN_BIT) << 1; /* sign extend only */
*offset = ((long)reg) * OFFSET_STEP;
return 0;
}
/*
* The offset register is a 7 bit signed value with a coarse bit in bit 7.
* The main difference between the two is normal offset adjusts the first
* second of n minutes every other hour, with 61, 62 and 63 being shoved
* into the 60th minute.
* The coarse adjustment does the same, but every hour.
* the two overlap, with every even normal offset value corresponding
* to a coarse offset. Based on this algorithm, it seems that despite the
* name, coarse offset is a better fit for overlapping values.
*/
static int pcf2123_set_offset(struct device *dev, long offset)
{
s8 reg;
if (offset > OFFSET_STEP * 127)
reg = 127;
else if (offset < OFFSET_STEP * -128)
reg = -128;
else
reg = (s8)((offset + (OFFSET_STEP >> 1)) / OFFSET_STEP);
/* choose fine offset only for odd values in the normal range */
if (reg & 1 && reg <= 63 && reg >= -64) {
/* Normal offset. Clear the coarse bit */
reg &= ~OFFSET_COARSE;
} else {
/* Coarse offset. Divide by 2 and set the coarse bit */
reg >>= 1;
reg |= OFFSET_COARSE;
}
return pcf2123_write_reg(dev, PCF2123_REG_OFFSET, reg);
}
static int pcf2123_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct spi_device *spi = to_spi_device(dev);
u8 txbuf[1], rxbuf[7];
u8 rxbuf[7];
int ret;
txbuf[0] = PCF2123_READ | PCF2123_REG_SC;
ret = spi_write_then_read(spi, txbuf, sizeof(txbuf),
rxbuf, sizeof(rxbuf));
ret = pcf2123_read(dev, PCF2123_REG_SC, rxbuf, sizeof(rxbuf));
if (ret < 0)
return ret;
pcf2123_delay_trec();
if (rxbuf[0] & OSC_HAS_STOPPED) {
dev_info(dev, "clock was stopped. Time is not valid\n");
return -EINVAL;
}
tm->tm_sec = bcd2bin(rxbuf[0] & 0x7F);
tm->tm_min = bcd2bin(rxbuf[1] & 0x7F);
@ -170,7 +295,6 @@ static int pcf2123_rtc_read_time(struct device *dev, struct rtc_time *tm)
static int pcf2123_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct spi_device *spi = to_spi_device(dev);
u8 txbuf[8];
int ret;
@ -181,15 +305,12 @@ static int pcf2123_rtc_set_time(struct device *dev, struct rtc_time *tm)
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
/* Stop the counter first */
txbuf[0] = PCF2123_WRITE | PCF2123_REG_CTRL1;
txbuf[1] = 0x20;
ret = spi_write(spi, txbuf, 2);
ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_STOP);
if (ret < 0)
return ret;
pcf2123_delay_trec();
/* Set the new time */
txbuf[0] = PCF2123_WRITE | PCF2123_REG_SC;
txbuf[0] = PCF2123_REG_SC;
txbuf[1] = bin2bcd(tm->tm_sec & 0x7F);
txbuf[2] = bin2bcd(tm->tm_min & 0x7F);
txbuf[3] = bin2bcd(tm->tm_hour & 0x3F);
@ -198,18 +319,48 @@ static int pcf2123_rtc_set_time(struct device *dev, struct rtc_time *tm)
txbuf[6] = bin2bcd((tm->tm_mon + 1) & 0x1F); /* rtc mn 1-12 */
txbuf[7] = bin2bcd(tm->tm_year < 100 ? tm->tm_year : tm->tm_year - 100);
ret = spi_write(spi, txbuf, sizeof(txbuf));
ret = pcf2123_write(dev, txbuf, sizeof(txbuf));
if (ret < 0)
return ret;
pcf2123_delay_trec();
/* Start the counter */
txbuf[0] = PCF2123_WRITE | PCF2123_REG_CTRL1;
txbuf[1] = 0x00;
ret = spi_write(spi, txbuf, 2);
ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_CLEAR);
if (ret < 0)
return ret;
return 0;
}
static int pcf2123_reset(struct device *dev)
{
int ret;
u8 rxbuf[2];
ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_SW_RESET);
if (ret < 0)
return ret;
/* Stop the counter */
dev_dbg(dev, "stopping RTC\n");
ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_STOP);
if (ret < 0)
return ret;
/* See if the counter was actually stopped */
dev_dbg(dev, "checking for presence of RTC\n");
ret = pcf2123_read(dev, PCF2123_REG_CTRL1, rxbuf, sizeof(rxbuf));
if (ret < 0)
return ret;
dev_dbg(dev, "received data from RTC (0x%02X 0x%02X)\n",
rxbuf[0], rxbuf[1]);
if (!(rxbuf[0] & CTRL1_STOP))
return -ENODEV;
/* Start the counter */
ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_CLEAR);
if (ret < 0)
return ret;
pcf2123_delay_trec();
return 0;
}
@ -217,13 +368,16 @@ static int pcf2123_rtc_set_time(struct device *dev, struct rtc_time *tm)
static const struct rtc_class_ops pcf2123_rtc_ops = {
.read_time = pcf2123_rtc_read_time,
.set_time = pcf2123_rtc_set_time,
.read_offset = pcf2123_read_offset,
.set_offset = pcf2123_set_offset,
};
static int pcf2123_probe(struct spi_device *spi)
{
struct rtc_device *rtc;
struct rtc_time tm;
struct pcf2123_plat_data *pdata;
u8 txbuf[2], rxbuf[2];
int ret, i;
pdata = devm_kzalloc(&spi->dev, sizeof(struct pcf2123_plat_data),
@ -232,56 +386,19 @@ static int pcf2123_probe(struct spi_device *spi)
return -ENOMEM;
spi->dev.platform_data = pdata;
/* Send a software reset command */
txbuf[0] = PCF2123_WRITE | PCF2123_REG_CTRL1;
txbuf[1] = 0x58;
dev_dbg(&spi->dev, "resetting RTC (0x%02X 0x%02X)\n",
txbuf[0], txbuf[1]);
ret = spi_write(spi, txbuf, 2 * sizeof(u8));
if (ret < 0)
goto kfree_exit;
pcf2123_delay_trec();
/* Stop the counter */
txbuf[0] = PCF2123_WRITE | PCF2123_REG_CTRL1;
txbuf[1] = 0x20;
dev_dbg(&spi->dev, "stopping RTC (0x%02X 0x%02X)\n",
txbuf[0], txbuf[1]);
ret = spi_write(spi, txbuf, 2 * sizeof(u8));
if (ret < 0)
goto kfree_exit;
pcf2123_delay_trec();
/* See if the counter was actually stopped */
txbuf[0] = PCF2123_READ | PCF2123_REG_CTRL1;
dev_dbg(&spi->dev, "checking for presence of RTC (0x%02X)\n",
txbuf[0]);
ret = spi_write_then_read(spi, txbuf, 1 * sizeof(u8),
rxbuf, 2 * sizeof(u8));
dev_dbg(&spi->dev, "received data from RTC (0x%02X 0x%02X)\n",
rxbuf[0], rxbuf[1]);
if (ret < 0)
goto kfree_exit;
pcf2123_delay_trec();
if (!(rxbuf[0] & 0x20)) {
dev_err(&spi->dev, "chip not found\n");
ret = -ENODEV;
goto kfree_exit;
ret = pcf2123_rtc_read_time(&spi->dev, &tm);
if (ret < 0) {
ret = pcf2123_reset(&spi->dev);
if (ret < 0) {
dev_err(&spi->dev, "chip not found\n");
goto kfree_exit;
}
}
dev_info(&spi->dev, "chip found, driver version " DRV_VERSION "\n");
dev_info(&spi->dev, "spiclk %u KHz.\n",
(spi->max_speed_hz + 500) / 1000);
/* Start the counter */
txbuf[0] = PCF2123_WRITE | PCF2123_REG_CTRL1;
txbuf[1] = 0x00;
ret = spi_write(spi, txbuf, sizeof(txbuf));
if (ret < 0)
goto kfree_exit;
pcf2123_delay_trec();
/* Finalize the initialization */
rtc = devm_rtc_device_register(&spi->dev, pcf2123_driver.driver.name,
&pcf2123_rtc_ops, THIS_MODULE);

View File

@ -1,12 +1,12 @@
/*
* An I2C driver for the NXP PCF2127 RTC
* An I2C and SPI driver for the NXP PCF2127/29 RTC
* Copyright 2013 Til-Technologies
*
* Author: Renaud Cerrato <r.cerrato@til-technologies.fr>
*
* based on the other drivers in this same directory.
*
* http://www.nxp.com/documents/data_sheet/PCF2127AT.pdf
* Datasheet: http://cache.nxp.com/documents/data_sheet/PCF2127.pdf
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -14,11 +14,13 @@
*/
#include <linux/i2c.h>
#include <linux/spi/spi.h>
#include <linux/bcd.h>
#include <linux/rtc.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regmap.h>
#define PCF2127_REG_CTRL1 (0x00) /* Control Register 1 */
#define PCF2127_REG_CTRL2 (0x01) /* Control Register 2 */
@ -36,29 +38,30 @@
#define PCF2127_OSF BIT(7) /* Oscillator Fail flag */
static struct i2c_driver pcf2127_driver;
struct pcf2127 {
struct rtc_device *rtc;
struct regmap *regmap;
};
/*
* In the routines that deal directly with the pcf2127 hardware, we use
* rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.
*/
static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm)
static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
unsigned char buf[10] = { PCF2127_REG_CTRL1 };
struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
unsigned char buf[10];
int ret;
/* read registers */
if (i2c_master_send(client, buf, 1) != 1 ||
i2c_master_recv(client, buf, sizeof(buf)) != sizeof(buf)) {
dev_err(&client->dev, "%s: read error\n", __func__);
return -EIO;
ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_CTRL1, buf,
sizeof(buf));
if (ret) {
dev_err(dev, "%s: read error\n", __func__);
return ret;
}
if (buf[PCF2127_REG_CTRL3] & PCF2127_REG_CTRL3_BLF)
dev_info(&client->dev,
dev_info(dev,
"low voltage detected, check/replace RTC battery.\n");
if (buf[PCF2127_REG_SC] & PCF2127_OSF) {
@ -66,12 +69,12 @@ static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm)
* no need clear the flag here,
* it will be cleared once the new date is saved
*/
dev_warn(&client->dev,
dev_warn(dev,
"oscillator stop detected, date/time is not reliable\n");
return -EINVAL;
}
dev_dbg(&client->dev,
dev_dbg(dev,
"%s: raw data is cr1=%02x, cr2=%02x, cr3=%02x, "
"sec=%02x, min=%02x, hr=%02x, "
"mday=%02x, wday=%02x, mon=%02x, year=%02x\n",
@ -91,7 +94,7 @@ static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm)
if (tm->tm_year < 70)
tm->tm_year += 100; /* assume we are in 1970...2069 */
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
"mday=%d, mon=%d, year=%d, wday=%d\n",
__func__,
tm->tm_sec, tm->tm_min, tm->tm_hour,
@ -100,20 +103,18 @@ static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm)
return rtc_valid_tm(tm);
}
static int pcf2127_set_datetime(struct i2c_client *client, struct rtc_time *tm)
static int pcf2127_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
unsigned char buf[8];
struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
unsigned char buf[7];
int i = 0, err;
dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "
dev_dbg(dev, "%s: secs=%d, mins=%d, hours=%d, "
"mday=%d, mon=%d, year=%d, wday=%d\n",
__func__,
tm->tm_sec, tm->tm_min, tm->tm_hour,
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
/* start register address */
buf[i++] = PCF2127_REG_SC;
/* hours, minutes and seconds */
buf[i++] = bin2bcd(tm->tm_sec); /* this will also clear OSF flag */
buf[i++] = bin2bcd(tm->tm_min);
@ -128,11 +129,11 @@ static int pcf2127_set_datetime(struct i2c_client *client, struct rtc_time *tm)
buf[i++] = bin2bcd(tm->tm_year % 100);
/* write register's data */
err = i2c_master_send(client, buf, i);
if (err != i) {
dev_err(&client->dev,
err = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_SC, buf, i);
if (err) {
dev_err(dev,
"%s: err=%d", __func__, err);
return -EIO;
return err;
}
return 0;
@ -142,26 +143,17 @@ static int pcf2127_set_datetime(struct i2c_client *client, struct rtc_time *tm)
static int pcf2127_rtc_ioctl(struct device *dev,
unsigned int cmd, unsigned long arg)
{
struct i2c_client *client = to_i2c_client(dev);
unsigned char buf = PCF2127_REG_CTRL3;
struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
int touser;
int ret;
switch (cmd) {
case RTC_VL_READ:
ret = i2c_master_send(client, &buf, 1);
if (!ret)
ret = -EIO;
if (ret < 0)
ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL3, &touser);
if (ret)
return ret;
ret = i2c_master_recv(client, &buf, 1);
if (!ret)
ret = -EIO;
if (ret < 0)
return ret;
touser = buf & PCF2127_REG_CTRL3_BLF ? 1 : 0;
touser = touser & PCF2127_REG_CTRL3_BLF ? 1 : 0;
if (copy_to_user((void __user *)arg, &touser, sizeof(int)))
return -EFAULT;
@ -174,71 +166,270 @@ static int pcf2127_rtc_ioctl(struct device *dev,
#define pcf2127_rtc_ioctl NULL
#endif
static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
return pcf2127_get_datetime(to_i2c_client(dev), tm);
}
static int pcf2127_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
return pcf2127_set_datetime(to_i2c_client(dev), tm);
}
static const struct rtc_class_ops pcf2127_rtc_ops = {
.ioctl = pcf2127_rtc_ioctl,
.read_time = pcf2127_rtc_read_time,
.set_time = pcf2127_rtc_set_time,
};
static int pcf2127_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int pcf2127_probe(struct device *dev, struct regmap *regmap,
const char *name)
{
struct pcf2127 *pcf2127;
dev_dbg(&client->dev, "%s\n", __func__);
dev_dbg(dev, "%s\n", __func__);
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV;
pcf2127 = devm_kzalloc(&client->dev, sizeof(struct pcf2127),
GFP_KERNEL);
pcf2127 = devm_kzalloc(dev, sizeof(*pcf2127), GFP_KERNEL);
if (!pcf2127)
return -ENOMEM;
i2c_set_clientdata(client, pcf2127);
pcf2127->regmap = regmap;
pcf2127->rtc = devm_rtc_device_register(&client->dev,
pcf2127_driver.driver.name,
&pcf2127_rtc_ops, THIS_MODULE);
dev_set_drvdata(dev, pcf2127);
pcf2127->rtc = devm_rtc_device_register(dev, name, &pcf2127_rtc_ops,
THIS_MODULE);
return PTR_ERR_OR_ZERO(pcf2127->rtc);
}
static const struct i2c_device_id pcf2127_id[] = {
{ "pcf2127", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, pcf2127_id);
#ifdef CONFIG_OF
static const struct of_device_id pcf2127_of_match[] = {
{ .compatible = "nxp,pcf2127" },
{ .compatible = "nxp,pcf2129" },
{}
};
MODULE_DEVICE_TABLE(of, pcf2127_of_match);
#endif
static struct i2c_driver pcf2127_driver = {
.driver = {
.name = "rtc-pcf2127",
.of_match_table = of_match_ptr(pcf2127_of_match),
},
.probe = pcf2127_probe,
.id_table = pcf2127_id,
#if IS_ENABLED(CONFIG_I2C)
static int pcf2127_i2c_write(void *context, const void *data, size_t count)
{
struct device *dev = context;
struct i2c_client *client = to_i2c_client(dev);
int ret;
ret = i2c_master_send(client, data, count);
if (ret != count)
return ret < 0 ? ret : -EIO;
return 0;
}
static int pcf2127_i2c_gather_write(void *context,
const void *reg, size_t reg_size,
const void *val, size_t val_size)
{
struct device *dev = context;
struct i2c_client *client = to_i2c_client(dev);
int ret;
void *buf;
if (WARN_ON(reg_size != 1))
return -EINVAL;
buf = kmalloc(val_size + 1, GFP_KERNEL);
if (!buf)
return -ENOMEM;
memcpy(buf, reg, 1);
memcpy(buf + 1, val, val_size);
ret = i2c_master_send(client, buf, val_size + 1);
if (ret != val_size + 1)
return ret < 0 ? ret : -EIO;
return 0;
}
static int pcf2127_i2c_read(void *context, const void *reg, size_t reg_size,
void *val, size_t val_size)
{
struct device *dev = context;
struct i2c_client *client = to_i2c_client(dev);
int ret;
if (WARN_ON(reg_size != 1))
return -EINVAL;
ret = i2c_master_send(client, reg, 1);
if (ret != 1)
return ret < 0 ? ret : -EIO;
ret = i2c_master_recv(client, val, val_size);
if (ret != val_size)
return ret < 0 ? ret : -EIO;
return 0;
}
/*
* The reason we need this custom regmap_bus instead of using regmap_init_i2c()
* is that the STOP condition is required between set register address and
* read register data when reading from registers.
*/
static const struct regmap_bus pcf2127_i2c_regmap = {
.write = pcf2127_i2c_write,
.gather_write = pcf2127_i2c_gather_write,
.read = pcf2127_i2c_read,
};
module_i2c_driver(pcf2127_driver);
static struct i2c_driver pcf2127_i2c_driver;
static int pcf2127_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct regmap *regmap;
static const struct regmap_config config = {
.reg_bits = 8,
.val_bits = 8,
};
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV;
regmap = devm_regmap_init(&client->dev, &pcf2127_i2c_regmap,
&client->dev, &config);
if (IS_ERR(regmap)) {
dev_err(&client->dev, "%s: regmap allocation failed: %ld\n",
__func__, PTR_ERR(regmap));
return PTR_ERR(regmap);
}
return pcf2127_probe(&client->dev, regmap,
pcf2127_i2c_driver.driver.name);
}
static const struct i2c_device_id pcf2127_i2c_id[] = {
{ "pcf2127", 0 },
{ "pcf2129", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, pcf2127_i2c_id);
static struct i2c_driver pcf2127_i2c_driver = {
.driver = {
.name = "rtc-pcf2127-i2c",
.of_match_table = of_match_ptr(pcf2127_of_match),
},
.probe = pcf2127_i2c_probe,
.id_table = pcf2127_i2c_id,
};
static int pcf2127_i2c_register_driver(void)
{
return i2c_add_driver(&pcf2127_i2c_driver);
}
static void pcf2127_i2c_unregister_driver(void)
{
i2c_del_driver(&pcf2127_i2c_driver);
}
#else
static int pcf2127_i2c_register_driver(void)
{
return 0;
}
static void pcf2127_i2c_unregister_driver(void)
{
}
#endif
#if IS_ENABLED(CONFIG_SPI_MASTER)
static struct spi_driver pcf2127_spi_driver;
static int pcf2127_spi_probe(struct spi_device *spi)
{
static const struct regmap_config config = {
.reg_bits = 8,
.val_bits = 8,
.read_flag_mask = 0xa0,
.write_flag_mask = 0x20,
};
struct regmap *regmap;
regmap = devm_regmap_init_spi(spi, &config);
if (IS_ERR(regmap)) {
dev_err(&spi->dev, "%s: regmap allocation failed: %ld\n",
__func__, PTR_ERR(regmap));
return PTR_ERR(regmap);
}
return pcf2127_probe(&spi->dev, regmap, pcf2127_spi_driver.driver.name);
}
static const struct spi_device_id pcf2127_spi_id[] = {
{ "pcf2127", 0 },
{ "pcf2129", 0 },
{ }
};
MODULE_DEVICE_TABLE(spi, pcf2127_spi_id);
static struct spi_driver pcf2127_spi_driver = {
.driver = {
.name = "rtc-pcf2127-spi",
.of_match_table = of_match_ptr(pcf2127_of_match),
},
.probe = pcf2127_spi_probe,
.id_table = pcf2127_spi_id,
};
static int pcf2127_spi_register_driver(void)
{
return spi_register_driver(&pcf2127_spi_driver);
}
static void pcf2127_spi_unregister_driver(void)
{
spi_unregister_driver(&pcf2127_spi_driver);
}
#else
static int pcf2127_spi_register_driver(void)
{
return 0;
}
static void pcf2127_spi_unregister_driver(void)
{
}
#endif
static int __init pcf2127_init(void)
{
int ret;
ret = pcf2127_i2c_register_driver();
if (ret) {
pr_err("Failed to register pcf2127 i2c driver: %d\n", ret);
return ret;
}
ret = pcf2127_spi_register_driver();
if (ret) {
pr_err("Failed to register pcf2127 spi driver: %d\n", ret);
pcf2127_i2c_unregister_driver();
}
return ret;
}
module_init(pcf2127_init)
static void __exit pcf2127_exit(void)
{
pcf2127_spi_unregister_driver();
pcf2127_i2c_unregister_driver();
}
module_exit(pcf2127_exit)
MODULE_AUTHOR("Renaud Cerrato <r.cerrato@til-technologies.fr>");
MODULE_DESCRIPTION("NXP PCF2127 RTC driver");
MODULE_DESCRIPTION("NXP PCF2127/29 RTC driver");
MODULE_LICENSE("GPL v2");

View File

@ -16,12 +16,12 @@
#include <linux/rtc.h>
#include <linux/module.h>
#define DRV_VERSION "0.0.1"
#define PCF85063_REG_CTRL1 0x00 /* status */
#define PCF85063_REG_CTRL1_STOP BIT(5)
#define PCF85063_REG_CTRL2 0x01
#define PCF85063_REG_SC 0x04 /* datetime */
#define PCF85063_REG_SC_OS 0x80
#define PCF85063_REG_MN 0x05
#define PCF85063_REG_HR 0x06
#define PCF85063_REG_DM 0x07
@ -29,15 +29,31 @@
#define PCF85063_REG_MO 0x09
#define PCF85063_REG_YR 0x0A
#define PCF85063_MO_C 0x80 /* century */
static struct i2c_driver pcf85063_driver;
struct pcf85063 {
struct rtc_device *rtc;
int c_polarity; /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */
int voltage_low; /* indicates if a low_voltage was detected */
};
static int pcf85063_stop_clock(struct i2c_client *client, u8 *ctrl1)
{
s32 ret;
ret = i2c_smbus_read_byte_data(client, PCF85063_REG_CTRL1);
if (ret < 0) {
dev_err(&client->dev, "Failing to stop the clock\n");
return -EIO;
}
/* stop the clock */
ret |= PCF85063_REG_CTRL1_STOP;
ret = i2c_smbus_write_byte_data(client, PCF85063_REG_CTRL1, ret);
if (ret < 0) {
dev_err(&client->dev, "Failing to stop the clock\n");
return -EIO;
}
*ctrl1 = ret;
return 0;
}
/*
* In the routines that deal directly with the pcf85063 hardware, we use
@ -45,81 +61,85 @@ struct pcf85063 {
*/
static int pcf85063_get_datetime(struct i2c_client *client, struct rtc_time *tm)
{
struct pcf85063 *pcf85063 = i2c_get_clientdata(client);
unsigned char buf[13] = { PCF85063_REG_CTRL1 };
struct i2c_msg msgs[] = {
{/* setup read ptr */
.addr = client->addr,
.len = 1,
.buf = buf
},
{/* read status + date */
.addr = client->addr,
.flags = I2C_M_RD,
.len = 13,
.buf = buf
},
};
int rc;
u8 regs[7];
/* read registers */
if ((i2c_transfer(client->adapter, msgs, 2)) != 2) {
dev_err(&client->dev, "%s: read error\n", __func__);
/*
* while reading, the time/date registers are blocked and not updated
* anymore until the access is finished. To not lose a second
* event, the access must be finished within one second. So, read all
* time/date registers in one turn.
*/
rc = i2c_smbus_read_i2c_block_data(client, PCF85063_REG_SC,
sizeof(regs), regs);
if (rc != sizeof(regs)) {
dev_err(&client->dev, "date/time register read error\n");
return -EIO;
}
tm->tm_sec = bcd2bin(buf[PCF85063_REG_SC] & 0x7F);
tm->tm_min = bcd2bin(buf[PCF85063_REG_MN] & 0x7F);
tm->tm_hour = bcd2bin(buf[PCF85063_REG_HR] & 0x3F); /* rtc hr 0-23 */
tm->tm_mday = bcd2bin(buf[PCF85063_REG_DM] & 0x3F);
tm->tm_wday = buf[PCF85063_REG_DW] & 0x07;
tm->tm_mon = bcd2bin(buf[PCF85063_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */
tm->tm_year = bcd2bin(buf[PCF85063_REG_YR]);
/* if the clock has lost its power it makes no sense to use its time */
if (regs[0] & PCF85063_REG_SC_OS) {
dev_warn(&client->dev, "Power loss detected, invalid time\n");
return -EINVAL;
}
tm->tm_sec = bcd2bin(regs[0] & 0x7F);
tm->tm_min = bcd2bin(regs[1] & 0x7F);
tm->tm_hour = bcd2bin(regs[2] & 0x3F); /* rtc hr 0-23 */
tm->tm_mday = bcd2bin(regs[3] & 0x3F);
tm->tm_wday = regs[4] & 0x07;
tm->tm_mon = bcd2bin(regs[5] & 0x1F) - 1; /* rtc mn 1-12 */
tm->tm_year = bcd2bin(regs[6]);
if (tm->tm_year < 70)
tm->tm_year += 100; /* assume we are in 1970...2069 */
/* detect the polarity heuristically. see note above. */
pcf85063->c_polarity = (buf[PCF85063_REG_MO] & PCF85063_MO_C) ?
(tm->tm_year >= 100) : (tm->tm_year < 100);
return rtc_valid_tm(tm);
}
static int pcf85063_set_datetime(struct i2c_client *client, struct rtc_time *tm)
{
int i = 0, err = 0;
unsigned char buf[11];
int rc;
u8 regs[8];
/* Control & status */
buf[PCF85063_REG_CTRL1] = 0;
buf[PCF85063_REG_CTRL2] = 5;
/*
* to accurately set the time, reset the divider chain and keep it in
* reset state until all time/date registers are written
*/
rc = pcf85063_stop_clock(client, &regs[7]);
if (rc != 0)
return rc;
/* hours, minutes and seconds */
buf[PCF85063_REG_SC] = bin2bcd(tm->tm_sec) & 0x7F;
regs[0] = bin2bcd(tm->tm_sec) & 0x7F; /* clear OS flag */
buf[PCF85063_REG_MN] = bin2bcd(tm->tm_min);
buf[PCF85063_REG_HR] = bin2bcd(tm->tm_hour);
regs[1] = bin2bcd(tm->tm_min);
regs[2] = bin2bcd(tm->tm_hour);
/* Day of month, 1 - 31 */
buf[PCF85063_REG_DM] = bin2bcd(tm->tm_mday);
regs[3] = bin2bcd(tm->tm_mday);
/* Day, 0 - 6 */
buf[PCF85063_REG_DW] = tm->tm_wday & 0x07;
regs[4] = tm->tm_wday & 0x07;
/* month, 1 - 12 */
buf[PCF85063_REG_MO] = bin2bcd(tm->tm_mon + 1);
regs[5] = bin2bcd(tm->tm_mon + 1);
/* year and century */
buf[PCF85063_REG_YR] = bin2bcd(tm->tm_year % 100);
regs[6] = bin2bcd(tm->tm_year % 100);
/* write register's data */
for (i = 0; i < sizeof(buf); i++) {
unsigned char data[2] = { i, buf[i] };
/*
* after all time/date registers are written, let the 'address auto
* increment' feature wrap around and write register CTRL1 to re-enable
* the clock divider chain again
*/
regs[7] &= ~PCF85063_REG_CTRL1_STOP;
err = i2c_master_send(client, data, sizeof(data));
if (err != sizeof(data)) {
dev_err(&client->dev, "%s: err=%d addr=%02x, data=%02x\n",
__func__, err, data[0], data[1]);
return -EIO;
}
/* write all registers at once */
rc = i2c_smbus_write_i2c_block_data(client, PCF85063_REG_SC,
sizeof(regs), regs);
if (rc < 0) {
dev_err(&client->dev, "date/time register write error\n");
return rc;
}
return 0;
@ -143,27 +163,18 @@ static const struct rtc_class_ops pcf85063_rtc_ops = {
static int pcf85063_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct pcf85063 *pcf85063;
struct rtc_device *rtc;
dev_dbg(&client->dev, "%s\n", __func__);
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV;
pcf85063 = devm_kzalloc(&client->dev, sizeof(struct pcf85063),
GFP_KERNEL);
if (!pcf85063)
return -ENOMEM;
rtc = devm_rtc_device_register(&client->dev,
pcf85063_driver.driver.name,
&pcf85063_rtc_ops, THIS_MODULE);
dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
i2c_set_clientdata(client, pcf85063);
pcf85063->rtc = devm_rtc_device_register(&client->dev,
pcf85063_driver.driver.name,
&pcf85063_rtc_ops, THIS_MODULE);
return PTR_ERR_OR_ZERO(pcf85063->rtc);
return PTR_ERR_OR_ZERO(rtc);
}
static const struct i2c_device_id pcf85063_id[] = {
@ -194,4 +205,3 @@ module_i2c_driver(pcf85063_driver);
MODULE_AUTHOR("Søren Andersen <san@rosetechnology.dk>");
MODULE_DESCRIPTION("PCF85063 RTC driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);

View File

@ -178,28 +178,8 @@ static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm)
if (err < 0)
return err;
if (regs[0] & REG_SECONDS_OS) {
/*
* If the oscillator was stopped, try to clear the flag. Upon
* power-up the flag is always set, but if we cannot clear it
* the oscillator isn't running properly for some reason. The
* sensible thing therefore is to return an error, signalling
* that the clock cannot be assumed to be correct.
*/
regs[0] &= ~REG_SECONDS_OS;
err = pcf8523_write(client, REG_SECONDS, regs[0]);
if (err < 0)
return err;
err = pcf8523_read(client, REG_SECONDS, &regs[0]);
if (err < 0)
return err;
if (regs[0] & REG_SECONDS_OS)
return -EAGAIN;
}
if (regs[0] & REG_SECONDS_OS)
return -EINVAL;
tm->tm_sec = bcd2bin(regs[0] & 0x7f);
tm->tm_min = bcd2bin(regs[1] & 0x7f);
@ -235,6 +215,7 @@ static int pcf8523_rtc_set_time(struct device *dev, struct rtc_time *tm)
return err;
regs[0] = REG_SECONDS;
/* This will purposely overwrite REG_SECONDS_OS */
regs[1] = bin2bcd(tm->tm_sec);
regs[2] = bin2bcd(tm->tm_min);
regs[3] = bin2bcd(tm->tm_hour);

411
drivers/rtc/rtc-pic32.c Normal file
View File

@ -0,0 +1,411 @@
/*
* PIC32 RTC driver
*
* Joshua Henderson <joshua.henderson@microchip.com>
* Copyright (C) 2016 Microchip Technology Inc. All rights reserved.
*
* 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.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/rtc.h>
#include <linux/bcd.h>
#include <asm/mach-pic32/pic32.h>
#define PIC32_RTCCON 0x00
#define PIC32_RTCCON_ON BIT(15)
#define PIC32_RTCCON_SIDL BIT(13)
#define PIC32_RTCCON_RTCCLKSEL (3 << 9)
#define PIC32_RTCCON_RTCCLKON BIT(6)
#define PIC32_RTCCON_RTCWREN BIT(3)
#define PIC32_RTCCON_RTCSYNC BIT(2)
#define PIC32_RTCCON_HALFSEC BIT(1)
#define PIC32_RTCCON_RTCOE BIT(0)
#define PIC32_RTCALRM 0x10
#define PIC32_RTCALRM_ALRMEN BIT(15)
#define PIC32_RTCALRM_CHIME BIT(14)
#define PIC32_RTCALRM_PIV BIT(13)
#define PIC32_RTCALRM_ALARMSYNC BIT(12)
#define PIC32_RTCALRM_AMASK 0x0F00
#define PIC32_RTCALRM_ARPT 0xFF
#define PIC32_RTCHOUR 0x23
#define PIC32_RTCMIN 0x22
#define PIC32_RTCSEC 0x21
#define PIC32_RTCYEAR 0x33
#define PIC32_RTCMON 0x32
#define PIC32_RTCDAY 0x31
#define PIC32_ALRMTIME 0x40
#define PIC32_ALRMDATE 0x50
#define PIC32_ALRMHOUR 0x43
#define PIC32_ALRMMIN 0x42
#define PIC32_ALRMSEC 0x41
#define PIC32_ALRMYEAR 0x53
#define PIC32_ALRMMON 0x52
#define PIC32_ALRMDAY 0x51
struct pic32_rtc_dev {
struct rtc_device *rtc;
void __iomem *reg_base;
struct clk *clk;
spinlock_t alarm_lock;
int alarm_irq;
bool alarm_clk_enabled;
};
static void pic32_rtc_alarm_clk_enable(struct pic32_rtc_dev *pdata,
bool enable)
{
unsigned long flags;
spin_lock_irqsave(&pdata->alarm_lock, flags);
if (enable) {
if (!pdata->alarm_clk_enabled) {
clk_enable(pdata->clk);
pdata->alarm_clk_enabled = true;
}
} else {
if (pdata->alarm_clk_enabled) {
clk_disable(pdata->clk);
pdata->alarm_clk_enabled = false;
}
}
spin_unlock_irqrestore(&pdata->alarm_lock, flags);
}
static irqreturn_t pic32_rtc_alarmirq(int irq, void *id)
{
struct pic32_rtc_dev *pdata = (struct pic32_rtc_dev *)id;
clk_enable(pdata->clk);
rtc_update_irq(pdata->rtc, 1, RTC_AF | RTC_IRQF);
clk_disable(pdata->clk);
pic32_rtc_alarm_clk_enable(pdata, false);
return IRQ_HANDLED;
}
static int pic32_rtc_setaie(struct device *dev, unsigned int enabled)
{
struct pic32_rtc_dev *pdata = dev_get_drvdata(dev);
void __iomem *base = pdata->reg_base;
clk_enable(pdata->clk);
writel(PIC32_RTCALRM_ALRMEN,
base + (enabled ? PIC32_SET(PIC32_RTCALRM) :
PIC32_CLR(PIC32_RTCALRM)));
clk_disable(pdata->clk);
pic32_rtc_alarm_clk_enable(pdata, enabled);
return 0;
}
static int pic32_rtc_setfreq(struct device *dev, int freq)
{
struct pic32_rtc_dev *pdata = dev_get_drvdata(dev);
void __iomem *base = pdata->reg_base;
clk_enable(pdata->clk);
writel(PIC32_RTCALRM_AMASK, base + PIC32_CLR(PIC32_RTCALRM));
writel(freq << 8, base + PIC32_SET(PIC32_RTCALRM));
writel(PIC32_RTCALRM_CHIME, base + PIC32_SET(PIC32_RTCALRM));
clk_disable(pdata->clk);
return 0;
}
static int pic32_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
{
struct pic32_rtc_dev *pdata = dev_get_drvdata(dev);
void __iomem *base = pdata->reg_base;
unsigned int tries = 0;
clk_enable(pdata->clk);
do {
rtc_tm->tm_hour = readb(base + PIC32_RTCHOUR);
rtc_tm->tm_min = readb(base + PIC32_RTCMIN);
rtc_tm->tm_mon = readb(base + PIC32_RTCMON);
rtc_tm->tm_mday = readb(base + PIC32_RTCDAY);
rtc_tm->tm_year = readb(base + PIC32_RTCYEAR);
rtc_tm->tm_sec = readb(base + PIC32_RTCSEC);
/*
* The only way to work out whether the system was mid-update
* when we read it is to check the second counter, and if it
* is zero, then we re-try the entire read.
*/
tries += 1;
} while (rtc_tm->tm_sec == 0 && tries < 2);
rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec);
rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min);
rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour);
rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday);
rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon) - 1;
rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year);
rtc_tm->tm_year += 100;
dev_dbg(dev, "read time %04d.%02d.%02d %02d:%02d:%02d\n",
1900 + rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,
rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);
clk_disable(pdata->clk);
return rtc_valid_tm(rtc_tm);
}
static int pic32_rtc_settime(struct device *dev, struct rtc_time *tm)
{
struct pic32_rtc_dev *pdata = dev_get_drvdata(dev);
void __iomem *base = pdata->reg_base;
int year = tm->tm_year - 100;
dev_dbg(dev, "set time %04d.%02d.%02d %02d:%02d:%02d\n",
1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
if (year < 0 || year >= 100) {
dev_err(dev, "rtc only supports 100 years\n");
return -EINVAL;
}
clk_enable(pdata->clk);
writeb(bin2bcd(tm->tm_sec), base + PIC32_RTCSEC);
writeb(bin2bcd(tm->tm_min), base + PIC32_RTCMIN);
writeb(bin2bcd(tm->tm_hour), base + PIC32_RTCHOUR);
writeb(bin2bcd(tm->tm_mday), base + PIC32_RTCDAY);
writeb(bin2bcd(tm->tm_mon + 1), base + PIC32_RTCMON);
writeb(bin2bcd(year), base + PIC32_RTCYEAR);
clk_disable(pdata->clk);
return 0;
}
static int pic32_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct pic32_rtc_dev *pdata = dev_get_drvdata(dev);
struct rtc_time *alm_tm = &alrm->time;
void __iomem *base = pdata->reg_base;
unsigned int alm_en;
clk_enable(pdata->clk);
alm_tm->tm_sec = readb(base + PIC32_ALRMSEC);
alm_tm->tm_min = readb(base + PIC32_ALRMMIN);
alm_tm->tm_hour = readb(base + PIC32_ALRMHOUR);
alm_tm->tm_mon = readb(base + PIC32_ALRMMON);
alm_tm->tm_mday = readb(base + PIC32_ALRMDAY);
alm_tm->tm_year = readb(base + PIC32_ALRMYEAR);
alm_en = readb(base + PIC32_RTCALRM);
alrm->enabled = (alm_en & PIC32_RTCALRM_ALRMEN) ? 1 : 0;
dev_dbg(dev, "getalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n",
alm_en,
1900 + alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday,
alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec);
alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec);
alm_tm->tm_min = bcd2bin(alm_tm->tm_min);
alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour);
alm_tm->tm_mday = bcd2bin(alm_tm->tm_mday);
alm_tm->tm_mon = bcd2bin(alm_tm->tm_mon) - 1;
alm_tm->tm_year = bcd2bin(alm_tm->tm_year);
clk_disable(pdata->clk);
return 0;
}
static int pic32_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct pic32_rtc_dev *pdata = dev_get_drvdata(dev);
struct rtc_time *tm = &alrm->time;
void __iomem *base = pdata->reg_base;
clk_enable(pdata->clk);
dev_dbg(dev, "setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n",
alrm->enabled,
1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
writel(0x00, base + PIC32_ALRMTIME);
writel(0x00, base + PIC32_ALRMDATE);
pic32_rtc_setaie(dev, alrm->enabled);
clk_disable(pdata->clk);
return 0;
}
static int pic32_rtc_proc(struct device *dev, struct seq_file *seq)
{
struct pic32_rtc_dev *pdata = dev_get_drvdata(dev);
void __iomem *base = pdata->reg_base;
unsigned int repeat;
clk_enable(pdata->clk);
repeat = readw(base + PIC32_RTCALRM);
repeat &= PIC32_RTCALRM_ARPT;
seq_printf(seq, "periodic_IRQ\t: %s\n", repeat ? "yes" : "no");
clk_disable(pdata->clk);
return 0;
}
static const struct rtc_class_ops pic32_rtcops = {
.read_time = pic32_rtc_gettime,
.set_time = pic32_rtc_settime,
.read_alarm = pic32_rtc_getalarm,
.set_alarm = pic32_rtc_setalarm,
.proc = pic32_rtc_proc,
.alarm_irq_enable = pic32_rtc_setaie,
};
static void pic32_rtc_enable(struct pic32_rtc_dev *pdata, int en)
{
void __iomem *base = pdata->reg_base;
if (!base)
return;
clk_enable(pdata->clk);
if (!en) {
writel(PIC32_RTCCON_ON, base + PIC32_CLR(PIC32_RTCCON));
} else {
pic32_syskey_unlock();
writel(PIC32_RTCCON_RTCWREN, base + PIC32_SET(PIC32_RTCCON));
writel(3 << 9, base + PIC32_CLR(PIC32_RTCCON));
if (!(readl(base + PIC32_RTCCON) & PIC32_RTCCON_ON))
writel(PIC32_RTCCON_ON, base + PIC32_SET(PIC32_RTCCON));
}
clk_disable(pdata->clk);
}
static int pic32_rtc_remove(struct platform_device *pdev)
{
struct pic32_rtc_dev *pdata = platform_get_drvdata(pdev);
pic32_rtc_setaie(&pdev->dev, 0);
clk_unprepare(pdata->clk);
pdata->clk = NULL;
return 0;
}
static int pic32_rtc_probe(struct platform_device *pdev)
{
struct pic32_rtc_dev *pdata;
struct resource *res;
int ret;
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
platform_set_drvdata(pdev, pdata);
pdata->alarm_irq = platform_get_irq(pdev, 0);
if (pdata->alarm_irq < 0) {
dev_err(&pdev->dev, "no irq for alarm\n");
return pdata->alarm_irq;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
pdata->reg_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(pdata->reg_base))
return PTR_ERR(pdata->reg_base);
pdata->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(pdata->clk)) {
dev_err(&pdev->dev, "failed to find rtc clock source\n");
ret = PTR_ERR(pdata->clk);
pdata->clk = NULL;
return ret;
}
spin_lock_init(&pdata->alarm_lock);
clk_prepare_enable(pdata->clk);
pic32_rtc_enable(pdata, 1);
device_init_wakeup(&pdev->dev, 1);
pdata->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&pic32_rtcops,
THIS_MODULE);
if (IS_ERR(pdata->rtc)) {
ret = PTR_ERR(pdata->rtc);
goto err_nortc;
}
pdata->rtc->max_user_freq = 128;
pic32_rtc_setfreq(&pdev->dev, 1);
ret = devm_request_irq(&pdev->dev, pdata->alarm_irq,
pic32_rtc_alarmirq, 0,
dev_name(&pdev->dev), pdata);
if (ret) {
dev_err(&pdev->dev,
"IRQ %d error %d\n", pdata->alarm_irq, ret);
goto err_nortc;
}
clk_disable(pdata->clk);
return 0;
err_nortc:
pic32_rtc_enable(pdata, 0);
clk_disable_unprepare(pdata->clk);
return ret;
}
static const struct of_device_id pic32_rtc_dt_ids[] = {
{ .compatible = "microchip,pic32mzda-rtc" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, pic32_rtc_dt_ids);
static struct platform_driver pic32_rtc_driver = {
.probe = pic32_rtc_probe,
.remove = pic32_rtc_remove,
.driver = {
.name = "pic32-rtc",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(pic32_rtc_dt_ids),
},
};
module_platform_driver(pic32_rtc_driver);
MODULE_DESCRIPTION("Microchip PIC32 RTC Driver");
MODULE_AUTHOR("Joshua Henderson <joshua.henderson@microchip.com>");
MODULE_LICENSE("GPL");

View File

@ -1,7 +1,8 @@
/*
* Micro Crystal RV-3029C2 rtc class driver
* Micro Crystal RV-3029 rtc class driver
*
* Author: Gregory Hermant <gregory.hermant@calao-systems.com>
* Michael Buesch <m@bues.ch>
*
* based on previously existing rtc class drivers
*
@ -9,89 +10,120 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* NOTE: Currently this driver only supports the bare minimum for read
* and write the RTC and alarms. The extra features provided by this chip
* (trickle charger, eeprom, T° compensation) are unavailable.
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/bcd.h>
#include <linux/rtc.h>
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
/* Register map */
/* control section */
#define RV3029C2_ONOFF_CTRL 0x00
#define RV3029C2_IRQ_CTRL 0x01
#define RV3029C2_IRQ_CTRL_AIE (1 << 0)
#define RV3029C2_IRQ_FLAGS 0x02
#define RV3029C2_IRQ_FLAGS_AF (1 << 0)
#define RV3029C2_STATUS 0x03
#define RV3029C2_STATUS_VLOW1 (1 << 2)
#define RV3029C2_STATUS_VLOW2 (1 << 3)
#define RV3029C2_STATUS_SR (1 << 4)
#define RV3029C2_STATUS_PON (1 << 5)
#define RV3029C2_STATUS_EEBUSY (1 << 7)
#define RV3029C2_RST_CTRL 0x04
#define RV3029C2_CONTROL_SECTION_LEN 0x05
#define RV3029_ONOFF_CTRL 0x00
#define RV3029_ONOFF_CTRL_WE BIT(0)
#define RV3029_ONOFF_CTRL_TE BIT(1)
#define RV3029_ONOFF_CTRL_TAR BIT(2)
#define RV3029_ONOFF_CTRL_EERE BIT(3)
#define RV3029_ONOFF_CTRL_SRON BIT(4)
#define RV3029_ONOFF_CTRL_TD0 BIT(5)
#define RV3029_ONOFF_CTRL_TD1 BIT(6)
#define RV3029_ONOFF_CTRL_CLKINT BIT(7)
#define RV3029_IRQ_CTRL 0x01
#define RV3029_IRQ_CTRL_AIE BIT(0)
#define RV3029_IRQ_CTRL_TIE BIT(1)
#define RV3029_IRQ_CTRL_V1IE BIT(2)
#define RV3029_IRQ_CTRL_V2IE BIT(3)
#define RV3029_IRQ_CTRL_SRIE BIT(4)
#define RV3029_IRQ_FLAGS 0x02
#define RV3029_IRQ_FLAGS_AF BIT(0)
#define RV3029_IRQ_FLAGS_TF BIT(1)
#define RV3029_IRQ_FLAGS_V1IF BIT(2)
#define RV3029_IRQ_FLAGS_V2IF BIT(3)
#define RV3029_IRQ_FLAGS_SRF BIT(4)
#define RV3029_STATUS 0x03
#define RV3029_STATUS_VLOW1 BIT(2)
#define RV3029_STATUS_VLOW2 BIT(3)
#define RV3029_STATUS_SR BIT(4)
#define RV3029_STATUS_PON BIT(5)
#define RV3029_STATUS_EEBUSY BIT(7)
#define RV3029_RST_CTRL 0x04
#define RV3029_RST_CTRL_SYSR BIT(4)
#define RV3029_CONTROL_SECTION_LEN 0x05
/* watch section */
#define RV3029C2_W_SEC 0x08
#define RV3029C2_W_MINUTES 0x09
#define RV3029C2_W_HOURS 0x0A
#define RV3029C2_REG_HR_12_24 (1<<6) /* 24h/12h mode */
#define RV3029C2_REG_HR_PM (1<<5) /* PM/AM bit in 12h mode */
#define RV3029C2_W_DATE 0x0B
#define RV3029C2_W_DAYS 0x0C
#define RV3029C2_W_MONTHS 0x0D
#define RV3029C2_W_YEARS 0x0E
#define RV3029C2_WATCH_SECTION_LEN 0x07
#define RV3029_W_SEC 0x08
#define RV3029_W_MINUTES 0x09
#define RV3029_W_HOURS 0x0A
#define RV3029_REG_HR_12_24 BIT(6) /* 24h/12h mode */
#define RV3029_REG_HR_PM BIT(5) /* PM/AM bit in 12h mode */
#define RV3029_W_DATE 0x0B
#define RV3029_W_DAYS 0x0C
#define RV3029_W_MONTHS 0x0D
#define RV3029_W_YEARS 0x0E
#define RV3029_WATCH_SECTION_LEN 0x07
/* alarm section */
#define RV3029C2_A_SC 0x10
#define RV3029C2_A_MN 0x11
#define RV3029C2_A_HR 0x12
#define RV3029C2_A_DT 0x13
#define RV3029C2_A_DW 0x14
#define RV3029C2_A_MO 0x15
#define RV3029C2_A_YR 0x16
#define RV3029C2_ALARM_SECTION_LEN 0x07
#define RV3029_A_SC 0x10
#define RV3029_A_MN 0x11
#define RV3029_A_HR 0x12
#define RV3029_A_DT 0x13
#define RV3029_A_DW 0x14
#define RV3029_A_MO 0x15
#define RV3029_A_YR 0x16
#define RV3029_ALARM_SECTION_LEN 0x07
/* timer section */
#define RV3029C2_TIMER_LOW 0x18
#define RV3029C2_TIMER_HIGH 0x19
#define RV3029_TIMER_LOW 0x18
#define RV3029_TIMER_HIGH 0x19
/* temperature section */
#define RV3029C2_TEMP_PAGE 0x20
#define RV3029_TEMP_PAGE 0x20
/* eeprom data section */
#define RV3029C2_E2P_EEDATA1 0x28
#define RV3029C2_E2P_EEDATA2 0x29
#define RV3029_E2P_EEDATA1 0x28
#define RV3029_E2P_EEDATA2 0x29
#define RV3029_E2PDATA_SECTION_LEN 0x02
/* eeprom control section */
#define RV3029C2_CONTROL_E2P_EECTRL 0x30
#define RV3029C2_TRICKLE_1K (1<<0) /* 1K resistance */
#define RV3029C2_TRICKLE_5K (1<<1) /* 5K resistance */
#define RV3029C2_TRICKLE_20K (1<<2) /* 20K resistance */
#define RV3029C2_TRICKLE_80K (1<<3) /* 80K resistance */
#define RV3029C2_CONTROL_E2P_XTALOFFSET 0x31
#define RV3029C2_CONTROL_E2P_QCOEF 0x32
#define RV3029C2_CONTROL_E2P_TURNOVER 0x33
#define RV3029_CONTROL_E2P_EECTRL 0x30
#define RV3029_EECTRL_THP BIT(0) /* temp scan interval */
#define RV3029_EECTRL_THE BIT(1) /* thermometer enable */
#define RV3029_EECTRL_FD0 BIT(2) /* CLKOUT */
#define RV3029_EECTRL_FD1 BIT(3) /* CLKOUT */
#define RV3029_TRICKLE_1K BIT(4) /* 1.5K resistance */
#define RV3029_TRICKLE_5K BIT(5) /* 5K resistance */
#define RV3029_TRICKLE_20K BIT(6) /* 20K resistance */
#define RV3029_TRICKLE_80K BIT(7) /* 80K resistance */
#define RV3029_TRICKLE_MASK (RV3029_TRICKLE_1K |\
RV3029_TRICKLE_5K |\
RV3029_TRICKLE_20K |\
RV3029_TRICKLE_80K)
#define RV3029_TRICKLE_SHIFT 4
#define RV3029_CONTROL_E2P_XOFFS 0x31 /* XTAL offset */
#define RV3029_CONTROL_E2P_XOFFS_SIGN BIT(7) /* Sign: 1->pos, 0->neg */
#define RV3029_CONTROL_E2P_QCOEF 0x32 /* XTAL temp drift coef */
#define RV3029_CONTROL_E2P_TURNOVER 0x33 /* XTAL turnover temp (in *C) */
#define RV3029_CONTROL_E2P_TOV_MASK 0x3F /* XTAL turnover temp mask */
/* user ram section */
#define RV3029C2_USR1_RAM_PAGE 0x38
#define RV3029C2_USR1_SECTION_LEN 0x04
#define RV3029C2_USR2_RAM_PAGE 0x3C
#define RV3029C2_USR2_SECTION_LEN 0x04
#define RV3029_USR1_RAM_PAGE 0x38
#define RV3029_USR1_SECTION_LEN 0x04
#define RV3029_USR2_RAM_PAGE 0x3C
#define RV3029_USR2_SECTION_LEN 0x04
static int
rv3029c2_i2c_read_regs(struct i2c_client *client, u8 reg, u8 *buf,
unsigned len)
rv3029_i2c_read_regs(struct i2c_client *client, u8 reg, u8 *buf,
unsigned len)
{
int ret;
if ((reg > RV3029C2_USR1_RAM_PAGE + 7) ||
(reg + len > RV3029C2_USR1_RAM_PAGE + 8))
if ((reg > RV3029_USR1_RAM_PAGE + 7) ||
(reg + len > RV3029_USR1_RAM_PAGE + 8))
return -EINVAL;
ret = i2c_smbus_read_i2c_block_data(client, reg, len, buf);
@ -103,20 +135,38 @@ rv3029c2_i2c_read_regs(struct i2c_client *client, u8 reg, u8 *buf,
}
static int
rv3029c2_i2c_write_regs(struct i2c_client *client, u8 reg, u8 const buf[],
unsigned len)
rv3029_i2c_write_regs(struct i2c_client *client, u8 reg, u8 const buf[],
unsigned len)
{
if ((reg > RV3029C2_USR1_RAM_PAGE + 7) ||
(reg + len > RV3029C2_USR1_RAM_PAGE + 8))
if ((reg > RV3029_USR1_RAM_PAGE + 7) ||
(reg + len > RV3029_USR1_RAM_PAGE + 8))
return -EINVAL;
return i2c_smbus_write_i2c_block_data(client, reg, len, buf);
}
static int
rv3029c2_i2c_get_sr(struct i2c_client *client, u8 *buf)
rv3029_i2c_update_bits(struct i2c_client *client, u8 reg, u8 mask, u8 set)
{
int ret = rv3029c2_i2c_read_regs(client, RV3029C2_STATUS, buf, 1);
u8 buf;
int ret;
ret = rv3029_i2c_read_regs(client, reg, &buf, 1);
if (ret < 0)
return ret;
buf &= ~mask;
buf |= set & mask;
ret = rv3029_i2c_write_regs(client, reg, &buf, 1);
if (ret < 0)
return ret;
return 0;
}
static int
rv3029_i2c_get_sr(struct i2c_client *client, u8 *buf)
{
int ret = rv3029_i2c_read_regs(client, RV3029_STATUS, buf, 1);
if (ret < 0)
return -EIO;
@ -125,83 +175,224 @@ rv3029c2_i2c_get_sr(struct i2c_client *client, u8 *buf)
}
static int
rv3029c2_i2c_set_sr(struct i2c_client *client, u8 val)
rv3029_i2c_set_sr(struct i2c_client *client, u8 val)
{
u8 buf[1];
int sr;
buf[0] = val;
sr = rv3029c2_i2c_write_regs(client, RV3029C2_STATUS, buf, 1);
sr = rv3029_i2c_write_regs(client, RV3029_STATUS, buf, 1);
dev_dbg(&client->dev, "status = 0x%.2x (%d)\n", buf[0], buf[0]);
if (sr < 0)
return -EIO;
return 0;
}
static int rv3029_eeprom_busywait(struct i2c_client *client)
{
int i, ret;
u8 sr;
for (i = 100; i > 0; i--) {
ret = rv3029_i2c_get_sr(client, &sr);
if (ret < 0)
break;
if (!(sr & RV3029_STATUS_EEBUSY))
break;
usleep_range(1000, 10000);
}
if (i <= 0) {
dev_err(&client->dev, "EEPROM busy wait timeout.\n");
return -ETIMEDOUT;
}
return ret;
}
static int rv3029_eeprom_exit(struct i2c_client *client)
{
/* Re-enable eeprom refresh */
return rv3029_i2c_update_bits(client, RV3029_ONOFF_CTRL,
RV3029_ONOFF_CTRL_EERE,
RV3029_ONOFF_CTRL_EERE);
}
static int rv3029_eeprom_enter(struct i2c_client *client)
{
int ret;
u8 sr;
/* Check whether we are in the allowed voltage range. */
ret = rv3029_i2c_get_sr(client, &sr);
if (ret < 0)
return ret;
if (sr & (RV3029_STATUS_VLOW1 | RV3029_STATUS_VLOW2)) {
/* We clear the bits and retry once just in case
* we had a brown out in early startup.
*/
sr &= ~RV3029_STATUS_VLOW1;
sr &= ~RV3029_STATUS_VLOW2;
ret = rv3029_i2c_set_sr(client, sr);
if (ret < 0)
return ret;
usleep_range(1000, 10000);
ret = rv3029_i2c_get_sr(client, &sr);
if (ret < 0)
return ret;
if (sr & (RV3029_STATUS_VLOW1 | RV3029_STATUS_VLOW2)) {
dev_err(&client->dev,
"Supply voltage is too low to safely access the EEPROM.\n");
return -ENODEV;
}
}
/* Disable eeprom refresh. */
ret = rv3029_i2c_update_bits(client, RV3029_ONOFF_CTRL,
RV3029_ONOFF_CTRL_EERE, 0);
if (ret < 0)
return ret;
/* Wait for any previous eeprom accesses to finish. */
ret = rv3029_eeprom_busywait(client);
if (ret < 0)
rv3029_eeprom_exit(client);
return ret;
}
static int rv3029_eeprom_read(struct i2c_client *client, u8 reg,
u8 buf[], size_t len)
{
int ret, err;
err = rv3029_eeprom_enter(client);
if (err < 0)
return err;
ret = rv3029_i2c_read_regs(client, reg, buf, len);
err = rv3029_eeprom_exit(client);
if (err < 0)
return err;
return ret;
}
static int rv3029_eeprom_write(struct i2c_client *client, u8 reg,
u8 const buf[], size_t len)
{
int ret, err;
size_t i;
u8 tmp;
err = rv3029_eeprom_enter(client);
if (err < 0)
return err;
for (i = 0; i < len; i++, reg++) {
ret = rv3029_i2c_read_regs(client, reg, &tmp, 1);
if (ret < 0)
break;
if (tmp != buf[i]) {
ret = rv3029_i2c_write_regs(client, reg, &buf[i], 1);
if (ret < 0)
break;
}
ret = rv3029_eeprom_busywait(client);
if (ret < 0)
break;
}
err = rv3029_eeprom_exit(client);
if (err < 0)
return err;
return ret;
}
static int rv3029_eeprom_update_bits(struct i2c_client *client,
u8 reg, u8 mask, u8 set)
{
u8 buf;
int ret;
ret = rv3029_eeprom_read(client, reg, &buf, 1);
if (ret < 0)
return ret;
buf &= ~mask;
buf |= set & mask;
ret = rv3029_eeprom_write(client, reg, &buf, 1);
if (ret < 0)
return ret;
return 0;
}
static int
rv3029c2_i2c_read_time(struct i2c_client *client, struct rtc_time *tm)
rv3029_i2c_read_time(struct i2c_client *client, struct rtc_time *tm)
{
u8 buf[1];
int ret;
u8 regs[RV3029C2_WATCH_SECTION_LEN] = { 0, };
u8 regs[RV3029_WATCH_SECTION_LEN] = { 0, };
ret = rv3029c2_i2c_get_sr(client, buf);
ret = rv3029_i2c_get_sr(client, buf);
if (ret < 0) {
dev_err(&client->dev, "%s: reading SR failed\n", __func__);
return -EIO;
}
ret = rv3029c2_i2c_read_regs(client, RV3029C2_W_SEC , regs,
RV3029C2_WATCH_SECTION_LEN);
ret = rv3029_i2c_read_regs(client, RV3029_W_SEC, regs,
RV3029_WATCH_SECTION_LEN);
if (ret < 0) {
dev_err(&client->dev, "%s: reading RTC section failed\n",
__func__);
return ret;
}
tm->tm_sec = bcd2bin(regs[RV3029C2_W_SEC-RV3029C2_W_SEC]);
tm->tm_min = bcd2bin(regs[RV3029C2_W_MINUTES-RV3029C2_W_SEC]);
tm->tm_sec = bcd2bin(regs[RV3029_W_SEC-RV3029_W_SEC]);
tm->tm_min = bcd2bin(regs[RV3029_W_MINUTES-RV3029_W_SEC]);
/* HR field has a more complex interpretation */
{
const u8 _hr = regs[RV3029C2_W_HOURS-RV3029C2_W_SEC];
if (_hr & RV3029C2_REG_HR_12_24) {
const u8 _hr = regs[RV3029_W_HOURS-RV3029_W_SEC];
if (_hr & RV3029_REG_HR_12_24) {
/* 12h format */
tm->tm_hour = bcd2bin(_hr & 0x1f);
if (_hr & RV3029C2_REG_HR_PM) /* PM flag set */
if (_hr & RV3029_REG_HR_PM) /* PM flag set */
tm->tm_hour += 12;
} else /* 24h format */
tm->tm_hour = bcd2bin(_hr & 0x3f);
}
tm->tm_mday = bcd2bin(regs[RV3029C2_W_DATE-RV3029C2_W_SEC]);
tm->tm_mon = bcd2bin(regs[RV3029C2_W_MONTHS-RV3029C2_W_SEC]) - 1;
tm->tm_year = bcd2bin(regs[RV3029C2_W_YEARS-RV3029C2_W_SEC]) + 100;
tm->tm_wday = bcd2bin(regs[RV3029C2_W_DAYS-RV3029C2_W_SEC]) - 1;
tm->tm_mday = bcd2bin(regs[RV3029_W_DATE-RV3029_W_SEC]);
tm->tm_mon = bcd2bin(regs[RV3029_W_MONTHS-RV3029_W_SEC]) - 1;
tm->tm_year = bcd2bin(regs[RV3029_W_YEARS-RV3029_W_SEC]) + 100;
tm->tm_wday = bcd2bin(regs[RV3029_W_DAYS-RV3029_W_SEC]) - 1;
return 0;
}
static int rv3029c2_rtc_read_time(struct device *dev, struct rtc_time *tm)
static int rv3029_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
return rv3029c2_i2c_read_time(to_i2c_client(dev), tm);
return rv3029_i2c_read_time(to_i2c_client(dev), tm);
}
static int
rv3029c2_i2c_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm)
rv3029_i2c_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm)
{
struct rtc_time *const tm = &alarm->time;
int ret;
u8 regs[8];
ret = rv3029c2_i2c_get_sr(client, regs);
ret = rv3029_i2c_get_sr(client, regs);
if (ret < 0) {
dev_err(&client->dev, "%s: reading SR failed\n", __func__);
return -EIO;
}
ret = rv3029c2_i2c_read_regs(client, RV3029C2_A_SC, regs,
RV3029C2_ALARM_SECTION_LEN);
ret = rv3029_i2c_read_regs(client, RV3029_A_SC, regs,
RV3029_ALARM_SECTION_LEN);
if (ret < 0) {
dev_err(&client->dev, "%s: reading alarm section failed\n",
@ -209,51 +400,42 @@ rv3029c2_i2c_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm)
return ret;
}
tm->tm_sec = bcd2bin(regs[RV3029C2_A_SC-RV3029C2_A_SC] & 0x7f);
tm->tm_min = bcd2bin(regs[RV3029C2_A_MN-RV3029C2_A_SC] & 0x7f);
tm->tm_hour = bcd2bin(regs[RV3029C2_A_HR-RV3029C2_A_SC] & 0x3f);
tm->tm_mday = bcd2bin(regs[RV3029C2_A_DT-RV3029C2_A_SC] & 0x3f);
tm->tm_mon = bcd2bin(regs[RV3029C2_A_MO-RV3029C2_A_SC] & 0x1f) - 1;
tm->tm_year = bcd2bin(regs[RV3029C2_A_YR-RV3029C2_A_SC] & 0x7f) + 100;
tm->tm_wday = bcd2bin(regs[RV3029C2_A_DW-RV3029C2_A_SC] & 0x07) - 1;
tm->tm_sec = bcd2bin(regs[RV3029_A_SC-RV3029_A_SC] & 0x7f);
tm->tm_min = bcd2bin(regs[RV3029_A_MN-RV3029_A_SC] & 0x7f);
tm->tm_hour = bcd2bin(regs[RV3029_A_HR-RV3029_A_SC] & 0x3f);
tm->tm_mday = bcd2bin(regs[RV3029_A_DT-RV3029_A_SC] & 0x3f);
tm->tm_mon = bcd2bin(regs[RV3029_A_MO-RV3029_A_SC] & 0x1f) - 1;
tm->tm_year = bcd2bin(regs[RV3029_A_YR-RV3029_A_SC] & 0x7f) + 100;
tm->tm_wday = bcd2bin(regs[RV3029_A_DW-RV3029_A_SC] & 0x07) - 1;
return 0;
}
static int
rv3029c2_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
rv3029_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
return rv3029c2_i2c_read_alarm(to_i2c_client(dev), alarm);
return rv3029_i2c_read_alarm(to_i2c_client(dev), alarm);
}
static int rv3029c2_rtc_i2c_alarm_set_irq(struct i2c_client *client,
static int rv3029_rtc_i2c_alarm_set_irq(struct i2c_client *client,
int enable)
{
int ret;
u8 buf[1];
/* enable AIE irq */
ret = rv3029c2_i2c_read_regs(client, RV3029C2_IRQ_CTRL, buf, 1);
/* enable/disable AIE irq */
ret = rv3029_i2c_update_bits(client, RV3029_IRQ_CTRL,
RV3029_IRQ_CTRL_AIE,
(enable ? RV3029_IRQ_CTRL_AIE : 0));
if (ret < 0) {
dev_err(&client->dev, "can't read INT reg\n");
return ret;
}
if (enable)
buf[0] |= RV3029C2_IRQ_CTRL_AIE;
else
buf[0] &= ~RV3029C2_IRQ_CTRL_AIE;
ret = rv3029c2_i2c_write_regs(client, RV3029C2_IRQ_CTRL, buf, 1);
if (ret < 0) {
dev_err(&client->dev, "can't set INT reg\n");
dev_err(&client->dev, "can't update INT reg\n");
return ret;
}
return 0;
}
static int rv3029c2_rtc_i2c_set_alarm(struct i2c_client *client,
struct rtc_wkalrm *alarm)
static int rv3029_rtc_i2c_set_alarm(struct i2c_client *client,
struct rtc_wkalrm *alarm)
{
struct rtc_time *const tm = &alarm->time;
int ret;
@ -267,50 +449,41 @@ static int rv3029c2_rtc_i2c_set_alarm(struct i2c_client *client,
if (tm->tm_year < 100)
return -EINVAL;
ret = rv3029c2_i2c_get_sr(client, regs);
ret = rv3029_i2c_get_sr(client, regs);
if (ret < 0) {
dev_err(&client->dev, "%s: reading SR failed\n", __func__);
return -EIO;
}
regs[RV3029C2_A_SC-RV3029C2_A_SC] = bin2bcd(tm->tm_sec & 0x7f);
regs[RV3029C2_A_MN-RV3029C2_A_SC] = bin2bcd(tm->tm_min & 0x7f);
regs[RV3029C2_A_HR-RV3029C2_A_SC] = bin2bcd(tm->tm_hour & 0x3f);
regs[RV3029C2_A_DT-RV3029C2_A_SC] = bin2bcd(tm->tm_mday & 0x3f);
regs[RV3029C2_A_MO-RV3029C2_A_SC] = bin2bcd((tm->tm_mon & 0x1f) - 1);
regs[RV3029C2_A_DW-RV3029C2_A_SC] = bin2bcd((tm->tm_wday & 7) - 1);
regs[RV3029C2_A_YR-RV3029C2_A_SC] = bin2bcd((tm->tm_year & 0x7f) - 100);
regs[RV3029_A_SC-RV3029_A_SC] = bin2bcd(tm->tm_sec & 0x7f);
regs[RV3029_A_MN-RV3029_A_SC] = bin2bcd(tm->tm_min & 0x7f);
regs[RV3029_A_HR-RV3029_A_SC] = bin2bcd(tm->tm_hour & 0x3f);
regs[RV3029_A_DT-RV3029_A_SC] = bin2bcd(tm->tm_mday & 0x3f);
regs[RV3029_A_MO-RV3029_A_SC] = bin2bcd((tm->tm_mon & 0x1f) - 1);
regs[RV3029_A_DW-RV3029_A_SC] = bin2bcd((tm->tm_wday & 7) - 1);
regs[RV3029_A_YR-RV3029_A_SC] = bin2bcd((tm->tm_year & 0x7f) - 100);
ret = rv3029c2_i2c_write_regs(client, RV3029C2_A_SC, regs,
RV3029C2_ALARM_SECTION_LEN);
ret = rv3029_i2c_write_regs(client, RV3029_A_SC, regs,
RV3029_ALARM_SECTION_LEN);
if (ret < 0)
return ret;
if (alarm->enabled) {
u8 buf[1];
/* clear AF flag */
ret = rv3029c2_i2c_read_regs(client, RV3029C2_IRQ_FLAGS,
buf, 1);
ret = rv3029_i2c_update_bits(client, RV3029_IRQ_FLAGS,
RV3029_IRQ_FLAGS_AF, 0);
if (ret < 0) {
dev_err(&client->dev, "can't read alarm flag\n");
return ret;
}
buf[0] &= ~RV3029C2_IRQ_FLAGS_AF;
ret = rv3029c2_i2c_write_regs(client, RV3029C2_IRQ_FLAGS,
buf, 1);
if (ret < 0) {
dev_err(&client->dev, "can't set alarm flag\n");
dev_err(&client->dev, "can't clear alarm flag\n");
return ret;
}
/* enable AIE irq */
ret = rv3029c2_rtc_i2c_alarm_set_irq(client, 1);
ret = rv3029_rtc_i2c_alarm_set_irq(client, 1);
if (ret)
return ret;
dev_dbg(&client->dev, "alarm IRQ armed\n");
} else {
/* disable AIE irq */
ret = rv3029c2_rtc_i2c_alarm_set_irq(client, 0);
ret = rv3029_rtc_i2c_alarm_set_irq(client, 0);
if (ret)
return ret;
@ -320,13 +493,13 @@ static int rv3029c2_rtc_i2c_set_alarm(struct i2c_client *client,
return 0;
}
static int rv3029c2_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
static int rv3029_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
return rv3029c2_rtc_i2c_set_alarm(to_i2c_client(dev), alarm);
return rv3029_rtc_i2c_set_alarm(to_i2c_client(dev), alarm);
}
static int
rv3029c2_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm)
rv3029_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm)
{
u8 regs[8];
int ret;
@ -339,26 +512,26 @@ rv3029c2_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm)
if (tm->tm_year < 100)
return -EINVAL;
regs[RV3029C2_W_SEC-RV3029C2_W_SEC] = bin2bcd(tm->tm_sec);
regs[RV3029C2_W_MINUTES-RV3029C2_W_SEC] = bin2bcd(tm->tm_min);
regs[RV3029C2_W_HOURS-RV3029C2_W_SEC] = bin2bcd(tm->tm_hour);
regs[RV3029C2_W_DATE-RV3029C2_W_SEC] = bin2bcd(tm->tm_mday);
regs[RV3029C2_W_MONTHS-RV3029C2_W_SEC] = bin2bcd(tm->tm_mon+1);
regs[RV3029C2_W_DAYS-RV3029C2_W_SEC] = bin2bcd((tm->tm_wday & 7)+1);
regs[RV3029C2_W_YEARS-RV3029C2_W_SEC] = bin2bcd(tm->tm_year - 100);
regs[RV3029_W_SEC-RV3029_W_SEC] = bin2bcd(tm->tm_sec);
regs[RV3029_W_MINUTES-RV3029_W_SEC] = bin2bcd(tm->tm_min);
regs[RV3029_W_HOURS-RV3029_W_SEC] = bin2bcd(tm->tm_hour);
regs[RV3029_W_DATE-RV3029_W_SEC] = bin2bcd(tm->tm_mday);
regs[RV3029_W_MONTHS-RV3029_W_SEC] = bin2bcd(tm->tm_mon+1);
regs[RV3029_W_DAYS-RV3029_W_SEC] = bin2bcd((tm->tm_wday & 7)+1);
regs[RV3029_W_YEARS-RV3029_W_SEC] = bin2bcd(tm->tm_year - 100);
ret = rv3029c2_i2c_write_regs(client, RV3029C2_W_SEC, regs,
RV3029C2_WATCH_SECTION_LEN);
ret = rv3029_i2c_write_regs(client, RV3029_W_SEC, regs,
RV3029_WATCH_SECTION_LEN);
if (ret < 0)
return ret;
ret = rv3029c2_i2c_get_sr(client, regs);
ret = rv3029_i2c_get_sr(client, regs);
if (ret < 0) {
dev_err(&client->dev, "%s: reading SR failed\n", __func__);
return ret;
}
/* clear PON bit */
ret = rv3029c2_i2c_set_sr(client, (regs[0] & ~RV3029C2_STATUS_PON));
ret = rv3029_i2c_set_sr(client, (regs[0] & ~RV3029_STATUS_PON));
if (ret < 0) {
dev_err(&client->dev, "%s: reading SR failed\n", __func__);
return ret;
@ -367,26 +540,238 @@ rv3029c2_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm)
return 0;
}
static int rv3029c2_rtc_set_time(struct device *dev, struct rtc_time *tm)
static int rv3029_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
return rv3029c2_i2c_set_time(to_i2c_client(dev), tm);
return rv3029_i2c_set_time(to_i2c_client(dev), tm);
}
static const struct rtc_class_ops rv3029c2_rtc_ops = {
.read_time = rv3029c2_rtc_read_time,
.set_time = rv3029c2_rtc_set_time,
.read_alarm = rv3029c2_rtc_read_alarm,
.set_alarm = rv3029c2_rtc_set_alarm,
static const struct rv3029_trickle_tab_elem {
u32 r; /* resistance in ohms */
u8 conf; /* trickle config bits */
} rv3029_trickle_tab[] = {
{
.r = 1076,
.conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K |
RV3029_TRICKLE_20K | RV3029_TRICKLE_80K,
}, {
.r = 1091,
.conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K |
RV3029_TRICKLE_20K,
}, {
.r = 1137,
.conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K |
RV3029_TRICKLE_80K,
}, {
.r = 1154,
.conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K,
}, {
.r = 1371,
.conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_20K |
RV3029_TRICKLE_80K,
}, {
.r = 1395,
.conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_20K,
}, {
.r = 1472,
.conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_80K,
}, {
.r = 1500,
.conf = RV3029_TRICKLE_1K,
}, {
.r = 3810,
.conf = RV3029_TRICKLE_5K | RV3029_TRICKLE_20K |
RV3029_TRICKLE_80K,
}, {
.r = 4000,
.conf = RV3029_TRICKLE_5K | RV3029_TRICKLE_20K,
}, {
.r = 4706,
.conf = RV3029_TRICKLE_5K | RV3029_TRICKLE_80K,
}, {
.r = 5000,
.conf = RV3029_TRICKLE_5K,
}, {
.r = 16000,
.conf = RV3029_TRICKLE_20K | RV3029_TRICKLE_80K,
}, {
.r = 20000,
.conf = RV3029_TRICKLE_20K,
}, {
.r = 80000,
.conf = RV3029_TRICKLE_80K,
},
};
static struct i2c_device_id rv3029c2_id[] = {
static void rv3029_trickle_config(struct i2c_client *client)
{
struct device_node *of_node = client->dev.of_node;
const struct rv3029_trickle_tab_elem *elem;
int i, err;
u32 ohms;
u8 trickle_set_bits;
if (!of_node)
return;
/* Configure the trickle charger. */
err = of_property_read_u32(of_node, "trickle-resistor-ohms", &ohms);
if (err) {
/* Disable trickle charger. */
trickle_set_bits = 0;
} else {
/* Enable trickle charger. */
for (i = 0; i < ARRAY_SIZE(rv3029_trickle_tab); i++) {
elem = &rv3029_trickle_tab[i];
if (elem->r >= ohms)
break;
}
trickle_set_bits = elem->conf;
dev_info(&client->dev,
"Trickle charger enabled at %d ohms resistance.\n",
elem->r);
}
err = rv3029_eeprom_update_bits(client, RV3029_CONTROL_E2P_EECTRL,
RV3029_TRICKLE_MASK,
trickle_set_bits);
if (err < 0) {
dev_err(&client->dev,
"Failed to update trickle charger config\n");
}
}
#ifdef CONFIG_RTC_DRV_RV3029_HWMON
static int rv3029_read_temp(struct i2c_client *client, int *temp_mC)
{
int ret;
u8 temp;
ret = rv3029_i2c_read_regs(client, RV3029_TEMP_PAGE, &temp, 1);
if (ret < 0)
return ret;
*temp_mC = ((int)temp - 60) * 1000;
return 0;
}
static ssize_t rv3029_hwmon_show_temp(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct i2c_client *client = dev_get_drvdata(dev);
int ret, temp_mC;
ret = rv3029_read_temp(client, &temp_mC);
if (ret < 0)
return ret;
return sprintf(buf, "%d\n", temp_mC);
}
static ssize_t rv3029_hwmon_set_update_interval(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t count)
{
struct i2c_client *client = dev_get_drvdata(dev);
unsigned long interval_ms;
int ret;
u8 th_set_bits = 0;
ret = kstrtoul(buf, 10, &interval_ms);
if (ret < 0)
return ret;
if (interval_ms != 0) {
th_set_bits |= RV3029_EECTRL_THE;
if (interval_ms >= 16000)
th_set_bits |= RV3029_EECTRL_THP;
}
ret = rv3029_eeprom_update_bits(client, RV3029_CONTROL_E2P_EECTRL,
RV3029_EECTRL_THE | RV3029_EECTRL_THP,
th_set_bits);
if (ret < 0)
return ret;
return count;
}
static ssize_t rv3029_hwmon_show_update_interval(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct i2c_client *client = dev_get_drvdata(dev);
int ret, interval_ms;
u8 eectrl;
ret = rv3029_eeprom_read(client, RV3029_CONTROL_E2P_EECTRL,
&eectrl, 1);
if (ret < 0)
return ret;
if (eectrl & RV3029_EECTRL_THE) {
if (eectrl & RV3029_EECTRL_THP)
interval_ms = 16000;
else
interval_ms = 1000;
} else {
interval_ms = 0;
}
return sprintf(buf, "%d\n", interval_ms);
}
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, rv3029_hwmon_show_temp,
NULL, 0);
static SENSOR_DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO,
rv3029_hwmon_show_update_interval,
rv3029_hwmon_set_update_interval, 0);
static struct attribute *rv3029_hwmon_attrs[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_update_interval.dev_attr.attr,
NULL,
};
ATTRIBUTE_GROUPS(rv3029_hwmon);
static void rv3029_hwmon_register(struct i2c_client *client)
{
struct device *hwmon_dev;
hwmon_dev = devm_hwmon_device_register_with_groups(
&client->dev, client->name, client, rv3029_hwmon_groups);
if (IS_ERR(hwmon_dev)) {
dev_warn(&client->dev,
"unable to register hwmon device %ld\n",
PTR_ERR(hwmon_dev));
}
}
#else /* CONFIG_RTC_DRV_RV3029_HWMON */
static void rv3029_hwmon_register(struct i2c_client *client)
{
}
#endif /* CONFIG_RTC_DRV_RV3029_HWMON */
static const struct rtc_class_ops rv3029_rtc_ops = {
.read_time = rv3029_rtc_read_time,
.set_time = rv3029_rtc_set_time,
.read_alarm = rv3029_rtc_read_alarm,
.set_alarm = rv3029_rtc_set_alarm,
};
static struct i2c_device_id rv3029_id[] = {
{ "rv3029", 0 },
{ "rv3029c2", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, rv3029c2_id);
MODULE_DEVICE_TABLE(i2c, rv3029_id);
static int rv3029c2_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int rv3029_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct rtc_device *rtc;
int rc = 0;
@ -395,14 +780,17 @@ static int rv3029c2_probe(struct i2c_client *client,
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_EMUL))
return -ENODEV;
rc = rv3029c2_i2c_get_sr(client, buf);
rc = rv3029_i2c_get_sr(client, buf);
if (rc < 0) {
dev_err(&client->dev, "reading status failed\n");
return rc;
}
rv3029_trickle_config(client);
rv3029_hwmon_register(client);
rtc = devm_rtc_device_register(&client->dev, client->name,
&rv3029c2_rtc_ops, THIS_MODULE);
&rv3029_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
@ -412,16 +800,17 @@ static int rv3029c2_probe(struct i2c_client *client,
return 0;
}
static struct i2c_driver rv3029c2_driver = {
static struct i2c_driver rv3029_driver = {
.driver = {
.name = "rtc-rv3029c2",
},
.probe = rv3029c2_probe,
.id_table = rv3029c2_id,
.probe = rv3029_probe,
.id_table = rv3029_id,
};
module_i2c_driver(rv3029c2_driver);
module_i2c_driver(rv3029_driver);
MODULE_AUTHOR("Gregory Hermant <gregory.hermant@calao-systems.com>");
MODULE_DESCRIPTION("Micro Crystal RV3029C2 RTC driver");
MODULE_AUTHOR("Michael Buesch <m@bues.ch>");
MODULE_DESCRIPTION("Micro Crystal RV3029 RTC driver");
MODULE_LICENSE("GPL");

View File

@ -52,7 +52,7 @@
struct rv8803_data {
struct i2c_client *client;
struct rtc_device *rtc;
spinlock_t flags_lock;
struct mutex flags_lock;
u8 ctrl;
};
@ -63,11 +63,11 @@ static irqreturn_t rv8803_handle_irq(int irq, void *dev_id)
unsigned long events = 0;
int flags;
spin_lock(&rv8803->flags_lock);
mutex_lock(&rv8803->flags_lock);
flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
if (flags <= 0) {
spin_unlock(&rv8803->flags_lock);
mutex_unlock(&rv8803->flags_lock);
return IRQ_NONE;
}
@ -102,7 +102,7 @@ static irqreturn_t rv8803_handle_irq(int irq, void *dev_id)
rv8803->ctrl);
}
spin_unlock(&rv8803->flags_lock);
mutex_unlock(&rv8803->flags_lock);
return IRQ_HANDLED;
}
@ -155,7 +155,6 @@ static int rv8803_set_time(struct device *dev, struct rtc_time *tm)
struct rv8803_data *rv8803 = dev_get_drvdata(dev);
u8 date[7];
int flags, ret;
unsigned long irqflags;
if ((tm->tm_year < 100) || (tm->tm_year > 199))
return -EINVAL;
@ -173,18 +172,18 @@ static int rv8803_set_time(struct device *dev, struct rtc_time *tm)
if (ret < 0)
return ret;
spin_lock_irqsave(&rv8803->flags_lock, irqflags);
mutex_lock(&rv8803->flags_lock);
flags = i2c_smbus_read_byte_data(rv8803->client, RV8803_FLAG);
if (flags < 0) {
spin_unlock_irqrestore(&rv8803->flags_lock, irqflags);
mutex_unlock(&rv8803->flags_lock);
return flags;
}
ret = i2c_smbus_write_byte_data(rv8803->client, RV8803_FLAG,
flags & ~RV8803_FLAG_V2F);
spin_unlock_irqrestore(&rv8803->flags_lock, irqflags);
mutex_unlock(&rv8803->flags_lock);
return ret;
}
@ -226,7 +225,6 @@ static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
u8 alarmvals[3];
u8 ctrl[2];
int ret, err;
unsigned long irqflags;
/* The alarm has no seconds, round up to nearest minute */
if (alrm->time.tm_sec) {
@ -236,11 +234,11 @@ static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
rtc_time64_to_tm(alarm_time, &alrm->time);
}
spin_lock_irqsave(&rv8803->flags_lock, irqflags);
mutex_lock(&rv8803->flags_lock);
ret = i2c_smbus_read_i2c_block_data(client, RV8803_FLAG, 2, ctrl);
if (ret != 2) {
spin_unlock_irqrestore(&rv8803->flags_lock, irqflags);
mutex_unlock(&rv8803->flags_lock);
return ret < 0 ? ret : -EIO;
}
@ -253,14 +251,14 @@ static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
err = i2c_smbus_write_byte_data(rv8803->client, RV8803_CTRL,
rv8803->ctrl);
if (err) {
spin_unlock_irqrestore(&rv8803->flags_lock, irqflags);
mutex_unlock(&rv8803->flags_lock);
return err;
}
}
ctrl[1] &= ~RV8803_FLAG_AF;
err = i2c_smbus_write_byte_data(rv8803->client, RV8803_FLAG, ctrl[1]);
spin_unlock_irqrestore(&rv8803->flags_lock, irqflags);
mutex_unlock(&rv8803->flags_lock);
if (err)
return err;
@ -289,7 +287,6 @@ static int rv8803_alarm_irq_enable(struct device *dev, unsigned int enabled)
struct i2c_client *client = to_i2c_client(dev);
struct rv8803_data *rv8803 = dev_get_drvdata(dev);
int ctrl, flags, err;
unsigned long irqflags;
ctrl = rv8803->ctrl;
@ -305,15 +302,15 @@ static int rv8803_alarm_irq_enable(struct device *dev, unsigned int enabled)
ctrl &= ~RV8803_CTRL_AIE;
}
spin_lock_irqsave(&rv8803->flags_lock, irqflags);
mutex_lock(&rv8803->flags_lock);
flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
if (flags < 0) {
spin_unlock_irqrestore(&rv8803->flags_lock, irqflags);
mutex_unlock(&rv8803->flags_lock);
return flags;
}
flags &= ~(RV8803_FLAG_AF | RV8803_FLAG_UF);
err = i2c_smbus_write_byte_data(client, RV8803_FLAG, flags);
spin_unlock_irqrestore(&rv8803->flags_lock, irqflags);
mutex_unlock(&rv8803->flags_lock);
if (err)
return err;
@ -333,7 +330,6 @@ static int rv8803_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
struct i2c_client *client = to_i2c_client(dev);
struct rv8803_data *rv8803 = dev_get_drvdata(dev);
int flags, ret = 0;
unsigned long irqflags;
switch (cmd) {
case RTC_VL_READ:
@ -355,16 +351,16 @@ static int rv8803_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
return 0;
case RTC_VL_CLR:
spin_lock_irqsave(&rv8803->flags_lock, irqflags);
mutex_lock(&rv8803->flags_lock);
flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
if (flags < 0) {
spin_unlock_irqrestore(&rv8803->flags_lock, irqflags);
mutex_unlock(&rv8803->flags_lock);
return flags;
}
flags &= ~(RV8803_FLAG_V1F | RV8803_FLAG_V2F);
ret = i2c_smbus_write_byte_data(client, RV8803_FLAG, flags);
spin_unlock_irqrestore(&rv8803->flags_lock, irqflags);
mutex_unlock(&rv8803->flags_lock);
if (ret < 0)
return ret;
@ -441,6 +437,7 @@ static int rv8803_probe(struct i2c_client *client,
if (!rv8803)
return -ENOMEM;
mutex_init(&rv8803->flags_lock);
rv8803->client = client;
i2c_set_clientdata(client, rv8803);

402
drivers/rtc/rtc-rx6110.c Normal file
View File

@ -0,0 +1,402 @@
/*
* Driver for the Epson RTC module RX-6110 SA
*
* Copyright(C) 2015 Pengutronix, Steffen Trumtrar <kernel@pengutronix.de>
* Copyright(C) SEIKO EPSON CORPORATION 2013. All rights reserved.
*
* This driver software is distributed as is, without any warranty of any kind,
* either express or implied as further specified in the GNU Public License.
* This software may be used and distributed according to the terms of the GNU
* Public License, version 2 as published by the Free Software Foundation.
* See the file COPYING in the main directory of this archive for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/bcd.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/regmap.h>
#include <linux/rtc.h>
#include <linux/spi/spi.h>
/* RX-6110 Register definitions */
#define RX6110_REG_SEC 0x10
#define RX6110_REG_MIN 0x11
#define RX6110_REG_HOUR 0x12
#define RX6110_REG_WDAY 0x13
#define RX6110_REG_MDAY 0x14
#define RX6110_REG_MONTH 0x15
#define RX6110_REG_YEAR 0x16
#define RX6110_REG_RES1 0x17
#define RX6110_REG_ALMIN 0x18
#define RX6110_REG_ALHOUR 0x19
#define RX6110_REG_ALWDAY 0x1A
#define RX6110_REG_TCOUNT0 0x1B
#define RX6110_REG_TCOUNT1 0x1C
#define RX6110_REG_EXT 0x1D
#define RX6110_REG_FLAG 0x1E
#define RX6110_REG_CTRL 0x1F
#define RX6110_REG_USER0 0x20
#define RX6110_REG_USER1 0x21
#define RX6110_REG_USER2 0x22
#define RX6110_REG_USER3 0x23
#define RX6110_REG_USER4 0x24
#define RX6110_REG_USER5 0x25
#define RX6110_REG_USER6 0x26
#define RX6110_REG_USER7 0x27
#define RX6110_REG_USER8 0x28
#define RX6110_REG_USER9 0x29
#define RX6110_REG_USERA 0x2A
#define RX6110_REG_USERB 0x2B
#define RX6110_REG_USERC 0x2C
#define RX6110_REG_USERD 0x2D
#define RX6110_REG_USERE 0x2E
#define RX6110_REG_USERF 0x2F
#define RX6110_REG_RES2 0x30
#define RX6110_REG_RES3 0x31
#define RX6110_REG_IRQ 0x32
#define RX6110_BIT_ALARM_EN BIT(7)
/* Extension Register (1Dh) bit positions */
#define RX6110_BIT_EXT_TSEL0 BIT(0)
#define RX6110_BIT_EXT_TSEL1 BIT(1)
#define RX6110_BIT_EXT_TSEL2 BIT(2)
#define RX6110_BIT_EXT_WADA BIT(3)
#define RX6110_BIT_EXT_TE BIT(4)
#define RX6110_BIT_EXT_USEL BIT(5)
#define RX6110_BIT_EXT_FSEL0 BIT(6)
#define RX6110_BIT_EXT_FSEL1 BIT(7)
/* Flag Register (1Eh) bit positions */
#define RX6110_BIT_FLAG_VLF BIT(1)
#define RX6110_BIT_FLAG_AF BIT(3)
#define RX6110_BIT_FLAG_TF BIT(4)
#define RX6110_BIT_FLAG_UF BIT(5)
/* Control Register (1Fh) bit positions */
#define RX6110_BIT_CTRL_TBKE BIT(0)
#define RX6110_BIT_CTRL_TBKON BIT(1)
#define RX6110_BIT_CTRL_TSTP BIT(2)
#define RX6110_BIT_CTRL_AIE BIT(3)
#define RX6110_BIT_CTRL_TIE BIT(4)
#define RX6110_BIT_CTRL_UIE BIT(5)
#define RX6110_BIT_CTRL_STOP BIT(6)
#define RX6110_BIT_CTRL_TEST BIT(7)
enum {
RTC_SEC = 0,
RTC_MIN,
RTC_HOUR,
RTC_WDAY,
RTC_MDAY,
RTC_MONTH,
RTC_YEAR,
RTC_NR_TIME
};
#define RX6110_DRIVER_NAME "rx6110"
struct rx6110_data {
struct rtc_device *rtc;
struct regmap *regmap;
};
/**
* rx6110_rtc_tm_to_data - convert rtc_time to native time encoding
*
* @tm: holds date and time
* @data: holds the encoding in rx6110 native form
*/
static int rx6110_rtc_tm_to_data(struct rtc_time *tm, u8 *data)
{
pr_debug("%s: date %ds %dm %dh %dmd %dm %dy\n", __func__,
tm->tm_sec, tm->tm_min, tm->tm_hour,
tm->tm_mday, tm->tm_mon, tm->tm_year);
/*
* The year in the RTC is a value between 0 and 99.
* Assume that this represents the current century
* and disregard all other values.
*/
if (tm->tm_year < 100 || tm->tm_year >= 200)
return -EINVAL;
data[RTC_SEC] = bin2bcd(tm->tm_sec);
data[RTC_MIN] = bin2bcd(tm->tm_min);
data[RTC_HOUR] = bin2bcd(tm->tm_hour);
data[RTC_WDAY] = BIT(bin2bcd(tm->tm_wday));
data[RTC_MDAY] = bin2bcd(tm->tm_mday);
data[RTC_MONTH] = bin2bcd(tm->tm_mon + 1);
data[RTC_YEAR] = bin2bcd(tm->tm_year % 100);
return 0;
}
/**
* rx6110_data_to_rtc_tm - convert native time encoding to rtc_time
*
* @data: holds the encoding in rx6110 native form
* @tm: holds date and time
*/
static int rx6110_data_to_rtc_tm(u8 *data, struct rtc_time *tm)
{
tm->tm_sec = bcd2bin(data[RTC_SEC] & 0x7f);
tm->tm_min = bcd2bin(data[RTC_MIN] & 0x7f);
/* only 24-hour clock */
tm->tm_hour = bcd2bin(data[RTC_HOUR] & 0x3f);
tm->tm_wday = ffs(data[RTC_WDAY] & 0x7f);
tm->tm_mday = bcd2bin(data[RTC_MDAY] & 0x3f);
tm->tm_mon = bcd2bin(data[RTC_MONTH] & 0x1f) - 1;
tm->tm_year = bcd2bin(data[RTC_YEAR]) + 100;
pr_debug("%s: date %ds %dm %dh %dmd %dm %dy\n", __func__,
tm->tm_sec, tm->tm_min, tm->tm_hour,
tm->tm_mday, tm->tm_mon, tm->tm_year);
/*
* The year in the RTC is a value between 0 and 99.
* Assume that this represents the current century
* and disregard all other values.
*/
if (tm->tm_year < 100 || tm->tm_year >= 200)
return -EINVAL;
return 0;
}
/**
* rx6110_set_time - set the current time in the rx6110 registers
*
* @dev: the rtc device in use
* @tm: holds date and time
*
* BUG: The HW assumes every year that is a multiple of 4 to be a leap
* year. Next time this is wrong is 2100, which will not be a leap year
*
* Note: If STOP is not set/cleared, the clock will start when the seconds
* register is written
*
*/
static int rx6110_set_time(struct device *dev, struct rtc_time *tm)
{
struct rx6110_data *rx6110 = dev_get_drvdata(dev);
u8 data[RTC_NR_TIME];
int ret;
ret = rx6110_rtc_tm_to_data(tm, data);
if (ret < 0)
return ret;
/* set STOP bit before changing clock/calendar */
ret = regmap_update_bits(rx6110->regmap, RX6110_REG_CTRL,
RX6110_BIT_CTRL_STOP, RX6110_BIT_CTRL_STOP);
if (ret)
return ret;
ret = regmap_bulk_write(rx6110->regmap, RX6110_REG_SEC, data,
RTC_NR_TIME);
if (ret)
return ret;
/* The time in the RTC is valid. Be sure to have VLF cleared. */
ret = regmap_update_bits(rx6110->regmap, RX6110_REG_FLAG,
RX6110_BIT_FLAG_VLF, 0);
if (ret)
return ret;
/* clear STOP bit after changing clock/calendar */
ret = regmap_update_bits(rx6110->regmap, RX6110_REG_CTRL,
RX6110_BIT_CTRL_STOP, 0);
return ret;
}
/**
* rx6110_get_time - get the current time from the rx6110 registers
* @dev: the rtc device in use
* @tm: holds date and time
*/
static int rx6110_get_time(struct device *dev, struct rtc_time *tm)
{
struct rx6110_data *rx6110 = dev_get_drvdata(dev);
u8 data[RTC_NR_TIME];
int flags;
int ret;
ret = regmap_read(rx6110->regmap, RX6110_REG_FLAG, &flags);
if (ret)
return -EINVAL;
/* check for VLF Flag (set at power-on) */
if ((flags & RX6110_BIT_FLAG_VLF)) {
dev_warn(dev, "Voltage low, data is invalid.\n");
return -EINVAL;
}
/* read registers to date */
ret = regmap_bulk_read(rx6110->regmap, RX6110_REG_SEC, data,
RTC_NR_TIME);
if (ret)
return ret;
ret = rx6110_data_to_rtc_tm(data, tm);
if (ret)
return ret;
dev_dbg(dev, "%s: date %ds %dm %dh %dmd %dm %dy\n", __func__,
tm->tm_sec, tm->tm_min, tm->tm_hour,
tm->tm_mday, tm->tm_mon, tm->tm_year);
return rtc_valid_tm(tm);
}
static const struct reg_sequence rx6110_default_regs[] = {
{ RX6110_REG_RES1, 0xB8 },
{ RX6110_REG_RES2, 0x00 },
{ RX6110_REG_RES3, 0x10 },
{ RX6110_REG_IRQ, 0x00 },
{ RX6110_REG_ALMIN, 0x00 },
{ RX6110_REG_ALHOUR, 0x00 },
{ RX6110_REG_ALWDAY, 0x00 },
};
/**
* rx6110_init - initialize the rx6110 registers
*
* @rx6110: pointer to the rx6110 struct in use
*
*/
static int rx6110_init(struct rx6110_data *rx6110)
{
struct rtc_device *rtc = rx6110->rtc;
int flags;
int ret;
ret = regmap_update_bits(rx6110->regmap, RX6110_REG_EXT,
RX6110_BIT_EXT_TE, 0);
if (ret)
return ret;
ret = regmap_register_patch(rx6110->regmap, rx6110_default_regs,
ARRAY_SIZE(rx6110_default_regs));
if (ret)
return ret;
ret = regmap_read(rx6110->regmap, RX6110_REG_FLAG, &flags);
if (ret)
return ret;
/* check for VLF Flag (set at power-on) */
if ((flags & RX6110_BIT_FLAG_VLF))
dev_warn(&rtc->dev, "Voltage low, data loss detected.\n");
/* check for Alarm Flag */
if (flags & RX6110_BIT_FLAG_AF)
dev_warn(&rtc->dev, "An alarm may have been missed.\n");
/* check for Periodic Timer Flag */
if (flags & RX6110_BIT_FLAG_TF)
dev_warn(&rtc->dev, "Periodic timer was detected\n");
/* check for Update Timer Flag */
if (flags & RX6110_BIT_FLAG_UF)
dev_warn(&rtc->dev, "Update timer was detected\n");
/* clear all flags BUT VLF */
ret = regmap_update_bits(rx6110->regmap, RX6110_REG_FLAG,
RX6110_BIT_FLAG_AF |
RX6110_BIT_FLAG_UF |
RX6110_BIT_FLAG_TF,
0);
return ret;
}
static struct rtc_class_ops rx6110_rtc_ops = {
.read_time = rx6110_get_time,
.set_time = rx6110_set_time,
};
static struct regmap_config regmap_spi_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = RX6110_REG_IRQ,
.read_flag_mask = 0x80,
};
/**
* rx6110_probe - initialize rtc driver
* @spi: pointer to spi device
*/
static int rx6110_probe(struct spi_device *spi)
{
struct rx6110_data *rx6110;
int err;
if ((spi->bits_per_word && spi->bits_per_word != 8) ||
(spi->max_speed_hz > 2000000) ||
(spi->mode != (SPI_CS_HIGH | SPI_CPOL | SPI_CPHA))) {
dev_warn(&spi->dev, "SPI settings: bits_per_word: %d, max_speed_hz: %d, mode: %xh\n",
spi->bits_per_word, spi->max_speed_hz, spi->mode);
dev_warn(&spi->dev, "driving device in an unsupported mode");
}
rx6110 = devm_kzalloc(&spi->dev, sizeof(*rx6110), GFP_KERNEL);
if (!rx6110)
return -ENOMEM;
rx6110->regmap = devm_regmap_init_spi(spi, &regmap_spi_config);
if (IS_ERR(rx6110->regmap)) {
dev_err(&spi->dev, "regmap init failed for rtc rx6110\n");
return PTR_ERR(rx6110->regmap);
}
spi_set_drvdata(spi, rx6110);
rx6110->rtc = devm_rtc_device_register(&spi->dev,
RX6110_DRIVER_NAME,
&rx6110_rtc_ops, THIS_MODULE);
if (IS_ERR(rx6110->rtc))
return PTR_ERR(rx6110->rtc);
err = rx6110_init(rx6110);
if (err)
return err;
rx6110->rtc->max_user_freq = 1;
return 0;
}
static int rx6110_remove(struct spi_device *spi)
{
return 0;
}
static const struct spi_device_id rx6110_id[] = {
{ "rx6110", 0 },
{ }
};
MODULE_DEVICE_TABLE(spi, rx6110_id);
static struct spi_driver rx6110_driver = {
.driver = {
.name = RX6110_DRIVER_NAME,
.owner = THIS_MODULE,
},
.probe = rx6110_probe,
.remove = rx6110_remove,
.id_table = rx6110_id,
};
module_spi_driver(rx6110_driver);
MODULE_AUTHOR("Val Krutov <val.krutov@erd.epson.com>");
MODULE_DESCRIPTION("RX-6110 SA RTC driver");
MODULE_LICENSE("GPL");

View File

@ -65,7 +65,6 @@
static const struct i2c_device_id rx8025_id[] = {
{ "rx8025", 0 },
{ "rv8803", 1 },
{ }
};
MODULE_DEVICE_TABLE(i2c, rx8025_id);
@ -147,8 +146,10 @@ static irqreturn_t rx8025_handle_irq(int irq, void *dev_id)
{
struct i2c_client *client = dev_id;
struct rx8025_data *rx8025 = i2c_get_clientdata(client);
struct mutex *lock = &rx8025->rtc->ops_lock;
int status;
mutex_lock(lock);
status = rx8025_read_reg(client, RX8025_REG_CTRL2);
if (status < 0)
goto out;
@ -173,6 +174,8 @@ static irqreturn_t rx8025_handle_irq(int irq, void *dev_id)
}
out:
mutex_unlock(lock);
return IRQ_HANDLED;
}
@ -341,7 +344,17 @@ static int rx8025_set_alarm(struct device *dev, struct rtc_wkalrm *t)
if (client->irq <= 0)
return -EINVAL;
/* Hardware alarm precision is 1 minute! */
/*
* Hardware alarm precision is 1 minute!
* round up to nearest minute
*/
if (t->time.tm_sec) {
time64_t alarm_time = rtc_tm_to_time64(&t->time);
alarm_time += 60 - t->time.tm_sec;
rtc_time64_to_tm(alarm_time, &t->time);
}
ald[0] = bin2bcd(t->time.tm_min);
if (rx8025->ctrl1 & RX8025_BIT_CTRL1_1224)
ald[1] = bin2bcd(t->time.tm_hour);
@ -539,8 +552,9 @@ static int rx8025_probe(struct i2c_client *client,
if (client->irq > 0) {
dev_info(&client->dev, "IRQ %d supplied\n", client->irq);
err = devm_request_threaded_irq(&client->dev, client->irq, NULL,
rx8025_handle_irq, 0, "rx8025",
client);
rx8025_handle_irq,
IRQF_ONESHOT,
"rx8025", client);
if (err) {
dev_err(&client->dev, "unable to request IRQ, alarms disabled\n");
client->irq = 0;
@ -549,6 +563,9 @@ static int rx8025_probe(struct i2c_client *client,
rx8025->rtc->max_user_freq = 1;
/* the rx8025 alarm only supports a minute accuracy */
rx8025->rtc->uie_unsupported = 1;
err = rx8025_sysfs_register(&client->dev);
return err;
}

View File

@ -216,7 +216,7 @@ static int s5m8767_tm_to_data(struct rtc_time *tm, u8 *data)
* Read RTC_UDR_CON register and wait till UDR field is cleared.
* This indicates that time/alarm update ended.
*/
static inline int s5m8767_wait_for_udr_update(struct s5m_rtc_info *info)
static int s5m8767_wait_for_udr_update(struct s5m_rtc_info *info)
{
int ret, retry = UDR_READ_RETRY_CNT;
unsigned int data;
@ -231,7 +231,7 @@ static inline int s5m8767_wait_for_udr_update(struct s5m_rtc_info *info)
return ret;
}
static inline int s5m_check_peding_alarm_interrupt(struct s5m_rtc_info *info,
static int s5m_check_peding_alarm_interrupt(struct s5m_rtc_info *info,
struct rtc_wkalrm *alarm)
{
int ret;
@ -264,7 +264,7 @@ static inline int s5m_check_peding_alarm_interrupt(struct s5m_rtc_info *info,
return 0;
}
static inline int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info)
static int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info)
{
int ret;
unsigned int data;
@ -288,7 +288,7 @@ static inline int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info)
return ret;
}
static inline int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info)
static int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info)
{
int ret;
unsigned int data;

View File

@ -218,6 +218,34 @@ wakealarm_store(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR_RW(wakealarm);
static ssize_t
offset_show(struct device *dev, struct device_attribute *attr, char *buf)
{
ssize_t retval;
long offset;
retval = rtc_read_offset(to_rtc_device(dev), &offset);
if (retval == 0)
retval = sprintf(buf, "%ld\n", offset);
return retval;
}
static ssize_t
offset_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t n)
{
ssize_t retval;
long offset;
retval = kstrtol(buf, 10, &offset);
if (retval == 0)
retval = rtc_set_offset(to_rtc_device(dev), offset);
return (retval < 0) ? retval : n;
}
static DEVICE_ATTR_RW(offset);
static struct attribute *rtc_attrs[] = {
&dev_attr_name.attr,
&dev_attr_date.attr,
@ -226,6 +254,7 @@ static struct attribute *rtc_attrs[] = {
&dev_attr_max_user_freq.attr,
&dev_attr_hctosys.attr,
&dev_attr_wakealarm.attr,
&dev_attr_offset.attr,
NULL,
};
@ -249,9 +278,13 @@ static umode_t rtc_attr_is_visible(struct kobject *kobj,
struct rtc_device *rtc = to_rtc_device(dev);
umode_t mode = attr->mode;
if (attr == &dev_attr_wakealarm.attr)
if (attr == &dev_attr_wakealarm.attr) {
if (!rtc_does_wakealarm(rtc))
mode = 0;
} else if (attr == &dev_attr_offset.attr) {
if (!rtc->ops->set_offset)
mode = 0;
}
return mode;
}

View File

@ -286,7 +286,7 @@ static int tps6586x_rtc_probe(struct platform_device *pdev)
ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL,
tps6586x_rtc_irq,
IRQF_ONESHOT | IRQF_EARLY_RESUME,
IRQF_ONESHOT,
dev_name(&pdev->dev), rtc);
if (ret < 0) {
dev_err(&pdev->dev, "request IRQ(%d) failed with ret %d\n",

View File

@ -268,7 +268,7 @@ static int tps65910_rtc_probe(struct platform_device *pdev)
}
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
tps65910_rtc_interrupt, IRQF_TRIGGER_LOW | IRQF_EARLY_RESUME,
tps65910_rtc_interrupt, IRQF_TRIGGER_LOW,
dev_name(&pdev->dev), &pdev->dev);
if (ret < 0) {
dev_err(&pdev->dev, "IRQ is not free.\n");

View File

@ -287,7 +287,7 @@ static int tps80031_rtc_probe(struct platform_device *pdev)
ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL,
tps80031_rtc_irq,
IRQF_ONESHOT | IRQF_EARLY_RESUME,
IRQF_ONESHOT,
dev_name(&pdev->dev), rtc);
if (ret < 0) {
dev_err(&pdev->dev, "request IRQ:%d failed, err = %d\n",

View File

@ -272,12 +272,13 @@ static irqreturn_t rtclong1_interrupt(int irq, void *dev_id)
}
static const struct rtc_class_ops vr41xx_rtc_ops = {
.release = vr41xx_rtc_release,
.ioctl = vr41xx_rtc_ioctl,
.read_time = vr41xx_rtc_read_time,
.set_time = vr41xx_rtc_set_time,
.read_alarm = vr41xx_rtc_read_alarm,
.set_alarm = vr41xx_rtc_set_alarm,
.release = vr41xx_rtc_release,
.ioctl = vr41xx_rtc_ioctl,
.read_time = vr41xx_rtc_read_time,
.set_time = vr41xx_rtc_set_time,
.read_alarm = vr41xx_rtc_read_alarm,
.set_alarm = vr41xx_rtc_set_alarm,
.alarm_irq_enable = vr41xx_rtc_alarm_irq_enable,
};
static int rtc_probe(struct platform_device *pdev)

View File

@ -437,14 +437,11 @@ enum max77686_irq {
struct max77686_dev {
struct device *dev;
struct i2c_client *i2c; /* 0xcc / PMIC, Battery Control, and FLASH */
struct i2c_client *rtc; /* slave addr 0x0c */
unsigned long type;
struct regmap *regmap; /* regmap for mfd */
struct regmap *rtc_regmap; /* regmap for rtc */
struct regmap_irq_chip_data *irq_data;
struct regmap_irq_chip_data *rtc_irq_data;
int irq;
struct mutex irqlock;

View File

@ -89,6 +89,8 @@ struct rtc_class_ops {
int (*set_mmss)(struct device *, unsigned long secs);
int (*read_callback)(struct device *, int data);
int (*alarm_irq_enable)(struct device *, unsigned int enabled);
int (*read_offset)(struct device *, long *offset);
int (*set_offset)(struct device *, long offset);
};
#define RTC_DEVICE_NAME_SIZE 20
@ -208,6 +210,8 @@ void rtc_timer_init(struct rtc_timer *timer, void (*f)(void *p), void *data);
int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer *timer,
ktime_t expires, ktime_t period);
void rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer *timer);
int rtc_read_offset(struct rtc_device *rtc, long *offset);
int rtc_set_offset(struct rtc_device *rtc, long offset);
void rtc_timer_do_work(struct work_struct *work);
static inline bool is_leap_year(unsigned int year)