EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
% K) G+ E( |' r E3 k: i# q' |6 y
开发板: 各位版主、工程师们你们好: 请教你们一些问题: (1)在内核中配置pcf8563时钟芯片启动完成,内核启动后 /dev/rtc/ 中没有pcf8563芯片对应的 rtc 节点; (2)内核启动过程中打印 drivers/rtc/hctosys.c: unable to open rtc device (rtc0); (3)pcf8563芯片驱动程序的 pcf8563_probe()在整个启动过程中没有被执行; (4)请问这是怎么回事?该怎么修改??? (5)驱动程序代码如下: 驱动代码:
2 u& H4 g/ M' U; W) J( W#include <linux/i2c.h>
8 J# w! K% i8 x' R( G#include <linux/bcd.h>0 x/ p$ g5 n2 v7 B3 J
#include <linux/rtc.h>
% z! `7 E# K2 I+ M5 N" ?( ~( C#include <linux/slab.h>) q) t( E# R4 K$ `3 h
$ x! l3 O! l$ Q7 H+ {#define DRV_VERSION "0.4.3"
) g$ ~; Q ]0 s2 E
1 M1 q6 y/ p4 B5 Z#define PCF8563_REG_ST1 0x00 /* status */
0 R3 j( a- x8 k#define PCF8563_REG_ST2 0x01
) w' t/ y( }( S; N7 `( q7 @6 J$ s z. d) Y- U! X5 P8 }
#define PCF8563_REG_SC 0x02 /* datetime */( h2 a8 R F$ u. \7 A
#define PCF8563_REG_MN 0x03
; A) g4 }, ~- }+ ?3 ~, [#define PCF8563_REG_HR 0x04
* U( a$ c6 g' h, r#define PCF8563_REG_DM 0x05
" T; Q' G3 n9 H: m: L' z#define PCF8563_REG_DW 0x06 u7 _5 S7 ?; \0 y* l
#define PCF8563_REG_MO 0x07+ V' h* `' I2 y0 ^- u3 p
#define PCF8563_REG_YR 0x081 W b9 H" [3 J7 w! K" V* x$ e
8 y6 Q/ g* r3 U2 X, c#define PCF8563_REG_AMN 0x09 /* alARM */4 r! K8 r/ A7 z5 o, ^
#define PCF8563_REG_AHR 0x0A. Y) d$ v: X1 v6 t5 c, ^
#define PCF8563_REG_ADM 0x0B0 h; m1 m$ v7 f! M G& O5 u
#define PCF8563_REG_ADW 0x0C2 G$ j& r! x& x V+ d& _6 [( ^. O
/ k7 R0 e- l0 p! v. k: s2 J#define PCF8563_REG_CLKO 0x0D /* clock out */+ Y. F; v$ I/ P# y' |1 \; s
#define PCF8563_REG_TMRC 0x0E /* timer control */
7 v. Z1 R5 Q- j, H8 k#define PCF8563_REG_TMR 0x0F /* timer */, G, y9 u+ X s1 i
2 } v* M. N$ I1 ^2 i
#define PCF8563_SC_LV 0x80 /* low voltage */0 c* Y# H4 L9 T* T! I- C: h) H
#define PCF8563_MO_C 0x80 /* century */
; r% X) u- A3 Z) M7 ]& v# N4 F+ I/ s: _& F- |. S
static struct i2c_driver pcf8563_driver;! y4 F. Z0 x- n$ A
3 T/ ^& e, M* B% F. X
struct pcf8563 {
6 G3 U; V {% a, j5 d struct rtc_device *rtc;2 U8 A4 ?1 m8 K/ j% h' Q5 C J* v
/*
- |) L4 D+ A9 n * The meaning of MO_C bit varies by the chip type.
+ c7 x. L5 }7 q- [+ b1 z2 ^1 C& n * From PCF8563 datasheet: this bit is toggled when the years
5 N: |6 o9 ^- B- c' z * register oveRFlows from 99 to 00+ Q+ m% J/ o+ ?1 {$ M: e
* 0 indicates the century is 20xx0 w s8 m, U5 o6 z! R
* 1 indicates the century is 19xx A. Y3 C. d: W/ J/ r4 F
* From RTC8564 datasheet: this bit indicates change of. q* S4 \! J# J1 S* L
* century. When the year digit data overflows from 99 to 00,3 {0 h) I# \3 m) X% ]: ?+ H
* this bit is set. By presetting it to 0 while still in the
) p/ a; J% P) z5 ^ * 20th century, it will be set in year 2000, ...6 U9 c7 f5 L! W
* There seems no reliable way to know how the system use this$ B$ d- R" H- u7 B& d
* bit. So let's do it heuristically, assuming we are live in/ @ l1 }/ m8 v. C2 p# P
* 1970...2069.9 L5 `! N& }% m* _% j/ Y
*/
& f( M- K" {* E# u) y$ P9 _+ a2 v int c_polarity; /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */
) l; @- E" I: o4 i};; h0 @3 g- g+ E- L0 V
. f& c( i$ H/ i# A
/*
# T+ k, b/ t% C% a) i* In the routines that deal directly with the pcf8563 hardware, we use% V7 B$ e/ N( L! z" ?; T
* rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.5 m1 e9 }) m; l5 b1 H g2 N9 `
*/1 [7 D) r' \: @) i4 h1 q1 Y6 u4 i
static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)7 x C; Q5 f1 t1 m+ g
{( R0 v" _6 a. K; _. q( R, a0 j
struct pcf8563 *pcf8563 = i2c_get_clientdata(client);
' T3 y \6 ?3 v9 | unsigned char buf[13] = { PCF8563_REG_ST1 };+ G: S0 t1 t U7 m4 j- x5 d# k1 \
; s; w C, m! e P& \
struct i2c_msg msgs[] = {
- c1 b" |: |, ~! a& n5 s { client->addr, 0, 1, buf }, /* setup read ptr */
# [, D4 n [+ c$ X! [8 v' D8 z { client->addr, I2C_M_RD, 13, buf }, /* read status + date */
% E1 V4 V- h/ f7 f2 m# u };* ]$ d6 A1 c0 e" g' A4 w! C
8 m7 \9 v& [' v) m0 k
/* read registers */9 A' v3 w w, |. m/ U. Q8 ~
if ((i2c_transfer(client->adapter, msgs, 2)) != 2) {; b5 |" i/ f' x/ Z! j$ D# |1 x
dev_err(&client->dev, "%s: read error\n", __func__);5 A7 q! j0 K O. s/ [- `6 M. w
return -EIO;+ G, t5 u- Z$ [: L! P
}
7 x6 b- M8 s9 K# Y/ X( L# |4 l! C7 L" v3 x% \# B
if (buf[PCF8563_REG_SC] & PCF8563_SC_LV)7 n: u6 S0 o4 A- U7 Y- C7 v" v* G
dev_info(&client->dev,
+ B6 j5 t0 q5 Z! @9 D+ C4 d "low voltage detected, date/time is not reliable.\n");
2 }/ d! W9 }+ g, h( v' B
1 r8 F' p. u4 i& I. f! Y) S7 r4 M dev_dbg(&client->dev,
" E" p) Z6 H) E4 |: W "%s: raw data is st1=%02x, st2=%02x, sec=%02x, min=%02x, hr=%02x, ") H, ~5 G: y. J
"mday=%02x, wday=%02x, mon=%02x, year=%02x\n",
; o) u9 `6 j! I& Q d __func__,
% U0 A# |0 }0 M+ v/ y; ?# E buf[0], buf[1], buf[2], buf[3],
. y+ F7 A* a" v5 \. h* V7 b buf[4], buf[5], buf[6], buf[7],3 `% p8 P4 o3 P) O
buf[8]);( t* `; c$ u8 a; K& u
- a2 _" }1 w m6 T5 ~
f+ s8 k- B9 ?& F0 I" L. |8 L8 U tm->tm_sec = bcd2bin(buf[PCF8563_REG_SC] & 0x7F);% J$ t* K, @ K6 l/ B9 _
tm->tm_min = bcd2bin(buf[PCF8563_REG_MN] & 0x7F);
) h8 x+ K$ q1 K tm->tm_hour = bcd2bin(buf[PCF8563_REG_HR] & 0x3F); /* rtc hr 0-23 */- q# V: p( x, G+ }% ]4 w; ]: ~9 R8 g
tm->tm_mday = bcd2bin(buf[PCF8563_REG_DM] & 0x3F);
8 h% w5 T+ G% x' D8 ~+ U2 t1 G tm->tm_wday = buf[PCF8563_REG_DW] & 0x07;
5 `- _/ ]$ A6 M- ?( W7 q8 D2 w- ? tm->tm_mon = bcd2bin(buf[PCF8563_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */0 E5 f2 B1 v1 Q
tm->tm_year = bcd2bin(buf[PCF8563_REG_YR]);
0 g7 L# M" g. B' J if (tm->tm_year < 70)
' g/ O8 P( l$ @6 u2 C; M4 `4 [7 l tm->tm_year += 100; /* assume we are in 1970...2069 */
6 j2 R! G. p) Z) \7 B/ L& y! } /* detect the polarity heuristically. see note above. */
2 F: F! Y0 l- D5 N( T9 g pcf8563->c_polarity = (buf[PCF8563_REG_MO] & PCF8563_MO_C) ?% l/ |3 Z, J! K' X1 O- B" U
(tm->tm_year >= 100) : (tm->tm_year < 100);
2 c& R3 v, R: z# h M/ D3 T( u/ b" u( Z. i4 g8 Q+ C9 W& O9 h
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "5 ]8 n% `" _2 \
"mday=%d, mon=%d, year=%d, wday=%d\n",9 ^# d" S y, b; n4 m7 d+ o8 }
__func__,
& w z J- @4 T ? l+ T# Q, J tm->tm_sec, tm->tm_min, tm->tm_hour,/ s2 e2 h" Y& G- G
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);/ O( _. f d% f" e
7 {3 k# r+ C* E/ `: Q9 Q- {
/* the clock can give out invalid datetime, but we cannot return
. ~7 U' ?+ \( O: j7 R * -EINVAL otherwise hwclock will refuse to set the time on bootup.
, N# [) c( a) j) w- k+ n! a */4 a) w" {7 m, B$ P6 o
if (rtc_valid_tm(tm) < 0)
9 B8 b- y( W- z: c( l& b8 r dev_err(&client->dev, "retrieved date/time is not valid.\n");
+ L7 u$ d4 Q7 z; Z5 M
. D; e- z6 s Q$ H return 0;
4 D4 y$ T' G' W: l/ D( m}+ H" Q7 b5 N; S: m# D$ I
& x0 q1 {& S9 d3 Ystatic int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm)
/ `- E) x. z, F4 K/ o% i2 {/ A& S{9 {' Y3 _8 w v' d5 V
struct pcf8563 *pcf8563 = i2c_get_clientdata(client);
4 \! n# s1 z# | int i, err;
3 r) [1 T/ [$ y' W& e( ]' [) S unsigned char buf[9];/ n. N0 Y) T7 c/ F% ?& ^ F r
5 J" ]; Z; P# k; r! x' J7 M
dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, ". Y( G: }1 R6 i2 Y
"mday=%d, mon=%d, year=%d, wday=%d\n",1 N) E7 k$ q' F. |2 b7 B
__func__,
b1 ?0 o2 K+ ] tm->tm_sec, tm->tm_min, tm->tm_hour,' r0 N% ? b" C# J
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
3 \3 D5 |+ A3 P
" ^' j' y1 ?$ S7 r /* hours, minutes and seconds */
* Q1 W& e& k! | buf[PCF8563_REG_SC] = bin2bcd(tm->tm_sec);' f4 j2 Q& |6 o3 w: Y3 _% u# z- L( Z
buf[PCF8563_REG_MN] = bin2bcd(tm->tm_min);1 {: [7 a4 k7 g" V0 J% j( r
buf[PCF8563_REG_HR] = bin2bcd(tm->tm_hour);
$ G! V+ r% ?& l6 U
1 `/ t5 M9 A" M' \8 |* @ buf[PCF8563_REG_DM] = bin2bcd(tm->tm_mday);
7 C6 P+ w ]1 W
: W) c9 K7 V: m C3 I /* month, 1 - 12 */
4 i4 k: j: W; Y3 Z buf[PCF8563_REG_MO] = bin2bcd(tm->tm_mon + 1);
& B+ H% ` K! ~0 H$ J) d% H) x( `" _" ^ T8 B. F. K
/* year and century */9 v7 ^) i% v2 F l) r% E
buf[PCF8563_REG_YR] = bin2bcd(tm->tm_year % 100);: v9 {0 ~' ~ ~ }. b9 H3 Y
if (pcf8563->c_polarity ? (tm->tm_year >= 100) : (tm->tm_year < 100))
' P2 t) b7 D. `% n4 S2 x8 d buf[PCF8563_REG_MO] |= PCF8563_MO_C;
( _ O9 q) C1 d6 g; m9 _) n$ T! z0 V2 q2 |
buf[PCF8563_REG_DW] = tm->tm_wday & 0x07;( r+ y7 A% X$ N9 s; U5 S
; c$ U: L: B6 A% k$ Z/ x$ x; G
/* write register's data */
" k; q% Z6 }& J. O for (i = 0; i < 7; i++) {% \4 L; b5 D( \: ?5 Z( K9 _$ C% i: g
unsigned char data[2] = { PCF8563_REG_SC + i,
8 A. y! F8 K( O" l buf[PCF8563_REG_SC + i] };4 K6 K: c9 F7 i4 i
5 i; B. {* C/ }1 [# C. e E+ P# s
err = i2c_master_send(client, data, sizeof(data));
; |* u9 y8 @- I5 Q) Q if (err != sizeof(data)) {
/ v) ?% `( ?8 o8 Y0 P" P3 c dev_err(&client->dev,
9 ]2 t% |8 }; K' C- r* C1 }/ f8 ` "%s: err=%d addr=%02x, data=%02x\n",0 H& Z/ }( u0 ~) o
__func__, err, data[0], data[1]);* v5 W0 v# `' N
return -EIO;! a% U1 O& T) p( Z7 m) Z" |, O8 Y
}
6 L- j8 `8 K7 n4 p3 v7 @ };0 t( w, Z" K+ l# c. r
0 ^+ {1 d% Z: Y" w g
return 0;
# H F, g( s" B) X- ~}
: g" a; y8 C2 P0 s4 G$ i7 V( x- c
" X6 q9 m2 [. F5 mstatic int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm)3 K. P% O& K1 r5 b/ Q$ o1 O
{2 O. j0 B6 Z8 P
return pcf8563_get_datetime(to_i2c_client(dev), tm);
% ~* _" O& J- j7 Z+ z}
8 s/ z" ?7 _( F ~6 J5 W' y7 D. _ F; l# U( u c `) a4 F6 {
static int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm)
9 n5 E5 Y- A, s* @" b" C) P{9 G. V9 B9 ]0 [, A# U
return pcf8563_set_datetime(to_i2c_client(dev), tm);5 A [/ \, t+ ]# v- U+ q a
}6 h, l5 y6 a, ~8 y) D
2 ?( C9 U0 r" k0 O P: K# Y# [
static const struct rtc_class_ops pcf8563_rtc_ops = {
% u7 j$ u$ q+ ~! Z Z( N( V- r4 K) ^ .read_time = pcf8563_rtc_read_time,: e" g0 ~. Y9 l6 @$ S% J
.set_time = pcf8563_rtc_set_time,
, J7 z% b: z- B) x1 L}; x. J' R0 R! P% |5 I& Q
; q& p! J! \$ X% I
static int pcf8563_probe(struct i2c_client *client,# a& m3 |( G5 e; Y
const struct i2c_device_id *id)
& w' {. q% x* K8 l{
$ P* z1 ]8 p2 r8 \' P T struct pcf8563 *pcf8563;
; L% ~- f7 y2 @1 E: Z/ [: P9 z; q4 s! N6 ^
int err = 0;; {0 e* z) a. Z' m! }! _: Z
4 E! J1 \) _5 C
dev_dbg(&client->dev, "%s\n", __func__);2 C; c' B7 X; ]( t. c* N
+ S$ c; K5 h7 h5 K2 m if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
: ?9 g( b7 {/ h. L6 D: R return -ENODEV;
/ I7 Y+ N+ _" S* g) C2 ?2 m- O& L8 x$ N& k) Z/ M! s! ]: W
pcf8563 = kzalloc(sizeof(struct pcf8563), GFP_KERNEL);! w7 y; h- G" _% J: n
if (!pcf8563)& t' p$ O& [. w" I* d
return -ENOMEM;
9 n A; U) c& C i' [/ j1 o# W1 u; ]; T* L$ q* g
dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
# M5 ^3 z4 w$ d* {! }- X% g. j& o
) E. i! A1 g" J i2c_set_clientdata(client, pcf8563);6 \, {2 q1 P; |. b/ ]
p8 C6 y8 i" p( G5 j4 }/ Z pcf8563->rtc = rtc_device_register(pcf8563_driver.driver.name,2 H, p; A4 v9 ~
&client->dev, &pcf8563_rtc_ops, THIS_MODULE);
. E+ q6 t7 v8 i0 }$ W8 m* _+ [ J* J( r; `) c2 i0 {
if (IS_ERR(pcf8563->rtc)) {4 d3 o* E/ g7 g3 p* E+ ^8 r0 x0 H. p
err = PTR_ERR(pcf8563->rtc);$ F& z- w1 E. e- r6 a+ P7 T2 {
goto exit_kfree;
. H i" _5 I& r' C( d( C }# q I; i' S% ] G
0 c M9 Q# N8 u8 t; I
return 0;
' U. M" S v" f% B4 a
$ I0 R8 L- {# U- j2 rexit_kfree:3 l% N! O# g2 C: I7 r, U, h' g7 E
kfree(pcf8563);9 M) s. k$ W" q
0 W* Q$ y/ t# n( S, D0 \
return err;
5 f; y" v* y- g! `! N( e5 S}& D/ v0 @- x+ x) x9 b5 w. ~
: t! D& O& w+ w* b5 N9 n5 xstatic int pcf8563_remove(struct i2c_client *client)
& g& P, r% c6 s: g5 k \ @8 i{
; V+ k# r+ P N+ c struct pcf8563 *pcf8563 = i2c_get_clientdata(client);; I q* a1 k5 ?, A1 g
3 c" z/ s1 f5 M: L% o7 a; z* x" `
if (pcf8563->rtc)7 Z. d/ F9 Y# ]5 F* e% k4 c, s
rtc_device_unregister(pcf8563->rtc);
- d% \0 V" I# I* ?0 j8 l! V# ~5 d% J4 u: L6 k6 K
kfree(pcf8563);
* }+ Q7 g# k" ~% s6 o+ `$ @' \0 S7 D: z8 k
return 0;; z& Z$ v# D9 `9 x( Q( Q; o
}5 h# ^9 f1 F) Z4 u
$ t9 `( J+ m% m6 f7 R
static const struct i2c_device_id pcf8563_id[] = {
" V" O1 i4 g" I9 T( R { "pcf8563", 0 },# @/ f) [* d/ F& U6 P
{ "rtc8564", 0 },
9 k, Z$ V2 j% G c { }7 Z1 N, c. W3 c6 B4 N
};
8 T" {- q# l7 y! WMODULE_DEVICE_TABLE(i2c, pcf8563_id);
# J2 `6 J0 M: @. W& I
; a# l1 N L0 q* Istatic struct i2c_driver pcf8563_driver = {5 X% p1 x# Z m! a! w
.driver = {
- f6 @! U# u+ a% Q0 E% \( y .name = "rtc-pcf8563",
7 S6 U' a4 R8 N' M! d. v" L1 \% l },
1 m/ i6 M* w! D8 ^7 \; p* ~ .probe = pcf8563_probe,
! g% q* t O! x3 ] .remove = pcf8563_remove,0 ~0 w3 G$ {* \7 I8 p& e/ E5 r
.id_table = pcf8563_id,' B9 ] h2 w: x0 @0 l. E9 h# k: _
};# F) k1 s$ V8 s% k: n; N
6 a3 I" u h& |) K3 ystatic int __init pcf8563_init(void)
/ A" ?; }3 m7 J* u1 U; x{+ H( S& Z, L( C- k4 I
return i2c_add_driver(&pcf8563_driver);
/ W& n* C/ o' k2 L8 Z/ [}/ M" G- t, i6 |+ @ p/ ?+ {% J
5 z" n. a; v* ^; p5 ?! hstatic void __exit pcf8563_exit(void)
9 n( a2 j$ z' J @' g# t" E/ k{' F) h7 F# k8 X1 f% P1 Y
i2c_del_driver(&pcf8563_driver);
/ M0 @ G/ H7 `* s6 y}. j: g+ z6 X7 D& a6 U
: p& S( r9 k2 }$ K% z. d7 e7 B3 xMODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");3 q7 }& Q8 \4 U: f& w$ p# ?. n% X
MODULE_DESCRIPTION("Philips PCF8563/Epson RTC8564 RTC driver");
3 f% [1 Z' w1 y: b+ \2 qMODULE_LICENSE("GPL");
$ Q( n+ a- N4 S# k2 s, E, w" M" TMODULE_VERSION(DRV_VERSION);; Q' n+ }* y0 q- A: v
* L0 h! ^: M0 y
module_init(pcf8563_init);
3 [$ `2 s! t( A5 c# {module_exit(pcf8563_exit);
7 H) o. ]+ Y: w2 s5 r2 s |