/* * Ricoh has a family of I2C based RTCs, which differ only slightly from * each other. Differences center on pinout (e.g. how many interrupts, * output clock, etc) and how the control registers are used. The '372 * is significant only because that's the one this driver first supported.
*/ #define RS5C372_REG_SECS 0 #define RS5C372_REG_MINS 1 #define RS5C372_REG_HOURS 2 #define RS5C372_REG_WDAY 3 #define RS5C372_REG_DAY 4 #define RS5C372_REG_MONTH 5 #define RS5C372_REG_YEAR 6 #define RS5C372_REG_TRIM 7 # define RS5C372_TRIM_XSL 0x80 /* only if RS5C372[a|b] */ # define RS5C372_TRIM_MASK 0x7F # define R2221TL_TRIM_DEV (1 << 7) /* only if R2221TL */ # define RS5C372_TRIM_DECR (1 << 6)
/* REVISIT: this assumes that: * - we're in the 21st century, so it's safe to ignore the century * bit for rv5c38[67] (REG_MONTH bit 7); * - we should use ALARM_A not ALARM_B (may be wrong on some boards)
*/ struct rs5c372 { struct i2c_client *client; struct rtc_device *rtc; enum rtc_type type; unsigned time24:1; unsigned has_irq:1; unsigned smbus:1; char buf[17]; char *regs;
};
/* This implements the third reading method from the datasheet, using * an internal address that's reset after each transaction (by STOP) * to 0x0f ... so we read extra registers, and skip the first one. * * The first method doesn't work with the iop3xx adapter driver, on at * least 80219 chips; this works around that bug. * * The third method on the other hand doesn't work for the SMBus-only * configurations, so we use the first method there, stripping off * the extra register in the process.
*/ if (rs5c->smbus) { int addr = RS5C_ADDR(RS5C372_REG_SECS); int size = sizeof(rs5c->buf) - 1;
if (i2c_smbus_write_byte_data(client, addr, buf) < 0) {
dev_warn(dev, "can't update alarm\n");
status = -EIO;
} else
rs5c->regs[RS5C_REG_CTRL1] = buf;
return status;
}
/* NOTE: Since RTC_WKALM_{RD,SET} were originally defined for EFI, * which only exposes a polled programming interface; and since * these calls map directly to those EFI requests; we don't demand * we have an IRQ for this chip when we go through this API. * * The older x86_pc derived RTC_ALM_{READ,SET} calls require irqs * though, managed through RTC_AIE_{ON,OFF} requests.
*/
/* only handle up to 24 hours in the future, like RTC_ALM_SET */ if (t->time.tm_mday != -1
|| t->time.tm_mon != -1
|| t->time.tm_year != -1) return -EINVAL;
/* REVISIT: round up tm_sec */
/* if needed, disable irq (clears pending status) */
status = rs5c_get_regs(rs5c); if (status < 0) return status; if (rs5c->regs[RS5C_REG_CTRL1] & RS5C_CTRL1_AALE) {
addr = RS5C_ADDR(RS5C_REG_CTRL1);
buf[0] = rs5c->regs[RS5C_REG_CTRL1] & ~RS5C_CTRL1_AALE; if (i2c_smbus_write_byte_data(client, addr, buf[0]) < 0) {
dev_dbg(dev, "can't disable alarm\n"); return -EIO;
}
rs5c->regs[RS5C_REG_CTRL1] = buf[0];
}
/* set alarm */
buf[0] = bin2bcd(t->time.tm_min);
buf[1] = rs5c_hr2reg(rs5c, t->time.tm_hour);
buf[2] = 0x7f; /* any/all days */
for (i = 0; i < sizeof(buf); i++) {
addr = RS5C_ADDR(RS5C_REG_ALARM_A_MIN + i); if (i2c_smbus_write_byte_data(client, addr, buf[i]) < 0) {
dev_dbg(dev, "can't set alarm time\n"); return -EIO;
}
}
/* ... and maybe enable its irq */ if (t->enabled) {
addr = RS5C_ADDR(RS5C_REG_CTRL1);
buf[0] = rs5c->regs[RS5C_REG_CTRL1] | RS5C_CTRL1_AALE; if (i2c_smbus_write_byte_data(client, addr, buf[0]) < 0)
dev_warn(dev, "can't enable alarm\n");
rs5c->regs[RS5C_REG_CTRL1] = buf[0];
}
switch (rs5c->type) { case rtc_r2025sd: case rtc_r2221tl: if ((rs5c->type == rtc_r2025sd && !(ctrl2 & R2x2x_CTRL2_XSTP)) ||
(rs5c->type == rtc_r2221tl && (ctrl2 & R2x2x_CTRL2_XSTP))) {
flags |= RTC_VL_DATA_INVALID;
} if (ctrl2 & R2x2x_CTRL2_VDET)
flags |= RTC_VL_BACKUP_LOW; break; default: if (ctrl2 & RS5C_CTRL2_XSTP)
flags |= RTC_VL_DATA_INVALID; break;
}
return put_user(flags, (unsignedint __user *)arg); case RTC_VL_CLR: /* clear VDET bit */ if (rs5c->type == rtc_r2025sd || rs5c->type == rtc_r2221tl) {
ctrl2 &= ~R2x2x_CTRL2_VDET; if (i2c_smbus_write_byte_data(rs5c->client, addr, ctrl2) < 0) {
dev_dbg(&rs5c->client->dev, "%s: write error in line %i\n",
__func__, __LINE__); return -EIO;
}
} return 0; default: return -ENOIOCTLCMD;
} return 0;
} #else #define rs5c372_ioctl NULL #endif
staticint rs5c372_read_offset(struct device *dev, long *offset)
{ struct rs5c372 *rs5c = i2c_get_clientdata(to_i2c_client(dev));
u8 val = rs5c->regs[RS5C372_REG_TRIM]; long ppb_per_step = 0; bool decr = val & RS5C372_TRIM_DECR;
switch (rs5c->type) { case rtc_r2221tl:
ppb_per_step = val & R2221TL_TRIM_DEV ? 1017 : 3051; break; case rtc_rs5c372a: case rtc_rs5c372b:
ppb_per_step = val & RS5C372_TRIM_XSL ? 3125 : 3051; break; default:
ppb_per_step = 3051; break;
}
/* Only bits[0:5] repsents the time counts */
val &= 0x3F;
/* If bits[1:5] are all 0, it means no increment or decrement */ if (!(val & 0x3E)) {
*offset = 0;
} else { if (decr)
*offset = -(((~val) & 0x3F) + 1) * ppb_per_step; else
*offset = (val - 1) * ppb_per_step;
}
return 0;
}
staticint rs5c372_set_offset(struct device *dev, long offset)
{ struct rs5c372 *rs5c = i2c_get_clientdata(to_i2c_client(dev)); int addr = RS5C_ADDR(RS5C372_REG_TRIM);
u8 val = 0;
u8 tmp = 0; long ppb_per_step = 3051; long steps = LONG_MIN;
switch (rs5c->type) { case rtc_rs5c372a: case rtc_rs5c372b:
tmp = rs5c->regs[RS5C372_REG_TRIM]; if (tmp & RS5C372_TRIM_XSL) {
ppb_per_step = 3125;
val |= RS5C372_TRIM_XSL;
} break; case rtc_r2221tl: /* * Check if it is possible to use high resolution mode (DEV=1). * In this mode, the minimum resolution is 2 / (32768 * 20 * 3), * which is about 1017 ppb.
*/
steps = DIV_ROUND_CLOSEST(offset, 1017); if (steps >= -0x3E && steps <= 0x3E) {
ppb_per_step = 1017;
val |= R2221TL_TRIM_DEV;
} else { /* * offset is out of the range of high resolution mode. * Try to use low resolution mode (DEV=0). In this mode, * the minimum resolution is 2 / (32768 * 20), which is * about 3051 ppb.
*/
steps = LONG_MIN;
} break; default: break;
}
if (steps == LONG_MIN) {
steps = DIV_ROUND_CLOSEST(offset, ppb_per_step); if (steps > 0x3E || steps < -0x3E) return -ERANGE;
}
if (steps > 0) {
val |= steps + 1;
} else {
val |= RS5C372_TRIM_DECR;
val |= (~(-steps - 1)) & 0x3F;
}
if (!steps || !(val & 0x3E)) { /* * if offset is too small, set oscillation adjustment register * or time trimming register with its default value whic means * no increment or decrement. But for rs5c372[a|b], the XSL bit * should be kept unchanged.
*/ if (rs5c->type == rtc_rs5c372a || rs5c->type == rtc_rs5c372b)
val &= RS5C372_TRIM_XSL; else
val = 0;
}
dev_dbg(&rs5c->client->dev, "write 0x%x for offset %ld\n", val, offset);
if (i2c_smbus_write_byte_data(rs5c->client, addr, val) < 0) {
dev_err(&rs5c->client->dev, "failed to write 0x%x to reg %d\n", val, addr); return -EIO;
}
staticint rs5c372_probe(struct i2c_client *client)
{ int err = 0; int smbus_mode = 0; struct rs5c372 *rs5c372;
dev_dbg(&client->dev, "%s\n", __func__);
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_I2C_BLOCK)) { /* * If we don't have any master mode adapter, try breaking * it down in to the barest of capabilities.
*/ if (i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_I2C_BLOCK))
smbus_mode = 1; else { /* Still no good, give up */
err = -ENODEV; gotoexit;
}
}
/* we read registers 0x0f then 0x00-0x0f; skip the first one */
rs5c372->regs = &rs5c372->buf[1];
rs5c372->smbus = smbus_mode;
err = rs5c_get_regs(rs5c372); if (err < 0) gotoexit;
/* clock may be set for am/pm or 24 hr time */ switch (rs5c372->type) { case rtc_rs5c372a: case rtc_rs5c372b: /* alarm uses ALARM_A; and nINTRA on 372a, nINTR on 372b. * so does periodic irq, except some 327a modes.
*/ if (rs5c372->regs[RS5C_REG_CTRL2] & RS5C372_CTRL2_24)
rs5c372->time24 = 1; break; case rtc_r2025sd: case rtc_r2221tl: case rtc_rv5c386: case rtc_rv5c387a: if (rs5c372->regs[RS5C_REG_CTRL1] & RV5C387_CTRL1_24)
rs5c372->time24 = 1; /* alarm uses ALARM_W; and nINTRB for alarm and periodic * irq, on both 386 and 387
*/ break; default:
dev_err(&client->dev, "unknown RTC type\n"); gotoexit;
}
/* if the oscillator lost power and no other software (like * the bootloader) set it up, do it here. * * The R2025S/D does this a little differently than the other * parts, so we special case that..
*/
err = rs5c_oscillator_setup(rs5c372); if (unlikely(err < 0)) {
dev_err(&client->dev, "setup error\n"); gotoexit;
}
dev_info(&client->dev, "%s found, %s\n",
({ char *s; switch (rs5c372->type) { case rtc_r2025sd: s = "r2025sd"; break; case rtc_r2221tl: s = "r2221tl"; break; case rtc_rs5c372a: s = "rs5c372a"; break; case rtc_rs5c372b: s = "rs5c372b"; break; case rtc_rv5c386: s = "rv5c386"; break; case rtc_rv5c387a: s = "rv5c387a"; break; default: s = "chip"; break;
}; s;}),
rs5c372->time24 ? "24hr" : "am/pm"
);
/* REVISIT use client->irq to register alarm irq ... */
rs5c372->rtc = devm_rtc_device_register(&client->dev,
rs5c372_driver.driver.name,
&rs5c372_rtc_ops, THIS_MODULE);
if (IS_ERR(rs5c372->rtc)) {
err = PTR_ERR(rs5c372->rtc); gotoexit;
}
err = rs5c_sysfs_register(&client->dev); if (err) gotoexit;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.