EDA365欢迎您!
您需要 登录 才可以下载或查看,没有帐号?注册
x
2 ~( E/ \6 u8 E# ] 开发板: 各位版主、工程师们你们好: 请教你们一些问题: (1)在内核中配置pcf8563时钟芯片启动完成,内核启动后 /dev/rtc/ 中没有pcf8563芯片对应的 rtc 节点; (2)内核启动过程中打印 drivers/rtc/hctosys.c: unable to open rtc device (rtc0); (3)pcf8563芯片驱动程序的 pcf8563_probe()在整个启动过程中没有被执行; (4)请问这是怎么回事?该怎么修改??? (5)驱动程序代码如下: 驱动代码:
! i9 k6 Z1 H, N5 l/ E#include <linux/i2c.h>6 I! s8 \9 l6 }! P
#include <linux/bcd.h>' J8 r$ k. u' } w
#include <linux/rtc.h>
) P/ A* b2 v7 \# L5 V+ k, l$ g#include <linux/slab.h>, _) H- o1 E' S9 B+ r
( ~& j& E$ T: u$ \, j
#define DRV_VERSION "0.4.3") Q$ A* v$ B1 i3 K0 x7 `& H" Y
. X b7 n' {5 e1 @7 a
#define PCF8563_REG_ST1 0x00 /* status */" g/ c' u: U* ~! A3 V
#define PCF8563_REG_ST2 0x01
: S) o# \: `: F$ B* ~. M; [8 Z( P( I* _% e* N8 k! D% G( N
#define PCF8563_REG_SC 0x02 /* datetime */% J5 N" Q$ I/ t
#define PCF8563_REG_MN 0x03
$ R% |+ v' F. M' E" N! R# x! U#define PCF8563_REG_HR 0x04
$ N2 n. U, g- `- D6 Y5 I3 h5 E#define PCF8563_REG_DM 0x05
" E& \5 V( P m3 D0 M#define PCF8563_REG_DW 0x064 S. L- D, F4 X u4 ]' c! D" x
#define PCF8563_REG_MO 0x07
* A* o8 k6 r( p% q( y+ a/ L#define PCF8563_REG_YR 0x08& I) P3 a C. l1 j% n
7 z$ D, N( {" H
#define PCF8563_REG_AMN 0x09 /* alarm */
. ? X$ \: B. F( q/ x! `0 d+ I( s#define PCF8563_REG_AHR 0x0A2 r' E9 v- _3 g
#define PCF8563_REG_ADM 0x0B
. S8 d1 V# F2 v# p#define PCF8563_REG_ADW 0x0C
Y" p$ K9 b: G# ^8 M+ M4 v
4 n' H% P5 C) r#define PCF8563_REG_CLKO 0x0D /* clock out */
% O1 b% h% @, c* v+ `8 R& B#define PCF8563_REG_TMRC 0x0E /* timer control */
5 v, ]" x; F/ E, J; w# l, L#define PCF8563_REG_TMR 0x0F /* timer */. O: p& i+ Q% j9 Y
5 p& k: T- T' h: x8 a0 P& O#define PCF8563_SC_LV 0x80 /* low voltage */
* U9 Z) e) |& O3 i+ ]2 e#define PCF8563_MO_C 0x80 /* century */
9 r( [; O) q5 o/ W: s* M6 s/ U
, T, j( H$ n4 sstatic struct i2c_driver pcf8563_driver;. g# C6 |( |8 \9 E
" K; N. R T" S" j, [2 q
struct pcf8563 {
7 l- a/ ~" }0 f struct rtc_device *rtc;8 r5 B0 y: h2 V1 z
/*
' h4 X% \& y& Z- w: ~7 a * The meaning of MO_C bit varies by the chip type.: q, `$ \& k6 S" i6 R3 O
* From PCF8563 datasheet: this bit is toggled when the years
+ H' b# @; J0 K) t8 n1 b * register overflows from 99 to 00
/ P$ W% N6 p8 r2 ] * 0 indicates the century is 20xx# E4 }; X6 M# C* K" E. L1 `
* 1 indicates the century is 19xx K+ K) \5 E8 F& b( \$ E
* From RTC8564 datasheet: this bit indicates change of
) D4 H8 t! u, G& X* J, E0 E * century. When the year digit data overflows from 99 to 00,
: {4 `3 d: \1 V* k * this bit is set. By presetting it to 0 while still in the
; H% W1 @9 @8 x% k V$ r/ q, o * 20th century, it will be set in year 2000, ...
) c. P ]! l5 S2 J! T * There seems no reliable way to know how the system use this
2 {" l! a" I% b6 j6 p/ h * bit. So let's do it heuristically, assuming we are live in' m9 W, v# |9 e: j& p
* 1970...2069.
6 U: c+ F3 u3 f1 ~/ c */
3 t# @- y. h& `+ \/ \. G int c_polarity; /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */
# b8 @, e" c, B% F. A, X$ j2 D};" p8 p7 _. B+ E, g' f' m% D
% _4 A& k* ~. `+ Y/ k& n4 @/*. M0 x: A& A, E! R, M
* In the routines that deal directly with the pcf8563 hardware, we use
8 t' E9 O( a7 X3 P* q* rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.
4 H8 F$ C( x5 R8 o1 y*/+ i; w) O3 f! C8 C% t
static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
' `* S& h8 R2 C! M/ o{
) ]1 X0 h) A9 l" H6 F$ G struct pcf8563 *pcf8563 = i2c_get_clientdata(client);" `- f' E! ~4 B1 @- p, E& q8 A! n& z
unsigned char buf[13] = { PCF8563_REG_ST1 };& C+ ?, L+ Y" h7 i( n3 v @* f
* f+ ]4 r! M1 E; p0 Q+ y; p3 r0 S
struct i2c_msg msgs[] = {
. F& z# R$ W& Z* }& H- y { client->addr, 0, 1, buf }, /* setup read ptr */
" Y/ \' P, p4 I) P2 o0 _ s { client->addr, I2C_M_RD, 13, buf }, /* read status + date */
2 [- j# |; X" b# S, Q& G. X- P$ | };
6 y) X( ]4 j! _( J; m0 E8 R G; v3 ?& H& Q" `- m
/* read registers */
- Z% J; I9 u% m% m4 s4 w/ B if ((i2c_transfer(client->adapter, msgs, 2)) != 2) { E; P1 X6 O# F" y' @! }1 X
dev_err(&client->dev, "%s: read error\n", __func__);
2 \" }( T+ n! z9 Q, u return -EIO;' M7 G; t' ^! t. A7 h3 L5 u
}3 ~2 a( W. T: Y6 a* L
! ^1 {- a) P f) M* B
if (buf[PCF8563_REG_SC] & PCF8563_SC_LV)
% V+ u; Q3 s& {9 ~: J dev_info(&client->dev,
( J2 h$ N1 Q" }( R. D' q "low voltage detected, date/time is not reliable.\n");. O7 n, `# F2 a7 R: _ ]
! x1 Z( {+ _/ V! {% X
dev_dbg(&client->dev,/ o3 N1 \* c, x" E' X8 @
"%s: raw data is st1=%02x, st2=%02x, sec=%02x, min=%02x, hr=%02x, "
" `1 N& A9 [' L* C: i "mday=%02x, wday=%02x, mon=%02x, year=%02x\n",
. i- E; P: u7 A, c' S9 S/ H2 t$ A __func__,
% i; [7 c5 V4 W4 D7 ~" n) q/ | buf[0], buf[1], buf[2], buf[3],8 l" B: ?7 m' h- Y8 ^
buf[4], buf[5], buf[6], buf[7],
( H6 J k& W. Y" h V buf[8]);
]5 [- d$ d% u! ]# w# ]3 T- V& l8 c6 n
$ ^# u* `) L# O! L$ ] tm->tm_sec = bcd2bin(buf[PCF8563_REG_SC] & 0x7F);
, i5 y4 a' Y6 T tm->tm_min = bcd2bin(buf[PCF8563_REG_MN] & 0x7F);
0 l" s- }% [1 l! N. {# n$ M" Z! n tm->tm_hour = bcd2bin(buf[PCF8563_REG_HR] & 0x3F); /* rtc hr 0-23 */* C8 A! C9 U5 X" O, U8 H$ O
tm->tm_mday = bcd2bin(buf[PCF8563_REG_DM] & 0x3F); u" M% G8 q0 f- B- N/ ?
tm->tm_wday = buf[PCF8563_REG_DW] & 0x07;( L2 T; c6 H, t: T! C: z. u4 ?
tm->tm_mon = bcd2bin(buf[PCF8563_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */
7 o5 Y6 F F/ A6 e A8 [/ {6 n5 F tm->tm_year = bcd2bin(buf[PCF8563_REG_YR]);
6 S6 z/ e* M+ ` if (tm->tm_year < 70)7 L- w0 S5 N0 K# V- s4 n9 C: H" j
tm->tm_year += 100; /* assume we are in 1970...2069 */& [7 K- b- B9 m9 C7 \/ j) Z
/* detect the polarity heuristically. see note above. */
" e, v* Z7 G9 E( t1 k, [ pcf8563->c_polarity = (buf[PCF8563_REG_MO] & PCF8563_MO_C) ?: D+ u/ m+ e- g
(tm->tm_year >= 100) : (tm->tm_year < 100);
1 b& E0 U# U% l5 \9 h
* I, D# ^" \$ L+ \ dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
0 \" t0 B5 i$ ?; k( U, E "mday=%d, mon=%d, year=%d, wday=%d\n",) g+ k% A; V3 V( f- G" f
__func__,. k1 W4 J6 L( d* l4 Z
tm->tm_sec, tm->tm_min, tm->tm_hour,! o4 V& @% k& _1 I
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);7 x1 h0 H2 S9 M5 W8 n. `; {; o
$ F0 s5 J. g, h- {% i
/* the clock can give out invalid datetime, but we cannot return
) u2 B1 }, H d+ _4 K/ i * -EINVAL otherwise hwclock will refuse to set the time on bootup.
3 H1 ]$ L( \ n# ~. v( Z& Y */5 ]0 ^1 L0 F# z' C/ ]- i
if (rtc_valid_tm(tm) < 0)
4 j8 x: p7 G e. ]( s2 a; y dev_err(&client->dev, "retrieved date/time is not valid.\n");
: d% }( B" J* F# V. f/ a7 p1 J9 x! j& @ C' j+ Z% X6 ~
return 0;
: [1 K; v& v1 Q" `% h% T/ ?}
3 v2 v/ B3 Z3 [# `# i+ U7 R3 W [8 W H3 X' x
static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm)
" K1 y' J5 }. i- L' j3 P{
+ j+ ^5 x' l8 Y3 i# e; h5 ~3 i struct pcf8563 *pcf8563 = i2c_get_clientdata(client);
; G( O# X+ E2 g6 B" X& [ int i, err;, A$ W, B6 h4 h! i1 z' D! A
unsigned char buf[9];
( K3 C* G0 m2 B" P( p$ L
- F. b: u, A+ l7 u2 c dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "
/ a! h: _1 p$ S& R( ]. } "mday=%d, mon=%d, year=%d, wday=%d\n",
: V. e5 m! O) \* S2 R, t7 D% m __func__,
5 d' `6 s2 b) m3 b0 M) z' J+ f tm->tm_sec, tm->tm_min, tm->tm_hour,; @3 g$ Z7 r8 ]7 b: u9 M/ T
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
% ^8 B7 ^+ D! P
3 Y6 l {( o$ `/ e9 m /* hours, minutes and seconds */: M- j' j: N# B8 q
buf[PCF8563_REG_SC] = bin2bcd(tm->tm_sec); s, y) i4 V. N/ C
buf[PCF8563_REG_MN] = bin2bcd(tm->tm_min);6 q2 {% s$ }0 F( x. _
buf[PCF8563_REG_HR] = bin2bcd(tm->tm_hour);9 d- X! Q$ c* n. ], P
. X t8 Y0 Z+ f$ ]$ j. |
buf[PCF8563_REG_DM] = bin2bcd(tm->tm_mday);9 M) u' l! L) n# {' D# U& b% g
. B9 J/ S8 _- q
/* month, 1 - 12 */
5 S( z6 x8 w( s( @( ] buf[PCF8563_REG_MO] = bin2bcd(tm->tm_mon + 1);
: B+ C# J1 K8 N3 u# V) [4 ]3 V4 E( r( N2 |" c# V
/* year and century */
9 W' V! `( R. N# g buf[PCF8563_REG_YR] = bin2bcd(tm->tm_year % 100);4 F. b; \6 E9 {) F
if (pcf8563->c_polarity ? (tm->tm_year >= 100) : (tm->tm_year < 100))1 O* K2 s0 e9 ~) v" h3 I6 ~
buf[PCF8563_REG_MO] |= PCF8563_MO_C;
) _3 R9 Y. o2 [9 {! K2 B8 H* \9 x5 P0 y3 ]
buf[PCF8563_REG_DW] = tm->tm_wday & 0x07;
8 S: j. t1 C; P4 t( {5 T1 g
5 s- C9 X; |0 F( M. P' m /* write register's data */ c6 \; k" F& B
for (i = 0; i < 7; i++) {! m. h s6 J2 v+ p" Q7 T9 U/ N
unsigned char data[2] = { PCF8563_REG_SC + i,$ D, q, z' }8 D+ }
buf[PCF8563_REG_SC + i] }; ~7 d @; y ^/ H, x
7 n+ h- K( |& j" S' a8 m) M err = i2c_master_send(client, data, sizeof(data));0 x& M: `1 N5 T0 s* p
if (err != sizeof(data)) {
. W) M4 k5 z* }, v dev_err(&client->dev,
2 I2 t( T: F6 f/ f- R4 @ "%s: err=%d addr=%02x, data=%02x\n",9 w1 v# w; S6 j! G+ z
__func__, err, data[0], data[1]);; q+ w4 e2 i5 J, ?- I7 f
return -EIO;4 v9 H4 b- ^4 e
}
7 Z! z) s4 \5 D7 W5 X# ~2 u };
" v0 g% W! }# r$ F' w5 ~; Y3 A4 i, h
return 0;4 {/ Z# [9 s' s* [$ V4 ]7 u/ m4 C! j
}# z" a( s1 Y) `0 L
' W$ }5 @% U2 a( ?3 E7 Fstatic int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm)) ^, e2 i" o5 g2 p
{
+ U" H% b, u; b4 @1 P* N return pcf8563_get_datetime(to_i2c_client(dev), tm);/ w9 C: X0 c8 a8 D! {. _9 m/ a
}
% m# w$ y* S4 f" ?
9 R* L: |% ~, Cstatic int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm)
" k ~4 _5 M, P4 S{
; o* J4 ^3 y) M. E return pcf8563_set_datetime(to_i2c_client(dev), tm);
8 R3 @. B5 T5 w6 [! V}" v6 {) n; ~) F* q8 d
6 C& z% u9 E; v! v) X2 n% n
static const struct rtc_class_ops pcf8563_rtc_ops = {
6 B4 s7 ]0 W: m" j4 i* | .read_time = pcf8563_rtc_read_time, s, B6 a3 P3 G! S5 o r1 u
.set_time = pcf8563_rtc_set_time,
# }7 r& h& D- l5 T};3 F& W1 w* ]# m& ^& y* G5 c, i
i' V* A' C! R1 ]9 g
static int pcf8563_probe(struct i2c_client *client,
+ o4 ^. [# {$ I! _8 Y+ q const struct i2c_device_id *id)5 W$ q0 ?5 T: N& ^
{6 @$ }8 u4 p0 N0 O" w: Z
struct pcf8563 *pcf8563;/ x! A- g& k c: C7 `$ V i
9 e# [7 s+ u% {9 w. N int err = 0;
' z; n U; ]9 h" I! A( ]( t0 X" ?3 Q
1 v( r- f: h2 ^' w2 ` dev_dbg(&client->dev, "%s\n", __func__);7 J( G" g* U* w4 E8 L
. @' w* u, g" A, x
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))! O& U; V* h5 m1 l) ]
return -ENODEV;. c4 ?- J4 ?7 [+ ?* D% c4 f& C
3 \% e' t' h! [- z- o7 n pcf8563 = kzalloc(sizeof(struct pcf8563), GFP_KERNEL);
$ m$ h* h: I r if (!pcf8563)/ j4 F, W. P, }; R$ `, _" d
return -ENOMEM;3 R/ j! I6 }; ~6 V. \, Q
/ \: g% @) ^' }# N dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");9 s0 w, k" Q( M; }9 p& K/ t
! v' @- G: D. k! ?; e1 P
i2c_set_clientdata(client, pcf8563);6 O& p3 g. B, W8 ?3 r v
; k9 u* i1 Z" P& |7 c5 V pcf8563->rtc = rtc_device_register(pcf8563_driver.driver.name,
9 `' y3 F m( ~- ?& \ &client->dev, &pcf8563_rtc_ops, THIS_MODULE);
: a c' R& K' V) J+ D, M" J
1 c) l( f3 \# a' w4 O0 i if (IS_ERR(pcf8563->rtc)) {+ S7 E" @0 F) q6 T: b/ J* ]
err = PTR_ERR(pcf8563->rtc);
0 k# Z0 Y: y, F7 B4 Q' u, n5 j# n goto exit_kfree;
: u$ s# C3 [. b1 w! X }& k4 I: j, r1 r3 L
5 E# L2 T7 Z/ ^! A
return 0;: q. h" E, C) i4 C$ W1 q: p# }
/ a r& m1 s4 Q& _4 c# e# K8 K6 Q
exit_kfree:% ?- N8 G6 l, E+ H* F# I2 I z b) j
kfree(pcf8563);! t$ t6 f. U8 r% B& w. N0 L
* o, S* t2 E& o* \
return err;
# X$ Z# ^, X/ Q+ j7 v w9 {}
1 w: f B |5 y; U9 @' ~( O) K
- I! `( v' X) t! Ustatic int pcf8563_remove(struct i2c_client *client)
( I3 l. B. c$ ^9 p( _- B{
5 |# t/ T5 W' ^) n. `% W/ d struct pcf8563 *pcf8563 = i2c_get_clientdata(client);
( D. B- g" T; F+ l2 O) R; ^* Y" x' g" |7 m+ l i! }
if (pcf8563->rtc)
' k) i7 C* V# C2 a% n rtc_device_unregister(pcf8563->rtc);
2 m# {" p$ s! Z- O1 v
0 s k# N) l6 U6 h1 Q1 m8 u4 e kfree(pcf8563);
- ]5 M* k: O0 Q* l$ M
, Q( x4 u5 [1 d0 o8 | return 0;
% o; X# r0 n: m. W! L4 B) b2 }}
4 l: o) L! c# I2 Y7 ?( b
0 g2 H! x H7 T& Y8 m! |4 dstatic const struct i2c_device_id pcf8563_id[] = {
! {0 e: ^' Q8 U d { "pcf8563", 0 },5 q5 C( D/ O! e6 R v
{ "rtc8564", 0 },0 @& Q& Z( N3 Z
{ }
3 x" q( Q; v4 `2 Z$ t};
9 Z6 W; ~, R* k- [MODULE_DEVICE_TABLE(i2c, pcf8563_id);: y; E& \5 G/ @$ E8 Z
9 O3 T3 A, n, N( g7 q |
static struct i2c_driver pcf8563_driver = {0 q$ ?- H1 [& Z1 P' N) G; y
.driver = {
4 p7 k# K. f( ]3 H* t! K$ L .name = "rtc-pcf8563",
. N Y! d7 ?+ K/ a* k3 [ ^ },
6 e% @9 a4 c; ^; h .probe = pcf8563_probe,2 v6 A Q0 f- N4 m7 P. d8 R- {
.remove = pcf8563_remove,8 Z5 _7 e! e: ^) S- b9 X" Y, w
.id_table = pcf8563_id,% Z2 h" Y H' K- P, r
};8 D: y5 [; K6 \- \7 B4 T4 u
1 |- i8 G v5 b# Gstatic int __init pcf8563_init(void), W4 [3 j& `1 }4 Z$ ~) \
{
4 j: l# Z. O% [9 _; N* s return i2c_add_driver(&pcf8563_driver);
3 n2 D# a; a* M" i}
% U1 W. r/ c- h+ R, {) f6 X4 \# {2 q' ?+ S9 O
static void __exit pcf8563_exit(void)3 F, p' P; U5 F x1 W
{' a# `- y, q" w6 j# u
i2c_del_driver(&pcf8563_driver);
+ ?! E' T; v+ s4 u6 u+ W}
1 r& _& {- B% n" E4 \
# Q5 H L: A T$ y- UMODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
) g# F$ C: n/ a- Q1 O3 {! ~MODULE_DESCRIPTION("Philips PCF8563/Epson RTC8564 RTC driver");
" e+ ] `# e* T8 ]) @MODULE_LICENSE("GPL");8 ^& W: C8 O$ s
MODULE_VERSION(DRV_VERSION);. X; ^1 N: s. O2 g% G
( c, M' C8 D7 \9 S) N7 Ymodule_init(pcf8563_init);+ X9 O" r/ g7 a: }- v, e& e
module_exit(pcf8563_exit); 7 n. F5 ?) |$ F
|