Message ID | 1444982369-26046-1-git-send-email-hs@denx.de |
---|---|
State | Superseded, archived |
Headers | show |
Hi Heiko, [auto build test WARNING on abelloni/rtc-next -- if it's inappropriate base, please suggest rules for selecting the more suitable base] url: https://github.com/0day-ci/linux/commits/Heiko-Schocher/rtc-pcf8563-add-CLKOUT-to-common-clock-framework/20151016-160221 config: parisc-allyesconfig (attached as .config) reproduce: wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # save the attached .config to linux build tree make.cross ARCH=parisc All warnings (new ones prefixed by >>): drivers/rtc/rtc-pcf8563.c:87:17: error: field 'clkout_hw' has incomplete type struct clk_hw clkout_hw; ^ In file included from arch/parisc/include/asm/bug.h:4:0, from include/linux/bug.h:4, from include/linux/io.h:23, from include/linux/clk-provider.h:14, from drivers/rtc/rtc-pcf8563.c:17: drivers/rtc/rtc-pcf8563.c: In function 'pcf8563_clkout_recalc_rate': include/linux/kernel.h:811:48: warning: initialization from incompatible pointer type const typeof( ((type *)0)->member ) *__mptr = (ptr); \ ^ drivers/rtc/rtc-pcf8563.c:406:35: note: in expansion of macro 'container_of' #define clkout_hw_to_pcf8563(_hw) container_of(_hw, struct pcf8563, clkout_hw) ^ drivers/rtc/rtc-pcf8563.c:418:28: note: in expansion of macro 'clkout_hw_to_pcf8563' struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw); ^ >> include/linux/kernel.h:811:48: warning: (near initialization for 'pcf8563') const typeof( ((type *)0)->member ) *__mptr = (ptr); \ ^ drivers/rtc/rtc-pcf8563.c:406:35: note: in expansion of macro 'container_of' #define clkout_hw_to_pcf8563(_hw) container_of(_hw, struct pcf8563, clkout_hw) ^ drivers/rtc/rtc-pcf8563.c:418:28: note: in expansion of macro 'clkout_hw_to_pcf8563' struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw); ^ drivers/rtc/rtc-pcf8563.c: In function 'pcf8563_clkout_set_rate': include/linux/kernel.h:811:48: warning: initialization from incompatible pointer type const typeof( ((type *)0)->member ) *__mptr = (ptr); \ ^ drivers/rtc/rtc-pcf8563.c:406:35: note: in expansion of macro 'container_of' #define clkout_hw_to_pcf8563(_hw) container_of(_hw, struct pcf8563, clkout_hw) ^ drivers/rtc/rtc-pcf8563.c:445:28: note: in expansion of macro 'clkout_hw_to_pcf8563' struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw); ^ >> include/linux/kernel.h:811:48: warning: (near initialization for 'pcf8563') const typeof( ((type *)0)->member ) *__mptr = (ptr); \ ^ drivers/rtc/rtc-pcf8563.c:406:35: note: in expansion of macro 'container_of' #define clkout_hw_to_pcf8563(_hw) container_of(_hw, struct pcf8563, clkout_hw) ^ drivers/rtc/rtc-pcf8563.c:445:28: note: in expansion of macro 'clkout_hw_to_pcf8563' struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw); ^ drivers/rtc/rtc-pcf8563.c: In function 'pcf8563_clkout_control': include/linux/kernel.h:811:48: warning: initialization from incompatible pointer type const typeof( ((type *)0)->member ) *__mptr = (ptr); \ ^ drivers/rtc/rtc-pcf8563.c:406:35: note: in expansion of macro 'container_of' #define clkout_hw_to_pcf8563(_hw) container_of(_hw, struct pcf8563, clkout_hw) ^ drivers/rtc/rtc-pcf8563.c:469:28: note: in expansion of macro 'clkout_hw_to_pcf8563' struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw); ^ >> include/linux/kernel.h:811:48: warning: (near initialization for 'pcf8563') const typeof( ((type *)0)->member ) *__mptr = (ptr); \ ^ drivers/rtc/rtc-pcf8563.c:406:35: note: in expansion of macro 'container_of' #define clkout_hw_to_pcf8563(_hw) container_of(_hw, struct pcf8563, clkout_hw) ^ drivers/rtc/rtc-pcf8563.c:469:28: note: in expansion of macro 'clkout_hw_to_pcf8563' struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw); ^ drivers/rtc/rtc-pcf8563.c: In function 'pcf8563_clkout_is_prepared': include/linux/kernel.h:811:48: warning: initialization from incompatible pointer type const typeof( ((type *)0)->member ) *__mptr = (ptr); \ ^ drivers/rtc/rtc-pcf8563.c:406:35: note: in expansion of macro 'container_of' #define clkout_hw_to_pcf8563(_hw) container_of(_hw, struct pcf8563, clkout_hw) ^ drivers/rtc/rtc-pcf8563.c:498:28: note: in expansion of macro 'clkout_hw_to_pcf8563' struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw); ^ >> include/linux/kernel.h:811:48: warning: (near initialization for 'pcf8563') const typeof( ((type *)0)->member ) *__mptr = (ptr); \ ^ drivers/rtc/rtc-pcf8563.c:406:35: note: in expansion of macro 'container_of' #define clkout_hw_to_pcf8563(_hw) container_of(_hw, struct pcf8563, clkout_hw) ^ drivers/rtc/rtc-pcf8563.c:498:28: note: in expansion of macro 'clkout_hw_to_pcf8563' struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw); ^ drivers/rtc/rtc-pcf8563.c: At top level: drivers/rtc/rtc-pcf8563.c:509:21: error: variable 'pcf8563_clkout_ops' has initializer but incomplete type static const struct clk_ops pcf8563_clkout_ops = { ^ drivers/rtc/rtc-pcf8563.c:510:2: error: unknown field 'prepare' specified in initializer .prepare = pcf8563_clkout_prepare, ^ drivers/rtc/rtc-pcf8563.c:510:2: warning: excess elements in struct initializer >> drivers/rtc/rtc-pcf8563.c:510:2: warning: (near initialization for 'pcf8563_clkout_ops') drivers/rtc/rtc-pcf8563.c:511:2: error: unknown field 'unprepare' specified in initializer .unprepare = pcf8563_clkout_unprepare, ^ drivers/rtc/rtc-pcf8563.c:511:2: warning: excess elements in struct initializer drivers/rtc/rtc-pcf8563.c:511:2: warning: (near initialization for 'pcf8563_clkout_ops') drivers/rtc/rtc-pcf8563.c:512:2: error: unknown field 'is_prepared' specified in initializer .is_prepared = pcf8563_clkout_is_prepared, ^ drivers/rtc/rtc-pcf8563.c:512:2: warning: excess elements in struct initializer drivers/rtc/rtc-pcf8563.c:512:2: warning: (near initialization for 'pcf8563_clkout_ops') drivers/rtc/rtc-pcf8563.c:513:2: error: unknown field 'recalc_rate' specified in initializer .recalc_rate = pcf8563_clkout_recalc_rate, ^ drivers/rtc/rtc-pcf8563.c:513:2: warning: excess elements in struct initializer drivers/rtc/rtc-pcf8563.c:513:2: warning: (near initialization for 'pcf8563_clkout_ops') drivers/rtc/rtc-pcf8563.c:514:2: error: unknown field 'round_rate' specified in initializer .round_rate = pcf8563_clkout_round_rate, ^ drivers/rtc/rtc-pcf8563.c:514:2: warning: excess elements in struct initializer drivers/rtc/rtc-pcf8563.c:514:2: warning: (near initialization for 'pcf8563_clkout_ops') drivers/rtc/rtc-pcf8563.c:515:2: error: unknown field 'set_rate' specified in initializer .set_rate = pcf8563_clkout_set_rate, ^ drivers/rtc/rtc-pcf8563.c:515:2: warning: excess elements in struct initializer drivers/rtc/rtc-pcf8563.c:515:2: warning: (near initialization for 'pcf8563_clkout_ops') drivers/rtc/rtc-pcf8563.c: In function 'pcf8563_clkout_register_clk': drivers/rtc/rtc-pcf8563.c:523:23: error: storage size of 'init' isn't known struct clk_init_data init; ^ drivers/rtc/rtc-pcf8563.c:535:15: error: 'CLK_IS_ROOT' undeclared (first use in this function) init.flags = CLK_IS_ROOT; ^ drivers/rtc/rtc-pcf8563.c:535:15: note: each undeclared identifier is reported only once for each function it appears in drivers/rtc/rtc-pcf8563.c:544:2: error: implicit declaration of function 'clk_register' [-Werror=implicit-function-declaration] clk = clk_register(&client->dev, &pcf8563->clkout_hw); ^ drivers/rtc/rtc-pcf8563.c:547:3: error: implicit declaration of function 'of_clk_add_provider' [-Werror=implicit-function-declaration] of_clk_add_provider(node, of_clk_src_simple_get, clk); ^ drivers/rtc/rtc-pcf8563.c:547:29: error: 'of_clk_src_simple_get' undeclared (first use in this function) of_clk_add_provider(node, of_clk_src_simple_get, clk); ^ drivers/rtc/rtc-pcf8563.c:523:23: warning: unused variable 'init' [-Wunused-variable] struct clk_init_data init; ^ cc1: some warnings being treated as errors vim +/pcf8563_clkout_ops +510 drivers/rtc/rtc-pcf8563.c 503 if (ret < 0) 504 return ret; 505 506 return !!(buf & PCF8563_REG_CLKO_FE); 507 } 508 > 509 static const struct clk_ops pcf8563_clkout_ops = { > 510 .prepare = pcf8563_clkout_prepare, 511 .unprepare = pcf8563_clkout_unprepare, 512 .is_prepared = pcf8563_clkout_is_prepared, 513 .recalc_rate = pcf8563_clkout_recalc_rate, --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation
Hi Heiko, [auto build test WARNING on abelloni/rtc-next -- if it's inappropriate base, please suggest rules for selecting the more suitable base] url: https://github.com/0day-ci/linux/commits/Heiko-Schocher/rtc-pcf8563-add-CLKOUT-to-common-clock-framework/20151016-160221 config: sh-ap325rxa_defconfig (attached as .config) reproduce: wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # save the attached .config to linux build tree make.cross ARCH=sh All warnings (new ones prefixed by >>): drivers/rtc/rtc-pcf8563.c:87:17: error: field 'clkout_hw' has incomplete type drivers/rtc/rtc-pcf8563.c: In function 'pcf8563_clkout_recalc_rate': drivers/rtc/rtc-pcf8563.c:418:28: warning: initialization from incompatible pointer type [enabled by default] >> drivers/rtc/rtc-pcf8563.c:418:28: warning: (near initialization for 'pcf8563') [enabled by default] drivers/rtc/rtc-pcf8563.c: In function 'pcf8563_clkout_set_rate': drivers/rtc/rtc-pcf8563.c:445:28: warning: initialization from incompatible pointer type [enabled by default] drivers/rtc/rtc-pcf8563.c:445:28: warning: (near initialization for 'pcf8563') [enabled by default] drivers/rtc/rtc-pcf8563.c: In function 'pcf8563_clkout_control': drivers/rtc/rtc-pcf8563.c:469:28: warning: initialization from incompatible pointer type [enabled by default] drivers/rtc/rtc-pcf8563.c:469:28: warning: (near initialization for 'pcf8563') [enabled by default] drivers/rtc/rtc-pcf8563.c: In function 'pcf8563_clkout_is_prepared': drivers/rtc/rtc-pcf8563.c:498:28: warning: initialization from incompatible pointer type [enabled by default] drivers/rtc/rtc-pcf8563.c:498:28: warning: (near initialization for 'pcf8563') [enabled by default] drivers/rtc/rtc-pcf8563.c: At top level: drivers/rtc/rtc-pcf8563.c:509:21: error: variable 'pcf8563_clkout_ops' has initializer but incomplete type drivers/rtc/rtc-pcf8563.c:510:2: error: unknown field 'prepare' specified in initializer drivers/rtc/rtc-pcf8563.c:510:2: warning: excess elements in struct initializer [enabled by default] drivers/rtc/rtc-pcf8563.c:510:2: warning: (near initialization for 'pcf8563_clkout_ops') [enabled by default] drivers/rtc/rtc-pcf8563.c:511:2: error: unknown field 'unprepare' specified in initializer drivers/rtc/rtc-pcf8563.c:511:2: warning: excess elements in struct initializer [enabled by default] drivers/rtc/rtc-pcf8563.c:511:2: warning: (near initialization for 'pcf8563_clkout_ops') [enabled by default] drivers/rtc/rtc-pcf8563.c:512:2: error: unknown field 'is_prepared' specified in initializer drivers/rtc/rtc-pcf8563.c:512:2: warning: excess elements in struct initializer [enabled by default] drivers/rtc/rtc-pcf8563.c:512:2: warning: (near initialization for 'pcf8563_clkout_ops') [enabled by default] drivers/rtc/rtc-pcf8563.c:513:2: error: unknown field 'recalc_rate' specified in initializer drivers/rtc/rtc-pcf8563.c:513:2: warning: excess elements in struct initializer [enabled by default] drivers/rtc/rtc-pcf8563.c:513:2: warning: (near initialization for 'pcf8563_clkout_ops') [enabled by default] drivers/rtc/rtc-pcf8563.c:514:2: error: unknown field 'round_rate' specified in initializer drivers/rtc/rtc-pcf8563.c:514:2: warning: excess elements in struct initializer [enabled by default] drivers/rtc/rtc-pcf8563.c:514:2: warning: (near initialization for 'pcf8563_clkout_ops') [enabled by default] drivers/rtc/rtc-pcf8563.c:515:2: error: unknown field 'set_rate' specified in initializer drivers/rtc/rtc-pcf8563.c:515:2: warning: excess elements in struct initializer [enabled by default] drivers/rtc/rtc-pcf8563.c:515:2: warning: (near initialization for 'pcf8563_clkout_ops') [enabled by default] drivers/rtc/rtc-pcf8563.c: In function 'pcf8563_clkout_register_clk': drivers/rtc/rtc-pcf8563.c:523:23: error: storage size of 'init' isn't known drivers/rtc/rtc-pcf8563.c:535:15: error: 'CLK_IS_ROOT' undeclared (first use in this function) drivers/rtc/rtc-pcf8563.c:535:15: note: each undeclared identifier is reported only once for each function it appears in drivers/rtc/rtc-pcf8563.c:544:2: error: implicit declaration of function 'clk_register' [-Werror=implicit-function-declaration] drivers/rtc/rtc-pcf8563.c:547:3: error: implicit declaration of function 'of_clk_add_provider' [-Werror=implicit-function-declaration] drivers/rtc/rtc-pcf8563.c:547:29: error: 'of_clk_src_simple_get' undeclared (first use in this function) drivers/rtc/rtc-pcf8563.c:523:23: warning: unused variable 'init' [-Wunused-variable] cc1: some warnings being treated as errors vim +/pcf8563 +418 drivers/rtc/rtc-pcf8563.c 402 /* 403 * Handling of the clkout 404 */ 405 406 #define clkout_hw_to_pcf8563(_hw) container_of(_hw, struct pcf8563, clkout_hw) 407 408 static int clkout_rates[] = { 409 32768, 410 1024, 411 32, 412 1, 413 }; 414 415 static unsigned long pcf8563_clkout_recalc_rate(struct clk_hw *hw, 416 unsigned long parent_rate) 417 { > 418 struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw); 419 struct i2c_client *client = pcf8563->client; 420 unsigned char buf; 421 int ret = pcf8563_read_block_data(client, PCF8563_REG_CLKO, 1, &buf); 422 423 if (ret < 0) 424 return 0; 425 426 buf &= PCF8563_REG_CLKO_F_MASK; --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation
Hi, On 16/10/2015 at 09:59:29 +0200, Heiko Schocher wrote : > Add the clkout output clk to the common clock framework. > Disable the CLKOUT of the RTC after power-up. > After power-up/reset of the RTC, CLKOUT is enabled by default, > with CLKOUT enabled the RTC chip has 2-3 times higher power > consumption. > > Signed-off-by: Heiko Schocher <hs@denx.de> > --- > > Changes in v2: > - add comments from Alexandre Belloni > - remove the DT property, instead > register for the CLKOUT a clk in the common > clk framework. The clk is disabled by default. > > Documentation/devicetree/bindings/rtc/pcf8563.txt | 28 ++++ > drivers/rtc/rtc-pcf8563.c | 164 +++++++++++++++++++++- > 2 files changed, 191 insertions(+), 1 deletion(-) > create mode 100644 Documentation/devicetree/bindings/rtc/pcf8563.txt > > diff --git a/Documentation/devicetree/bindings/rtc/pcf8563.txt b/Documentation/devicetree/bindings/rtc/pcf8563.txt > new file mode 100644 > index 0000000..cdb81ef > --- /dev/null > +++ b/Documentation/devicetree/bindings/rtc/pcf8563.txt > @@ -0,0 +1,28 @@ > +* Philips PCF8563/Epson RTC8564 Real Time Clock > + > +Philips PCF8563/Epson RTC8564 Real Time Clock > + > +Required properties: > +see: Documentation/devicetree/bindings/i2c/trivial-devices.txt > + > +Optional property: > +- #clock-cells: Should be 1. > +- clocks: Reference to the clock entry. > +- clock-output-names: > + overwrite the default clock name "pcf8563-clkout" > + > +Example: > + > +rtcclk: rtcclk { > + compatible = "fixed-clock"; > + #clock-cells = <1>; > + clock-frequency = <1>; > + clock-output-names = "rtcclk"; > +}; > + > +pcf8563@51 { > + compatible = "nxp,pcf8563"; > + reg = <0x51>; > + #clock-cells = <1>; > + clocks = <&rtcclk 0>; > +}; You don't seem to be using rtcclk, I would remove it from the example. > +static struct clk *pcf8563_clkout_register_clk(struct pcf8563 *pcf8563) > +{ > + struct i2c_client *client = pcf8563->client; > + struct device_node *node = client->dev.of_node; > + struct clk *clk; > + struct clk_init_data init; > + int ret; > + unsigned char buf; > + > + /* disable the clkout output */ > + buf = 0; > + ret = pcf8563_write_block_data(client, PCF8563_REG_CLKO, 1, &buf); > + if (ret < 0) > + return ERR_PTR(ret); > + Isn't that done automatically for an unused clock? However, I would do that in the probe as you will have to sprinkle some #ifdef CONFIG_COMMON_CLK after seeing the kbuild report. > > + /* register clk in common clk framework */ > + pcf8563_clkout_register_clk(pcf8563); > + > /* the pcf8563 alarm only supports a minute accuracy */ > pcf8563->rtc->uie_unsupported = 1; > You probably need to unregister the clock at some point. Maybe using devm_clk_register() is the best thing to do.
On 16/10/2015 at 12:54:46 +0200, Alexandre Belloni wrote : > > +static struct clk *pcf8563_clkout_register_clk(struct pcf8563 *pcf8563) > > +{ > > + struct i2c_client *client = pcf8563->client; > > + struct device_node *node = client->dev.of_node; > > + struct clk *clk; > > + struct clk_init_data init; > > + int ret; > > + unsigned char buf; > > + > > + /* disable the clkout output */ > > + buf = 0; > > + ret = pcf8563_write_block_data(client, PCF8563_REG_CLKO, 1, &buf); > > + if (ret < 0) > > + return ERR_PTR(ret); > > + > > Isn't that done automatically for an unused clock? However, I would do > that in the probe as you will have to sprinkle some #ifdef > CONFIG_COMMON_CLK after seeing the kbuild report. I'm rethinking about your comment about breaking existing boards. I'd say that probably nobody is using the output from the rtc but maybe (highly unlikely) some are configuring it from the bootloader and in that case it is not nice to undo that configuration. Let's keep that block here as long as it works fine for you.
Hello Alexandre, Am 16.10.2015 um 13:00 schrieb Alexandre Belloni: > On 16/10/2015 at 12:54:46 +0200, Alexandre Belloni wrote : >>> +static struct clk *pcf8563_clkout_register_clk(struct pcf8563 *pcf8563) >>> +{ >>> + struct i2c_client *client = pcf8563->client; >>> + struct device_node *node = client->dev.of_node; >>> + struct clk *clk; >>> + struct clk_init_data init; >>> + int ret; >>> + unsigned char buf; >>> + >>> + /* disable the clkout output */ >>> + buf = 0; >>> + ret = pcf8563_write_block_data(client, PCF8563_REG_CLKO, 1, &buf); >>> + if (ret < 0) >>> + return ERR_PTR(ret); >>> + >> >> Isn't that done automatically for an unused clock? However, I would do >> that in the probe as you will have to sprinkle some #ifdef >> CONFIG_COMMON_CLK after seeing the kbuild report. > > I'm rethinking about your comment about breaking existing boards. I'd > say that probably nobody is using the output from the rtc but maybe > (highly unlikely) some are configuring it from the bootloader and in > that case it is not nice to undo that configuration. Let's keep that > block here as long as it works fine for you. Ok, so I have also a better feeling with it ... removing it back ;-) bye, Heiko
diff --git a/Documentation/devicetree/bindings/rtc/pcf8563.txt b/Documentation/devicetree/bindings/rtc/pcf8563.txt new file mode 100644 index 0000000..cdb81ef --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/pcf8563.txt @@ -0,0 +1,28 @@ +* Philips PCF8563/Epson RTC8564 Real Time Clock + +Philips PCF8563/Epson RTC8564 Real Time Clock + +Required properties: +see: Documentation/devicetree/bindings/i2c/trivial-devices.txt + +Optional property: +- #clock-cells: Should be 1. +- clocks: Reference to the clock entry. +- clock-output-names: + overwrite the default clock name "pcf8563-clkout" + +Example: + +rtcclk: rtcclk { + compatible = "fixed-clock"; + #clock-cells = <1>; + clock-frequency = <1>; + clock-output-names = "rtcclk"; +}; + +pcf8563@51 { + compatible = "nxp,pcf8563"; + reg = <0x51>; + #clock-cells = <1>; + clocks = <&rtcclk 0>; +}; diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index e569243..0c2f85f 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -14,6 +14,7 @@ * published by the Free Software Foundation. */ +#include <linux/clk-provider.h> #include <linux/i2c.h> #include <linux/bcd.h> #include <linux/rtc.h> @@ -40,7 +41,14 @@ #define PCF8563_REG_AMN 0x09 /* alarm */ -#define PCF8563_REG_CLKO 0x0D /* clock out */ +#define PCF8563_REG_CLKO 0x0D /* clock out */ +#define PCF8563_REG_CLKO_FE 0x80 /* clock out enabled */ +#define PCF8563_REG_CLKO_F_MASK 0x03 /* frequenc mask */ +#define PCF8563_REG_CLKO_F_32768HZ 0x00 +#define PCF8563_REG_CLKO_F_1024HZ 0x01 +#define PCF8563_REG_CLKO_F_32HZ 0x02 +#define PCF8563_REG_CLKO_F_1HZ 0x03 + #define PCF8563_REG_TMRC 0x0E /* timer control */ #define PCF8563_TMRC_ENABLE BIT(7) #define PCF8563_TMRC_4096 0 @@ -76,6 +84,7 @@ struct pcf8563 { int voltage_low; /* incicates if a low_voltage was detected */ struct i2c_client *client; + struct clk_hw clkout_hw; }; static int pcf8563_read_block_data(struct i2c_client *client, unsigned char reg, @@ -390,6 +399,156 @@ static int pcf8563_irq_enable(struct device *dev, unsigned int enabled) return pcf8563_set_alarm_mode(to_i2c_client(dev), !!enabled); } +/* + * Handling of the clkout + */ + +#define clkout_hw_to_pcf8563(_hw) container_of(_hw, struct pcf8563, clkout_hw) + +static int clkout_rates[] = { + 32768, + 1024, + 32, + 1, +}; + +static unsigned long pcf8563_clkout_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw); + struct i2c_client *client = pcf8563->client; + unsigned char buf; + int ret = pcf8563_read_block_data(client, PCF8563_REG_CLKO, 1, &buf); + + if (ret < 0) + return 0; + + buf &= PCF8563_REG_CLKO_F_MASK; + return clkout_rates[ret]; +} + +static long pcf8563_clkout_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(clkout_rates); i++) + if (clkout_rates[i] <= rate) + return clkout_rates[i]; + + return 0; +} + +static int pcf8563_clkout_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw); + struct i2c_client *client = pcf8563->client; + unsigned char buf; + int ret = pcf8563_read_block_data(client, PCF8563_REG_CLKO, 1, &buf); + int i; + + if (ret < 0) + return ret; + + for (i = 0; i < ARRAY_SIZE(clkout_rates); i++) + if (clkout_rates[i] == rate) { + buf &= ~PCF8563_REG_CLKO_F_MASK; + buf |= i; + ret = pcf8563_write_block_data(client, + PCF8563_REG_CLKO, 1, + &buf); + return ret; + } + + return -EINVAL; +} + +static int pcf8563_clkout_control(struct clk_hw *hw, bool enable) +{ + struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw); + struct i2c_client *client = pcf8563->client; + unsigned char buf; + int ret = pcf8563_read_block_data(client, PCF8563_REG_CLKO, 1, &buf); + + if (ret < 0) + return ret; + + if (enable) + buf |= PCF8563_REG_CLKO_FE; + else + buf &= ~PCF8563_REG_CLKO_FE; + + ret = pcf8563_write_block_data(client, PCF8563_REG_CLKO, 1, &buf); + return ret; +} + +static int pcf8563_clkout_prepare(struct clk_hw *hw) +{ + return pcf8563_clkout_control(hw, 1); +} + +static void pcf8563_clkout_unprepare(struct clk_hw *hw) +{ + pcf8563_clkout_control(hw, 0); +} + +static int pcf8563_clkout_is_prepared(struct clk_hw *hw) +{ + struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw); + struct i2c_client *client = pcf8563->client; + unsigned char buf; + int ret = pcf8563_read_block_data(client, PCF8563_REG_CLKO, 1, &buf); + + if (ret < 0) + return ret; + + return !!(buf & PCF8563_REG_CLKO_FE); +} + +static const struct clk_ops pcf8563_clkout_ops = { + .prepare = pcf8563_clkout_prepare, + .unprepare = pcf8563_clkout_unprepare, + .is_prepared = pcf8563_clkout_is_prepared, + .recalc_rate = pcf8563_clkout_recalc_rate, + .round_rate = pcf8563_clkout_round_rate, + .set_rate = pcf8563_clkout_set_rate, +}; + +static struct clk *pcf8563_clkout_register_clk(struct pcf8563 *pcf8563) +{ + struct i2c_client *client = pcf8563->client; + struct device_node *node = client->dev.of_node; + struct clk *clk; + struct clk_init_data init; + int ret; + unsigned char buf; + + /* disable the clkout output */ + buf = 0; + ret = pcf8563_write_block_data(client, PCF8563_REG_CLKO, 1, &buf); + if (ret < 0) + return ERR_PTR(ret); + + init.name = "pcf8563-clkout"; + init.ops = &pcf8563_clkout_ops; + init.flags = CLK_IS_ROOT; + init.parent_names = NULL; + init.num_parents = 0; + pcf8563->clkout_hw.init = &init; + + /* optional override of the clockname */ + of_property_read_string(node, "clock-output-names", &init.name); + + /* register the clock */ + clk = clk_register(&client->dev, &pcf8563->clkout_hw); + + if (!IS_ERR(clk)) + of_clk_add_provider(node, of_clk_src_simple_get, clk); + + return clk; +} + static const struct rtc_class_ops pcf8563_rtc_ops = { .ioctl = pcf8563_rtc_ioctl, .read_time = pcf8563_rtc_read_time, @@ -459,6 +618,9 @@ static int pcf8563_probe(struct i2c_client *client, } + /* register clk in common clk framework */ + pcf8563_clkout_register_clk(pcf8563); + /* the pcf8563 alarm only supports a minute accuracy */ pcf8563->rtc->uie_unsupported = 1;
Add the clkout output clk to the common clock framework. Disable the CLKOUT of the RTC after power-up. After power-up/reset of the RTC, CLKOUT is enabled by default, with CLKOUT enabled the RTC chip has 2-3 times higher power consumption. Signed-off-by: Heiko Schocher <hs@denx.de> --- Changes in v2: - add comments from Alexandre Belloni - remove the DT property, instead register for the CLKOUT a clk in the common clk framework. The clk is disabled by default. Documentation/devicetree/bindings/rtc/pcf8563.txt | 28 ++++ drivers/rtc/rtc-pcf8563.c | 164 +++++++++++++++++++++- 2 files changed, 191 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/rtc/pcf8563.txt