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 enum hid_time_channel
{
27 CHANNEL_SCAN_INDEX_YEAR
,
28 CHANNEL_SCAN_INDEX_MONTH
,
29 CHANNEL_SCAN_INDEX_DAY
,
30 CHANNEL_SCAN_INDEX_HOUR
,
31 CHANNEL_SCAN_INDEX_MINUTE
,
32 CHANNEL_SCAN_INDEX_SECOND
,
36 struct hid_time_state
{
37 struct hid_sensor_hub_callbacks callbacks
;
38 struct hid_sensor_common common_attributes
;
39 struct hid_sensor_hub_attribute_info info
[TIME_RTC_CHANNEL_MAX
];
40 struct rtc_time last_time
;
41 spinlock_t lock_last_time
;
42 struct completion comp_last_time
;
43 struct rtc_time time_buf
;
44 struct rtc_device
*rtc
;
47 static const u32 hid_time_addresses
[TIME_RTC_CHANNEL_MAX
] = {
48 HID_USAGE_SENSOR_TIME_YEAR
,
49 HID_USAGE_SENSOR_TIME_MONTH
,
50 HID_USAGE_SENSOR_TIME_DAY
,
51 HID_USAGE_SENSOR_TIME_HOUR
,
52 HID_USAGE_SENSOR_TIME_MINUTE
,
53 HID_USAGE_SENSOR_TIME_SECOND
,
56 /* Channel names for verbose error messages */
57 static const char * const hid_time_channel_names
[TIME_RTC_CHANNEL_MAX
] = {
58 "year", "month", "day", "hour", "minute", "second",
61 /* Callback handler to send event after all samples are received and captured */
62 static int hid_time_proc_event(struct hid_sensor_hub_device
*hsdev
,
63 unsigned usage_id
, void *priv
)
66 struct hid_time_state
*time_state
= platform_get_drvdata(priv
);
68 spin_lock_irqsave(&time_state
->lock_last_time
, flags
);
69 time_state
->last_time
= time_state
->time_buf
;
70 spin_unlock_irqrestore(&time_state
->lock_last_time
, flags
);
71 complete(&time_state
->comp_last_time
);
75 static u32
hid_time_value(size_t raw_len
, char *raw_data
)
79 return *(u8
*)raw_data
;
81 return *(u16
*)raw_data
;
83 return *(u32
*)raw_data
;
85 return (u32
)(~0U); /* 0xff... or -1 to denote an error */
89 static int hid_time_capture_sample(struct hid_sensor_hub_device
*hsdev
,
90 unsigned usage_id
, size_t raw_len
,
91 char *raw_data
, void *priv
)
93 struct hid_time_state
*time_state
= platform_get_drvdata(priv
);
94 struct rtc_time
*time_buf
= &time_state
->time_buf
;
97 case HID_USAGE_SENSOR_TIME_YEAR
:
99 * The draft for HID-sensors (HUTRR39) currently doesn't define
100 * the range for the year attribute. Therefor we support
101 * 8 bit (0-99) and 16 or 32 bits (full) as size for the year.
104 time_buf
->tm_year
= *(u8
*)raw_data
;
105 if (time_buf
->tm_year
< 70)
106 /* assume we are in 1970...2069 */
107 time_buf
->tm_year
+= 100;
110 (int)hid_time_value(raw_len
, raw_data
)-1900;
112 case HID_USAGE_SENSOR_TIME_MONTH
:
113 /* sensors are sending the month as 1-12, we need 0-11 */
114 time_buf
->tm_mon
= (int)hid_time_value(raw_len
, raw_data
)-1;
116 case HID_USAGE_SENSOR_TIME_DAY
:
117 time_buf
->tm_mday
= (int)hid_time_value(raw_len
, raw_data
);
119 case HID_USAGE_SENSOR_TIME_HOUR
:
120 time_buf
->tm_hour
= (int)hid_time_value(raw_len
, raw_data
);
122 case HID_USAGE_SENSOR_TIME_MINUTE
:
123 time_buf
->tm_min
= (int)hid_time_value(raw_len
, raw_data
);
125 case HID_USAGE_SENSOR_TIME_SECOND
:
126 time_buf
->tm_sec
= (int)hid_time_value(raw_len
, raw_data
);
134 /* small helper, haven't found any other way */
135 static const char *hid_time_attrib_name(u32 attrib_id
)
137 static const char unknown
[] = "unknown";
140 for (i
= 0; i
< TIME_RTC_CHANNEL_MAX
; ++i
) {
141 if (hid_time_addresses
[i
] == attrib_id
)
142 return hid_time_channel_names
[i
];
144 return unknown
; /* should never happen */
147 static int hid_time_parse_report(struct platform_device
*pdev
,
148 struct hid_sensor_hub_device
*hsdev
,
150 struct hid_time_state
*time_state
)
154 for (i
= 0; i
< TIME_RTC_CHANNEL_MAX
; ++i
)
155 if (sensor_hub_input_get_attribute_info(hsdev
,
156 HID_INPUT_REPORT
, usage_id
,
157 hid_time_addresses
[i
],
158 &time_state
->info
[i
]) < 0)
160 /* Check the (needed) attributes for sanity */
161 report_id
= time_state
->info
[0].report_id
;
163 dev_err(&pdev
->dev
, "bad report ID!\n");
166 for (i
= 0; i
< TIME_RTC_CHANNEL_MAX
; ++i
) {
167 if (time_state
->info
[i
].report_id
!= report_id
) {
169 "not all needed attributes inside the same report!\n");
172 if (time_state
->info
[i
].size
== 3 ||
173 time_state
->info
[i
].size
> 4) {
175 "attribute '%s' not 8, 16 or 32 bits wide!\n",
176 hid_time_attrib_name(
177 time_state
->info
[i
].attrib_id
));
180 if (time_state
->info
[i
].units
!=
181 HID_USAGE_SENSOR_UNITS_NOT_SPECIFIED
&&
182 /* allow attribute seconds with unit seconds */
183 !(time_state
->info
[i
].attrib_id
==
184 HID_USAGE_SENSOR_TIME_SECOND
&&
185 time_state
->info
[i
].units
==
186 HID_USAGE_SENSOR_UNITS_SECOND
)) {
188 "attribute '%s' hasn't a unit of type 'none'!\n",
189 hid_time_attrib_name(
190 time_state
->info
[i
].attrib_id
));
193 if (time_state
->info
[i
].unit_expo
) {
195 "attribute '%s' hasn't a unit exponent of 1!\n",
196 hid_time_attrib_name(
197 time_state
->info
[i
].attrib_id
));
205 static int hid_rtc_read_time(struct device
*dev
, struct rtc_time
*tm
)
208 struct hid_time_state
*time_state
=
209 platform_get_drvdata(to_platform_device(dev
));
212 INIT_COMPLETION(time_state
->comp_last_time
);
213 /* get a report with all values through requesting one value */
214 sensor_hub_input_attr_get_raw_value(time_state
->common_attributes
.hsdev
,
215 HID_USAGE_SENSOR_TIME
, hid_time_addresses
[0],
216 time_state
->info
[0].report_id
);
217 /* wait for all values (event) */
218 ret
= wait_for_completion_killable_timeout(
219 &time_state
->comp_last_time
, HZ
*6);
222 spin_lock_irqsave(&time_state
->lock_last_time
, flags
);
223 *tm
= time_state
->last_time
;
224 spin_unlock_irqrestore(&time_state
->lock_last_time
, flags
);
228 return -EIO
; /* timeouted */
229 return ret
; /* killed (-ERESTARTSYS) */
232 static const struct rtc_class_ops hid_time_rtc_ops
= {
233 .read_time
= hid_rtc_read_time
,
236 static int hid_time_probe(struct platform_device
*pdev
)
239 struct hid_sensor_hub_device
*hsdev
= pdev
->dev
.platform_data
;
240 struct hid_time_state
*time_state
= devm_kzalloc(&pdev
->dev
,
241 sizeof(struct hid_time_state
), GFP_KERNEL
);
243 if (time_state
== NULL
)
246 platform_set_drvdata(pdev
, time_state
);
248 spin_lock_init(&time_state
->lock_last_time
);
249 init_completion(&time_state
->comp_last_time
);
250 time_state
->common_attributes
.hsdev
= hsdev
;
251 time_state
->common_attributes
.pdev
= pdev
;
253 ret
= hid_sensor_parse_common_attributes(hsdev
,
254 HID_USAGE_SENSOR_TIME
,
255 &time_state
->common_attributes
);
257 dev_err(&pdev
->dev
, "failed to setup common attributes!\n");
261 ret
= hid_time_parse_report(pdev
, hsdev
, HID_USAGE_SENSOR_TIME
,
264 dev_err(&pdev
->dev
, "failed to setup attributes!\n");
268 time_state
->callbacks
.send_event
= hid_time_proc_event
;
269 time_state
->callbacks
.capture_sample
= hid_time_capture_sample
;
270 time_state
->callbacks
.pdev
= pdev
;
271 ret
= sensor_hub_register_callback(hsdev
, HID_USAGE_SENSOR_TIME
,
272 &time_state
->callbacks
);
274 dev_err(&pdev
->dev
, "register callback failed!\n");
278 time_state
->rtc
= devm_rtc_device_register(&pdev
->dev
,
279 "hid-sensor-time", &hid_time_rtc_ops
,
282 if (IS_ERR_OR_NULL(time_state
->rtc
)) {
283 ret
= time_state
->rtc
? PTR_ERR(time_state
->rtc
) : -ENODEV
;
284 time_state
->rtc
= NULL
;
285 sensor_hub_remove_callback(hsdev
, HID_USAGE_SENSOR_TIME
);
286 dev_err(&pdev
->dev
, "rtc device register failed!\n");
292 static int hid_time_remove(struct platform_device
*pdev
)
294 struct hid_sensor_hub_device
*hsdev
= pdev
->dev
.platform_data
;
296 sensor_hub_remove_callback(hsdev
, HID_USAGE_SENSOR_TIME
);
301 static struct platform_device_id hid_time_ids
[] = {
303 /* Format: HID-SENSOR-usage_id_in_hex_lowercase */
304 .name
= "HID-SENSOR-2000a0",
308 MODULE_DEVICE_TABLE(platform
, hid_time_ids
);
310 static struct platform_driver hid_time_platform_driver
= {
311 .id_table
= hid_time_ids
,
313 .name
= KBUILD_MODNAME
,
314 .owner
= THIS_MODULE
,
316 .probe
= hid_time_probe
,
317 .remove
= hid_time_remove
,
319 module_platform_driver(hid_time_platform_driver
);
321 MODULE_DESCRIPTION("HID Sensor Time");
322 MODULE_AUTHOR("Alexander Holler <holler@ahsoftware.de>");
323 MODULE_LICENSE("GPL");