xref: /linux/drivers/misc/ti-st/st_ll.c (revision 4505153954fdb1465d2b178288a9bf646f2a2166)
1*45051539SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2a0cc2f3bSPavan Savoy /*
3a0cc2f3bSPavan Savoy  *  Shared Transport driver
4a0cc2f3bSPavan Savoy  *	HCI-LL module responsible for TI proprietary HCI_LL protocol
5a0cc2f3bSPavan Savoy  *  Copyright (C) 2009-2010 Texas Instruments
6a0cc2f3bSPavan Savoy  *  Author: Pavan Savoy <pavan_savoy@ti.com>
7a0cc2f3bSPavan Savoy  */
8a0cc2f3bSPavan Savoy 
9a0cc2f3bSPavan Savoy #define pr_fmt(fmt) "(stll) :" fmt
10a0cc2f3bSPavan Savoy #include <linux/skbuff.h>
11a0cc2f3bSPavan Savoy #include <linux/module.h>
120d7c5f25SPavan Savoy #include <linux/platform_device.h>
13a0cc2f3bSPavan Savoy #include <linux/ti_wilink_st.h>
14a0cc2f3bSPavan Savoy 
15a0cc2f3bSPavan Savoy /**********************************************************************/
16a0cc2f3bSPavan Savoy /* internal functions */
17a0cc2f3bSPavan Savoy static void send_ll_cmd(struct st_data_s *st_data,
18a0cc2f3bSPavan Savoy 	unsigned char cmd)
19a0cc2f3bSPavan Savoy {
20a0cc2f3bSPavan Savoy 
216710fcffSPavan Savoy 	pr_debug("%s: writing %x", __func__, cmd);
22a0cc2f3bSPavan Savoy 	st_int_write(st_data, &cmd, 1);
23a0cc2f3bSPavan Savoy 	return;
24a0cc2f3bSPavan Savoy }
25a0cc2f3bSPavan Savoy 
26a0cc2f3bSPavan Savoy static void ll_device_want_to_sleep(struct st_data_s *st_data)
27a0cc2f3bSPavan Savoy {
280d7c5f25SPavan Savoy 	struct kim_data_s	*kim_data;
290d7c5f25SPavan Savoy 	struct ti_st_plat_data	*pdata;
300d7c5f25SPavan Savoy 
31a0cc2f3bSPavan Savoy 	pr_debug("%s", __func__);
32a0cc2f3bSPavan Savoy 	/* sanity check */
33a0cc2f3bSPavan Savoy 	if (st_data->ll_state != ST_LL_AWAKE)
34a0cc2f3bSPavan Savoy 		pr_err("ERR hcill: ST_LL_GO_TO_SLEEP_IND"
35a0cc2f3bSPavan Savoy 			  "in state %ld", st_data->ll_state);
36a0cc2f3bSPavan Savoy 
37a0cc2f3bSPavan Savoy 	send_ll_cmd(st_data, LL_SLEEP_ACK);
38a0cc2f3bSPavan Savoy 	/* update state */
39a0cc2f3bSPavan Savoy 	st_data->ll_state = ST_LL_ASLEEP;
400d7c5f25SPavan Savoy 
410d7c5f25SPavan Savoy 	/* communicate to platform about chip asleep */
420d7c5f25SPavan Savoy 	kim_data = st_data->kim_data;
430d7c5f25SPavan Savoy 	pdata = kim_data->kim_pdev->dev.platform_data;
440d7c5f25SPavan Savoy 	if (pdata->chip_asleep)
450d7c5f25SPavan Savoy 		pdata->chip_asleep(NULL);
46a0cc2f3bSPavan Savoy }
47a0cc2f3bSPavan Savoy 
48a0cc2f3bSPavan Savoy static void ll_device_want_to_wakeup(struct st_data_s *st_data)
49a0cc2f3bSPavan Savoy {
500d7c5f25SPavan Savoy 	struct kim_data_s	*kim_data;
510d7c5f25SPavan Savoy 	struct ti_st_plat_data	*pdata;
520d7c5f25SPavan Savoy 
53a0cc2f3bSPavan Savoy 	/* diff actions in diff states */
54a0cc2f3bSPavan Savoy 	switch (st_data->ll_state) {
55a0cc2f3bSPavan Savoy 	case ST_LL_ASLEEP:
56a0cc2f3bSPavan Savoy 		send_ll_cmd(st_data, LL_WAKE_UP_ACK);	/* send wake_ack */
57a0cc2f3bSPavan Savoy 		break;
58a0cc2f3bSPavan Savoy 	case ST_LL_ASLEEP_TO_AWAKE:
59a0cc2f3bSPavan Savoy 		/* duplicate wake_ind */
60a0cc2f3bSPavan Savoy 		pr_err("duplicate wake_ind while waiting for Wake ack");
61a0cc2f3bSPavan Savoy 		break;
62a0cc2f3bSPavan Savoy 	case ST_LL_AWAKE:
63a0cc2f3bSPavan Savoy 		/* duplicate wake_ind */
64a0cc2f3bSPavan Savoy 		pr_err("duplicate wake_ind already AWAKE");
65a0cc2f3bSPavan Savoy 		break;
66a0cc2f3bSPavan Savoy 	case ST_LL_AWAKE_TO_ASLEEP:
67a0cc2f3bSPavan Savoy 		/* duplicate wake_ind */
68a0cc2f3bSPavan Savoy 		pr_err("duplicate wake_ind");
69a0cc2f3bSPavan Savoy 		break;
70a0cc2f3bSPavan Savoy 	}
71a0cc2f3bSPavan Savoy 	/* update state */
72a0cc2f3bSPavan Savoy 	st_data->ll_state = ST_LL_AWAKE;
730d7c5f25SPavan Savoy 
740d7c5f25SPavan Savoy 	/* communicate to platform about chip wakeup */
750d7c5f25SPavan Savoy 	kim_data = st_data->kim_data;
760d7c5f25SPavan Savoy 	pdata = kim_data->kim_pdev->dev.platform_data;
77f3d9d365SMatthias Kaehlcke 	if (pdata->chip_awake)
780d7c5f25SPavan Savoy 		pdata->chip_awake(NULL);
79a0cc2f3bSPavan Savoy }
80a0cc2f3bSPavan Savoy 
81a0cc2f3bSPavan Savoy /**********************************************************************/
82a0cc2f3bSPavan Savoy /* functions invoked by ST Core */
83a0cc2f3bSPavan Savoy 
84a0cc2f3bSPavan Savoy /* called when ST Core wants to
85a0cc2f3bSPavan Savoy  * enable ST LL */
86a0cc2f3bSPavan Savoy void st_ll_enable(struct st_data_s *ll)
87a0cc2f3bSPavan Savoy {
88a0cc2f3bSPavan Savoy 	ll->ll_state = ST_LL_AWAKE;
89a0cc2f3bSPavan Savoy }
90a0cc2f3bSPavan Savoy 
91a0cc2f3bSPavan Savoy /* called when ST Core /local module wants to
92a0cc2f3bSPavan Savoy  * disable ST LL */
93a0cc2f3bSPavan Savoy void st_ll_disable(struct st_data_s *ll)
94a0cc2f3bSPavan Savoy {
95a0cc2f3bSPavan Savoy 	ll->ll_state = ST_LL_INVALID;
96a0cc2f3bSPavan Savoy }
97a0cc2f3bSPavan Savoy 
98a0cc2f3bSPavan Savoy /* called when ST Core wants to update the state */
99a0cc2f3bSPavan Savoy void st_ll_wakeup(struct st_data_s *ll)
100a0cc2f3bSPavan Savoy {
101a0cc2f3bSPavan Savoy 	if (likely(ll->ll_state != ST_LL_AWAKE)) {
102a0cc2f3bSPavan Savoy 		send_ll_cmd(ll, LL_WAKE_UP_IND);	/* WAKE_IND */
103a0cc2f3bSPavan Savoy 		ll->ll_state = ST_LL_ASLEEP_TO_AWAKE;
104a0cc2f3bSPavan Savoy 	} else {
105a0cc2f3bSPavan Savoy 		/* don't send the duplicate wake_indication */
106a0cc2f3bSPavan Savoy 		pr_err(" Chip already AWAKE ");
107a0cc2f3bSPavan Savoy 	}
108a0cc2f3bSPavan Savoy }
109a0cc2f3bSPavan Savoy 
110a0cc2f3bSPavan Savoy /* called when ST Core wants the state */
111a0cc2f3bSPavan Savoy unsigned long st_ll_getstate(struct st_data_s *ll)
112a0cc2f3bSPavan Savoy {
113a0cc2f3bSPavan Savoy 	pr_debug(" returning state %ld", ll->ll_state);
114a0cc2f3bSPavan Savoy 	return ll->ll_state;
115a0cc2f3bSPavan Savoy }
116a0cc2f3bSPavan Savoy 
117a0cc2f3bSPavan Savoy /* called from ST Core, when a PM related packet arrives */
118a0cc2f3bSPavan Savoy unsigned long st_ll_sleep_state(struct st_data_s *st_data,
119a0cc2f3bSPavan Savoy 	unsigned char cmd)
120a0cc2f3bSPavan Savoy {
121a0cc2f3bSPavan Savoy 	switch (cmd) {
122a0cc2f3bSPavan Savoy 	case LL_SLEEP_IND:	/* sleep ind */
1236710fcffSPavan Savoy 		pr_debug("sleep indication recvd");
124a0cc2f3bSPavan Savoy 		ll_device_want_to_sleep(st_data);
125a0cc2f3bSPavan Savoy 		break;
126a0cc2f3bSPavan Savoy 	case LL_SLEEP_ACK:	/* sleep ack */
127a0cc2f3bSPavan Savoy 		pr_err("sleep ack rcvd: host shouldn't");
128a0cc2f3bSPavan Savoy 		break;
129a0cc2f3bSPavan Savoy 	case LL_WAKE_UP_IND:	/* wake ind */
1306710fcffSPavan Savoy 		pr_debug("wake indication recvd");
131a0cc2f3bSPavan Savoy 		ll_device_want_to_wakeup(st_data);
132a0cc2f3bSPavan Savoy 		break;
133a0cc2f3bSPavan Savoy 	case LL_WAKE_UP_ACK:	/* wake ack */
1346710fcffSPavan Savoy 		pr_debug("wake ack rcvd");
135a0cc2f3bSPavan Savoy 		st_data->ll_state = ST_LL_AWAKE;
136a0cc2f3bSPavan Savoy 		break;
137a0cc2f3bSPavan Savoy 	default:
138a0cc2f3bSPavan Savoy 		pr_err(" unknown input/state ");
13970442664SPavan Savoy 		return -EINVAL;
140a0cc2f3bSPavan Savoy 	}
141a0cc2f3bSPavan Savoy 	return 0;
142a0cc2f3bSPavan Savoy }
143a0cc2f3bSPavan Savoy 
144a0cc2f3bSPavan Savoy /* Called from ST CORE to initialize ST LL */
145a0cc2f3bSPavan Savoy long st_ll_init(struct st_data_s *ll)
146a0cc2f3bSPavan Savoy {
147a0cc2f3bSPavan Savoy 	/* set state to invalid */
148a0cc2f3bSPavan Savoy 	ll->ll_state = ST_LL_INVALID;
149a0cc2f3bSPavan Savoy 	return 0;
150a0cc2f3bSPavan Savoy }
151a0cc2f3bSPavan Savoy 
152a0cc2f3bSPavan Savoy /* Called from ST CORE to de-initialize ST LL */
153a0cc2f3bSPavan Savoy long st_ll_deinit(struct st_data_s *ll)
154a0cc2f3bSPavan Savoy {
155a0cc2f3bSPavan Savoy 	return 0;
156a0cc2f3bSPavan Savoy }
157