1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Abilis Systems Single DVB-T Receiver 4 * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com> 5 */ 6 7 #include <linux/kernel.h> 8 #include "as102_drv.h" 9 #include "as10x_cmd.h" 10 11 /***************************/ 12 /* FUNCTION DEFINITION */ 13 /***************************/ 14 15 /** 16 * as10x_cmd_get_context - Send get context command to AS10x 17 * @adap: pointer to AS10x bus adapter 18 * @tag: context tag 19 * @pvalue: pointer where to store context value read 20 * 21 * Return 0 on success or negative value in case of error. 22 */ 23 int as10x_cmd_get_context(struct as10x_bus_adapter_t *adap, uint16_t tag, 24 uint32_t *pvalue) 25 { 26 int error; 27 struct as10x_cmd_t *pcmd, *prsp; 28 29 pcmd = adap->cmd; 30 prsp = adap->rsp; 31 32 /* prepare command */ 33 as10x_cmd_build(pcmd, (++adap->cmd_xid), 34 sizeof(pcmd->body.context.req)); 35 36 /* fill command */ 37 pcmd->body.context.req.proc_id = cpu_to_le16(CONTROL_PROC_CONTEXT); 38 pcmd->body.context.req.tag = cpu_to_le16(tag); 39 pcmd->body.context.req.type = cpu_to_le16(GET_CONTEXT_DATA); 40 41 /* send command */ 42 if (adap->ops->xfer_cmd) { 43 error = adap->ops->xfer_cmd(adap, 44 (uint8_t *) pcmd, 45 sizeof(pcmd->body.context.req) 46 + HEADER_SIZE, 47 (uint8_t *) prsp, 48 sizeof(prsp->body.context.rsp) 49 + HEADER_SIZE); 50 } else { 51 error = AS10X_CMD_ERROR; 52 } 53 54 if (error < 0) 55 goto out; 56 57 /* parse response: context command do not follow the common response */ 58 /* structure -> specific handling response parse required */ 59 error = as10x_context_rsp_parse(prsp, CONTROL_PROC_CONTEXT_RSP); 60 61 if (error == 0) { 62 /* Response OK -> get response data */ 63 *pvalue = le32_to_cpu((__force __le32)prsp->body.context.rsp.reg_val.u.value32); 64 /* value returned is always a 32-bit value */ 65 } 66 67 out: 68 return error; 69 } 70 71 /** 72 * as10x_cmd_set_context - send set context command to AS10x 73 * @adap: pointer to AS10x bus adapter 74 * @tag: context tag 75 * @value: value to set in context 76 * 77 * Return 0 on success or negative value in case of error. 78 */ 79 int as10x_cmd_set_context(struct as10x_bus_adapter_t *adap, uint16_t tag, 80 uint32_t value) 81 { 82 int error; 83 struct as10x_cmd_t *pcmd, *prsp; 84 85 pcmd = adap->cmd; 86 prsp = adap->rsp; 87 88 /* prepare command */ 89 as10x_cmd_build(pcmd, (++adap->cmd_xid), 90 sizeof(pcmd->body.context.req)); 91 92 /* fill command */ 93 pcmd->body.context.req.proc_id = cpu_to_le16(CONTROL_PROC_CONTEXT); 94 /* pcmd->body.context.req.reg_val.mode initialization is not required */ 95 pcmd->body.context.req.reg_val.u.value32 = (__force u32)cpu_to_le32(value); 96 pcmd->body.context.req.tag = cpu_to_le16(tag); 97 pcmd->body.context.req.type = cpu_to_le16(SET_CONTEXT_DATA); 98 99 /* send command */ 100 if (adap->ops->xfer_cmd) { 101 error = adap->ops->xfer_cmd(adap, 102 (uint8_t *) pcmd, 103 sizeof(pcmd->body.context.req) 104 + HEADER_SIZE, 105 (uint8_t *) prsp, 106 sizeof(prsp->body.context.rsp) 107 + HEADER_SIZE); 108 } else { 109 error = AS10X_CMD_ERROR; 110 } 111 112 if (error < 0) 113 goto out; 114 115 /* parse response: context command do not follow the common response */ 116 /* structure -> specific handling response parse required */ 117 error = as10x_context_rsp_parse(prsp, CONTROL_PROC_CONTEXT_RSP); 118 119 out: 120 return error; 121 } 122 123 /** 124 * as10x_cmd_eLNA_change_mode - send eLNA change mode command to AS10x 125 * @adap: pointer to AS10x bus adapter 126 * @mode: mode selected: 127 * - ON : 0x0 => eLNA always ON 128 * - OFF : 0x1 => eLNA always OFF 129 * - AUTO : 0x2 => eLNA follow hysteresis parameters 130 * to be ON or OFF 131 * 132 * Return 0 on success or negative value in case of error. 133 */ 134 int as10x_cmd_eLNA_change_mode(struct as10x_bus_adapter_t *adap, uint8_t mode) 135 { 136 int error; 137 struct as10x_cmd_t *pcmd, *prsp; 138 139 pcmd = adap->cmd; 140 prsp = adap->rsp; 141 142 /* prepare command */ 143 as10x_cmd_build(pcmd, (++adap->cmd_xid), 144 sizeof(pcmd->body.cfg_change_mode.req)); 145 146 /* fill command */ 147 pcmd->body.cfg_change_mode.req.proc_id = 148 cpu_to_le16(CONTROL_PROC_ELNA_CHANGE_MODE); 149 pcmd->body.cfg_change_mode.req.mode = mode; 150 151 /* send command */ 152 if (adap->ops->xfer_cmd) { 153 error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd, 154 sizeof(pcmd->body.cfg_change_mode.req) 155 + HEADER_SIZE, (uint8_t *) prsp, 156 sizeof(prsp->body.cfg_change_mode.rsp) 157 + HEADER_SIZE); 158 } else { 159 error = AS10X_CMD_ERROR; 160 } 161 162 if (error < 0) 163 goto out; 164 165 /* parse response */ 166 error = as10x_rsp_parse(prsp, CONTROL_PROC_ELNA_CHANGE_MODE_RSP); 167 168 out: 169 return error; 170 } 171 172 /** 173 * as10x_context_rsp_parse - Parse context command response 174 * @prsp: pointer to AS10x command response buffer 175 * @proc_id: id of the command 176 * 177 * Since the contex command response does not follow the common 178 * response, a specific parse function is required. 179 * Return 0 on success or negative value in case of error. 180 */ 181 int as10x_context_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id) 182 { 183 int err; 184 185 err = prsp->body.context.rsp.error; 186 187 if ((err == 0) && 188 (le16_to_cpu(prsp->body.context.rsp.proc_id) == proc_id)) { 189 return 0; 190 } 191 return AS10X_CMD_ERROR; 192 } 193