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