EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
4 r) l- m3 C/ y( I: N 开发板: 各位版主、工程师们你们好: 请教你们一些问题: (1)在内核中配置pcf8563时钟芯片启动完成,内核启动后 /dev/rtc/ 中没有pcf8563芯片对应的 rtc 节点; (2)内核启动过程中打印 drivers/rtc/hctosys.c: unable to open rtc device (rtc0); (3)pcf8563芯片驱动程序的 pcf8563_probe()在整个启动过程中没有被执行; (4)请问这是怎么回事?该怎么修改??? (5)驱动程序代码如下: 驱动代码:
2 V# ^1 L; x. X E8 e2 B#include <linux/i2c.h>1 Y7 e. V! K. h. `+ f2 a, @
#include <linux/bcd.h>
" \$ t+ b) P% ?" K6 u. Y7 T2 o#include <linux/rtc.h># J7 p4 O7 j: u7 L
#include <linux/slab.h>
) O2 P& Z) w' o' ~+ L
8 V6 a* k2 r- u1 |2 X4 h#define DRV_VERSION "0.4.3"9 d' U% L5 x: B3 S% j
$ u1 I" J: R# a, m7 l \$ }#define PCF8563_REG_ST1 0x00 /* status */
/ X$ O$ H, g1 _#define PCF8563_REG_ST2 0x01& D' X, e( x. l
0 }4 e; k2 v# Z# P9 N$ C4 m
#define PCF8563_REG_SC 0x02 /* datetime */% W6 Y9 L6 [8 {
#define PCF8563_REG_MN 0x03/ }3 p6 c* h# d, O
#define PCF8563_REG_HR 0x04
) l9 l$ K: h2 S' O3 |#define PCF8563_REG_DM 0x05- f% A' u9 [: {9 x( S1 y8 Y. D
#define PCF8563_REG_DW 0x06
; ~1 r# m2 B+ J6 W#define PCF8563_REG_MO 0x07
$ ]3 S4 J/ p6 L0 V! p" o+ s$ {. A#define PCF8563_REG_YR 0x08
9 a/ N6 E/ B( c1 G4 f7 l4 b5 X
! f9 ~$ J; ]' u" Y" Z#define PCF8563_REG_AMN 0x09 /* alARM */3 ?1 D) l( w: d! y7 e; s* }( z
#define PCF8563_REG_AHR 0x0A
- Y- }0 x9 E( O2 q/ o! n2 d; e0 o: A#define PCF8563_REG_ADM 0x0B
& O6 W0 r* q( J& V/ W#define PCF8563_REG_ADW 0x0C
' _ p9 C& x2 Y: V* x
* r# x) F7 T& E+ a/ y#define PCF8563_REG_CLKO 0x0D /* clock out */( D2 S( {' V& w% R8 Z7 R
#define PCF8563_REG_TMRC 0x0E /* timer control */
, N. d' W3 @% d8 n H0 x#define PCF8563_REG_TMR 0x0F /* timer */
5 o' M& l& b3 K# D! b/ \1 z8 F3 v8 k9 f! |* ?1 ~3 s
#define PCF8563_SC_LV 0x80 /* low voltage */6 a/ L' D# U8 F! Z* c& C
#define PCF8563_MO_C 0x80 /* century */3 i0 c) t0 u6 W/ j8 G# a
7 W9 ?7 c7 n# m
static struct i2c_driver pcf8563_driver;1 T+ I. o1 Z1 O2 K7 _& O
- k. Z% I8 P3 M$ d8 zstruct pcf8563 { d9 K* z2 p1 C. c- U
struct rtc_device *rtc;
; |7 p1 B6 a% U- o$ L, e- d( k /*( H- h" Y( B5 X. {
* The meaning of MO_C bit varies by the chip type.' ~2 i8 v6 v0 ~/ y" g
* From PCF8563 datasheet: this bit is toggled when the years
; h' e" U( x9 d! c4 O9 h G' ~ * register oveRFlows from 99 to 00
7 v6 L) u' b8 ^' u3 c: R) V * 0 indicates the century is 20xx0 M9 _7 J" M: C
* 1 indicates the century is 19xx& @- P$ F7 k' ^
* From RTC8564 datasheet: this bit indicates change of
! m" I' v8 B$ U8 Y# R7 {) s * century. When the year digit data overflows from 99 to 00,
/ T+ \ p9 C6 r2 u7 q4 L" k/ t+ K * this bit is set. By presetting it to 0 while still in the0 h" {, @$ B- l' q( ^: b/ [# d; @
* 20th century, it will be set in year 2000, ...% |2 L' T! ?% i" j- m1 u; X' p
* There seems no reliable way to know how the system use this4 {% N7 e G) Z" l& K. Z6 P3 ~
* bit. So let's do it heuristically, assuming we are live in9 V) b1 m- T( M7 w% h; u" B
* 1970...2069.7 S2 Y7 n+ Z" |4 i) ^1 X8 r
*/
, y' G. K8 A- j' a1 g) q int c_polarity; /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */+ @2 Y: C0 K* Q& H5 `) e
};
- W7 C) c" O3 e! w) O7 t5 |; ~8 N# K6 i! M$ T0 x8 ~
/*5 N$ O' G0 d2 h) l' K' _5 J
* In the routines that deal directly with the pcf8563 hardware, we use; a& ]# |% S+ F! L, D
* rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.0 m+ k G8 Q- g
*/$ j9 B& p8 Y! r
static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)+ z5 g5 s/ A& r# X: A* d# ]
{6 w! [/ S: _" i+ H3 ~
struct pcf8563 *pcf8563 = i2c_get_clientdata(client);' o% W$ _1 W- K8 b, n1 h! M, u6 d+ n
unsigned char buf[13] = { PCF8563_REG_ST1 };" a# U( z- U n E) A: l- F2 l
% X5 E5 R5 Q8 K, U+ S$ c7 }1 E: {* @
struct i2c_msg msgs[] = {
9 g* B6 Y0 C% v! S, H) w( M { client->addr, 0, 1, buf }, /* setup read ptr */+ P4 U6 A& I: O6 u* Z( [
{ client->addr, I2C_M_RD, 13, buf }, /* read status + date */! z4 q# j& a! X
};; q6 m$ p$ N; V$ r
|2 e' N, K3 u/ x3 n' E* E7 O /* read registers */
) W" ]# |! u! J$ W8 ? if ((i2c_transfer(client->adapter, msgs, 2)) != 2) {
$ n0 F8 L- r0 i0 P a dev_err(&client->dev, "%s: read error\n", __func__);
0 [- C* c/ C, S% c8 ] return -EIO;
2 I8 d2 k& n: i. [; K/ [! r: i }
0 P9 J+ G: P1 ^! o* C$ d
8 p* M7 C) r |6 P$ n, W if (buf[PCF8563_REG_SC] & PCF8563_SC_LV)& Z6 u1 n5 G( K
dev_info(&client->dev,% ?" q0 S, J# K' M* w, o
"low voltage detected, date/time is not reliable.\n");
" \; M3 s0 {4 E+ p! e0 j# e" t
) P2 V( C4 o1 i dev_dbg(&client->dev,7 M2 o6 ~8 M8 b) H! ^7 S
"%s: raw data is st1=%02x, st2=%02x, sec=%02x, min=%02x, hr=%02x, "5 M }3 B# d) Z, E
"mday=%02x, wday=%02x, mon=%02x, year=%02x\n",& ]- C- K& _/ f8 h- p
__func__,
" G0 i) J& h4 ^& s% @ buf[0], buf[1], buf[2], buf[3],
" u) L, k5 Z* ?7 V2 G7 m* W buf[4], buf[5], buf[6], buf[7],
5 M2 q: x/ n: m2 |( ~3 k5 [" W buf[8]);; D; z& ?4 \( m0 i: K5 M
: H& F' q& @' G! z) B8 u- p
; e. _. A& q. S% ?0 E7 O tm->tm_sec = bcd2bin(buf[PCF8563_REG_SC] & 0x7F);5 \* c0 u9 H, C% _# ~7 h
tm->tm_min = bcd2bin(buf[PCF8563_REG_MN] & 0x7F);
. ]9 B5 E6 R2 m$ n7 \5 _6 p tm->tm_hour = bcd2bin(buf[PCF8563_REG_HR] & 0x3F); /* rtc hr 0-23 */! X; Z, b2 L9 V- L \8 h5 @" d
tm->tm_mday = bcd2bin(buf[PCF8563_REG_DM] & 0x3F);
$ g) O* I6 ~5 |1 A tm->tm_wday = buf[PCF8563_REG_DW] & 0x07;0 n8 D& U# R3 w* ^( n1 K( u
tm->tm_mon = bcd2bin(buf[PCF8563_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */2 o% j/ D5 |4 x9 N9 ~6 u1 Y' T* Y3 i
tm->tm_year = bcd2bin(buf[PCF8563_REG_YR]);4 o& V f% c+ J5 o
if (tm->tm_year < 70)' v! e, K" P% i' o3 I
tm->tm_year += 100; /* assume we are in 1970...2069 */2 d d0 K, ]6 ^& q! Y9 ]
/* detect the polarity heuristically. see note above. */1 \ ~0 H# }) c6 D
pcf8563->c_polarity = (buf[PCF8563_REG_MO] & PCF8563_MO_C) ?
, V/ z' L# l2 U: }/ H' V7 \4 l (tm->tm_year >= 100) : (tm->tm_year < 100);
+ W( e; l R, v, U! \# U- f2 N q3 g J h
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
2 T; ~- K% [! r+ x# z: b9 } "mday=%d, mon=%d, year=%d, wday=%d\n",
/ W B" ~; b' @- d3 ^- U% B __func__,
+ @, I- c0 ~0 ~2 J7 }% U5 k8 O tm->tm_sec, tm->tm_min, tm->tm_hour,/ S# G- y" l$ [+ ^5 L; ]
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); x+ a3 k+ L+ C/ t
7 S7 S2 ^# c/ k /* the clock can give out invalid datetime, but we cannot return* o. S" d8 b) }- a* [1 ]- ]
* -EINVAL otherwise hwclock will refuse to set the time on bootup.3 O( ?: C& N7 W" {. Q
*/
4 ~; ^; P9 o% T* i: [ if (rtc_valid_tm(tm) < 0)
( S9 H1 o& T: ]; b dev_err(&client->dev, "retrieved date/time is not valid.\n");7 l1 b: ^* ?* W. Q5 _! G1 D/ R: u
& A* [1 J% K6 W return 0;0 I9 t/ I% U% w* G w
}9 F* h' i& n& v9 t1 }
; y7 z4 T/ T: _static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm)4 K; M; A4 J b
{
. g$ G. y: g1 e* e# [- u6 d2 B; u struct pcf8563 *pcf8563 = i2c_get_clientdata(client);) Q! h7 D/ \6 B: B& M) k
int i, err;+ `; m1 x6 w, q% e6 O+ l
unsigned char buf[9];7 m( z- r" w O; y0 u6 W5 F
. Z+ C$ x' p8 I7 C; q0 c dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "8 e S b- w8 a& d4 p+ |' s
"mday=%d, mon=%d, year=%d, wday=%d\n",
' A [4 r: o9 P/ Q __func__,1 D2 k8 }4 Z! n
tm->tm_sec, tm->tm_min, tm->tm_hour,
1 N5 ~+ l/ x, m tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
: [4 K# W$ _2 e. i' D- I7 [1 m8 z0 D ?6 L9 D1 x1 T
/* hours, minutes and seconds */
$ ~9 N _, e! ~ buf[PCF8563_REG_SC] = bin2bcd(tm->tm_sec);' h' m+ n; W) Y' h9 u& V: i5 G
buf[PCF8563_REG_MN] = bin2bcd(tm->tm_min);6 ?: n! j! k0 t6 L
buf[PCF8563_REG_HR] = bin2bcd(tm->tm_hour);9 f! R5 X3 F/ D7 e7 A
. A0 Y2 c8 X, P
buf[PCF8563_REG_DM] = bin2bcd(tm->tm_mday);6 g( Q" F" A1 L( F! h7 V
; E% V1 w3 O7 g$ B/ Z* x8 B /* month, 1 - 12 */! U& O" H8 n3 I4 ]/ f
buf[PCF8563_REG_MO] = bin2bcd(tm->tm_mon + 1);3 V$ c& a7 }2 b! u! x4 W
7 K7 }" P- f; j* X1 z% H8 u /* year and century */
8 I7 T3 ~$ A) L* } buf[PCF8563_REG_YR] = bin2bcd(tm->tm_year % 100);1 m" x4 H/ K9 [$ \3 }% i
if (pcf8563->c_polarity ? (tm->tm_year >= 100) : (tm->tm_year < 100))
7 h0 P5 q D- s. U buf[PCF8563_REG_MO] |= PCF8563_MO_C;% r: G8 z. K! B) N7 x; x
+ F0 H! Q& _7 o" h" y# ~( m
buf[PCF8563_REG_DW] = tm->tm_wday & 0x07;4 v/ z, Q) C0 C1 E; `1 I3 X
: b6 [1 p, u. M, S
/* write register's data */
8 V+ ^8 m. D' u for (i = 0; i < 7; i++) {6 U7 Z( ^ L5 L& C0 a
unsigned char data[2] = { PCF8563_REG_SC + i,8 _+ o, V5 U0 D" o7 ?4 ^
buf[PCF8563_REG_SC + i] };9 o; K6 z& m/ `5 ?6 e, L% T: }
4 |6 r: O& k j1 }
err = i2c_master_send(client, data, sizeof(data));. W E; @) P6 K3 _% d' o
if (err != sizeof(data)) {
2 V' r# q5 X" c- L6 i/ q; P9 { dev_err(&client->dev,
+ s1 s/ z- W( o2 N$ ^ "%s: err=%d addr=%02x, data=%02x\n",
$ p) H& H, {4 t) p __func__, err, data[0], data[1]);
; g- b1 @- N, h( s7 ? return -EIO;' U( `! U$ L* |5 C/ ~
}
9 G) e3 e0 C' u8 U) g4 l2 C. G };; q3 O4 Y1 c$ f% l; l
. q, E! ~3 s U) X return 0;
; z* @) o( P* c8 [4 \2 H# P) j/ u. r} u, ]3 L" {4 q. |: J* e! y
5 l ~% d- a s$ m1 h% m4 O3 \+ Lstatic int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm)
8 Q$ ]1 J$ u. }{ q8 A6 e" r/ f8 ^( ?
return pcf8563_get_datetime(to_i2c_client(dev), tm);% V; W1 @; I \: J
}! l! m7 d# n/ p E% R$ G* J
% O5 r5 \$ u. d E7 Z+ v+ Y5 D
static int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm)
, Z4 u7 `2 K/ o+ h, u{9 |5 z( e) Q' w; ]
return pcf8563_set_datetime(to_i2c_client(dev), tm);
8 H- \4 E8 b" g3 i1 {& c! U/ N0 U) j}
- s9 S8 S m8 l) l' \& M* ^) x$ ?2 Q9 g6 B' t! R# I; Q* N0 T
static const struct rtc_class_ops pcf8563_rtc_ops = {' [- M {' X- H, C
.read_time = pcf8563_rtc_read_time,# B5 T6 A' X9 Z
.set_time = pcf8563_rtc_set_time,
4 D6 M8 q5 W y+ \. d/ M8 x8 V};0 T) I3 a: _3 M! ^ S
8 r; f# w( } { Y1 z7 [! ^* W
static int pcf8563_probe(struct i2c_client *client,
; b, b2 H9 r0 H+ a! x/ T const struct i2c_device_id *id)
* r- J4 G: @! H0 `% h: e' X{* h6 Q ]2 ~, @" E$ p
struct pcf8563 *pcf8563;# r3 e8 @8 h- [ y3 C
. R0 R( w, F1 M9 X. L2 _7 I: K+ r* C$ e int err = 0;
( H% H! N$ K% M9 ?* _
; p7 Y# h0 p2 R- b5 F dev_dbg(&client->dev, "%s\n", __func__);
. Q5 I8 d; j" [! T- _
7 z4 S0 \) Z3 |8 B X# r. Q" {& ?6 z if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
, V9 a& e9 r j0 g return -ENODEV;- F( `- w5 x2 M, R- a; |
: ]" X; z% r7 e% {, z
pcf8563 = kzalloc(sizeof(struct pcf8563), GFP_KERNEL);
. t3 ^2 A9 g0 m2 L! D if (!pcf8563)
9 i3 |4 a3 f5 ]. p0 y# f; e9 q return -ENOMEM;
0 E3 s U; m, n- h0 H; ?, Z+ T4 V. F/ k! W! `7 G2 s
dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
6 S6 _0 x, s# U |# B7 C) k( {* V# i- t W
i2c_set_clientdata(client, pcf8563);1 P9 A4 `+ s2 }# R
{- z F8 C0 H
pcf8563->rtc = rtc_device_register(pcf8563_driver.driver.name,
0 p. p0 L3 l2 U &client->dev, &pcf8563_rtc_ops, THIS_MODULE);
# F3 y2 j: H) }1 G% u; r# V+ E! L5 q% f: v3 Z
if (IS_ERR(pcf8563->rtc)) {, I$ a" p* k1 C' Y6 }
err = PTR_ERR(pcf8563->rtc);
* q: D8 Y$ g; x, M2 _: e goto exit_kfree; y% t$ x, k3 Y5 q s
}
, y3 j+ c# q' \9 P: O2 X$ M. y! X# t i F8 q: K6 Y
return 0;# w2 ]8 r4 B8 l
/ n# ~1 B' d3 e- p2 Dexit_kfree:
$ D. z9 B1 {0 O1 ] kfree(pcf8563);
- k& ?0 d: l" A& ~" h! o1 C0 a% Z% \6 A. |6 G, z6 [) z
return err;
4 y/ z* |$ E5 V* s}
+ {0 C5 O7 R7 G' G4 J1 p1 B& h. G# o) l# H
static int pcf8563_remove(struct i2c_client *client)
5 ]. {9 \6 @6 \% [& C{ D- G: x+ d7 `% a
struct pcf8563 *pcf8563 = i2c_get_clientdata(client);' j" Y& {: y7 X+ J7 T/ Y7 R
/ l5 U2 q: m" i& N
if (pcf8563->rtc)+ Q" u0 L! R* K% t
rtc_device_unregister(pcf8563->rtc);& Y; D) x, r. D* @+ ?0 u6 L! f9 t
( o8 ^7 y# K; ]; Y. z$ V kfree(pcf8563);
& k/ I' T3 q4 T" a- R% ^- s" [0 B% t' [+ i' O2 W; W" F
return 0;/ r: T+ C$ D4 [+ S
}5 i3 p4 ^2 |7 B% O9 [/ l. Q
! b( V0 t' X$ J, g% m. l sstatic const struct i2c_device_id pcf8563_id[] = {1 j( s% `5 t5 y! G6 K
{ "pcf8563", 0 },: O7 d& r1 t m2 D% B: L
{ "rtc8564", 0 },
& L& n* l# O4 {8 `$ j { }6 n* u: \7 E2 [8 w: @
};
0 x: K& L+ w& O$ O4 HMODULE_DEVICE_TABLE(i2c, pcf8563_id);
7 t7 P$ B+ ]7 P6 s0 s
: R0 l/ v8 ~4 m3 `static struct i2c_driver pcf8563_driver = {
, g I2 p6 I' y3 u+ z+ g .driver = {0 S R& D: ? L5 ]+ n5 G
.name = "rtc-pcf8563",' ]6 k7 H" i; g2 l. n
},! A7 i2 ]% I! g0 r" ?% K
.probe = pcf8563_probe,5 P4 Y+ d& s! ^8 y1 L2 W
.remove = pcf8563_remove,9 Q( A$ y% h7 Q, ~# d1 y( l! ~( Q( b
.id_table = pcf8563_id,
9 t4 d+ f$ _; B h. {) Z9 \3 O& j};
/ M3 _* R0 @# D. r
+ Y/ G0 B. w9 C+ J1 d$ [2 H5 J+ ?static int __init pcf8563_init(void)9 {/ @# D' ~7 |! Y
{) F- ^3 m+ E" |3 K
return i2c_add_driver(&pcf8563_driver);$ i6 { i* h( Q% G: ~
} w6 T4 k/ f7 t2 Y6 B
1 Z. [9 | ?) I! }6 \+ a0 J
static void __exit pcf8563_exit(void)
b1 H) u2 F8 m5 Z$ e1 t6 q{" S3 J2 M5 D: E8 o1 k
i2c_del_driver(&pcf8563_driver);
( C% b- b4 z" {2 m$ A}
! k, r0 X6 s( V" n3 @! j6 G1 K% y5 ~% N( k$ c3 ~- M
MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");/ r% Z4 @% f" D% K- \# k, E
MODULE_DESCRIPTION("Philips PCF8563/Epson RTC8564 RTC driver");" P! n* D( Y1 k/ W. N
MODULE_LICENSE("GPL");7 {6 Q3 a' e, x9 P9 N2 ]$ p/ K
MODULE_VERSION(DRV_VERSION);# M5 T( o7 I+ v3 i6 J
! E% B% s) y3 y& J- L7 }module_init(pcf8563_init);
6 _6 G% i m u z- `4 `1 B% umodule_exit(pcf8563_exit);
: ^1 ^8 k0 H Y9 x2 Z) t. Y8 e |