aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/rtc')
-rw-r--r--drivers/rtc/Kconfig33
-rw-r--r--drivers/rtc/Makefile4
-rw-r--r--drivers/rtc/rtc-generic.c84
-rw-r--r--drivers/rtc/rtc-m41t80.c18
-rw-r--r--drivers/rtc/rtc-parisc.c86
-rw-r--r--drivers/rtc/rtc-ppc.c69
-rw-r--r--drivers/rtc/rtc-ps3.c104
-rw-r--r--drivers/rtc/rtc-v3020.c190
8 files changed, 391 insertions, 197 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 09d5cd33a3f6..ffe34a12f446 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -225,11 +225,11 @@ config RTC_DRV_PCF8583
225 will be called rtc-pcf8583. 225 will be called rtc-pcf8583.
226 226
227config RTC_DRV_M41T80 227config RTC_DRV_M41T80
228 tristate "ST M41T65/M41T80/81/82/83/84/85/87" 228 tristate "ST M41T62/65/M41T80/81/82/83/84/85/87"
229 help 229 help
230 If you say Y here you will get support for the ST M41T60 230 If you say Y here you will get support for the ST M41T60
231 and M41T80 RTC chips series. Currently, the following chips are 231 and M41T80 RTC chips series. Currently, the following chips are
232 supported: M41T65, M41T80, M41T81, M41T82, M41T83, M41ST84, 232 supported: M41T62, M41T65, M41T80, M41T81, M41T82, M41T83, M41ST84,
233 M41ST85, and M41ST87. 233 M41ST85, and M41ST87.
234 234
235 This driver can also be built as a module. If so, the module 235 This driver can also be built as a module. If so, the module
@@ -688,22 +688,16 @@ config RTC_DRV_RS5C313
688 help 688 help
689 If you say yes here you get support for the Ricoh RS5C313 RTC chips. 689 If you say yes here you get support for the Ricoh RS5C313 RTC chips.
690 690
691config RTC_DRV_PARISC 691config RTC_DRV_GENERIC
692 tristate "PA-RISC firmware RTC support" 692 tristate "Generic RTC support"
693 depends on PARISC 693 # Please consider writing a new RTC driver instead of using the generic
694 # RTC abstraction
695 depends on PARISC || M68K || PPC
694 help 696 help
695 Say Y or M here to enable RTC support on PA-RISC systems using 697 Say Y or M here to enable RTC support on systems using the generic
696 firmware calls. If you do not know what you are doing, you should 698 RTC abstraction. If you do not know what you are doing, you should
697 just say Y. 699 just say Y.
698 700
699config RTC_DRV_PPC
700 tristate "PowerPC machine dependent RTC support"
701 depends on PPC
702 help
703 The PowerPC kernel has machine-specific functions for accessing
704 the RTC. This exposes that functionality through the generic RTC
705 class.
706
707config RTC_DRV_PXA 701config RTC_DRV_PXA
708 tristate "PXA27x/PXA3xx" 702 tristate "PXA27x/PXA3xx"
709 depends on ARCH_PXA 703 depends on ARCH_PXA
@@ -747,4 +741,13 @@ config RTC_DRV_MV
747 This driver can also be built as a module. If so, the module 741 This driver can also be built as a module. If so, the module
748 will be called rtc-mv. 742 will be called rtc-mv.
749 743
744config RTC_DRV_PS3
745 tristate "PS3 RTC"
746 depends on PPC_PS3
747 help
748 If you say yes here you will get support for the RTC on PS3.
749
750 This driver can also be built as a module. If so, the module
751 will be called rtc-ps3.
752
750endif # RTC_CLASS 753endif # RTC_CLASS
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index e7b09986d26e..6c0639a14f09 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -56,8 +56,7 @@ obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o
56obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o 56obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o
57obj-$(CONFIG_RTC_DRV_PL030) += rtc-pl030.o 57obj-$(CONFIG_RTC_DRV_PL030) += rtc-pl030.o
58obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o 58obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o
59obj-$(CONFIG_RTC_DRV_PARISC) += rtc-parisc.o 59obj-$(CONFIG_RTC_DRV_GENERIC) += rtc-generic.o
60obj-$(CONFIG_RTC_DRV_PPC) += rtc-ppc.o
61obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o 60obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o
62obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o 61obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o
63obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o 62obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o
@@ -77,3 +76,4 @@ obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o
77obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o 76obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o
78obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o 77obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
79obj-$(CONFIG_RTC_DRV_PCF50633) += rtc-pcf50633.o 78obj-$(CONFIG_RTC_DRV_PCF50633) += rtc-pcf50633.o
79obj-$(CONFIG_RTC_DRV_PS3) += rtc-ps3.o
diff --git a/drivers/rtc/rtc-generic.c b/drivers/rtc/rtc-generic.c
new file mode 100644
index 000000000000..98322004ad2e
--- /dev/null
+++ b/drivers/rtc/rtc-generic.c
@@ -0,0 +1,84 @@
1/* rtc-generic: RTC driver using the generic RTC abstraction
2 *
3 * Copyright (C) 2008 Kyle McMartin <kyle@mcmartin.ca>
4 */
5
6#include <linux/kernel.h>
7#include <linux/module.h>
8#include <linux/time.h>
9#include <linux/platform_device.h>
10#include <linux/rtc.h>
11
12#include <asm/rtc.h>
13
14static int generic_get_time(struct device *dev, struct rtc_time *tm)
15{
16 unsigned int ret = get_rtc_time(tm);
17
18 if (ret & RTC_BATT_BAD)
19 return -EOPNOTSUPP;
20
21 return rtc_valid_tm(tm);
22}
23
24static int generic_set_time(struct device *dev, struct rtc_time *tm)
25{
26 if (set_rtc_time(tm) < 0)
27 return -EOPNOTSUPP;
28
29 return 0;
30}
31
32static const struct rtc_class_ops generic_rtc_ops = {
33 .read_time = generic_get_time,
34 .set_time = generic_set_time,
35};
36
37static int __init generic_rtc_probe(struct platform_device *dev)
38{
39 struct rtc_device *rtc;
40
41 rtc = rtc_device_register("rtc-generic", &dev->dev, &generic_rtc_ops,
42 THIS_MODULE);
43 if (IS_ERR(rtc))
44 return PTR_ERR(rtc);
45
46 platform_set_drvdata(dev, rtc);
47
48 return 0;
49}
50
51static int __exit generic_rtc_remove(struct platform_device *dev)
52{
53 struct rtc_device *rtc = platform_get_drvdata(dev);
54
55 rtc_device_unregister(rtc);
56
57 return 0;
58}
59
60static struct platform_driver generic_rtc_driver = {
61 .driver = {
62 .name = "rtc-generic",
63 .owner = THIS_MODULE,
64 },
65 .remove = __exit_p(generic_rtc_remove),
66};
67
68static int __init generic_rtc_init(void)
69{
70 return platform_driver_probe(&generic_rtc_driver, generic_rtc_probe);
71}
72
73static void __exit generic_rtc_fini(void)
74{
75 platform_driver_unregister(&generic_rtc_driver);
76}
77
78module_init(generic_rtc_init);
79module_exit(generic_rtc_fini);
80
81MODULE_AUTHOR("Kyle McMartin <kyle@mcmartin.ca>");
82MODULE_LICENSE("GPL");
83MODULE_DESCRIPTION("Generic RTC driver");
84MODULE_ALIAS("platform:rtc-generic");
diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c
index 893f7dece239..60fe266f0f49 100644
--- a/drivers/rtc/rtc-m41t80.c
+++ b/drivers/rtc/rtc-m41t80.c
@@ -64,10 +64,12 @@
64#define M41T80_FEATURE_BL (1 << 1) /* Battery low indicator */ 64#define M41T80_FEATURE_BL (1 << 1) /* Battery low indicator */
65#define M41T80_FEATURE_SQ (1 << 2) /* Squarewave feature */ 65#define M41T80_FEATURE_SQ (1 << 2) /* Squarewave feature */
66#define M41T80_FEATURE_WD (1 << 3) /* Extra watchdog resolution */ 66#define M41T80_FEATURE_WD (1 << 3) /* Extra watchdog resolution */
67#define M41T80_FEATURE_SQ_ALT (1 << 4) /* RSx bits are in reg 4 */
67 68
68#define DRV_VERSION "0.05" 69#define DRV_VERSION "0.05"
69 70
70static const struct i2c_device_id m41t80_id[] = { 71static const struct i2c_device_id m41t80_id[] = {
72 { "m41t62", M41T80_FEATURE_SQ | M41T80_FEATURE_SQ_ALT },
71 { "m41t65", M41T80_FEATURE_HT | M41T80_FEATURE_WD }, 73 { "m41t65", M41T80_FEATURE_HT | M41T80_FEATURE_WD },
72 { "m41t80", M41T80_FEATURE_SQ }, 74 { "m41t80", M41T80_FEATURE_SQ },
73 { "m41t81", M41T80_FEATURE_HT | M41T80_FEATURE_SQ}, 75 { "m41t81", M41T80_FEATURE_HT | M41T80_FEATURE_SQ},
@@ -393,12 +395,15 @@ static ssize_t m41t80_sysfs_show_sqwfreq(struct device *dev,
393{ 395{
394 struct i2c_client *client = to_i2c_client(dev); 396 struct i2c_client *client = to_i2c_client(dev);
395 struct m41t80_data *clientdata = i2c_get_clientdata(client); 397 struct m41t80_data *clientdata = i2c_get_clientdata(client);
396 int val; 398 int val, reg_sqw;
397 399
398 if (!(clientdata->features & M41T80_FEATURE_SQ)) 400 if (!(clientdata->features & M41T80_FEATURE_SQ))
399 return -EINVAL; 401 return -EINVAL;
400 402
401 val = i2c_smbus_read_byte_data(client, M41T80_REG_SQW); 403 reg_sqw = M41T80_REG_SQW;
404 if (clientdata->features & M41T80_FEATURE_SQ_ALT)
405 reg_sqw = M41T80_REG_WDAY;
406 val = i2c_smbus_read_byte_data(client, reg_sqw);
402 if (val < 0) 407 if (val < 0)
403 return -EIO; 408 return -EIO;
404 val = (val >> 4) & 0xf; 409 val = (val >> 4) & 0xf;
@@ -419,7 +424,7 @@ static ssize_t m41t80_sysfs_set_sqwfreq(struct device *dev,
419{ 424{
420 struct i2c_client *client = to_i2c_client(dev); 425 struct i2c_client *client = to_i2c_client(dev);
421 struct m41t80_data *clientdata = i2c_get_clientdata(client); 426 struct m41t80_data *clientdata = i2c_get_clientdata(client);
422 int almon, sqw; 427 int almon, sqw, reg_sqw;
423 int val = simple_strtoul(buf, NULL, 0); 428 int val = simple_strtoul(buf, NULL, 0);
424 429
425 if (!(clientdata->features & M41T80_FEATURE_SQ)) 430 if (!(clientdata->features & M41T80_FEATURE_SQ))
@@ -440,13 +445,16 @@ static ssize_t m41t80_sysfs_set_sqwfreq(struct device *dev,
440 almon = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON); 445 almon = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
441 if (almon < 0) 446 if (almon < 0)
442 return -EIO; 447 return -EIO;
443 sqw = i2c_smbus_read_byte_data(client, M41T80_REG_SQW); 448 reg_sqw = M41T80_REG_SQW;
449 if (clientdata->features & M41T80_FEATURE_SQ_ALT)
450 reg_sqw = M41T80_REG_WDAY;
451 sqw = i2c_smbus_read_byte_data(client, reg_sqw);
444 if (sqw < 0) 452 if (sqw < 0)
445 return -EIO; 453 return -EIO;
446 sqw = (sqw & 0x0f) | (val << 4); 454 sqw = (sqw & 0x0f) | (val << 4);
447 if (i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, 455 if (i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
448 almon & ~M41T80_ALMON_SQWE) < 0 || 456 almon & ~M41T80_ALMON_SQWE) < 0 ||
449 i2c_smbus_write_byte_data(client, M41T80_REG_SQW, sqw) < 0) 457 i2c_smbus_write_byte_data(client, reg_sqw, sqw) < 0)
450 return -EIO; 458 return -EIO;
451 if (val && i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, 459 if (val && i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
452 almon | M41T80_ALMON_SQWE) < 0) 460 almon | M41T80_ALMON_SQWE) < 0)
diff --git a/drivers/rtc/rtc-parisc.c b/drivers/rtc/rtc-parisc.c
deleted file mode 100644
index b966f56da976..000000000000
--- a/drivers/rtc/rtc-parisc.c
+++ /dev/null
@@ -1,86 +0,0 @@
1/* rtc-parisc: RTC for HP PA-RISC firmware
2 *
3 * Copyright (C) 2008 Kyle McMartin <kyle@mcmartin.ca>
4 */
5
6#include <linux/kernel.h>
7#include <linux/module.h>
8#include <linux/time.h>
9#include <linux/platform_device.h>
10#include <linux/rtc.h>
11
12#include <asm/rtc.h>
13
14static int parisc_get_time(struct device *dev, struct rtc_time *tm)
15{
16 unsigned long ret;
17
18 ret = get_rtc_time(tm);
19
20 if (ret & RTC_BATT_BAD)
21 return -EOPNOTSUPP;
22
23 return rtc_valid_tm(tm);
24}
25
26static int parisc_set_time(struct device *dev, struct rtc_time *tm)
27{
28 if (set_rtc_time(tm) < 0)
29 return -EOPNOTSUPP;
30
31 return 0;
32}
33
34static const struct rtc_class_ops parisc_rtc_ops = {
35 .read_time = parisc_get_time,
36 .set_time = parisc_set_time,
37};
38
39static int __init parisc_rtc_probe(struct platform_device *dev)
40{
41 struct rtc_device *rtc;
42
43 rtc = rtc_device_register("rtc-parisc", &dev->dev, &parisc_rtc_ops,
44 THIS_MODULE);
45 if (IS_ERR(rtc))
46 return PTR_ERR(rtc);
47
48 platform_set_drvdata(dev, rtc);
49
50 return 0;
51}
52
53static int __exit parisc_rtc_remove(struct platform_device *dev)
54{
55 struct rtc_device *rtc = platform_get_drvdata(dev);
56
57 rtc_device_unregister(rtc);
58
59 return 0;
60}
61
62static struct platform_driver parisc_rtc_driver = {
63 .driver = {
64 .name = "rtc-parisc",
65 .owner = THIS_MODULE,
66 },
67 .probe = parisc_rtc_probe,
68 .remove = __devexit_p(parisc_rtc_remove),
69};
70
71static int __init parisc_rtc_init(void)
72{
73 return platform_driver_probe(&parisc_rtc_driver, parisc_rtc_probe);
74}
75
76static void __exit parisc_rtc_fini(void)
77{
78 platform_driver_unregister(&parisc_rtc_driver);
79}
80
81module_init(parisc_rtc_init);
82module_exit(parisc_rtc_fini);
83
84MODULE_AUTHOR("Kyle McMartin <kyle@mcmartin.ca>");
85MODULE_LICENSE("GPL");
86MODULE_DESCRIPTION("HP PA-RISC RTC driver");
diff --git a/drivers/rtc/rtc-ppc.c b/drivers/rtc/rtc-ppc.c
deleted file mode 100644
index c8e97e25ef7e..000000000000
--- a/drivers/rtc/rtc-ppc.c
+++ /dev/null
@@ -1,69 +0,0 @@
1/*
2 * RTC driver for ppc_md RTC functions
3 *
4 * © 2007 Red Hat, Inc.
5 *
6 * Author: David Woodhouse <dwmw2@infradead.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13
14#include <linux/module.h>
15#include <linux/err.h>
16#include <linux/rtc.h>
17#include <linux/platform_device.h>
18#include <asm/machdep.h>
19
20static int ppc_rtc_read_time(struct device *dev, struct rtc_time *tm)
21{
22 ppc_md.get_rtc_time(tm);
23 return 0;
24}
25
26static int ppc_rtc_set_time(struct device *dev, struct rtc_time *tm)
27{
28 return ppc_md.set_rtc_time(tm);
29}
30
31static const struct rtc_class_ops ppc_rtc_ops = {
32 .set_time = ppc_rtc_set_time,
33 .read_time = ppc_rtc_read_time,
34};
35
36static struct rtc_device *rtc;
37static struct platform_device *ppc_rtc_pdev;
38
39static int __init ppc_rtc_init(void)
40{
41 if (!ppc_md.get_rtc_time || !ppc_md.set_rtc_time)
42 return -ENODEV;
43
44 ppc_rtc_pdev = platform_device_register_simple("ppc-rtc", 0, NULL, 0);
45 if (IS_ERR(ppc_rtc_pdev))
46 return PTR_ERR(ppc_rtc_pdev);
47
48 rtc = rtc_device_register("ppc_md", &ppc_rtc_pdev->dev,
49 &ppc_rtc_ops, THIS_MODULE);
50 if (IS_ERR(rtc)) {
51 platform_device_unregister(ppc_rtc_pdev);
52 return PTR_ERR(rtc);
53 }
54
55 return 0;
56}
57
58static void __exit ppc_rtc_exit(void)
59{
60 rtc_device_unregister(rtc);
61 platform_device_unregister(ppc_rtc_pdev);
62}
63
64module_init(ppc_rtc_init);
65module_exit(ppc_rtc_exit);
66
67MODULE_LICENSE("GPL");
68MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
69MODULE_DESCRIPTION("Generic RTC class driver for PowerPC");
diff --git a/drivers/rtc/rtc-ps3.c b/drivers/rtc/rtc-ps3.c
new file mode 100644
index 000000000000..968133ce1ee8
--- /dev/null
+++ b/drivers/rtc/rtc-ps3.c
@@ -0,0 +1,104 @@
1/*
2 * PS3 RTC Driver
3 *
4 * Copyright 2009 Sony Corporation
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program.
17 * If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <linux/kernel.h>
21#include <linux/module.h>
22#include <linux/platform_device.h>
23#include <linux/rtc.h>
24
25#include <asm/lv1call.h>
26#include <asm/ps3.h>
27
28
29static u64 read_rtc(void)
30{
31 int result;
32 u64 rtc_val;
33 u64 tb_val;
34
35 result = lv1_get_rtc(&rtc_val, &tb_val);
36 BUG_ON(result);
37
38 return rtc_val;
39}
40
41static int ps3_get_time(struct device *dev, struct rtc_time *tm)
42{
43 rtc_time_to_tm(read_rtc() + ps3_os_area_get_rtc_diff(), tm);
44 return rtc_valid_tm(tm);
45}
46
47static int ps3_set_time(struct device *dev, struct rtc_time *tm)
48{
49 unsigned long now;
50
51 rtc_tm_to_time(tm, &now);
52 ps3_os_area_set_rtc_diff(now - read_rtc());
53 return 0;
54}
55
56static const struct rtc_class_ops ps3_rtc_ops = {
57 .read_time = ps3_get_time,
58 .set_time = ps3_set_time,
59};
60
61static int __init ps3_rtc_probe(struct platform_device *dev)
62{
63 struct rtc_device *rtc;
64
65 rtc = rtc_device_register("rtc-ps3", &dev->dev, &ps3_rtc_ops,
66 THIS_MODULE);
67 if (IS_ERR(rtc))
68 return PTR_ERR(rtc);
69
70 platform_set_drvdata(dev, rtc);
71 return 0;
72}
73
74static int __exit ps3_rtc_remove(struct platform_device *dev)
75{
76 rtc_device_unregister(platform_get_drvdata(dev));
77 return 0;
78}
79
80static struct platform_driver ps3_rtc_driver = {
81 .driver = {
82 .name = "rtc-ps3",
83 .owner = THIS_MODULE,
84 },
85 .remove = __exit_p(ps3_rtc_remove),
86};
87
88static int __init ps3_rtc_init(void)
89{
90 return platform_driver_probe(&ps3_rtc_driver, ps3_rtc_probe);
91}
92
93static void __exit ps3_rtc_fini(void)
94{
95 platform_driver_unregister(&ps3_rtc_driver);
96}
97
98module_init(ps3_rtc_init);
99module_exit(ps3_rtc_fini);
100
101MODULE_AUTHOR("Sony Corporation");
102MODULE_LICENSE("GPL");
103MODULE_DESCRIPTION("ps3 RTC driver");
104MODULE_ALIAS("platform:rtc-ps3");
diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c
index 66955cc9c746..ad164056feb6 100644
--- a/drivers/rtc/rtc-v3020.c
+++ b/drivers/rtc/rtc-v3020.c
@@ -27,17 +27,162 @@
27#include <linux/bcd.h> 27#include <linux/bcd.h>
28#include <linux/rtc-v3020.h> 28#include <linux/rtc-v3020.h>
29#include <linux/delay.h> 29#include <linux/delay.h>
30#include <linux/gpio.h>
30 31
31#include <linux/io.h> 32#include <linux/io.h>
32 33
33#undef DEBUG 34#undef DEBUG
34 35
36struct v3020;
37
38struct v3020_chip_ops {
39 int (*map_io)(struct v3020 *chip, struct platform_device *pdev,
40 struct v3020_platform_data *pdata);
41 void (*unmap_io)(struct v3020 *chip);
42 unsigned char (*read_bit)(struct v3020 *chip);
43 void (*write_bit)(struct v3020 *chip, unsigned char bit);
44};
45
46#define V3020_CS 0
47#define V3020_WR 1
48#define V3020_RD 2
49#define V3020_IO 3
50
51struct v3020_gpio {
52 const char *name;
53 unsigned int gpio;
54};
55
35struct v3020 { 56struct v3020 {
57 /* MMIO access */
36 void __iomem *ioaddress; 58 void __iomem *ioaddress;
37 int leftshift; 59 int leftshift;
60
61 /* GPIO access */
62 struct v3020_gpio *gpio;
63
64 struct v3020_chip_ops *ops;
65
38 struct rtc_device *rtc; 66 struct rtc_device *rtc;
39}; 67};
40 68
69
70static int v3020_mmio_map(struct v3020 *chip, struct platform_device *pdev,
71 struct v3020_platform_data *pdata)
72{
73 if (pdev->num_resources != 1)
74 return -EBUSY;
75
76 if (pdev->resource[0].flags != IORESOURCE_MEM)
77 return -EBUSY;
78
79 chip->leftshift = pdata->leftshift;
80 chip->ioaddress = ioremap(pdev->resource[0].start, 1);
81 if (chip->ioaddress == NULL)
82 return -EBUSY;
83
84 return 0;
85}
86
87static void v3020_mmio_unmap(struct v3020 *chip)
88{
89 iounmap(chip->ioaddress);
90}
91
92static void v3020_mmio_write_bit(struct v3020 *chip, unsigned char bit)
93{
94 writel(bit << chip->leftshift, chip->ioaddress);
95}
96
97static unsigned char v3020_mmio_read_bit(struct v3020 *chip)
98{
99 return readl(chip->ioaddress) & (1 << chip->leftshift);
100}
101
102static struct v3020_chip_ops v3020_mmio_ops = {
103 .map_io = v3020_mmio_map,
104 .unmap_io = v3020_mmio_unmap,
105 .read_bit = v3020_mmio_read_bit,
106 .write_bit = v3020_mmio_write_bit,
107};
108
109static struct v3020_gpio v3020_gpio[] = {
110 { "RTC CS", 0 },
111 { "RTC WR", 0 },
112 { "RTC RD", 0 },
113 { "RTC IO", 0 },
114};
115
116static int v3020_gpio_map(struct v3020 *chip, struct platform_device *pdev,
117 struct v3020_platform_data *pdata)
118{
119 int i, err;
120
121 v3020_gpio[V3020_CS].gpio = pdata->gpio_cs;
122 v3020_gpio[V3020_WR].gpio = pdata->gpio_wr;
123 v3020_gpio[V3020_RD].gpio = pdata->gpio_rd;
124 v3020_gpio[V3020_IO].gpio = pdata->gpio_io;
125
126 for (i = 0; i < ARRAY_SIZE(v3020_gpio); i++) {
127 err = gpio_request(v3020_gpio[i].gpio, v3020_gpio[i].name);
128 if (err)
129 goto err_request;
130
131 gpio_direction_output(v3020_gpio[i].gpio, 1);
132 }
133
134 chip->gpio = v3020_gpio;
135
136 return 0;
137
138err_request:
139 while (--i >= 0)
140 gpio_free(v3020_gpio[i].gpio);
141
142 return err;
143}
144
145static void v3020_gpio_unmap(struct v3020 *chip)
146{
147 int i;
148
149 for (i = 0; i < ARRAY_SIZE(v3020_gpio); i++)
150 gpio_free(v3020_gpio[i].gpio);
151}
152
153static void v3020_gpio_write_bit(struct v3020 *chip, unsigned char bit)
154{
155 gpio_direction_output(chip->gpio[V3020_IO].gpio, bit);
156 gpio_set_value(chip->gpio[V3020_CS].gpio, 0);
157 gpio_set_value(chip->gpio[V3020_WR].gpio, 0);
158 udelay(1);
159 gpio_set_value(chip->gpio[V3020_WR].gpio, 1);
160 gpio_set_value(chip->gpio[V3020_CS].gpio, 1);
161}
162
163static unsigned char v3020_gpio_read_bit(struct v3020 *chip)
164{
165 int bit;
166
167 gpio_direction_input(chip->gpio[V3020_IO].gpio);
168 gpio_set_value(chip->gpio[V3020_CS].gpio, 0);
169 gpio_set_value(chip->gpio[V3020_RD].gpio, 0);
170 udelay(1);
171 bit = !!gpio_get_value(chip->gpio[V3020_IO].gpio);
172 udelay(1);
173 gpio_set_value(chip->gpio[V3020_RD].gpio, 1);
174 gpio_set_value(chip->gpio[V3020_CS].gpio, 1);
175
176 return bit;
177}
178
179static struct v3020_chip_ops v3020_gpio_ops = {
180 .map_io = v3020_gpio_map,
181 .unmap_io = v3020_gpio_unmap,
182 .read_bit = v3020_gpio_read_bit,
183 .write_bit = v3020_gpio_write_bit,
184};
185
41static void v3020_set_reg(struct v3020 *chip, unsigned char address, 186static void v3020_set_reg(struct v3020 *chip, unsigned char address,
42 unsigned char data) 187 unsigned char data)
43{ 188{
@@ -46,7 +191,7 @@ static void v3020_set_reg(struct v3020 *chip, unsigned char address,
46 191
47 tmp = address; 192 tmp = address;
48 for (i = 0; i < 4; i++) { 193 for (i = 0; i < 4; i++) {
49 writel((tmp & 1) << chip->leftshift, chip->ioaddress); 194 chip->ops->write_bit(chip, (tmp & 1));
50 tmp >>= 1; 195 tmp >>= 1;
51 udelay(1); 196 udelay(1);
52 } 197 }
@@ -54,7 +199,7 @@ static void v3020_set_reg(struct v3020 *chip, unsigned char address,
54 /* Commands dont have data */ 199 /* Commands dont have data */
55 if (!V3020_IS_COMMAND(address)) { 200 if (!V3020_IS_COMMAND(address)) {
56 for (i = 0; i < 8; i++) { 201 for (i = 0; i < 8; i++) {
57 writel((data & 1) << chip->leftshift, chip->ioaddress); 202 chip->ops->write_bit(chip, (data & 1));
58 data >>= 1; 203 data >>= 1;
59 udelay(1); 204 udelay(1);
60 } 205 }
@@ -67,14 +212,14 @@ static unsigned char v3020_get_reg(struct v3020 *chip, unsigned char address)
67 int i; 212 int i;
68 213
69 for (i = 0; i < 4; i++) { 214 for (i = 0; i < 4; i++) {
70 writel((address & 1) << chip->leftshift, chip->ioaddress); 215 chip->ops->write_bit(chip, (address & 1));
71 address >>= 1; 216 address >>= 1;
72 udelay(1); 217 udelay(1);
73 } 218 }
74 219
75 for (i = 0; i < 8; i++) { 220 for (i = 0; i < 8; i++) {
76 data >>= 1; 221 data >>= 1;
77 if (readl(chip->ioaddress) & (1 << chip->leftshift)) 222 if (chip->ops->read_bit(chip))
78 data |= 0x80; 223 data |= 0x80;
79 udelay(1); 224 udelay(1);
80 } 225 }
@@ -164,25 +309,23 @@ static int rtc_probe(struct platform_device *pdev)
164 int i; 309 int i;
165 int temp; 310 int temp;
166 311
167 if (pdev->num_resources != 1)
168 return -EBUSY;
169
170 if (pdev->resource[0].flags != IORESOURCE_MEM)
171 return -EBUSY;
172
173 chip = kzalloc(sizeof *chip, GFP_KERNEL); 312 chip = kzalloc(sizeof *chip, GFP_KERNEL);
174 if (!chip) 313 if (!chip)
175 return -ENOMEM; 314 return -ENOMEM;
176 315
177 chip->leftshift = pdata->leftshift; 316 if (pdata->use_gpio)
178 chip->ioaddress = ioremap(pdev->resource[0].start, 1); 317 chip->ops = &v3020_gpio_ops;
179 if (chip->ioaddress == NULL) 318 else
319 chip->ops = &v3020_mmio_ops;
320
321 retval = chip->ops->map_io(chip, pdev, pdata);
322 if (retval)
180 goto err_chip; 323 goto err_chip;
181 324
182 /* Make sure the v3020 expects a communication cycle 325 /* Make sure the v3020 expects a communication cycle
183 * by reading 8 times */ 326 * by reading 8 times */
184 for (i = 0; i < 8; i++) 327 for (i = 0; i < 8; i++)
185 temp = readl(chip->ioaddress); 328 temp = chip->ops->read_bit(chip);
186 329
187 /* Test chip by doing a write/read sequence 330 /* Test chip by doing a write/read sequence
188 * to the chip ram */ 331 * to the chip ram */
@@ -196,10 +339,17 @@ static int rtc_probe(struct platform_device *pdev)
196 * are all disabled */ 339 * are all disabled */
197 v3020_set_reg(chip, V3020_STATUS_0, 0x0); 340 v3020_set_reg(chip, V3020_STATUS_0, 0x0);
198 341
199 dev_info(&pdev->dev, "Chip available at physical address 0x%llx," 342 if (pdata->use_gpio)
200 "data connected to D%d\n", 343 dev_info(&pdev->dev, "Chip available at GPIOs "
201 (unsigned long long)pdev->resource[0].start, 344 "%d, %d, %d, %d\n",
202 chip->leftshift); 345 chip->gpio[V3020_CS].gpio, chip->gpio[V3020_WR].gpio,
346 chip->gpio[V3020_RD].gpio, chip->gpio[V3020_IO].gpio);
347 else
348 dev_info(&pdev->dev, "Chip available at "
349 "physical address 0x%llx,"
350 "data connected to D%d\n",
351 (unsigned long long)pdev->resource[0].start,
352 chip->leftshift);
203 353
204 platform_set_drvdata(pdev, chip); 354 platform_set_drvdata(pdev, chip);
205 355
@@ -214,7 +364,7 @@ static int rtc_probe(struct platform_device *pdev)
214 return 0; 364 return 0;
215 365
216err_io: 366err_io:
217 iounmap(chip->ioaddress); 367 chip->ops->unmap_io(chip);
218err_chip: 368err_chip:
219 kfree(chip); 369 kfree(chip);
220 370
@@ -229,7 +379,7 @@ static int rtc_remove(struct platform_device *dev)
229 if (rtc) 379 if (rtc)
230 rtc_device_unregister(rtc); 380 rtc_device_unregister(rtc);
231 381
232 iounmap(chip->ioaddress); 382 chip->ops->unmap_io(chip);
233 kfree(chip); 383 kfree(chip);
234 384
235 return 0; 385 return 0;