Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 98681
b: refs/heads/master
c: 471d47e
h: refs/heads/master
i:
  98679: 68311c9
v: v3
  • Loading branch information
Michael Hamel authored and Linus Torvalds committed Jul 4, 2008
1 parent c13b868 commit c6ab65a
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 21 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 7a36a752d006f6874049da510297eeb7f09d92a7
refs/heads/master: 471d47e3223311d2638755717f97dc9a298f6dc9
111 changes: 91 additions & 20 deletions trunk/drivers/rtc/rtc-x1205.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,16 @@
#define X1205_SR_RTCF 0x01 /* Clock failure */
#define X1205_SR_WEL 0x02 /* Write Enable Latch */
#define X1205_SR_RWEL 0x04 /* Register Write Enable */
#define X1205_SR_AL0 0x20 /* Alarm 0 match */

#define X1205_DTR_DTR0 0x01
#define X1205_DTR_DTR1 0x02
#define X1205_DTR_DTR2 0x04

#define X1205_HR_MIL 0x80 /* Set in ccr.hour for 24 hr mode */

#define X1205_INT_AL0E 0x20 /* Alarm 0 enable */

static struct i2c_driver x1205_driver;

/*
Expand All @@ -89,16 +92,16 @@ static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm,
unsigned char reg_base)
{
unsigned char dt_addr[2] = { 0, reg_base };

unsigned char buf[8];
int i;

struct i2c_msg msgs[] = {
{ client->addr, 0, 2, dt_addr }, /* setup read ptr */
{ client->addr, I2C_M_RD, 8, buf }, /* read date */
};

/* read date registers */
if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
dev_err(&client->dev, "%s: read error\n", __func__);
return -EIO;
}
Expand All @@ -110,6 +113,11 @@ static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm,
buf[0], buf[1], buf[2], buf[3],
buf[4], buf[5], buf[6], buf[7]);

/* Mask out the enable bits if these are alarm registers */
if (reg_base < X1205_CCR_BASE)
for (i = 0; i <= 4; i++)
buf[i] &= 0x7F;

tm->tm_sec = BCD2BIN(buf[CCR_SEC]);
tm->tm_min = BCD2BIN(buf[CCR_MIN]);
tm->tm_hour = BCD2BIN(buf[CCR_HOUR] & 0x3F); /* hr is 0-23 */
Expand Down Expand Up @@ -138,7 +146,7 @@ static int x1205_get_status(struct i2c_client *client, unsigned char *sr)
};

/* read status register */
if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
dev_err(&client->dev, "%s: read error\n", __func__);
return -EIO;
}
Expand All @@ -147,10 +155,11 @@ static int x1205_get_status(struct i2c_client *client, unsigned char *sr)
}

static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm,
int datetoo, u8 reg_base)
int datetoo, u8 reg_base, unsigned char alm_enable)
{
int i, xfer;
int i, xfer, nbytes;
unsigned char buf[8];
unsigned char rdata[10] = { 0, reg_base };

static const unsigned char wel[3] = { 0, X1205_REG_SR,
X1205_SR_WEL };
Expand Down Expand Up @@ -189,6 +198,11 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm,
buf[CCR_Y2K] = BIN2BCD(tm->tm_year / 100);
}

/* If writing alarm registers, set compare bits on registers 0-4 */
if (reg_base < X1205_CCR_BASE)
for (i = 0; i <= 4; i++)
buf[i] |= 0x80;

/* this sequence is required to unlock the chip */
if ((xfer = i2c_master_send(client, wel, 3)) != 3) {
dev_err(&client->dev, "%s: wel - %d\n", __func__, xfer);
Expand All @@ -200,19 +214,57 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm,
return -EIO;
}


