Lines Matching +full:surface +full:- +full:sam
1 // SPDX-License-Identifier: GPL-2.0+
3 * Surface System Aggregator Module (SSAM) tablet mode switch driver.
19 /* -- SSAM generic tablet switch driver framework. -------------------------- */
73 const char *state = sw->ops.state_name(sw, &sw->state); in state_show()
94 status = sw->ops.get_state(sw, &state); in ssam_tablet_sw_update_workfn()
98 if (sw->state.source == state.source && sw->state.state == state.state) in ssam_tablet_sw_update_workfn()
100 sw->state = state; in ssam_tablet_sw_update_workfn()
103 tablet = sw->ops.state_is_tablet_mode(sw, &state); in ssam_tablet_sw_update_workfn()
104 input_report_switch(sw->mode_switch, SW_TABLET_MODE, tablet); in ssam_tablet_sw_update_workfn()
105 input_sync(sw->mode_switch); in ssam_tablet_sw_update_workfn()
112 schedule_work(&sw->update_work); in ssam_tablet_sw_resume()
126 return -EINVAL; in ssam_tablet_sw_probe()
129 sw = devm_kzalloc(&sdev->dev, sizeof(*sw), GFP_KERNEL); in ssam_tablet_sw_probe()
131 return -ENOMEM; in ssam_tablet_sw_probe()
133 sw->sdev = sdev; in ssam_tablet_sw_probe()
135 sw->ops.get_state = desc->ops.get_state; in ssam_tablet_sw_probe()
136 sw->ops.state_name = desc->ops.state_name; in ssam_tablet_sw_probe()
137 sw->ops.state_is_tablet_mode = desc->ops.state_is_tablet_mode; in ssam_tablet_sw_probe()
139 INIT_WORK(&sw->update_work, ssam_tablet_sw_update_workfn); in ssam_tablet_sw_probe()
144 status = sw->ops.get_state(sw, &sw->state); in ssam_tablet_sw_probe()
149 sw->mode_switch = devm_input_allocate_device(&sdev->dev); in ssam_tablet_sw_probe()
150 if (!sw->mode_switch) in ssam_tablet_sw_probe()
151 return -ENOMEM; in ssam_tablet_sw_probe()
153 sw->mode_switch->name = desc->dev.name; in ssam_tablet_sw_probe()
154 sw->mode_switch->phys = desc->dev.phys; in ssam_tablet_sw_probe()
155 sw->mode_switch->id.bustype = BUS_HOST; in ssam_tablet_sw_probe()
156 sw->mode_switch->dev.parent = &sdev->dev; in ssam_tablet_sw_probe()
158 tablet = sw->ops.state_is_tablet_mode(sw, &sw->state); in ssam_tablet_sw_probe()
159 input_set_capability(sw->mode_switch, EV_SW, SW_TABLET_MODE); in ssam_tablet_sw_probe()
160 input_report_switch(sw->mode_switch, SW_TABLET_MODE, tablet); in ssam_tablet_sw_probe()
162 status = input_register_device(sw->mode_switch); in ssam_tablet_sw_probe()
167 sw->notif.base.priority = 0; in ssam_tablet_sw_probe()
168 sw->notif.base.fn = desc->ops.notify; in ssam_tablet_sw_probe()
169 sw->notif.event.reg = desc->event.reg; in ssam_tablet_sw_probe()
170 sw->notif.event.id = desc->event.id; in ssam_tablet_sw_probe()
171 sw->notif.event.mask = desc->event.mask; in ssam_tablet_sw_probe()
172 sw->notif.event.flags = SSAM_EVENT_SEQUENCED; in ssam_tablet_sw_probe()
174 status = ssam_device_notifier_register(sdev, &sw->notif); in ssam_tablet_sw_probe()
178 status = sysfs_create_group(&sdev->dev.kobj, &ssam_tablet_sw_group); in ssam_tablet_sw_probe()
183 schedule_work(&sw->update_work); in ssam_tablet_sw_probe()
187 ssam_device_notifier_unregister(sdev, &sw->notif); in ssam_tablet_sw_probe()
188 cancel_work_sync(&sw->update_work); in ssam_tablet_sw_probe()
196 sysfs_remove_group(&sdev->dev.kobj, &ssam_tablet_sw_group); in ssam_tablet_sw_remove()
198 ssam_device_notifier_unregister(sdev, &sw->notif); in ssam_tablet_sw_remove()
199 cancel_work_sync(&sw->update_work); in ssam_tablet_sw_remove()
203 /* -- SSAM KIP tablet switch implementation. -------------------------------- */
219 switch (state->state) { in ssam_kip_cover_state_name()
230 return "folded-canvas"; in ssam_kip_cover_state_name()
233 return "folded-back"; in ssam_kip_cover_state_name()
239 dev_warn(&sw->sdev->dev, "unknown KIP cover state: %u\n", state->state); in ssam_kip_cover_state_name()
247 switch (state->state) { in ssam_kip_cover_state_is_tablet_mode()
259 dev_warn(&sw->sdev->dev, "unknown KIP cover state: %d\n", state->state); in ssam_kip_cover_state_is_tablet_mode()
276 status = ssam_retry(__ssam_kip_get_cover_state, sw->sdev->ctrl, &raw); in ssam_kip_get_cover_state()
278 dev_err(&sw->sdev->dev, "failed to query KIP lid state: %d\n", status); in ssam_kip_get_cover_state()
282 state->source = 0; /* Unused for KIP switch. */ in ssam_kip_get_cover_state()
283 state->state = raw; in ssam_kip_get_cover_state()
291 if (event->command_id != SSAM_EVENT_KIP_CID_COVER_STATE_CHANGED) in ssam_kip_sw_notif()
294 if (event->length < 1) in ssam_kip_sw_notif()
295 dev_warn(&sw->sdev->dev, "unexpected payload size: %u\n", event->length); in ssam_kip_sw_notif()
297 schedule_work(&sw->update_work); in ssam_kip_sw_notif()
303 .name = "Microsoft Surface KIP Tablet Mode Switch",
323 /* -- SSAM POS tablet switch implementation. -------------------------------- */
371 return "folded-canvas"; in ssam_pos_state_name_cover()
374 return "folded-back"; in ssam_pos_state_name_cover()
380 dev_warn(&sw->sdev->dev, "unknown device posture for type-cover: %u\n", state); in ssam_pos_state_name_cover()
401 dev_warn(&sw->sdev->dev, "unknown device posture for SLS: %u\n", state); in ssam_pos_state_name_sls()
409 switch (state->source) { in ssam_pos_state_name()
411 return ssam_pos_state_name_cover(sw, state->state); in ssam_pos_state_name()
414 return ssam_pos_state_name_sls(sw, state->state); in ssam_pos_state_name()
417 dev_warn(&sw->sdev->dev, "unknown device posture source: %u\n", state->source); in ssam_pos_state_name()
436 dev_warn(&sw->sdev->dev, "unknown device posture for type-cover: %u\n", state); in ssam_pos_state_is_tablet_mode_cover()
455 dev_warn(&sw->sdev->dev, "unknown device posture for SLS: %u\n", state); in ssam_pos_state_is_tablet_mode_sls()
463 switch (state->source) { in ssam_pos_state_is_tablet_mode()
465 return ssam_pos_state_is_tablet_mode_cover(sw, state->state); in ssam_pos_state_is_tablet_mode()
468 return ssam_pos_state_is_tablet_mode_sls(sw, state->state); in ssam_pos_state_is_tablet_mode()
471 dev_warn(&sw->sdev->dev, "unknown device posture source: %u\n", state->source); in ssam_pos_state_is_tablet_mode()
494 status = ssam_retry(ssam_request_do_sync_onstack, sw->sdev->ctrl, &rqst, &rsp, 0); in ssam_pos_get_sources_list()
498 /* We need at least the 'sources->count' field. */ in ssam_pos_get_sources_list()
500 dev_err(&sw->sdev->dev, "received source list response is too small\n"); in ssam_pos_get_sources_list()
501 return -EPROTO; in ssam_pos_get_sources_list()
504 /* Make sure 'sources->count' matches with the response length. */ in ssam_pos_get_sources_list()
505 if (get_unaligned_le32(&sources->count) * sizeof(__le32) + sizeof(__le32) != rsp.length) { in ssam_pos_get_sources_list()
506 dev_err(&sw->sdev->dev, "mismatch between number of sources and response size\n"); in ssam_pos_get_sources_list()
507 return -EPROTO; in ssam_pos_get_sources_list()
523 dev_err(&sw->sdev->dev, "no posture sources found\n"); in ssam_pos_get_source()
524 return -ENODEV; in ssam_pos_get_source()
553 status = ssam_retry(__ssam_pos_get_posture_for_source, sw->sdev->ctrl, in ssam_pos_get_posture_for_source()
570 dev_err(&sw->sdev->dev, "failed to get posture source ID: %d\n", status); in ssam_pos_get_posture()
576 dev_err(&sw->sdev->dev, "failed to get posture value for source %u: %d\n", in ssam_pos_get_posture()
581 state->source = source_id; in ssam_pos_get_posture()
582 state->state = source_state; in ssam_pos_get_posture()
590 if (event->command_id != SSAM_EVENT_POS_CID_POSTURE_CHANGED) in ssam_pos_sw_notif()
593 if (event->length != sizeof(__le32) * 3) in ssam_pos_sw_notif()
594 dev_warn(&sw->sdev->dev, "unexpected payload size: %u\n", event->length); in ssam_pos_sw_notif()
596 schedule_work(&sw->update_work); in ssam_pos_sw_notif()
602 .name = "Microsoft Surface POS Tablet Mode Switch",
622 /* -- Driver registration. -------------------------------------------------- */
625 { SSAM_SDEV(KIP, SAM, 0x00, 0x01), (unsigned long)&ssam_kip_sw_desc },
626 { SSAM_SDEV(POS, SAM, 0x00, 0x01), (unsigned long)&ssam_pos_sw_desc },
644 MODULE_DESCRIPTION("Tablet mode switch driver for Surface devices using the Surface Aggregator Modu…