EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
9 }5 {; y a+ w( a4 W8 T
开发板: 各位版主、工程师们你们好: 请教你们一些问题: (1)在内核中配置pcf8563时钟芯片启动完成,内核启动后 /dev/rtc/ 中没有pcf8563芯片对应的 rtc 节点; (2)内核启动过程中打印 drivers/rtc/hctosys.c: unable to open rtc device (rtc0); (3)pcf8563芯片驱动程序的 pcf8563_probe()在整个启动过程中没有被执行; (4)请问这是怎么回事?该怎么修改??? (5)驱动程序代码如下: 驱动代码:
! q8 b; j. l7 z" J# h9 K#include <linux/i2c.h>
v1 W4 e1 R" w% D4 w9 \* x#include <linux/bcd.h> I* L1 }/ C. N, v* H* d
#include <linux/rtc.h>
# i; |1 q) F2 b5 s#include <linux/slab.h>: R1 z7 h9 B. J, T
/ @7 g8 r: W- P8 u4 J: a' i3 h, }* r#define DRV_VERSION "0.4.3"
1 a n* T. E8 ^1 F
& X# a/ G B' B: c+ i ]#define PCF8563_REG_ST1 0x00 /* status */
) F$ r+ l( ], V#define PCF8563_REG_ST2 0x014 C. X2 E2 b# e& L& ]- E, e9 Y
/ G2 M, F3 l- l5 p. Q
#define PCF8563_REG_SC 0x02 /* datetime */- ^' x4 d4 S4 ?
#define PCF8563_REG_MN 0x03
: ^ e3 }8 v/ u9 K/ I$ k#define PCF8563_REG_HR 0x04" E! y! U, j: S0 O! v; j J0 _+ V
#define PCF8563_REG_DM 0x05
' C* H& X# p* m% l/ a; ?' W* B#define PCF8563_REG_DW 0x06
( B% F9 m" s4 G' ?: r' E* f- n#define PCF8563_REG_MO 0x07
1 T5 S- N' @6 u/ |# @, I#define PCF8563_REG_YR 0x08
2 b: r- [ {; O* A o$ ~8 l) X1 y' t+ t6 N' U
#define PCF8563_REG_AMN 0x09 /* alARM */
9 ^! n, P, g0 X) S#define PCF8563_REG_AHR 0x0A; m5 D- y/ L: j
#define PCF8563_REG_ADM 0x0B
* m/ n* l, s4 y2 P#define PCF8563_REG_ADW 0x0C
8 k( y; `; _0 p/ N' `
( x' Q$ x3 r# S4 G; G- |1 p. I#define PCF8563_REG_CLKO 0x0D /* clock out */
: A3 J9 E* t3 {( b! y, S! D2 U* N, S#define PCF8563_REG_TMRC 0x0E /* timer control */
5 ^ r F, L/ r" J#define PCF8563_REG_TMR 0x0F /* timer */
5 k3 P2 C/ f# e0 e0 e
( n3 G4 ?* ~+ T3 l3 M& C4 B5 H/ R# v#define PCF8563_SC_LV 0x80 /* low voltage */
: F- u! Q1 ?* l; B#define PCF8563_MO_C 0x80 /* century */
$ f4 V2 `7 B0 @/ C& e
0 c# `" L1 J, e4 bstatic struct i2c_driver pcf8563_driver;! Z! i6 O3 I* p
" h2 y! l0 ^8 X9 e7 Y" q6 h2 G$ z/ e
struct pcf8563 {8 I7 A) G6 @; D
struct rtc_device *rtc;
+ H: X8 H! r" i2 ]$ ` /** c+ M2 M- |6 g8 _3 ^
* The meaning of MO_C bit varies by the chip type.
r. G% [/ A. h4 J; n' m4 t9 j * From PCF8563 datasheet: this bit is toggled when the years
+ ^4 I: R; ~; ~7 {( p2 b * register oveRFlows from 99 to 00
) p8 h$ N4 _0 a5 C* D1 }6 } * 0 indicates the century is 20xx
4 ]! x0 E- K2 V0 }2 Z! N- }# ] * 1 indicates the century is 19xx0 p/ D& [- k! @0 w+ z. [2 @* {2 u
* From RTC8564 datasheet: this bit indicates change of6 ~' o t6 y# n' c0 ~ d6 t- c
* century. When the year digit data overflows from 99 to 00,( q) u; C i) k
* this bit is set. By presetting it to 0 while still in the. B* F [' }/ e% n/ o! ^8 c
* 20th century, it will be set in year 2000, ...
1 }+ S* | C3 \5 B# O1 F * There seems no reliable way to know how the system use this5 K# \1 E! B2 c# R+ f! s" o
* bit. So let's do it heuristically, assuming we are live in' a& S* c! w: p6 P
* 1970...2069.
5 u5 _. Q, b0 ] */
! o+ t, J3 k$ I8 Y int c_polarity; /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */
4 u4 U7 b1 d/ q2 f( {};
& e M! D1 l- W# |5 B7 H' t+ g- e! z. q$ R2 t) ^3 S
/*4 G, f2 [ o) n9 r
* In the routines that deal directly with the pcf8563 hardware, we use
$ D7 l$ `9 [: V$ q. t* rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.
2 y+ ^: X& z; S# p*/
; l4 L! T! {. G0 J; j3 Fstatic int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
. b2 g' s+ d. B1 Q+ w" ~3 n# \{
9 ]* W) X- s2 n4 s$ [, c struct pcf8563 *pcf8563 = i2c_get_clientdata(client);
& W7 m; {% i# z unsigned char buf[13] = { PCF8563_REG_ST1 };, g$ F ^" g: L. L
9 M ?, O, }, \; n: i
struct i2c_msg msgs[] = {% l1 w8 }3 j6 M
{ client->addr, 0, 1, buf }, /* setup read ptr */6 X0 x+ x* P( N6 z. Y6 u* F
{ client->addr, I2C_M_RD, 13, buf }, /* read status + date */
" K4 Y4 Z% G! }$ A0 a3 V3 c };
* {: W; L$ }2 _* h7 P
2 Q0 F; o- U1 | /* read registers */+ q* g# D5 |2 w% A& f6 g( Z- k" ^
if ((i2c_transfer(client->adapter, msgs, 2)) != 2) {
! J. w( y) G. @% g( D8 l! c _# h dev_err(&client->dev, "%s: read error\n", __func__);
y' D2 y' f8 b3 n+ M return -EIO;
2 r% I: f( U, C* o+ } }2 O& h+ }& j# X) a' @! `- B6 t$ F
, W; d8 X/ g' c) T a0 u: q
if (buf[PCF8563_REG_SC] & PCF8563_SC_LV)
5 g3 y0 d; F. v `; }' C dev_info(&client->dev,. o, K% v! V% @: U, ?3 Z
"low voltage detected, date/time is not reliable.\n");
' M5 y- [' x# x4 H/ r: M/ F& S4 ^; d
dev_dbg(&client->dev,' N3 {5 ^7 O. N, @+ V7 T
"%s: raw data is st1=%02x, st2=%02x, sec=%02x, min=%02x, hr=%02x, "
2 X* |3 U3 R, ?* z& q: ~( p( H$ a I "mday=%02x, wday=%02x, mon=%02x, year=%02x\n",
- O a% W) T% L: m& e T __func__,
8 \! @) m6 R7 c buf[0], buf[1], buf[2], buf[3],. w+ R2 i# A- k9 K1 u9 b( S
buf[4], buf[5], buf[6], buf[7],
. l# n$ {3 b/ y# c4 L: x buf[8]);+ e# z" H d2 x: m# |3 i) M/ t
0 a& \, T; I$ U1 N
7 w; B! t0 q) Y tm->tm_sec = bcd2bin(buf[PCF8563_REG_SC] & 0x7F);9 [# U4 B" k/ B: q& j6 x- B6 F1 j
tm->tm_min = bcd2bin(buf[PCF8563_REG_MN] & 0x7F);
- R2 l4 T9 [- T+ h) g! L" a tm->tm_hour = bcd2bin(buf[PCF8563_REG_HR] & 0x3F); /* rtc hr 0-23 */+ M1 Y# n3 S- \; A8 ?( W
tm->tm_mday = bcd2bin(buf[PCF8563_REG_DM] & 0x3F);
: s- @; t( q8 t* L& j tm->tm_wday = buf[PCF8563_REG_DW] & 0x07;
9 M" F$ B! b4 e, O9 y tm->tm_mon = bcd2bin(buf[PCF8563_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */
) ~6 Q _ r! @- L4 L tm->tm_year = bcd2bin(buf[PCF8563_REG_YR]);
! Q( Z3 H4 [0 N5 X0 Q if (tm->tm_year < 70)
' h8 {; C* l6 x! o' ?2 U2 ?4 N tm->tm_year += 100; /* assume we are in 1970...2069 */ f# {) k9 F- _+ w+ z/ \, @
/* detect the polarity heuristically. see note above. */- t: k Z* v2 V5 t! d% }
pcf8563->c_polarity = (buf[PCF8563_REG_MO] & PCF8563_MO_C) ?# S, r2 V+ S- K( u5 w
(tm->tm_year >= 100) : (tm->tm_year < 100);0 O& [# w: l- C" P/ Z6 h9 y8 c: l5 k
) V3 F7 w9 [" Y" O
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, ": {* h# @& E' I# H8 L- Q7 i
"mday=%d, mon=%d, year=%d, wday=%d\n",
7 o% t- z- A9 l4 m4 v& t __func__,8 e7 i/ m& ]7 E; @4 R/ m l, w
tm->tm_sec, tm->tm_min, tm->tm_hour,
/ B* @6 L$ o) ?1 x5 b- s B tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
; c- j# o. ^% w6 a. r; T
) k4 \( X& F. z0 ?& F /* the clock can give out invalid datetime, but we cannot return/ J7 m$ M" o3 P1 d
* -EINVAL otherwise hwclock will refuse to set the time on bootup.' k8 L( o0 M2 q; b
*/
3 Z& V8 B z# o0 ?* I, N if (rtc_valid_tm(tm) < 0)
# s/ Z' p: r+ }1 N) @% @3 j- ~2 K dev_err(&client->dev, "retrieved date/time is not valid.\n");* w# c) Q, z; ~' }$ u e1 \9 ?$ }
# e* g4 k; s2 N' x
return 0;
( g1 Q3 z2 f& B$ i( z4 E}
5 z3 S5 q( D3 ^2 z8 d+ i( {5 l/ H
% q/ T: D, p) U- |+ [$ {static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm). W+ C+ w' ^+ J' F
{
' |& d: j' J- `1 ^0 S" @ struct pcf8563 *pcf8563 = i2c_get_clientdata(client);4 Y5 L0 J0 K& e+ V, J) C- C$ M
int i, err;6 V$ e$ O( d% j0 `) w1 y/ |- v
unsigned char buf[9];
' E0 l" f7 ]/ H/ k0 h; r
( u1 I# w) q& F7 z5 O: v dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "
: I4 }% K9 Y+ j1 t4 \. C "mday=%d, mon=%d, year=%d, wday=%d\n", L+ V/ k' E& ?# u5 l
__func__,
% Q. m9 r4 r# z" I, V- J( S tm->tm_sec, tm->tm_min, tm->tm_hour,
) H$ {$ O! j+ x8 x5 @; J% q/ B tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
) x$ |3 S+ f2 r4 w# |3 d P! P, s9 _( O* g, E! N, a, F
/* hours, minutes and seconds */
' b6 J) V- Z% K: j2 W buf[PCF8563_REG_SC] = bin2bcd(tm->tm_sec);
* I- e2 m/ r- y! W+ d# n1 } buf[PCF8563_REG_MN] = bin2bcd(tm->tm_min);) ~/ ~4 r6 l! i+ ^2 j* Z' @
buf[PCF8563_REG_HR] = bin2bcd(tm->tm_hour);; f& H- F6 Q: {+ `
4 k# \" F6 s' K7 c
buf[PCF8563_REG_DM] = bin2bcd(tm->tm_mday);
' l5 f- m6 y6 S$ e+ [5 g+ L( A! E& }! \+ A
/* month, 1 - 12 */
' L& U5 b9 C: ]+ o, Z* x7 |; C' l buf[PCF8563_REG_MO] = bin2bcd(tm->tm_mon + 1);3 J$ p+ A$ j! \3 {
7 O$ x& [2 L/ d( R0 i
/* year and century */
I$ ^2 r' F0 k' L buf[PCF8563_REG_YR] = bin2bcd(tm->tm_year % 100);
: B7 @' U5 |3 \ if (pcf8563->c_polarity ? (tm->tm_year >= 100) : (tm->tm_year < 100))
. H9 ]* l4 K9 o! o- A% O q3 o buf[PCF8563_REG_MO] |= PCF8563_MO_C;) `: F. M x: E+ F7 O9 E
9 F0 J- s2 L0 Z ?7 |# D( N3 @* X buf[PCF8563_REG_DW] = tm->tm_wday & 0x07;
2 B* D {, s2 M) \7 h- H3 x" v# S. H k# Y% c1 D' a* W; e
/* write register's data */4 X0 S3 g Q6 \" F, a
for (i = 0; i < 7; i++) {
- B! V$ W f& {/ d- B unsigned char data[2] = { PCF8563_REG_SC + i,
6 p) n9 F4 B- @- ^& r* E buf[PCF8563_REG_SC + i] };, Z; P% L' |* o! V/ O6 p# X
, \- v, x& [- b( p: X# X
err = i2c_master_send(client, data, sizeof(data));
0 r) h# m( ^! H5 l3 r2 Y1 q if (err != sizeof(data)) {6 T; |& d% k7 l0 }' S6 O
dev_err(&client->dev,7 P* S1 S! f( y1 h% X( l# D5 N0 @
"%s: err=%d addr=%02x, data=%02x\n",* u) x& K( [4 K0 p1 [
__func__, err, data[0], data[1]);
$ A" N! R3 Z+ d- }! W return -EIO;
, ]- G( k' f ~) Z }; @' w( T3 j9 J# f1 b3 V- F
};
8 s7 q# c) K( |* `6 O! Q
3 `! O7 N4 J: ]/ O3 B# ~; H return 0;
& ~, \5 C% j0 Y0 s& f}* u( M& ], G7 w. Q; d O8 u
0 H- Y$ h ]5 d4 e3 z& ~" Sstatic int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm)
0 ]( r/ S/ j/ a* K/ C2 B/ }{
( N: u( U2 A5 N* b1 n return pcf8563_get_datetime(to_i2c_client(dev), tm);
# `) x0 m3 v2 I6 c}
8 o" [4 N( G) g" F( X6 A) q5 D E8 P
/ p3 j) D' K# i) V1 h4 Z+ B4 cstatic int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm)
& U/ e" N2 E- y0 \2 x# b% W P{
0 w6 L- t6 t+ M, e! n9 y return pcf8563_set_datetime(to_i2c_client(dev), tm);5 d( z3 d2 f. w! x2 B# j
}
' |8 `) J6 H& w4 d4 Z/ Y8 D
1 r2 p: V. T$ e/ R9 z# Lstatic const struct rtc_class_ops pcf8563_rtc_ops = {
7 h! O, s+ c, P+ X X .read_time = pcf8563_rtc_read_time,+ Z. v7 h4 n! n" R, x- k7 W) V4 F$ `
.set_time = pcf8563_rtc_set_time,
x. e( K# `; }8 I2 | o};' r; e) T/ v# G* Q
6 `2 C! ` U5 J! | o# S+ u8 r" s
static int pcf8563_probe(struct i2c_client *client,
& k* R/ e: F. W& Z& C0 T# N, { const struct i2c_device_id *id)5 k% {0 V- ^0 k
{2 }; `" Z3 I# i1 T
struct pcf8563 *pcf8563;+ {1 f; `2 B p4 @1 d* Z
& e L' @$ @3 ^8 ^* e8 d int err = 0;$ _7 r1 j8 l! {' F! H' A
3 V7 @# w6 R) ^) G, Q+ H
dev_dbg(&client->dev, "%s\n", __func__);
0 j: H' r) G5 O2 S- m, O0 X G; P7 g- D
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
. F& i* b4 f; S4 } return -ENODEV;/ ?8 J% A3 B& U+ w, \; ~, J3 c$ Y
& f1 d+ J$ O/ e4 B' J! g' y1 y pcf8563 = kzalloc(sizeof(struct pcf8563), GFP_KERNEL);
! R% l) o0 s& Y if (!pcf8563)
8 z* D7 }7 n$ \0 B return -ENOMEM;
5 A! Z) f1 X5 P3 `" _/ l2 U. y, M {+ p! |' n: }/ q$ T. ^
dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");0 V" t2 a6 `3 A S" o! x
3 |5 e; c4 n$ Y% q/ P' J i2c_set_clientdata(client, pcf8563);7 l j4 Y8 p( |: a7 Z; i3 G% L6 Z/ _5 q
6 x+ C8 N3 T. U$ p
pcf8563->rtc = rtc_device_register(pcf8563_driver.driver.name,
( S U. @7 |+ F &client->dev, &pcf8563_rtc_ops, THIS_MODULE);
' \4 T) @! \! B7 `- M+ X" }' h1 a/ y$ M H5 r& c% `
if (IS_ERR(pcf8563->rtc)) {
6 V t) e* K. s+ l" z err = PTR_ERR(pcf8563->rtc);
# q: d: r' R7 H6 h$ Z7 _ goto exit_kfree;
, r1 Q" T" T- |; P }
8 _( w% Y: {+ O9 ?7 d6 f) y3 c
4 q! p5 D4 {, x8 k' [& N return 0;
/ \0 ?! M+ l5 \8 z+ X. a2 I' l( b( W, \
exit_kfree:
O% {6 m; j4 b6 \ kfree(pcf8563);
# t6 k, a1 {0 I& R' f9 F" t% x) q. l+ O. Y- k5 L% i
return err;* R0 m7 k a; e' `
}- `* _7 E! m! h8 r6 w6 U$ i" E
# z4 X* l s, }& z5 d4 T: D# t/ D
static int pcf8563_remove(struct i2c_client *client)( L' W1 B4 @/ g, ?+ _* V
{
; Z8 @2 ?9 P! A struct pcf8563 *pcf8563 = i2c_get_clientdata(client);! A5 F) F5 N ^* T0 Z
- U% [7 k9 W' [/ p3 P9 T$ M if (pcf8563->rtc)
. h: \' P# F$ t: B rtc_device_unregister(pcf8563->rtc);7 O- v) | I1 A5 w
; V8 d: N0 ^9 R
kfree(pcf8563);
- v) X5 \1 I+ y+ Z8 P
4 I! k) R& N) L: q4 t2 H' { return 0;
1 c7 Z3 v9 l4 e7 K/ a p}* n5 k4 C! x3 z3 P! B
n. ^' @2 ]: |static const struct i2c_device_id pcf8563_id[] = {
+ S8 o+ A, `% v1 I { "pcf8563", 0 },
- o: T$ n+ H$ Z- {% Y$ W! a( U { "rtc8564", 0 },
7 ^# j! T3 y& \2 E { }) V8 ]* _' |" k& r( P
};
* s( X7 p* p" ~7 |; M# n8 DMODULE_DEVICE_TABLE(i2c, pcf8563_id);( h# b P0 R7 l1 i2 X4 s0 d
' X* k6 f8 u$ O- J n
static struct i2c_driver pcf8563_driver = {2 a8 `. x3 Y6 T( O' n p* @
.driver = {4 m W: ^& Y" o
.name = "rtc-pcf8563",
) h- r* N4 s( P- E },
* d' c; u( d' M0 Z, o0 c3 y2 f .probe = pcf8563_probe,
' C3 N4 p/ u8 g* K7 b; ] .remove = pcf8563_remove,
# i! u. w: z ~+ d' \$ n# q .id_table = pcf8563_id,
; l1 d! a R/ Z5 k8 o};! g% C( Q& }6 G7 \" K5 S
0 N( c* n/ m+ Xstatic int __init pcf8563_init(void)
% q+ P% N, R; E# S7 a% \6 m( n{
% i5 n# G v1 j return i2c_add_driver(&pcf8563_driver);
2 K3 `' E4 {9 Y5 [# O2 `* _}
7 k+ @- q4 n7 W( p l! D7 Z; o- V6 P. z
static void __exit pcf8563_exit(void)9 }+ k, m7 A5 a) `
{
: t, j' g4 M; g' b( v( Q: v' u# N6 I i2c_del_driver(&pcf8563_driver);9 A4 |5 }) P4 P3 a
}
0 n/ n9 _) {& a- D# q2 V
' N. V6 Z s! kMODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");( y( x& ~6 Z& @+ j; m
MODULE_DESCRIPTION("Philips PCF8563/Epson RTC8564 RTC driver");
. E7 e5 ]2 c" V4 K7 FMODULE_LICENSE("GPL");) G6 a$ F- ]! t( z4 ]% V
MODULE_VERSION(DRV_VERSION);
% ]8 V6 T Y$ q. q* I7 g1 o" o
module_init(pcf8563_init);
6 d! l& l: s- z8 \4 Kmodule_exit(pcf8563_exit);
1 d2 C3 E& H! z$ o0 I* {) K2 S2 q# S# ^ |