/* write register's data */
for (i = 0; i < (datetoo ? 8 : 3); i++) {
unsigned char rdata[3] = { 0, reg_base + i, buf[i] };
if (datetoo)
nbytes = 8;
else
nbytes = 3;
for (i = 0; i < nbytes; i++)
rdata[2+i] = buf[i];

xfer = i2c_master_send(client, rdata, nbytes+2);
if (xfer != nbytes+2) {
dev_err(&client->dev,
"%s: result=%d addr=%02x, data=%02x\n",
__func__,
xfer, rdata[1], rdata[2]);
return -EIO;
}

/* If we wrote to the nonvolatile region, wait 10msec for write cycle*/
if (reg_base < X1205_CCR_BASE) {
unsigned char al0e[3] = { 0, X1205_REG_INT, 0 };

msleep(10);

xfer = i2c_master_send(client, rdata, 3);
/* ...and set or clear the AL0E bit in the INT register */

/* Need to set RWEL again as the write has cleared it */
xfer = i2c_master_send(client, rwel, 3);
if (xfer != 3) {
dev_err(&client->dev,
"%s: xfer=%d addr=%02x, data=%02x\n",
"%s: aloe rwel - %d\n",
__func__,
xfer, rdata[1], rdata[2]);
xfer);
return -EIO;
}

if (alm_enable)
al0e[2] = X1205_INT_AL0E;

xfer = i2c_master_send(client, al0e, 3);
if (xfer != 3) {
dev_err(&client->dev,
"%s: al0e - %d\n",
__func__,
xfer);
return -EIO;
}
};

/* and wait 10msec again for this write to complete */
msleep(10);
}

/* disable further writes */
if ((xfer = i2c_master_send(client, diswe, 3)) != 3) {
Expand All @@ -230,9 +282,9 @@ static int x1205_fix_osc(struct i2c_client *client)

tm.tm_hour = tm.tm_min = tm.tm_sec = 0;

if ((err = x1205_set_datetime(client, &tm, 0, X1205_CCR_BASE)) < 0)
dev_err(&client->dev,
"unable to restart the oscillator\n");
err = x1205_set_datetime(client, &tm, 0, X1205_CCR_BASE, 0);
if (err < 0)
dev_err(&client->dev, "unable to restart the oscillator\n");

return err;
}
Expand All @@ -248,7 +300,7 @@ static int x1205_get_dtrim(struct i2c_client *client, int *trim)
};

/* read dtr register */
if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
dev_err(&client->dev, "%s: read error\n", __func__);
return -EIO;
}
Expand Down Expand Up @@ -280,7 +332,7 @@ static int x1205_get_atrim(struct i2c_client *client, int *trim)
};

/* read atr register */
if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
dev_err(&client->dev, "%s: read error\n", __func__);
return -EIO;
}
Expand Down Expand Up @@ -403,14 +455,33 @@ static int x1205_validate_client(struct i2c_client *client)

static int x1205_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
return x1205_get_datetime(to_i2c_client(dev),
&alrm->time, X1205_ALM0_BASE);
int err;
unsigned char intreg, status;
static unsigned char int_addr[2] = { 0, X1205_REG_INT };
struct i2c_client *client = to_i2c_client(dev);
struct i2c_msg msgs[] = {
{ client->addr, 0, 2, int_addr }, /* setup read ptr */
{ client->addr, I2C_M_RD, 1, &intreg }, /* read INT register */
};

/* read interrupt register and status register */
if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
dev_err(&client->dev, "%s: read error\n", __func__);
return -EIO;
}
err = x1205_get_status(client, &status);
if (err == 0) {
alrm->pending = (status & X1205_SR_AL0) ? 1 : 0;
alrm->enabled = (intreg & X1205_INT_AL0E) ? 1 : 0;
err = x1205_get_datetime(client, &alrm->time, X1205_ALM0_BASE);
}
return err;
}

static int x1205_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
return x1205_set_datetime(to_i2c_client(dev),
&alrm->time, 1, X1205_ALM0_BASE);
&alrm->time, 1, X1205_ALM0_BASE, alrm->enabled);
}

static int x1205_rtc_read_time(struct device *dev, struct rtc_time *tm)
Expand All @@ -422,7 +493,7 @@ static int x1205_rtc_read_time(struct device *dev, struct rtc_time *tm)
static int x1205_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
return x1205_set_datetime(to_i2c_client(dev),
tm, 1, X1205_CCR_BASE);
tm, 1, X1205_CCR_BASE, 0);
}

static int x1205_rtc_proc(struct device *dev, struct seq_file *seq)
Expand Down

0 comments on commit c6ab65a

Please sign in to comment.