EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
: ^; X* ~0 {$ Q2 i0 R# Y2 J' q$ J2 O- P
开发板: 各位版主、工程师们你们好: 请教你们一些问题: (1)在内核中配置pcf8563时钟芯片启动完成,内核启动后 /dev/rtc/ 中没有pcf8563芯片对应的 rtc 节点; (2)内核启动过程中打印 drivers/rtc/hctosys.c: unable to open rtc device (rtc0); (3)pcf8563芯片驱动程序的 pcf8563_probe()在整个启动过程中没有被执行; (4)请问这是怎么回事?该怎么修改??? (5)驱动程序代码如下: 驱动代码:
0 k* z8 T9 l6 I3 i& R8 s' B#include <linux/i2c.h>
9 Z: {+ O8 ^" t( g#include <linux/bcd.h>
( ]# t a! C/ S+ y! ^#include <linux/rtc.h>' k2 b1 \& l ^; s+ t
#include <linux/slab.h>- R" I2 y1 f) ~1 J9 |
* X, J& d1 @! d e! m6 X: W#define DRV_VERSION "0.4.3"
. y, ^- U" `: D' D, ^( n
5 K: n7 V4 f# N H. g- A#define PCF8563_REG_ST1 0x00 /* status */
. X5 [4 r2 d& G+ o#define PCF8563_REG_ST2 0x01# F% @. L0 h" q
, |, T$ F1 K* i0 X* E$ ^
#define PCF8563_REG_SC 0x02 /* datetime */2 ^) n+ d4 y* W- g
#define PCF8563_REG_MN 0x03
6 X: i! h s! J: h: B: O2 C#define PCF8563_REG_HR 0x042 D& R/ q9 a( T& k7 o( {
#define PCF8563_REG_DM 0x05
4 ^( M; _9 v' ^3 M. w( O#define PCF8563_REG_DW 0x06& e6 a7 z. ?' w. v# L
#define PCF8563_REG_MO 0x07
) `6 N6 s, n, m0 h* O! D: J#define PCF8563_REG_YR 0x08! T& s# }7 d# L+ F! ?: O
3 X( R' R, ^; E; t
#define PCF8563_REG_AMN 0x09 /* alARM */ J5 s; E0 U7 @( U4 |
#define PCF8563_REG_AHR 0x0A
: d4 L8 D3 i5 t#define PCF8563_REG_ADM 0x0B8 e7 L/ O8 Z# o( B
#define PCF8563_REG_ADW 0x0C+ k/ u% T; D/ M) T3 ^
9 w* k# B& V) Z4 x7 J
#define PCF8563_REG_CLKO 0x0D /* clock out */ y( I! \4 r6 M( Y: ]. S s# p
#define PCF8563_REG_TMRC 0x0E /* timer control */
4 O* r2 Q, x( k3 ^#define PCF8563_REG_TMR 0x0F /* timer */
( A4 Q) b7 X2 ^' [# e9 R7 l+ \% m( O( _$ R: g
#define PCF8563_SC_LV 0x80 /* low voltage */* X. ~& [3 u+ V5 f
#define PCF8563_MO_C 0x80 /* century */
5 t7 q4 u6 r3 T2 I P3 x: o# u/ j2 J& R% M- \
static struct i2c_driver pcf8563_driver;
3 v+ s _; n4 r U$ y/ V, T6 j; ^, E) e
struct pcf8563 {5 E* D) a: q$ N) F" N
struct rtc_device *rtc;
4 A3 P9 C) K9 I# h. C% o& m /*
( S& L% s4 G& F* V* l0 c; u' u$ V * The meaning of MO_C bit varies by the chip type.
9 C3 K8 ~1 R& F1 ~# a: y1 s * From PCF8563 datasheet: this bit is toggled when the years
$ v8 y- a6 g' u$ A * register oveRFlows from 99 to 00
% S1 @" @0 ?+ W. _, x( l * 0 indicates the century is 20xx9 I3 r2 w% l& c" e3 x4 X! a
* 1 indicates the century is 19xx' q* z+ {) n& |. B+ V
* From RTC8564 datasheet: this bit indicates change of
. [: }' b& J1 O8 t4 z, c * century. When the year digit data overflows from 99 to 00,
* s+ p0 P* M8 Z# P * this bit is set. By presetting it to 0 while still in the% _+ k, s. z% ~ `5 Z! O
* 20th century, it will be set in year 2000, ...
8 x+ ]6 R8 L$ O# N * There seems no reliable way to know how the system use this2 F- C0 a2 @; M8 P" d2 ?" q0 w5 M
* bit. So let's do it heuristically, assuming we are live in% l0 J6 S! {( J
* 1970...2069.
/ p. M- v8 z6 [4 u *// i( D2 J' @$ Z$ O$ t0 J( u8 f
int c_polarity; /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */5 m$ G" D2 u* E v7 b* ?+ x
};, z* }. k! U" E* y7 u
9 D- y, G4 r$ B6 ?/** p( l3 k2 ~% ?( F
* In the routines that deal directly with the pcf8563 hardware, we use: g* R! E7 O. A6 ?' L/ M2 k
* rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.4 b# { P: U) k1 Z
*/6 f' _3 H5 R# W% X7 k
static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
4 a( a& r& ~( _* o+ ^8 n: U{
6 @, n' T" }, p, p$ F6 V struct pcf8563 *pcf8563 = i2c_get_clientdata(client); y/ w. ~4 R5 q; `
unsigned char buf[13] = { PCF8563_REG_ST1 };% m* p3 j; P4 ^$ D
2 M$ A8 l, O& b4 _2 X/ I struct i2c_msg msgs[] = {
( y0 O4 X) w0 f3 v+ L+ ]4 b' Y2 s { client->addr, 0, 1, buf }, /* setup read ptr */$ q8 F* S0 B( s- {$ ?; Z! w
{ client->addr, I2C_M_RD, 13, buf }, /* read status + date */0 M& g6 ^. s- k' `
};
5 J7 M# y- }8 j3 d" t5 d# ?# M0 \( C }
/* read registers */
4 @- ?* S3 `1 n+ l4 ~ if ((i2c_transfer(client->adapter, msgs, 2)) != 2) {4 I5 y" u4 ?2 |7 c5 X" }! c$ O
dev_err(&client->dev, "%s: read error\n", __func__);
8 [+ n7 o, j7 o" n return -EIO;
1 _6 Z* |8 ]# J% t: U% b5 H( Y }
5 [9 w$ f" A0 f1 T' J& E& n% K5 X1 Y: V7 h
if (buf[PCF8563_REG_SC] & PCF8563_SC_LV)
. x3 b0 u( S7 m* K dev_info(&client->dev,1 R+ `$ k) [0 n2 }4 Q; o" m
"low voltage detected, date/time is not reliable.\n");( E, t% ? B8 A8 |& T
2 y0 S5 z- E, x7 N- m* x0 v
dev_dbg(&client->dev,
8 }+ d% y* I5 v "%s: raw data is st1=%02x, st2=%02x, sec=%02x, min=%02x, hr=%02x, "; f ^1 Q$ ~2 {% C1 K
"mday=%02x, wday=%02x, mon=%02x, year=%02x\n",
! }1 c9 F- b- O __func__,
* w. Y3 `6 t- x9 R; H/ Y6 z& u buf[0], buf[1], buf[2], buf[3],' l7 C5 r2 _9 O) x$ b P+ U
buf[4], buf[5], buf[6], buf[7],
9 u3 f* l3 ?+ J0 m buf[8]);8 q( g' ?; L6 P6 A5 k
7 c7 r8 E, f6 l3 d! [+ i) {
+ u' ~7 ]8 W9 c* S1 s tm->tm_sec = bcd2bin(buf[PCF8563_REG_SC] & 0x7F);% g7 i- W: O# [. m: s- a
tm->tm_min = bcd2bin(buf[PCF8563_REG_MN] & 0x7F);
& ?8 D' Q5 ~4 \ d& Y6 }2 }4 r1 L% P1 `0 @ tm->tm_hour = bcd2bin(buf[PCF8563_REG_HR] & 0x3F); /* rtc hr 0-23 */# z8 r& r- P& f) s$ O1 _, T
tm->tm_mday = bcd2bin(buf[PCF8563_REG_DM] & 0x3F);
; k1 i) r1 q: O" H# k tm->tm_wday = buf[PCF8563_REG_DW] & 0x07;3 o+ h; X8 `7 \/ x9 ]$ a
tm->tm_mon = bcd2bin(buf[PCF8563_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */
" U5 Z8 H; U) L6 R5 o( l, P tm->tm_year = bcd2bin(buf[PCF8563_REG_YR]);
$ i# J) X1 [# @' n5 m: ~" n8 V if (tm->tm_year < 70). M8 R% K* I3 S3 K( h$ n2 n
tm->tm_year += 100; /* assume we are in 1970...2069 */
$ p/ G, r+ }: x2 F. K /* detect the polarity heuristically. see note above. */
' W3 I8 K) _" f' n; n/ A pcf8563->c_polarity = (buf[PCF8563_REG_MO] & PCF8563_MO_C) ?& q# i0 P6 r4 Q% B
(tm->tm_year >= 100) : (tm->tm_year < 100);; v9 c% h# T9 f/ H
' i+ x% U5 x" ? dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, ", k$ w* W) C# l
"mday=%d, mon=%d, year=%d, wday=%d\n",
5 F1 g' J7 K, P. @ __func__,
v P- |* P" ~ tm->tm_sec, tm->tm_min, tm->tm_hour,
; n+ H, \# U. q tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
$ a4 B0 Y1 h0 Q: N
3 X7 k+ ?6 y! a /* the clock can give out invalid datetime, but we cannot return5 ^- Q# c3 ~: F- c; T, Y
* -EINVAL otherwise hwclock will refuse to set the time on bootup.# B' g8 S9 F- R) m
*/
8 A2 _" b; x% P( P4 C y if (rtc_valid_tm(tm) < 0)
5 H0 T2 X" D$ m# d4 g+ Q2 ]9 f dev_err(&client->dev, "retrieved date/time is not valid.\n");" O$ o2 H/ g; Y
, S0 S* O+ A9 C* o0 h. O, \ return 0;
! j) f1 F# K7 l4 g% O}
* s; I& i% N, R2 L; m
) q2 [/ ?2 ~9 F" w: V' bstatic int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm)
7 ~- w5 o/ P% `{3 C, X9 s, g) }8 b$ ~, q4 F1 L Z) R
struct pcf8563 *pcf8563 = i2c_get_clientdata(client);' x& ^, |! R$ \0 ?6 s0 ^, j% H
int i, err;
1 `! S& q8 E z( m: B unsigned char buf[9];
( {/ S8 f0 k' y8 E/ t% e6 ?( R' [% @3 `! V
dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "
) g) `, c% F' ?6 i% Q& E/ i: B "mday=%d, mon=%d, year=%d, wday=%d\n",( f; e: `4 a+ J' H4 [) e1 w7 [
__func__,
! \/ n! s8 q) H; R4 ^, t$ d tm->tm_sec, tm->tm_min, tm->tm_hour,% M( J2 ]- R/ ^* H3 N
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);; d* t. b* Q: D- ^0 M$ J
1 N8 L# z; [9 t8 C- s' V* b1 T
/* hours, minutes and seconds */
" f5 z* {4 Q1 h8 K3 r buf[PCF8563_REG_SC] = bin2bcd(tm->tm_sec);
5 `. n! g G% u& h buf[PCF8563_REG_MN] = bin2bcd(tm->tm_min);
/ B- G) {: f X5 A9 l1 r buf[PCF8563_REG_HR] = bin2bcd(tm->tm_hour);2 Y# s1 U4 R. ~- r& O3 v0 l
8 \+ O. O4 }' o* Y buf[PCF8563_REG_DM] = bin2bcd(tm->tm_mday);
0 F* E( d" m# x5 @" b# a* s) e! [1 c$ O" E
/* month, 1 - 12 */
) `) I& y0 m- `1 [7 } buf[PCF8563_REG_MO] = bin2bcd(tm->tm_mon + 1);, l+ W; Y. B' p4 L4 M4 u) F
/ ?0 U0 K/ J" B7 M- ~2 y
/* year and century */
; V( M4 X9 G( E! y buf[PCF8563_REG_YR] = bin2bcd(tm->tm_year % 100);
4 O! N6 J7 n0 z if (pcf8563->c_polarity ? (tm->tm_year >= 100) : (tm->tm_year < 100))' Y, G; z4 ]/ l* p% _ ~) D) h- b
buf[PCF8563_REG_MO] |= PCF8563_MO_C;
& K# J% S2 A! m! x, `) H8 D1 h& a
6 t6 _) [1 r/ Z2 C4 C' A buf[PCF8563_REG_DW] = tm->tm_wday & 0x07;) Y: O" i7 @/ o4 _9 Y7 @3 {
' a. {2 I; _3 l0 x8 O2 y /* write register's data */* y4 p- F, O5 G2 V1 `
for (i = 0; i < 7; i++) {
$ @/ d4 a; E5 }/ W4 n2 y- V+ h* e unsigned char data[2] = { PCF8563_REG_SC + i,0 S- E+ j( T$ I* w
buf[PCF8563_REG_SC + i] };/ F! }: r) i+ S8 k W( x" f
/ W7 R+ s3 J; z" H8 E) ^# O err = i2c_master_send(client, data, sizeof(data));
) R- c! h: F7 \) S* H3 B- s3 g if (err != sizeof(data)) {
% u1 k* X, ?' l7 [/ q* \ dev_err(&client->dev,
0 i" w$ o- R8 z" F1 O "%s: err=%d addr=%02x, data=%02x\n",
7 i+ i9 g6 r7 K1 k7 J3 s __func__, err, data[0], data[1]);/ `0 h* a& Q* ^
return -EIO;
) c4 ~- P% J6 I$ s" }. r) | }' c2 \+ j% _) I1 F" h1 W5 j K4 P6 }
};
, r7 z- D2 n8 d% R Z% l# L, n2 j0 u' R* p5 w* l1 a$ `/ g/ p
return 0;
; B# z" H2 I7 q# p; }}4 n$ W# o; x9 `% n" t9 ?( o
: ^4 |7 h! m" Y
static int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm)) W0 |' P0 @7 t' g B1 ], ~' e
{
. a+ J6 ~( r9 Z" n# I) @7 R return pcf8563_get_datetime(to_i2c_client(dev), tm);# i( K& c2 a: w
}& J2 ?8 t* q# l
4 r( w% ^) H b3 K+ ostatic int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm), L; B& M- M2 P8 e1 ^
{+ p# x: l/ S8 U: F5 h
return pcf8563_set_datetime(to_i2c_client(dev), tm);
L$ y1 Q. ~$ w/ V3 W6 ^3 a% X9 v}6 l& H1 r/ \" P* w+ Q+ A% i3 r
$ t4 C3 l; Z- X! Q) Z
static const struct rtc_class_ops pcf8563_rtc_ops = {
3 Z* }* ]% c3 T, Q1 a .read_time = pcf8563_rtc_read_time,
% ~6 o* x2 v, I1 W9 x) V5 G6 m3 Q% l9 u .set_time = pcf8563_rtc_set_time,
8 P! d" P0 y" r. n; O3 Q};4 a* q9 Q! V- z3 L$ \
9 f7 v# b4 f7 i( _
static int pcf8563_probe(struct i2c_client *client,
$ s7 j+ ?& Q c1 f% X const struct i2c_device_id *id)" A c4 Y2 ~- m6 U o& M' f
{3 z( r: U7 W! ~
struct pcf8563 *pcf8563;
3 q' k) k9 e; d( ]' b4 A4 V& z% i, `( c& g* I2 @
int err = 0;: b' t9 X* b. q
+ n0 Y/ S2 c+ j
dev_dbg(&client->dev, "%s\n", __func__);
, P% s, Q s7 y3 n( l6 H' _ h
. B# C; d6 I* a: Q if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
% ^5 O' b; L: ^6 N- @ return -ENODEV;$ v; x7 c7 ^. ^, W
. v7 H: C7 d: L# a, i: `# H
pcf8563 = kzalloc(sizeof(struct pcf8563), GFP_KERNEL);
3 J. N% Q m; l if (!pcf8563)
. a8 q* _3 W# U0 |, t9 b U return -ENOMEM;8 x. K. o) \7 W: l6 h
: m9 e) S6 e, q* S, S: p dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");% m3 U2 ^; w3 `
! g9 C9 x1 w* f7 ~$ [& ~+ ` i2c_set_clientdata(client, pcf8563);
! h; v: G+ u7 r. I) y) M* g' R
0 I0 S/ a2 v* M( _' S pcf8563->rtc = rtc_device_register(pcf8563_driver.driver.name,
% o$ v( Q8 S! M6 x( a8 x &client->dev, &pcf8563_rtc_ops, THIS_MODULE);# V. j' l) D* N# j! K
6 h- J% r5 @) O3 [3 C
if (IS_ERR(pcf8563->rtc)) {
' X. G3 d7 k. U! @) n. F6 e/ y err = PTR_ERR(pcf8563->rtc);, G, R: l% |4 l8 ?, G: ?
goto exit_kfree;
# p2 V. w# A+ K6 M. T1 {+ ? L }) C. j6 J* j4 C: E
7 c8 y4 R" v G2 n4 j# a
return 0;% a1 D7 S( R, [- L" E* v% M$ j9 C
+ `; E2 }% X9 W7 o1 x# d& @) e2 n
exit_kfree:/ z& R7 ~! }7 A# d6 T0 Z- B
kfree(pcf8563);5 n b* R4 F' |" b6 `5 H% |% N
5 I8 p/ P& Z6 `, k: [1 Z1 x9 T* L return err; C8 W, c. _$ V! z7 V3 T7 m! D
}
! H |" T( C. T `) ]: Q5 I" p7 A- s
static int pcf8563_remove(struct i2c_client *client): B; Q: \7 W2 l* r5 i- x
{( ^9 w7 ]( Y; @ }3 f
struct pcf8563 *pcf8563 = i2c_get_clientdata(client);
. k6 y2 _% H+ o2 c: m- w D7 s. B/ Y, v, L! _/ W( S# K
if (pcf8563->rtc)
( ^) D3 b+ k! ~1 v rtc_device_unregister(pcf8563->rtc);/ I1 d% t4 N! G8 z
# B7 G+ i% Y1 ]* ~0 ]- [ kfree(pcf8563);
: |2 h1 S; u6 g* a/ ~. N( n S" v; I6 M
9 y9 ~9 `# V' B" j, ? return 0;$ B7 L) [6 t$ A# |8 R3 K8 C
}0 q) P* b# x! u5 l- O
- S" K0 ~ P& G% ]* _$ E
static const struct i2c_device_id pcf8563_id[] = {
- c! A; r5 m! |/ V2 P9 C: n4 Y { "pcf8563", 0 },/ z/ W* U6 s) T( g7 j
{ "rtc8564", 0 },/ A+ i4 s& a& j- V3 Z
{ }* S3 C) B% k5 ^, t2 N6 i3 t
};
6 Q- z- w& l& u. SMODULE_DEVICE_TABLE(i2c, pcf8563_id);$ e8 `' s5 G8 d% l& G" T. `
/ A, q4 S; v( c; k C5 h- c
static struct i2c_driver pcf8563_driver = {
! e: s+ n# R7 \2 ]( S .driver = {
`# Z% S. E: W .name = "rtc-pcf8563",( o+ I! e. Y+ ]: ^ H- A5 t2 s
},
: X p3 f+ @' t .probe = pcf8563_probe," S! k8 f+ x/ ]1 P
.remove = pcf8563_remove,; b, d9 [5 B% p( ^, e
.id_table = pcf8563_id,! R% v/ T) t: o
};& S, M4 h( L8 u% i: m8 x3 n
2 Z5 b4 s2 w* x6 H" K1 Z
static int __init pcf8563_init(void)
0 k7 P/ J! T& D{
# E: {) f; N5 O6 v; U8 i* T4 e return i2c_add_driver(&pcf8563_driver);
9 P3 V3 {! @) J1 j* T$ |}
' N Z. y1 a6 w4 H9 n! E0 V# \6 l6 m( J* M9 q I
static void __exit pcf8563_exit(void)
6 g- q: B( i, }# {0 ~{
. C. k/ s! ~1 D6 E0 C i2c_del_driver(&pcf8563_driver);
' z! u7 R+ S& I5 D}5 v( I- H4 e& Q8 S4 c( S, W, ]
1 `( H7 h- ?5 BMODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");! o! q" S4 Z, @/ R! ]# f b
MODULE_DESCRIPTION("Philips PCF8563/Epson RTC8564 RTC driver");
* a! M4 y" V3 ?" C/ r" |+ mMODULE_LICENSE("GPL");9 l4 w& e7 q* D% M# ?
MODULE_VERSION(DRV_VERSION);
7 X2 I2 A$ e& Y9 o+ O0 O9 S1 l$ d
5 p% `. e5 I- Nmodule_init(pcf8563_init);
0 I- x; \0 l1 c! ^module_exit(pcf8563_exit); . B- i: v. O$ E- {+ R5 r: w
|