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