1 // SPDX-License-Identifier: GPL-2.0-only 2 // 3 // rt-sdw-common.c 4 // 5 // Copyright(c) 2024 Realtek Semiconductor Corp. 6 // 7 8 /* 9 * This file defines common functions used with Realtek soundwire codecs. 10 */ 11 12 #include <linux/module.h> 13 #include <linux/regmap.h> 14 #include <linux/bitops.h> 15 #include <linux/soundwire/sdw_registers.h> 16 #include <sound/jack.h> 17 18 #include "rt-sdw-common.h" 19 20 /** 21 * rt_sdca_index_write - Write a value to Realtek defined register. 22 * 23 * @map: map for setting. 24 * @nid: Realtek-defined ID. 25 * @reg: register. 26 * @value: value. 27 * 28 * A value of zero will be returned on success, a negative errno will 29 * be returned in error cases. 30 */ 31 int rt_sdca_index_write(struct regmap *map, unsigned int nid, 32 unsigned int reg, unsigned int value) 33 { 34 unsigned int addr = (nid << 20) | reg; 35 int ret; 36 37 ret = regmap_write(map, addr, value); 38 if (ret < 0) 39 pr_err("Failed to set value: %06x <= %04x ret=%d\n", 40 addr, value, ret); 41 42 return ret; 43 } 44 EXPORT_SYMBOL_GPL(rt_sdca_index_write); 45 46 /** 47 * rt_sdca_index_read - Read value from Realtek defined register. 48 * 49 * @map: map for setting. 50 * @nid: Realtek-defined ID. 51 * @reg: register. 52 * @value: value. 53 * 54 * A value of zero will be returned on success, a negative errno will 55 * be returned in error cases. 56 */ 57 int rt_sdca_index_read(struct regmap *map, unsigned int nid, 58 unsigned int reg, unsigned int *value) 59 { 60 unsigned int addr = (nid << 20) | reg; 61 int ret; 62 63 ret = regmap_read(map, addr, value); 64 if (ret < 0) 65 pr_err("Failed to get value: %06x => %04x ret=%d\n", 66 addr, *value, ret); 67 68 return ret; 69 } 70 EXPORT_SYMBOL_GPL(rt_sdca_index_read); 71 72 /** 73 * rt_sdca_index_update_bits - Update value on Realtek defined register. 74 * 75 * @map: map for setting. 76 * @nid: Realtek-defined ID. 77 * @reg: register. 78 * @mask: Bitmask to change 79 * @val: New value for bitmask 80 * 81 * A value of zero will be returned on success, a negative errno will 82 * be returned in error cases. 83 */ 84 85 int rt_sdca_index_update_bits(struct regmap *map, 86 unsigned int nid, unsigned int reg, unsigned int mask, unsigned int val) 87 { 88 unsigned int tmp; 89 int ret; 90 91 ret = rt_sdca_index_read(map, nid, reg, &tmp); 92 if (ret < 0) 93 return ret; 94 95 set_mask_bits(&tmp, mask, val); 96 return rt_sdca_index_write(map, nid, reg, tmp); 97 } 98 EXPORT_SYMBOL_GPL(rt_sdca_index_update_bits); 99 100 /** 101 * rt_sdca_btn_type - Decision of button type. 102 * 103 * @buffer: UMP message buffer. 104 * 105 * A button type will be returned regarding to buffer, 106 * it returns zero if buffer cannot be recognized. 107 */ 108 int rt_sdca_btn_type(unsigned char *buffer) 109 { 110 u8 btn_type = 0; 111 int ret = 0; 112 113 btn_type |= buffer[0] & 0xf; 114 btn_type |= (buffer[0] >> 4) & 0xf; 115 btn_type |= buffer[1] & 0xf; 116 btn_type |= (buffer[1] >> 4) & 0xf; 117 118 if (btn_type & BIT(0)) 119 ret |= SND_JACK_BTN_2; 120 if (btn_type & BIT(1)) 121 ret |= SND_JACK_BTN_3; 122 if (btn_type & BIT(2)) 123 ret |= SND_JACK_BTN_0; 124 if (btn_type & BIT(3)) 125 ret |= SND_JACK_BTN_1; 126 127 return ret; 128 } 129 EXPORT_SYMBOL_GPL(rt_sdca_btn_type); 130 131 /** 132 * rt_sdca_headset_detect - Headset jack type detection. 133 * 134 * @map: map for setting. 135 * @entity_id: SDCA entity ID. 136 * 137 * A headset jack type will be returned, a negative errno will 138 * be returned in error cases. 139 */ 140 int rt_sdca_headset_detect(struct regmap *map, unsigned int entity_id) 141 { 142 unsigned int det_mode, jack_type; 143 int ret; 144 145 /* get detected_mode */ 146 ret = regmap_read(map, SDW_SDCA_CTL(SDCA_NUM_JACK_CODEC, entity_id, 147 RT_SDCA_CTL_DETECTED_MODE, 0), &det_mode); 148 149 if (ret < 0) 150 goto io_error; 151 152 switch (det_mode) { 153 case 0x03: 154 jack_type = SND_JACK_HEADPHONE; 155 break; 156 case 0x05: 157 jack_type = SND_JACK_HEADSET; 158 break; 159 default: 160 jack_type = 0; 161 break; 162 } 163 164 /* write selected_mode */ 165 if (det_mode) { 166 ret = regmap_write(map, SDW_SDCA_CTL(SDCA_NUM_JACK_CODEC, entity_id, 167 RT_SDCA_CTL_SELECTED_MODE, 0), det_mode); 168 if (ret < 0) 169 goto io_error; 170 } 171 172 return jack_type; 173 174 io_error: 175 pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret); 176 return ret; 177 } 178 EXPORT_SYMBOL_GPL(rt_sdca_headset_detect); 179 180 /** 181 * rt_sdca_button_detect - Read UMP message and decide button type. 182 * 183 * @map: map for setting. 184 * @entity_id: SDCA entity ID. 185 * @hid_buf_addr: HID buffer address. 186 * @hid_id: Report ID for HID. 187 * 188 * A button type will be returned regarding to buffer, 189 * it returns zero if buffer cannot be recognized. 190 */ 191 int rt_sdca_button_detect(struct regmap *map, unsigned int entity_id, 192 unsigned int hid_buf_addr, unsigned int hid_id) 193 { 194 unsigned int btn_type = 0, offset, idx, val, owner; 195 unsigned char buf[3]; 196 int ret; 197 198 /* get current UMP message owner */ 199 ret = regmap_read(map, SDW_SDCA_CTL(SDCA_NUM_HID, entity_id, 200 RT_SDCA_CTL_HIDTX_CURRENT_OWNER, 0), &owner); 201 if (ret < 0) 202 return 0; 203 204 /* if owner is device then there is no button event from device */ 205 if (owner == 1) 206 return 0; 207 208 /* read UMP message offset */ 209 ret = regmap_read(map, SDW_SDCA_CTL(SDCA_NUM_HID, entity_id, 210 RT_SDCA_CTL_HIDTX_MESSAGE_OFFSET, 0), &offset); 211 if (ret < 0) 212 goto _end_btn_det_; 213 214 for (idx = 0; idx < sizeof(buf); idx++) { 215 ret = regmap_read(map, hid_buf_addr + offset + idx, &val); 216 if (ret < 0) 217 goto _end_btn_det_; 218 buf[idx] = val & 0xff; 219 } 220 /* Report ID for HID */ 221 if (buf[0] == hid_id) 222 btn_type = rt_sdca_btn_type(&buf[1]); 223 224 _end_btn_det_: 225 /* Host is owner, so set back to device */ 226 if (owner == 0) 227 /* set owner to device */ 228 regmap_write(map, 229 SDW_SDCA_CTL(SDCA_NUM_HID, entity_id, 230 RT_SDCA_CTL_HIDTX_CURRENT_OWNER, 0), 0x01); 231 232 return btn_type; 233 } 234 EXPORT_SYMBOL_GPL(rt_sdca_button_detect); 235 236 MODULE_DESCRIPTION("Realtek soundwire common functions"); 237 MODULE_AUTHOR("jack yu <jack.yu@realtek.com>"); 238 MODULE_LICENSE("GPL"); 239