EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
$ Z9 Q) a* |6 q! g 开发板: 各位版主、工程师们你们好: 请教你们一些问题: (1)在内核中配置pcf8563时钟芯片启动完成,内核启动后 /dev/rtc/ 中没有pcf8563芯片对应的 rtc 节点; (2)内核启动过程中打印 drivers/rtc/hctosys.c: unable to open rtc device (rtc0); (3)pcf8563芯片驱动程序的 pcf8563_probe()在整个启动过程中没有被执行; (4)请问这是怎么回事?该怎么修改??? (5)驱动程序代码如下: 驱动代码:
1 T+ C$ Y0 y6 K3 S# u4 J#include <linux/i2c.h>4 N z/ }- b% A; V8 \, a M
#include <linux/bcd.h>- l& i) P N; G. Y
#include <linux/rtc.h>' P, {9 p. g9 A! t( S Y8 C
#include <linux/slab.h>
" G, R. v2 o; I4 d% L3 F" ], [7 V0 A
/ K+ p! |2 ?, B$ D7 P#define DRV_VERSION "0.4.3"' [3 P% M" V/ S& K
+ u/ }8 L4 a/ R) `1 I
#define PCF8563_REG_ST1 0x00 /* status */
, F6 R$ [( G- s5 w/ n1 g9 W#define PCF8563_REG_ST2 0x015 Z% V5 |8 f% L- k" D; v4 i0 c
8 r0 n& Q) ~5 O. w
#define PCF8563_REG_SC 0x02 /* datetime */
: E- u; L7 r# Y4 ?6 T#define PCF8563_REG_MN 0x03. y- X5 y+ W3 L" q. u0 ]; d
#define PCF8563_REG_HR 0x04
. x& ^+ I9 F7 Y. O: \#define PCF8563_REG_DM 0x05* l/ x Z& o8 g3 m+ a
#define PCF8563_REG_DW 0x06- |; @* w ?; x7 f. E: L
#define PCF8563_REG_MO 0x07- K+ o2 y7 A. M
#define PCF8563_REG_YR 0x08
5 v, i# u/ @0 \' A/ `6 U2 K* N1 N( D! W, R
#define PCF8563_REG_AMN 0x09 /* alARM */8 n# h6 z9 t$ t* f$ E# {* }9 o7 v
#define PCF8563_REG_AHR 0x0A
! ]) t( ?$ \4 f- R, h#define PCF8563_REG_ADM 0x0B' `3 Z; P/ w. @. q: o6 k# s5 V \
#define PCF8563_REG_ADW 0x0C
" X+ O- f5 {4 }) }& _, j4 R% r2 G1 V- O; w P# N
#define PCF8563_REG_CLKO 0x0D /* clock out */2 H& I: u0 q+ Z& Q2 i
#define PCF8563_REG_TMRC 0x0E /* timer control */
! ]" B9 u3 v4 F% V4 h1 o) E! |#define PCF8563_REG_TMR 0x0F /* timer */
$ G! s. M3 N: G' K* H
' `' m( i9 a( }. n' I#define PCF8563_SC_LV 0x80 /* low voltage */" ?* ]( P4 U3 H. O$ {
#define PCF8563_MO_C 0x80 /* century */0 I7 r9 a/ A. q/ H! L( U
$ ~ S! c3 y$ i5 }
static struct i2c_driver pcf8563_driver;
! R( `( ], E. i; X3 H9 c3 o9 z* i0 c9 Z- t& O; m
struct pcf8563 {
. x. b! f) Q9 ]$ C8 ~ struct rtc_device *rtc;; p L; w1 q1 O1 v+ w
/*2 O4 k+ w5 k' y& P% u5 c; a. N
* The meaning of MO_C bit varies by the chip type.6 Q) @8 N* Z" @. B" H; [4 W, c
* From PCF8563 datasheet: this bit is toggled when the years
, l, U5 q. T! e Y, s1 G * register oveRFlows from 99 to 00
9 J% f* I' |- c+ |" K8 A0 R * 0 indicates the century is 20xx
/ D, [: a2 p# Q4 |8 V. U) o6 K6 q * 1 indicates the century is 19xx, R9 s: v( w* c7 g! V, W
* From RTC8564 datasheet: this bit indicates change of
* \8 Q6 x- h* _( g% p; _# P * century. When the year digit data overflows from 99 to 00,; J. Z% M5 r: Y w+ Y0 H0 m
* this bit is set. By presetting it to 0 while still in the0 f2 |# G+ B- H; p' M. ^
* 20th century, it will be set in year 2000, ...3 d$ n8 \% b8 `2 W; p Z1 R+ Y5 P
* There seems no reliable way to know how the system use this
" F. j& H4 \) F& I * bit. So let's do it heuristically, assuming we are live in# t0 E& y8 B5 m& U
* 1970...2069.
7 ?7 {1 V& f% Q+ v1 Q3 F */; Y/ z6 P, z8 i
int c_polarity; /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */' A: b$ n4 ^( Z* Q5 {
};
! X2 h; M" c! T/ K# ]/ f
: E& R: W0 ^4 k, x4 W" x3 I* c/*# N2 d: w; R. [0 f0 ^2 p
* In the routines that deal directly with the pcf8563 hardware, we use: h1 G4 i2 [# Z7 U) M2 X: F
* rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.
! g: u1 K3 u, e6 s# ^*/
1 C9 p2 Q) o2 ~& \0 Dstatic int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
* J- q! U6 I0 r! X9 u1 g{9 b7 P. {1 u& o# q
struct pcf8563 *pcf8563 = i2c_get_clientdata(client);3 o" p& N0 N H
unsigned char buf[13] = { PCF8563_REG_ST1 };
+ ?! D* V8 q$ h
( g x4 h0 J% O" [$ _7 K; | struct i2c_msg msgs[] = {6 K% t" t4 f% P0 }% W
{ client->addr, 0, 1, buf }, /* setup read ptr */
' S1 J" j0 W# F { client->addr, I2C_M_RD, 13, buf }, /* read status + date */% k+ y3 ]/ I+ _& D6 t7 y# _) Y
};
T$ b# }9 H6 d( H6 l1 h9 A/ `8 J9 g; X& b. P8 S/ {: O
/* read registers */, B# O) F/ U" z% ^8 d/ `
if ((i2c_transfer(client->adapter, msgs, 2)) != 2) {
6 v; Y2 M# C. n+ |( D6 M. p5 C dev_err(&client->dev, "%s: read error\n", __func__);
: o' w9 S0 g/ {' s5 ] return -EIO;
8 o; i# V( P# l: L }. L6 n* A* z) a. [
U5 \3 v5 }$ C- G# K
if (buf[PCF8563_REG_SC] & PCF8563_SC_LV)2 L: k5 M6 O8 Y* a- a
dev_info(&client->dev,* W0 L! B9 ~3 j( Q+ M7 b7 ]
"low voltage detected, date/time is not reliable.\n");
3 l7 y/ j; s) p' [9 Q3 Q6 ]- r9 J+ e
dev_dbg(&client->dev,
8 Z3 |, l& b8 C# P "%s: raw data is st1=%02x, st2=%02x, sec=%02x, min=%02x, hr=%02x, "; C4 q/ v* t( D: b5 N; |& [
"mday=%02x, wday=%02x, mon=%02x, year=%02x\n",
# K- E( `! H0 o6 |% Y, y, j8 ? __func__,/ V/ [; a% S2 H0 Z" d2 l3 K
buf[0], buf[1], buf[2], buf[3],
# r0 B/ Z$ U1 q5 u, I buf[4], buf[5], buf[6], buf[7],7 @: d* f/ E; r, B" \' a
buf[8]);
2 P# s1 V' K( X1 T5 P0 s/ P1 e3 i9 ]( Q( ?2 ^
$ q( O" H. D% L8 C; R tm->tm_sec = bcd2bin(buf[PCF8563_REG_SC] & 0x7F);
$ p1 H- A! e1 t tm->tm_min = bcd2bin(buf[PCF8563_REG_MN] & 0x7F);
) }, y' k. r, y* V" M/ W tm->tm_hour = bcd2bin(buf[PCF8563_REG_HR] & 0x3F); /* rtc hr 0-23 */3 n% ]9 {; M, v% X5 F& x1 g
tm->tm_mday = bcd2bin(buf[PCF8563_REG_DM] & 0x3F); p3 Y$ y8 L9 p+ C+ s
tm->tm_wday = buf[PCF8563_REG_DW] & 0x07;, H5 a- W4 k7 R6 W4 {
tm->tm_mon = bcd2bin(buf[PCF8563_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */& T8 Z$ n: m5 ~9 E4 [
tm->tm_year = bcd2bin(buf[PCF8563_REG_YR]);
9 p3 l) j3 b5 u' t if (tm->tm_year < 70)% ]( [2 C& z' j2 h1 v6 {* R
tm->tm_year += 100; /* assume we are in 1970...2069 */
0 q2 n2 J3 b, @/ } /* detect the polarity heuristically. see note above. */6 r/ S& r9 s0 y2 F
pcf8563->c_polarity = (buf[PCF8563_REG_MO] & PCF8563_MO_C) ?4 [2 p: E' U2 a7 ^" k- A9 \
(tm->tm_year >= 100) : (tm->tm_year < 100);
7 \- W" G8 g1 K1 w( f
9 J% }3 F+ t0 a1 a0 w) G/ C dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, ") ^. N; G" B1 T
"mday=%d, mon=%d, year=%d, wday=%d\n",, u! O S$ U( o1 I4 D6 l3 f9 J) F
__func__,
! \ _3 w! W' {- r- R. p tm->tm_sec, tm->tm_min, tm->tm_hour,8 T% k- P, I* C) y
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
' W; T) _5 h& z: F8 r3 S
+ }+ F( e4 P- @! h! v /* the clock can give out invalid datetime, but we cannot return
' v: l' h" x& }& G9 o" Q" O * -EINVAL otherwise hwclock will refuse to set the time on bootup.( A1 [' I# v% Y( d1 K' A+ ?+ a
*/
+ t' Q' ^" C1 E& A6 f; b+ E if (rtc_valid_tm(tm) < 0)" s1 {) J+ l1 q+ J. o( L2 O
dev_err(&client->dev, "retrieved date/time is not valid.\n");
& h& M- B7 V ~ y
; C9 R7 P+ M& W* L4 T) j return 0;
; |1 x" H5 Z3 O' F" o}4 M& E% E2 T+ o, H0 Q% C# r1 ~
3 \/ x4 B$ Z8 Q. d j: R- @
static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm)/ D' m8 C' M+ v
{# @. a8 Y- {( [' t. Z( t3 K
struct pcf8563 *pcf8563 = i2c_get_clientdata(client);
! B: ~5 }5 ~" E4 |% k" S, Q/ c int i, err;
$ i+ p! K; a' E2 Y$ C; e* U+ d1 Q unsigned char buf[9];
: N2 D% |, A5 U' _! p( j) d& D2 G }( @/ U- M8 `( ~0 X# ^4 h. F) y
dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "# n0 q# f% G I `* J) @6 w
"mday=%d, mon=%d, year=%d, wday=%d\n",. L. |5 A9 d3 R2 u9 ~
__func__,
6 y7 O9 z1 a# o) r( ` tm->tm_sec, tm->tm_min, tm->tm_hour,
* L/ I! }$ y! _, o+ U: H+ ~- e' ]0 S tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
! K" }& `; n; T' E, G: P
2 M1 H" F5 y1 n. `0 s% z /* hours, minutes and seconds */
' L- o# E. Q+ p. A buf[PCF8563_REG_SC] = bin2bcd(tm->tm_sec);: x& k8 J" q2 Y. V/ z P
buf[PCF8563_REG_MN] = bin2bcd(tm->tm_min);3 j8 I" f- |- t& K& f7 P; ?- z
buf[PCF8563_REG_HR] = bin2bcd(tm->tm_hour);0 r8 ]/ g! G. [6 G2 y' q3 J `# D3 h
% }' ?# A: {4 e
buf[PCF8563_REG_DM] = bin2bcd(tm->tm_mday);
( R9 ~8 X2 Q V" x
" U' \ _6 @5 [5 O! t/ h /* month, 1 - 12 */
* p9 X6 l% d2 N0 k2 h buf[PCF8563_REG_MO] = bin2bcd(tm->tm_mon + 1);3 Y- F& i/ Q/ x8 \7 v, D/ ]
! a; m7 J' T0 k: o% e" Y+ ^ /* year and century */
9 M/ O' Y) |6 }% d' `9 ^ buf[PCF8563_REG_YR] = bin2bcd(tm->tm_year % 100);6 Z& n) d* w% W
if (pcf8563->c_polarity ? (tm->tm_year >= 100) : (tm->tm_year < 100))
4 Y1 ^: ~; c& n' x; ^. w buf[PCF8563_REG_MO] |= PCF8563_MO_C;
; S, N6 w% O% Z! g0 `2 O3 t k' d8 T, x! H9 e) e; R
buf[PCF8563_REG_DW] = tm->tm_wday & 0x07;
2 K9 h S0 h' S- @" n; ~' v6 n8 W& c6 O& D
/* write register's data */! j" k, a. X, H* M; D7 ~% k6 M
for (i = 0; i < 7; i++) {! S- x$ {. Z8 ^% E# }
unsigned char data[2] = { PCF8563_REG_SC + i,9 f. b- M2 V J! ]& Q( J
buf[PCF8563_REG_SC + i] };
* e; L( m7 l( i3 n* P; [( b. e- O
4 u& ]+ C4 w: w& o Y$ j# \ err = i2c_master_send(client, data, sizeof(data));
) ?9 P8 f4 Y; H6 t& j if (err != sizeof(data)) {6 q# v! P4 |3 J% H2 n9 |# w
dev_err(&client->dev,
( `3 j& B, U g3 z6 A0 K2 y$ x" C "%s: err=%d addr=%02x, data=%02x\n",
- _; R4 e/ v6 L __func__, err, data[0], data[1]);
( g! E! z8 D0 r& t# G/ } return -EIO;
- n) ]8 V3 X6 b }& ]. k# \+ a- N8 z( h4 f
};
- a+ @7 w8 A2 j( k1 ^' r4 Z; P" X J3 w" t9 ^
return 0;5 I/ Z! g4 |) {) y& J6 n
}
+ {; I3 G/ y9 t! [% m8 Y6 p& k" R! l8 F% G+ Y6 m1 m1 L* Y& ^0 q* G
static int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm)! `2 e# h& D7 v' k; I
{
& i8 ]$ m' E% \0 M return pcf8563_get_datetime(to_i2c_client(dev), tm);4 t& R# |7 h8 G( I
}; Z" c0 C$ h8 X* v3 u5 o3 k
0 R* u* S1 }( [- U
static int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm)
8 q c4 t/ a) m9 N/ y{
, T9 r% z/ O% I) X5 E8 K% D return pcf8563_set_datetime(to_i2c_client(dev), tm);/ a7 K2 {% f% ^
}( i4 N$ W: o! r
4 P) @1 f7 q8 i2 {5 ?" J; n: i
static const struct rtc_class_ops pcf8563_rtc_ops = {
( N U2 N. @; n+ V8 W) F .read_time = pcf8563_rtc_read_time,
7 {3 g! d9 r$ c' x .set_time = pcf8563_rtc_set_time,
% E2 j* }; S# e' D, I/ W};
( O- k9 v2 K6 J6 z( A# d, b! V" }$ e( @' ~3 M% ?
static int pcf8563_probe(struct i2c_client *client,
( u3 A" ^; B% w2 X7 w& ^ const struct i2c_device_id *id)
) h3 J! j1 q, e9 T: J{
m* n! `+ A: O$ b& ? struct pcf8563 *pcf8563;1 k, b! N# {5 ~ A B( w) Z1 |
* w' v9 y S7 U0 A& r% S( f0 o' s8 x
int err = 0;0 u0 n) Z' c1 f1 R5 X
' r+ I5 \- B1 o0 n+ w# y! x1 B' ]; [ dev_dbg(&client->dev, "%s\n", __func__);
$ C! e+ @% v5 f* m# j& R
6 g/ } h+ P8 B7 {" f& p if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))1 Y- m4 w& C# n k6 n5 x* t
return -ENODEV;2 ]$ L3 R) x8 X( M z0 K
( O6 T# F) F$ @: B% s( h \ pcf8563 = kzalloc(sizeof(struct pcf8563), GFP_KERNEL); {. \9 z: ?; m9 ~! `- v: u
if (!pcf8563)# J) a$ h2 L% @; `" ~! B1 O
return -ENOMEM;+ a4 v, P5 n* v' I5 I( \5 h3 K
! P% \9 ?( h. Y1 o4 Z8 b
dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); E& l' J& D6 k) x1 O
5 n9 c: f- s: F \: p0 C
i2c_set_clientdata(client, pcf8563);* R) Z0 Y! M T1 e
0 ]2 d: Y0 Z# P j6 j* H
pcf8563->rtc = rtc_device_register(pcf8563_driver.driver.name,, k/ g4 x* |0 w* S% d* G1 K
&client->dev, &pcf8563_rtc_ops, THIS_MODULE);
! z1 J( q' B8 `( N! i5 Y, z* U) G& I6 C5 ?) ~( N
if (IS_ERR(pcf8563->rtc)) {4 P- z: O. Q" c Z2 F
err = PTR_ERR(pcf8563->rtc);
9 }! }" s) h& Y4 \9 P }( v goto exit_kfree;6 B V0 n# |! v( E) v
}2 }8 F# Z' |6 x
. a; t# }4 b/ k, { return 0;
& Z: A4 ?0 d# u; w; ^/ X9 V7 ]6 B1 a( x: {/ O
exit_kfree:# y3 P9 O; h5 i8 u$ Y& d; V
kfree(pcf8563);: J4 {0 x2 D4 e1 d F5 e! d
5 z; P2 o, P7 ~3 D1 k- O# K return err;7 B# F" |; b" M* J+ O& ?7 S
}6 ~4 w( `' P$ H
8 U2 v) b. `$ Y! ?! h
static int pcf8563_remove(struct i2c_client *client) d5 U. E1 C! ^2 ^: _
{
8 k. V0 b2 M8 P struct pcf8563 *pcf8563 = i2c_get_clientdata(client);
# F8 _0 p+ b' w6 v' C9 t l) t! V3 A& w" a0 K$ ~8 m
if (pcf8563->rtc)' q4 ]: U. g5 o6 Y# h0 f
rtc_device_unregister(pcf8563->rtc);
5 K9 ?" q) p9 \! P3 i. B! H9 N5 j' K& S* e# m5 L5 [$ |4 T
kfree(pcf8563);
1 X/ V1 K& L1 I0 A3 H
* i* m9 n4 J1 ], w2 {+ R; L2 l return 0;- }3 ]+ }" C, y" F/ o1 _
}
! g% J7 B/ A7 ~9 T% C, ^( L: ?( h( C/ M% q1 V. T; f0 I5 x9 V1 H
static const struct i2c_device_id pcf8563_id[] = {' ^9 r* S2 T/ T' D2 }; l5 |
{ "pcf8563", 0 },/ e' W; L T: M; I* A* e
{ "rtc8564", 0 },8 A' t( I6 v/ P' X8 H. v
{ }
* I. j& | c1 U) Y4 |0 g- \: }};% {2 F1 M9 T$ B# U
MODULE_DEVICE_TABLE(i2c, pcf8563_id);
- c8 a$ p; A7 h- a; R0 o( D
( }* I" t, |8 p1 w! gstatic struct i2c_driver pcf8563_driver = {: t1 H9 V, d. \/ M
.driver = {5 V- n- S. ^5 V" _- q- r
.name = "rtc-pcf8563",( l1 |. h- `& B8 h( v; s) D6 B3 h
},
3 b& r% u' M7 K .probe = pcf8563_probe,
0 f# {9 D- F' F, X .remove = pcf8563_remove,; a2 L H7 C. K6 K1 M
.id_table = pcf8563_id,
$ R& i7 a! s: \, Y};$ P( Z& O/ X W
. {7 Z5 f, E) _9 r$ e4 r& kstatic int __init pcf8563_init(void)
5 T1 x9 Q7 L# B1 J5 r ?* L{
( i) ^/ C ~$ ]8 V0 ~( s! Y return i2c_add_driver(&pcf8563_driver);
6 R2 \& {" ~: N w" K3 l}# y9 V+ ]6 T1 |
& } z, ]; a2 n% D/ J: Y( X
static void __exit pcf8563_exit(void)
1 B$ s8 C0 h4 t" g9 l: e. R! B, ?4 i{; v5 I! j! O7 T) A Z+ s7 A
i2c_del_driver(&pcf8563_driver);
2 e6 A1 N/ [9 O8 b" R}
5 x: j1 y" J$ i: N, y) h7 t: ~. W: p3 S/ w- M1 b. q
MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");! a1 [# R. v; S+ _6 J9 p% ]
MODULE_DESCRIPTION("Philips PCF8563/Epson RTC8564 RTC driver");7 g( u# M) V! X% }
MODULE_LICENSE("GPL"); v3 Z2 l6 I/ d( B9 W9 o
MODULE_VERSION(DRV_VERSION);# C6 P) I5 k7 Q3 K/ D; c
# r+ i+ q; u6 m$ ?; B, u8 [! p: pmodule_init(pcf8563_init);
5 c, l5 y6 T7 p. Tmodule_exit(pcf8563_exit);
9 U7 e3 O8 _2 J5 O |