make irq specifier to be provided when assigining irq
[lunaix-os.git] / lunaix-os / hal / rtc / rtc_device.c
1 #include <lunaix/fs/twifs.h>
2 #include <lunaix/fs/twimap.h>
3 #include <lunaix/mm/valloc.h>
4 #include <lunaix/status.h>
5 #include <lunaix/syslog.h>
6
7 #include <hal/hwrtc.h>
8
9 const struct hwrtc_potens* sysrtc = NULL;
10
11 static DEFINE_LLIST(rtcs);
12
13 LOG_MODULE("hwrtc")
14
15 void
16 hwrtc_walltime(datetime_t* dt)
17 {
18     sysrtc->ops->get_walltime(sysrtc, dt);
19 }
20
21 static inline struct hwrtc_potens*
22 __rtc_potens(struct device* wrapper)
23 {
24     struct potens_meta* pot;
25     pot = device_get_potens(wrapper, potens(HWRTC));
26     return ({ assert(pot); get_potens(pot, struct hwrtc_potens); });
27 }
28
29 static int
30 __hwrtc_ioctl(struct device* dev, u32_t req, va_list args)
31 {
32     struct hwrtc_potens* pot;
33     struct hwrtc_potens_ops* ops;
34     struct device* rtcdev;
35
36     rtcdev = (struct device*) dev->underlay;
37     pot = __rtc_potens(rtcdev);
38     ops = pot->ops;
39
40     switch (req) {
41         case RTCIO_IMSK:
42             ops->set_proactive(pot, false);
43             break;
44         case RTCIO_IUNMSK:
45             ops->set_proactive(pot, true);
46             break;
47         case RTCIO_SETDT:
48             datetime_t* dt = va_arg(args, datetime_t*);
49             ops->set_walltime(pot, dt);
50             break;
51         case RTCIO_SETFREQ:
52             ticks_t* freq = va_arg(args, ticks_t*);
53
54             if (!freq) {
55                 return EINVAL;
56             }
57             if (*freq) {
58                 return ops->chfreq(pot, *freq);
59             }
60
61             *freq = pot->base_freq;
62
63             break;
64         default:
65             return rtcdev->ops.exec_cmd(dev, req, args);
66     }
67
68     return 0;
69 }
70
71 static int
72 __hwrtc_read(struct device* dev, void* buf, size_t offset, size_t len)
73 {
74     struct hwrtc_potens* pot;
75
76     pot = __rtc_potens((struct device*)dev->underlay);
77     *((ticks_t*)buf) = pot->live;
78
79     return sizeof(ticks_t);
80 }
81
82 static struct devclass proxy_rtc_clas = DEVCLASS(LUNAIX, TIME, RTC);
83
84 static void
85 __hwrtc_create_proxy(struct hwrtc_potens* pot, struct device* raw_rtcdev)
86 {
87     struct device* dev;
88
89     dev = device_allocsys(NULL, raw_rtcdev);
90
91     dev->ops.exec_cmd = __hwrtc_ioctl;
92     dev->ops.read = __hwrtc_read;
93
94     register_device_var(dev, &proxy_rtc_clas, "rtc");
95
96     pot->rtc_proxy = dev;
97 }
98
99 struct hwrtc_potens*
100 hwrtc_attach_potens(struct device* raw_rtcdev, struct hwrtc_potens_ops* ops)
101 {
102     struct hwrtc_potens* hwpot;
103
104     if (!potens_check_unique(raw_rtcdev, potens(HWRTC)))
105     {
106         return NULL;
107     }
108
109     hwpot = new_potens(potens(HWRTC), struct hwrtc_potens);
110     hwpot->ops = ops;
111     
112     device_grant_potens(raw_rtcdev, potens_meta(hwpot));
113     llist_append(&rtcs, &hwpot->rtc_potentes);
114
115     __hwrtc_create_proxy(hwpot, raw_rtcdev);
116
117     return hwpot;
118 }
119
120 void
121 hwrtc_init()
122 {
123     assert(!llist_empty(&rtcs));
124
125     sysrtc = list_entry(rtcs.next, struct hwrtc_potens, rtc_potentes);
126     
127     if (!sysrtc->ops->calibrate) {
128         return;
129     }
130
131     int err = sysrtc->ops->calibrate(sysrtc);
132     if (err) {
133         FATAL("failed to calibrate rtc. name='%s', err=%d", 
134                 potens_dev(sysrtc)->name_val, err);
135     }
136 }
137
138 static void
139 __hwrtc_readinfo(struct twimap* mapping)
140 {
141     struct hwrtc_potens* pot;
142     struct device* owner;
143
144     pot = twimap_data(mapping, struct hwrtc_potens*);
145     owner = pot->pot_meta.owner;
146
147     twimap_printf(mapping, "device: %x.%x\n", 
148                     owner->ident.fn_grp, owner->ident.unique);
149
150     twimap_printf(mapping, "frequency: %dHz\n", pot->base_freq);
151     twimap_printf(mapping, "ticks count: %d\n", pot->live);
152     twimap_printf(mapping, "ticking: %s\n",
153                   (pot->state & RTC_STATE_MASKED) ? "no" : "yes");
154
155     datetime_t dt;
156     pot->ops->get_walltime(pot, &dt);
157
158     twimap_printf(
159         mapping, "recorded date: %d/%d/%d\n", dt.year, dt.month, dt.day);
160     twimap_printf(
161         mapping, "recorded time: %d:%d:%d\n", dt.hour, dt.minute, dt.second);
162     twimap_printf(mapping, "recorded weekday: %d\n", dt.weekday);
163 }
164
165 static void
166 hwrtc_twifs_export(struct hwrtc_potens* pot)
167 {
168     const char* name = pot->rtc_proxy->name_val;
169     struct twimap* rtc_mapping = twifs_mapping(NULL, pot, name);
170     rtc_mapping->read = __hwrtc_readinfo;
171 }
172
173 static void
174 hwrtc_twifs_export_all()
175 {
176     struct hwrtc_potens *pos, *next;
177     llist_for_each(pos, next, &rtcs, rtc_potentes)
178     {
179         hwrtc_twifs_export(pos);
180     }
181 }
182 EXPORT_TWIFS_PLUGIN(rtc_fsexport, hwrtc_twifs_export_all);