2 * HID Sensor Time Driver
3 * Copyright (c) 2012, Alexander Holler.
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
19 #include <linux/device.h>
20 #include <linux/platform_device.h>
21 #include <linux/module.h>
22 #include <linux/hid-sensor-hub.h>
23 #include <linux/iio/iio.h>
24 #include <linux/rtc.h>
26 /* Format: HID-SENSOR-usage_id_in_hex */
27 /* Usage ID from spec for Time: 0x2000A0 */
28 #define DRIVER_NAME "HID-SENSOR-2000a0" /* must be lowercase */
30 enum hid_time_channel
{
31 CHANNEL_SCAN_INDEX_YEAR
,
32 CHANNEL_SCAN_INDEX_MONTH
,
33 CHANNEL_SCAN_INDEX_DAY
,
34 CHANNEL_SCAN_INDEX_HOUR
,
35 CHANNEL_SCAN_INDEX_MINUTE
,
36 CHANNEL_SCAN_INDEX_SECOND
,
40 struct hid_time_state
{
41 struct hid_sensor_hub_callbacks callbacks
;
42 struct hid_sensor_common common_attributes
;
43 struct hid_sensor_hub_attribute_info info
[TIME_RTC_CHANNEL_MAX
];
44 struct rtc_time last_time
;
45 spinlock_t lock_last_time
;
46 struct completion comp_last_time
;
47 struct rtc_time time_buf
;
48 struct rtc_device
*rtc
;
51 static const u32 hid_time_addresses
[TIME_RTC_CHANNEL_MAX
] = {
52 HID_USAGE_SENSOR_TIME_YEAR
,
53 HID_USAGE_SENSOR_TIME_MONTH
,
54 HID_USAGE_SENSOR_TIME_DAY
,
55 HID_USAGE_SENSOR_TIME_HOUR
,
56 HID_USAGE_SENSOR_TIME_MINUTE
,
57 HID_USAGE_SENSOR_TIME_SECOND
,
60 /* Channel names for verbose error messages */
61 static const char * const hid_time_channel_names
[TIME_RTC_CHANNEL_MAX
] = {
62 "year", "month", "day", "hour", "minute", "second",
65 /* Callback handler to send event after all samples are received and captured */
66 static int hid_time_proc_event(struct hid_sensor_hub_device
*hsdev
,
67 unsigned usage_id
, void *priv
)
70 struct hid_time_state
*time_state
= platform_get_drvdata(priv
);
72 spin_lock_irqsave(&time_state
->lock_last_time
, flags
);
73 time_state
->last_time
= time_state
->time_buf
;
74 spin_unlock_irqrestore(&time_state
->lock_last_time
, flags
);
75 complete(&time_state
->comp_last_time
);
79 static u32
hid_time_value(size_t raw_len
, char *raw_data
)
83 return *(u8
*)raw_data
;
85 return *(u16
*)raw_data
;
87 return *(u32
*)raw_data
;
89 return (u32
)(~0U); /* 0xff... or -1 to denote an error */
93 static int hid_time_capture_sample(struct hid_sensor_hub_device
*hsdev
,
94 unsigned usage_id
, size_t raw_len
,
95 char *raw_data
, void *priv
)
97 struct hid_time_state
*time_state
= platform_get_drvdata(priv
);
98 struct rtc_time
*time_buf
= &time_state
->time_buf
;
101 case HID_USAGE_SENSOR_TIME_YEAR
:
103 * The draft for HID-sensors (HUTRR39) currently doesn't define
104 * the range for the year attribute. Therefor we support
105 * 8 bit (0-99) and 16 or 32 bits (full) as size for the year.
108 time_buf
->tm_year
= *(u8
*)raw_data
;
109 if (time_buf
->tm_year
< 70)
110 /* assume we are in 1970...2069 */
111 time_buf
->tm_year
+= 100;
114 (int)hid_time_value(raw_len
, raw_data
)-1900;
116 case HID_USAGE_SENSOR_TIME_MONTH
:
117 /* sensors are sending the month as 1-12, we need 0-11 */
118 time_buf
->tm_mon
= (int)hid_time_value(raw_len
, raw_data
)-1;
120 case HID_USAGE_SENSOR_TIME_DAY
:
121 time_buf
->tm_mday
= (int)hid_time_value(raw_len
, raw_data
);
123 case HID_USAGE_SENSOR_TIME_HOUR
:
124 time_buf
->tm_hour
= (int)hid_time_value(raw_len
, raw_data
);
126 case HID_USAGE_SENSOR_TIME_MINUTE
:
127 time_buf
->tm_min
= (int)hid_time_value(raw_len
, raw_data
);
129 case HID_USAGE_SENSOR_TIME_SECOND
:
130 time_buf
->tm_sec
= (int)hid_time_value(raw_len
, raw_data
);
138 /* small helper, haven't found any other way */
139 static const char *hid_time_attrib_name(u32 attrib_id
)
141 static const char unknown
[] = "unknown";
144 for (i
= 0; i
< TIME_RTC_CHANNEL_MAX
; ++i
) {
145 if (hid_time_addresses
[i
] == attrib_id
)
146 return hid_time_channel_names
[i
];
148 return unknown
; /* should never happen */
151 static int hid_time_parse_report(struct platform_device
*pdev
,
152 struct hid_sensor_hub_device
*hsdev
,
154 struct hid_time_state
*time_state
)
158 for (i
= 0; i
< TIME_RTC_CHANNEL_MAX
; ++i
)
159 if (sensor_hub_input_get_attribute_info(hsdev
,
160 HID_INPUT_REPORT
, usage_id
,
161 hid_time_addresses
[i
],
162 &time_state
->info
[i
]) < 0)
164 /* Check the (needed) attributes for sanity */
165 report_id
= time_state
->info
[0].report_id
;
167 dev_err(&pdev
->dev
, "bad report ID!\n");
170 for (i
= 0; i
< TIME_RTC_CHANNEL_MAX
; ++i
) {
171 if (time_state
->info
[i
].report_id
!= report_id
) {
173 "not all needed attributes inside the same report!\n");
176 if (time_state
->info
[i
].size
== 3 ||
177 time_state
->info
[i
].size
> 4) {
179 "attribute '%s' not 8, 16 or 32 bits wide!\n",
180 hid_time_attrib_name(
181 time_state
->info
[i
].attrib_id
));
184 if (time_state
->info
[i
].units
!=
185 HID_USAGE_SENSOR_UNITS_NOT_SPECIFIED
&&
186 /* allow attribute seconds with unit seconds */
187 !(time_state
->info
[i
].attrib_id
==
188 HID_USAGE_SENSOR_TIME_SECOND
&&
189 time_state
->info
[i
].units
==
190 HID_USAGE_SENSOR_UNITS_SECOND
)) {
192 "attribute '%s' hasn't a unit of type 'none'!\n",
193 hid_time_attrib_name(
194 time_state
->info
[i
].attrib_id
));
197 if (time_state
->info
[i
].unit_expo
) {
199 "attribute '%s' hasn't a unit exponent of 1!\n",
200 hid_time_attrib_name(
201 time_state
->info
[i
].attrib_id
));
209 static int hid_rtc_read_time(struct device
*dev
, struct rtc_time
*tm
)
212 struct hid_time_state
*time_state
=
213 platform_get_drvdata(to_platform_device(dev
));
216 INIT_COMPLETION(time_state
->comp_last_time
);
217 /* get a report with all values through requesting one value */
218 sensor_hub_input_attr_get_raw_value(time_state
->common_attributes
.hsdev
,
219 HID_USAGE_SENSOR_TIME
, hid_time_addresses
[0],
220 time_state
->info
[0].report_id
);
221 /* wait for all values (event) */
222 ret
= wait_for_completion_killable_timeout(
223 &time_state
->comp_last_time
, HZ
*6);
226 spin_lock_irqsave(&time_state
->lock_last_time
, flags
);
227 *tm
= time_state
->last_time
;
228 spin_unlock_irqrestore(&time_state
->lock_last_time
, flags
);
232 return -EIO
; /* timeouted */
233 return ret
; /* killed (-ERESTARTSYS) */
236 static const struct rtc_class_ops hid_time_rtc_ops
= {
237 .read_time
= hid_rtc_read_time
,
240 static int hid_time_probe(struct platform_device
*pdev
)
243 struct hid_sensor_hub_device
*hsdev
= pdev
->dev
.platform_data
;
244 struct hid_time_state
*time_state
= devm_kzalloc(&pdev
->dev
,
245 sizeof(struct hid_time_state
), GFP_KERNEL
);
247 if (time_state
== NULL
)
250 platform_set_drvdata(pdev
, time_state
);
252 spin_lock_init(&time_state
->lock_last_time
);
253 init_completion(&time_state
->comp_last_time
);
254 time_state
->common_attributes
.hsdev
= hsdev
;
255 time_state
->common_attributes
.pdev
= pdev
;
257 ret
= hid_sensor_parse_common_attributes(hsdev
,
258 HID_USAGE_SENSOR_TIME
,
259 &time_state
->common_attributes
);
261 dev_err(&pdev
->dev
, "failed to setup common attributes!\n");
265 ret
= hid_time_parse_report(pdev
, hsdev
, HID_USAGE_SENSOR_TIME
,
268 dev_err(&pdev
->dev
, "failed to setup attributes!\n");
272 time_state
->callbacks
.send_event
= hid_time_proc_event
;
273 time_state
->callbacks
.capture_sample
= hid_time_capture_sample
;
274 time_state
->callbacks
.pdev
= pdev
;
275 ret
= sensor_hub_register_callback(hsdev
, HID_USAGE_SENSOR_TIME
,
276 &time_state
->callbacks
);
278 dev_err(&pdev
->dev
, "register callback failed!\n");
282 time_state
->rtc
= devm_rtc_device_register(&pdev
->dev
,
283 "hid-sensor-time", &hid_time_rtc_ops
,
286 if (IS_ERR(time_state
->rtc
)) {
287 dev_err(&pdev
->dev
, "rtc device register failed!\n");
288 return PTR_ERR(time_state
->rtc
);
294 static int hid_time_remove(struct platform_device
*pdev
)
296 struct hid_sensor_hub_device
*hsdev
= pdev
->dev
.platform_data
;
298 sensor_hub_remove_callback(hsdev
, HID_USAGE_SENSOR_TIME
);
303 static struct platform_driver hid_time_platform_driver
= {
306 .owner
= THIS_MODULE
,
308 .probe
= hid_time_probe
,
309 .remove
= hid_time_remove
,
311 module_platform_driver(hid_time_platform_driver
);
313 MODULE_DESCRIPTION("HID Sensor Time");
314 MODULE_AUTHOR("Alexander Holler <holler@ahsoftware.de>");
315 MODULE_LICENSE("GPL");