mirror of
https://github.com/rd-stuffs/msm-4.14.git
synced 2025-02-20 11:45:48 +08:00
RTC for 4.6 #2
Drivers: - abx80x: handle both XT and RC oscillators, XT failure bit and autocalibration - m41t80: avoid out of range year values - rv8803: workaround an i2c HW issue -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCAAGBQJW9JdpAAoJEKbNnwlvZCyz9hYP/RU/8fJtdO2veoY+xLVta7UV mJahSrMn7CMkZeVh7vy/T8tIJDNB+G4TqkG6V8kT41yltzTZszn/Qm/t6vrEcwY3 GXj11NtIiOeo6UgGeEKj0feM9Imy/OtHvCfXc7XmTV78f0DYE5MvH+7rTXmFzNm0 qHE+aGPfp2CGYS8HhDYwedvXo9qphSCfbU3akm2PSdFfOkoCuIBndJgLkKsqdKXY St9hN0Z7xo3FayxtTbELftnW1xkvgsJiGcU19b3Uo89V3NS1L+5eJkhI7cx/kQxz bMlBBKkvpdmRwy2ng42NGipLXEXwTTOqx4ZlhKLjwhGAF1m4R9ThrCrrXrBT01LM 8TwO5HNqUEViQYXMSK95UF2F5ldE5S+kfYUjopdoV1N6/04Uz+X03o9+zMAJq4JH ZWjcLIYXb1lvmt8KzUD847O69001NtWC0zVgHoQJ3CldguyGX11BYzkRCxRn/u9y OWEivF8K0hXYw0Dcmnls6/lrDP1xQc7s6BiFg00UTEjGAmlZVR3eSNBxCXXUneyR nsv1dlvB9+mcVFFpEQI/MFFNdoBBx3KLRIE+pFJIadQ4yaWkUhrOJpTW4Y646QAj 1VMDV5Z6961sMqVkyqNMZqaqnVgrZY0DZWS9PMzYlNnrDSIXu3svu78xq+foBy0+ OuOHjLcIIKxFSRysMZu7 =PMVI -----END PGP SIGNATURE----- Merge tag 'rtc-4.6-2' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux Pull more RTC updates from Alexandre Belloni: "A second pull request for v4.6 with a few fixesi before -rc1. The new features for abx80x actually make the RTC behave correctly. Drivers: - abx80x: handle both XT and RC oscillators, XT failure bit and autocalibration - m41t80: avoid out of range year values - rv8803: workaround an i2c HW issue" * tag 'rtc-4.6-2' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: rtc: abx80x: handle the oscillator failure bit rtc: abx80x: handle autocalibration rtc: rv8803: workaround i2c HW issue rtc: mcp795: add devicetree support rtc: asm9260: remove incorrect __init/__exit annotations rtc: m41t80: avoid out of range year values rtc: s3c: Don't print an error on probe deferral rtc: rv3029: stop mentioning rv3029c2
This commit is contained in:
commit
8407ef4685
11
Documentation/devicetree/bindings/rtc/maxim,mcp795.txt
Normal file
11
Documentation/devicetree/bindings/rtc/maxim,mcp795.txt
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
* Maxim MCP795 SPI Serial Real-Time Clock
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: Should contain "maxim,mcp795".
|
||||||
|
- reg: SPI address for chip
|
||||||
|
|
||||||
|
Example:
|
||||||
|
mcp795: rtc@0 {
|
||||||
|
compatible = "maxim,mcp795";
|
||||||
|
reg = <0>;
|
||||||
|
};
|
@ -589,7 +589,7 @@ config RTC_DRV_RV3029_HWMON
|
|||||||
default y
|
default y
|
||||||
help
|
help
|
||||||
Say Y here if you want to expose temperature sensor data on
|
Say Y here if you want to expose temperature sensor data on
|
||||||
rtc-rv3029c2.
|
rtc-rv3029.
|
||||||
|
|
||||||
config RTC_DRV_RV8803
|
config RTC_DRV_RV8803
|
||||||
tristate "Micro Crystal RV8803"
|
tristate "Micro Crystal RV8803"
|
||||||
|
@ -49,7 +49,20 @@
|
|||||||
|
|
||||||
#define ABX8XX_REG_CD_TIMER_CTL 0x18
|
#define ABX8XX_REG_CD_TIMER_CTL 0x18
|
||||||
|
|
||||||
|
#define ABX8XX_REG_OSC 0x1c
|
||||||
|
#define ABX8XX_OSC_FOS BIT(3)
|
||||||
|
#define ABX8XX_OSC_BOS BIT(4)
|
||||||
|
#define ABX8XX_OSC_ACAL_512 BIT(5)
|
||||||
|
#define ABX8XX_OSC_ACAL_1024 BIT(6)
|
||||||
|
|
||||||
|
#define ABX8XX_OSC_OSEL BIT(7)
|
||||||
|
|
||||||
|
#define ABX8XX_REG_OSS 0x1d
|
||||||
|
#define ABX8XX_OSS_OF BIT(1)
|
||||||
|
#define ABX8XX_OSS_OMODE BIT(4)
|
||||||
|
|
||||||
#define ABX8XX_REG_CFG_KEY 0x1f
|
#define ABX8XX_REG_CFG_KEY 0x1f
|
||||||
|
#define ABX8XX_CFG_KEY_OSC 0xa1
|
||||||
#define ABX8XX_CFG_KEY_MISC 0x9d
|
#define ABX8XX_CFG_KEY_MISC 0x9d
|
||||||
|
|
||||||
#define ABX8XX_REG_ID0 0x28
|
#define ABX8XX_REG_ID0 0x28
|
||||||
@ -81,6 +94,20 @@ static struct abx80x_cap abx80x_caps[] = {
|
|||||||
[ABX80X] = {.pn = 0}
|
[ABX80X] = {.pn = 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int abx80x_is_rc_mode(struct i2c_client *client)
|
||||||
|
{
|
||||||
|
int flags = 0;
|
||||||
|
|
||||||
|
flags = i2c_smbus_read_byte_data(client, ABX8XX_REG_OSS);
|
||||||
|
if (flags < 0) {
|
||||||
|
dev_err(&client->dev,
|
||||||
|
"Failed to read autocalibration attribute\n");
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (flags & ABX8XX_OSS_OMODE) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int abx80x_enable_trickle_charger(struct i2c_client *client,
|
static int abx80x_enable_trickle_charger(struct i2c_client *client,
|
||||||
u8 trickle_cfg)
|
u8 trickle_cfg)
|
||||||
{
|
{
|
||||||
@ -112,7 +139,23 @@ static int abx80x_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
|||||||
{
|
{
|
||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
unsigned char buf[8];
|
unsigned char buf[8];
|
||||||
int err;
|
int err, flags, rc_mode = 0;
|
||||||
|
|
||||||
|
/* Read the Oscillator Failure only in XT mode */
|
||||||
|
rc_mode = abx80x_is_rc_mode(client);
|
||||||
|
if (rc_mode < 0)
|
||||||
|
return rc_mode;
|
||||||
|
|
||||||
|
if (!rc_mode) {
|
||||||
|
flags = i2c_smbus_read_byte_data(client, ABX8XX_REG_OSS);
|
||||||
|
if (flags < 0)
|
||||||
|
return flags;
|
||||||
|
|
||||||
|
if (flags & ABX8XX_OSS_OF) {
|
||||||
|
dev_err(dev, "Oscillator failure, data is invalid.\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = i2c_smbus_read_i2c_block_data(client, ABX8XX_REG_HTH,
|
err = i2c_smbus_read_i2c_block_data(client, ABX8XX_REG_HTH,
|
||||||
sizeof(buf), buf);
|
sizeof(buf), buf);
|
||||||
@ -140,7 +183,7 @@ static int abx80x_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
|||||||
{
|
{
|
||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
unsigned char buf[8];
|
unsigned char buf[8];
|
||||||
int err;
|
int err, flags;
|
||||||
|
|
||||||
if (tm->tm_year < 100)
|
if (tm->tm_year < 100)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -161,6 +204,18 @@ static int abx80x_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
|||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Clear the OF bit of Oscillator Status Register */
|
||||||
|
flags = i2c_smbus_read_byte_data(client, ABX8XX_REG_OSS);
|
||||||
|
if (flags < 0)
|
||||||
|
return flags;
|
||||||
|
|
||||||
|
err = i2c_smbus_write_byte_data(client, ABX8XX_REG_OSS,
|
||||||
|
flags & ~ABX8XX_OSS_OF);
|
||||||
|
if (err < 0) {
|
||||||
|
dev_err(&client->dev, "Unable to write oscillator status register\n");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,6 +303,174 @@ static int abx80x_set_alarm(struct device *dev, struct rtc_wkalrm *t)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int abx80x_rtc_set_autocalibration(struct device *dev,
|
||||||
|
int autocalibration)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
int retval, flags = 0;
|
||||||
|
|
||||||
|
if ((autocalibration != 0) && (autocalibration != 1024) &&
|
||||||
|
(autocalibration != 512)) {
|
||||||
|
dev_err(dev, "autocalibration value outside permitted range\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
flags = i2c_smbus_read_byte_data(client, ABX8XX_REG_OSC);
|
||||||
|
if (flags < 0)
|
||||||
|
return flags;
|
||||||
|
|
||||||
|
if (autocalibration == 0) {
|
||||||
|
flags &= ~(ABX8XX_OSC_ACAL_512 | ABX8XX_OSC_ACAL_1024);
|
||||||
|
} else if (autocalibration == 1024) {
|
||||||
|
/* 1024 autocalibration is 0x10 */
|
||||||
|
flags |= ABX8XX_OSC_ACAL_1024;
|
||||||
|
flags &= ~(ABX8XX_OSC_ACAL_512);
|
||||||
|
} else {
|
||||||
|
/* 512 autocalibration is 0x11 */
|
||||||
|
flags |= (ABX8XX_OSC_ACAL_1024 | ABX8XX_OSC_ACAL_512);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unlock write access to Oscillator Control Register */
|
||||||
|
retval = i2c_smbus_write_byte_data(client, ABX8XX_REG_CFG_KEY,
|
||||||
|
ABX8XX_CFG_KEY_OSC);
|
||||||
|
if (retval < 0) {
|
||||||
|
dev_err(dev, "Failed to write CONFIG_KEY register\n");
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = i2c_smbus_write_byte_data(client, ABX8XX_REG_OSC, flags);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int abx80x_rtc_get_autocalibration(struct device *dev)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
int flags = 0, autocalibration;
|
||||||
|
|
||||||
|
flags = i2c_smbus_read_byte_data(client, ABX8XX_REG_OSC);
|
||||||
|
if (flags < 0)
|
||||||
|
return flags;
|
||||||
|
|
||||||
|
if (flags & ABX8XX_OSC_ACAL_512)
|
||||||
|
autocalibration = 512;
|
||||||
|
else if (flags & ABX8XX_OSC_ACAL_1024)
|
||||||
|
autocalibration = 1024;
|
||||||
|
else
|
||||||
|
autocalibration = 0;
|
||||||
|
|
||||||
|
return autocalibration;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t autocalibration_store(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
unsigned long autocalibration = 0;
|
||||||
|
|
||||||
|
retval = kstrtoul(buf, 10, &autocalibration);
|
||||||
|
if (retval < 0) {
|
||||||
|
dev_err(dev, "Failed to store RTC autocalibration attribute\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = abx80x_rtc_set_autocalibration(dev, autocalibration);
|
||||||
|
|
||||||
|
return retval ? retval : count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t autocalibration_show(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
int autocalibration = 0;
|
||||||
|
|
||||||
|
autocalibration = abx80x_rtc_get_autocalibration(dev);
|
||||||
|
if (autocalibration < 0) {
|
||||||
|
dev_err(dev, "Failed to read RTC autocalibration\n");
|
||||||
|
sprintf(buf, "0\n");
|
||||||
|
return autocalibration;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sprintf(buf, "%d\n", autocalibration);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEVICE_ATTR_RW(autocalibration);
|
||||||
|
|
||||||
|
static ssize_t oscillator_store(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
int retval, flags, rc_mode = 0;
|
||||||
|
|
||||||
|
if (strncmp(buf, "rc", 2) == 0) {
|
||||||
|
rc_mode = 1;
|
||||||
|
} else if (strncmp(buf, "xtal", 4) == 0) {
|
||||||
|
rc_mode = 0;
|
||||||
|
} else {
|
||||||
|
dev_err(dev, "Oscillator selection value outside permitted ones\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
flags = i2c_smbus_read_byte_data(client, ABX8XX_REG_OSC);
|
||||||
|
if (flags < 0)
|
||||||
|
return flags;
|
||||||
|
|
||||||
|
if (rc_mode == 0)
|
||||||
|
flags &= ~(ABX8XX_OSC_OSEL);
|
||||||
|
else
|
||||||
|
flags |= (ABX8XX_OSC_OSEL);
|
||||||
|
|
||||||
|
/* Unlock write access on Oscillator Control register */
|
||||||
|
retval = i2c_smbus_write_byte_data(client, ABX8XX_REG_CFG_KEY,
|
||||||
|
ABX8XX_CFG_KEY_OSC);
|
||||||
|
if (retval < 0) {
|
||||||
|
dev_err(dev, "Failed to write CONFIG_KEY register\n");
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = i2c_smbus_write_byte_data(client, ABX8XX_REG_OSC, flags);
|
||||||
|
if (retval < 0) {
|
||||||
|
dev_err(dev, "Failed to write Oscillator Control register\n");
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval ? retval : count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t oscillator_show(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
int rc_mode = 0;
|
||||||
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
|
||||||
|
rc_mode = abx80x_is_rc_mode(client);
|
||||||
|
|
||||||
|
if (rc_mode < 0) {
|
||||||
|
dev_err(dev, "Failed to read RTC oscillator selection\n");
|
||||||
|
sprintf(buf, "\n");
|
||||||
|
return rc_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc_mode)
|
||||||
|
return sprintf(buf, "rc\n");
|
||||||
|
else
|
||||||
|
return sprintf(buf, "xtal\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEVICE_ATTR_RW(oscillator);
|
||||||
|
|
||||||
|
static struct attribute *rtc_calib_attrs[] = {
|
||||||
|
&dev_attr_autocalibration.attr,
|
||||||
|
&dev_attr_oscillator.attr,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct attribute_group rtc_calib_attr_group = {
|
||||||
|
.attrs = rtc_calib_attrs,
|
||||||
|
};
|
||||||
|
|
||||||
static int abx80x_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
static int abx80x_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
||||||
{
|
{
|
||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
@ -303,6 +526,13 @@ static int abx80x_dt_trickle_cfg(struct device_node *np)
|
|||||||
return (trickle_cfg | i);
|
return (trickle_cfg | i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rtc_calib_remove_sysfs_group(void *_dev)
|
||||||
|
{
|
||||||
|
struct device *dev = _dev;
|
||||||
|
|
||||||
|
sysfs_remove_group(&dev->kobj, &rtc_calib_attr_group);
|
||||||
|
}
|
||||||
|
|
||||||
static int abx80x_probe(struct i2c_client *client,
|
static int abx80x_probe(struct i2c_client *client,
|
||||||
const struct i2c_device_id *id)
|
const struct i2c_device_id *id)
|
||||||
{
|
{
|
||||||
@ -405,6 +635,24 @@ static int abx80x_probe(struct i2c_client *client,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Export sysfs entries */
|
||||||
|
err = sysfs_create_group(&(&client->dev)->kobj, &rtc_calib_attr_group);
|
||||||
|
if (err) {
|
||||||
|
dev_err(&client->dev, "Failed to create sysfs group: %d\n",
|
||||||
|
err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = devm_add_action(&client->dev, rtc_calib_remove_sysfs_group,
|
||||||
|
&client->dev);
|
||||||
|
if (err) {
|
||||||
|
rtc_calib_remove_sysfs_group(&client->dev);
|
||||||
|
dev_err(&client->dev,
|
||||||
|
"Failed to add sysfs cleanup action: %d\n",
|
||||||
|
err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,7 +255,7 @@ static const struct rtc_class_ops asm9260_rtc_ops = {
|
|||||||
.alarm_irq_enable = asm9260_alarm_irq_enable,
|
.alarm_irq_enable = asm9260_alarm_irq_enable,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init asm9260_rtc_probe(struct platform_device *pdev)
|
static int asm9260_rtc_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct asm9260_rtc_priv *priv;
|
struct asm9260_rtc_priv *priv;
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
@ -323,7 +323,7 @@ err_return:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __exit asm9260_rtc_remove(struct platform_device *pdev)
|
static int asm9260_rtc_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct asm9260_rtc_priv *priv = platform_get_drvdata(pdev);
|
struct asm9260_rtc_priv *priv = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
@ -176,7 +176,13 @@ static int m41t80_set_datetime(struct i2c_client *client, struct rtc_time *tm)
|
|||||||
bin2bcd(tm->tm_mday) | (buf[M41T80_REG_DAY] & ~0x3f);
|
bin2bcd(tm->tm_mday) | (buf[M41T80_REG_DAY] & ~0x3f);
|
||||||
buf[M41T80_REG_MON] =
|
buf[M41T80_REG_MON] =
|
||||||
bin2bcd(tm->tm_mon + 1) | (buf[M41T80_REG_MON] & ~0x1f);
|
bin2bcd(tm->tm_mon + 1) | (buf[M41T80_REG_MON] & ~0x1f);
|
||||||
|
|
||||||
/* assume 20YY not 19YY */
|
/* assume 20YY not 19YY */
|
||||||
|
if (tm->tm_year < 100 || tm->tm_year > 199) {
|
||||||
|
dev_err(&client->dev, "Year must be between 2000 and 2099. It's %d.\n",
|
||||||
|
tm->tm_year + 1900);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
buf[M41T80_REG_YEAR] = bin2bcd(tm->tm_year % 100);
|
buf[M41T80_REG_YEAR] = bin2bcd(tm->tm_year % 100);
|
||||||
|
|
||||||
if (i2c_transfer(client->adapter, msgs, 1) != 1) {
|
if (i2c_transfer(client->adapter, msgs, 1) != 1) {
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include <linux/printk.h>
|
#include <linux/printk.h>
|
||||||
#include <linux/spi/spi.h>
|
#include <linux/spi/spi.h>
|
||||||
#include <linux/rtc.h>
|
#include <linux/rtc.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
|
||||||
/* MCP795 Instructions, see datasheet table 3-1 */
|
/* MCP795 Instructions, see datasheet table 3-1 */
|
||||||
#define MCP795_EEREAD 0x03
|
#define MCP795_EEREAD 0x03
|
||||||
@ -183,9 +184,18 @@ static int mcp795_probe(struct spi_device *spi)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_OF
|
||||||
|
static const struct of_device_id mcp795_of_match[] = {
|
||||||
|
{ .compatible = "maxim,mcp795" },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, mcp795_of_match);
|
||||||
|
#endif
|
||||||
|
|
||||||
static struct spi_driver mcp795_driver = {
|
static struct spi_driver mcp795_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "rtc-mcp795",
|
.name = "rtc-mcp795",
|
||||||
|
.of_match_table = of_match_ptr(mcp795_of_match),
|
||||||
},
|
},
|
||||||
.probe = mcp795_probe,
|
.probe = mcp795_probe,
|
||||||
};
|
};
|
||||||
|
@ -61,11 +61,14 @@ static irqreturn_t rv8803_handle_irq(int irq, void *dev_id)
|
|||||||
struct i2c_client *client = dev_id;
|
struct i2c_client *client = dev_id;
|
||||||
struct rv8803_data *rv8803 = i2c_get_clientdata(client);
|
struct rv8803_data *rv8803 = i2c_get_clientdata(client);
|
||||||
unsigned long events = 0;
|
unsigned long events = 0;
|
||||||
int flags;
|
int flags, try = 0;
|
||||||
|
|
||||||
mutex_lock(&rv8803->flags_lock);
|
mutex_lock(&rv8803->flags_lock);
|
||||||
|
|
||||||
flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
|
do {
|
||||||
|
flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
|
||||||
|
try++;
|
||||||
|
} while ((flags == -ENXIO) && (try < 3));
|
||||||
if (flags <= 0) {
|
if (flags <= 0) {
|
||||||
mutex_unlock(&rv8803->flags_lock);
|
mutex_unlock(&rv8803->flags_lock);
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
@ -424,7 +427,7 @@ static int rv8803_probe(struct i2c_client *client,
|
|||||||
{
|
{
|
||||||
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
|
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
|
||||||
struct rv8803_data *rv8803;
|
struct rv8803_data *rv8803;
|
||||||
int err, flags;
|
int err, flags, try = 0;
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
|
||||||
I2C_FUNC_SMBUS_I2C_BLOCK)) {
|
I2C_FUNC_SMBUS_I2C_BLOCK)) {
|
||||||
@ -441,7 +444,16 @@ static int rv8803_probe(struct i2c_client *client,
|
|||||||
rv8803->client = client;
|
rv8803->client = client;
|
||||||
i2c_set_clientdata(client, rv8803);
|
i2c_set_clientdata(client, rv8803);
|
||||||
|
|
||||||
flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
|
/*
|
||||||
|
* There is a 60µs window where the RTC may not reply on the i2c bus in
|
||||||
|
* that case, the transfer is not ACKed. In that case, ensure there are
|
||||||
|
* multiple attempts.
|
||||||
|
*/
|
||||||
|
do {
|
||||||
|
flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
|
||||||
|
try++;
|
||||||
|
} while ((flags == -ENXIO) && (try < 3));
|
||||||
|
|
||||||
if (flags < 0)
|
if (flags < 0)
|
||||||
return flags;
|
return flags;
|
||||||
|
|
||||||
@ -476,8 +488,12 @@ static int rv8803_probe(struct i2c_client *client,
|
|||||||
return PTR_ERR(rv8803->rtc);
|
return PTR_ERR(rv8803->rtc);
|
||||||
}
|
}
|
||||||
|
|
||||||
err = i2c_smbus_write_byte_data(rv8803->client, RV8803_EXT,
|
try = 0;
|
||||||
RV8803_EXT_WADA);
|
do {
|
||||||
|
err = i2c_smbus_write_byte_data(rv8803->client, RV8803_EXT,
|
||||||
|
RV8803_EXT_WADA);
|
||||||
|
try++;
|
||||||
|
} while ((err == -ENXIO) && (try < 3));
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
@ -501,18 +501,27 @@ static int s3c_rtc_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
info->rtc_clk = devm_clk_get(&pdev->dev, "rtc");
|
info->rtc_clk = devm_clk_get(&pdev->dev, "rtc");
|
||||||
if (IS_ERR(info->rtc_clk)) {
|
if (IS_ERR(info->rtc_clk)) {
|
||||||
dev_err(&pdev->dev, "failed to find rtc clock\n");
|
ret = PTR_ERR(info->rtc_clk);
|
||||||
return PTR_ERR(info->rtc_clk);
|
if (ret != -EPROBE_DEFER)
|
||||||
|
dev_err(&pdev->dev, "failed to find rtc clock\n");
|
||||||
|
else
|
||||||
|
dev_dbg(&pdev->dev, "probe deferred due to missing rtc clk\n");
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
clk_prepare_enable(info->rtc_clk);
|
clk_prepare_enable(info->rtc_clk);
|
||||||
|
|
||||||
if (info->data->needs_src_clk) {
|
if (info->data->needs_src_clk) {
|
||||||
info->rtc_src_clk = devm_clk_get(&pdev->dev, "rtc_src");
|
info->rtc_src_clk = devm_clk_get(&pdev->dev, "rtc_src");
|
||||||
if (IS_ERR(info->rtc_src_clk)) {
|
if (IS_ERR(info->rtc_src_clk)) {
|
||||||
dev_err(&pdev->dev,
|
ret = PTR_ERR(info->rtc_src_clk);
|
||||||
"failed to find rtc source clock\n");
|
if (ret != -EPROBE_DEFER)
|
||||||
|
dev_err(&pdev->dev,
|
||||||
|
"failed to find rtc source clock\n");
|
||||||
|
else
|
||||||
|
dev_dbg(&pdev->dev,
|
||||||
|
"probe deferred due to missing rtc src clk\n");
|
||||||
clk_disable_unprepare(info->rtc_clk);
|
clk_disable_unprepare(info->rtc_clk);
|
||||||
return PTR_ERR(info->rtc_src_clk);
|
return ret;
|
||||||
}
|
}
|
||||||
clk_prepare_enable(info->rtc_src_clk);
|
clk_prepare_enable(info->rtc_src_clk);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user