18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * rl6347a.c - RL6347A class device shared support 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2015 Realtek Semiconductor Corp. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Oder Chiou <oder_chiou@realtek.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/i2c.h> 128c2ecf20Sopenharmony_ci#include <linux/regmap.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include "rl6347a.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ciint rl6347a_hw_write(void *context, unsigned int reg, unsigned int value) 178c2ecf20Sopenharmony_ci{ 188c2ecf20Sopenharmony_ci struct i2c_client *client = context; 198c2ecf20Sopenharmony_ci struct rl6347a_priv *rl6347a = i2c_get_clientdata(client); 208c2ecf20Sopenharmony_ci u8 data[4]; 218c2ecf20Sopenharmony_ci int ret, i; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci /* handle index registers */ 248c2ecf20Sopenharmony_ci if (reg <= 0xff) { 258c2ecf20Sopenharmony_ci rl6347a_hw_write(client, RL6347A_COEF_INDEX, reg); 268c2ecf20Sopenharmony_ci for (i = 0; i < rl6347a->index_cache_size; i++) { 278c2ecf20Sopenharmony_ci if (reg == rl6347a->index_cache[i].reg) { 288c2ecf20Sopenharmony_ci rl6347a->index_cache[i].def = value; 298c2ecf20Sopenharmony_ci break; 308c2ecf20Sopenharmony_ci } 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci } 338c2ecf20Sopenharmony_ci reg = RL6347A_PROC_COEF; 348c2ecf20Sopenharmony_ci } 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci data[0] = (reg >> 24) & 0xff; 378c2ecf20Sopenharmony_ci data[1] = (reg >> 16) & 0xff; 388c2ecf20Sopenharmony_ci /* 398c2ecf20Sopenharmony_ci * 4 bit VID: reg should be 0 408c2ecf20Sopenharmony_ci * 12 bit VID: value should be 0 418c2ecf20Sopenharmony_ci * So we use an OR operator to handle it rather than use if condition. 428c2ecf20Sopenharmony_ci */ 438c2ecf20Sopenharmony_ci data[2] = ((reg >> 8) & 0xff) | ((value >> 8) & 0xff); 448c2ecf20Sopenharmony_ci data[3] = value & 0xff; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci ret = i2c_master_send(client, data, 4); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci if (ret == 4) 498c2ecf20Sopenharmony_ci return 0; 508c2ecf20Sopenharmony_ci else 518c2ecf20Sopenharmony_ci dev_err(&client->dev, "I2C error %d\n", ret); 528c2ecf20Sopenharmony_ci if (ret < 0) 538c2ecf20Sopenharmony_ci return ret; 548c2ecf20Sopenharmony_ci else 558c2ecf20Sopenharmony_ci return -EIO; 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rl6347a_hw_write); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ciint rl6347a_hw_read(void *context, unsigned int reg, unsigned int *value) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci struct i2c_client *client = context; 628c2ecf20Sopenharmony_ci struct i2c_msg xfer[2]; 638c2ecf20Sopenharmony_ci int ret; 648c2ecf20Sopenharmony_ci __be32 be_reg, buf = 0x0; 658c2ecf20Sopenharmony_ci unsigned int index, vid; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci /* handle index registers */ 688c2ecf20Sopenharmony_ci if (reg <= 0xff) { 698c2ecf20Sopenharmony_ci rl6347a_hw_write(client, RL6347A_COEF_INDEX, reg); 708c2ecf20Sopenharmony_ci reg = RL6347A_PROC_COEF; 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci reg = reg | 0x80000; 748c2ecf20Sopenharmony_ci vid = (reg >> 8) & 0xfff; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci if (AC_VERB_GET_AMP_GAIN_MUTE == (vid & 0xf00)) { 778c2ecf20Sopenharmony_ci index = (reg >> 8) & 0xf; 788c2ecf20Sopenharmony_ci reg = (reg & ~0xf0f) | index; 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci be_reg = cpu_to_be32(reg); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci /* Write register */ 838c2ecf20Sopenharmony_ci xfer[0].addr = client->addr; 848c2ecf20Sopenharmony_ci xfer[0].flags = 0; 858c2ecf20Sopenharmony_ci xfer[0].len = 4; 868c2ecf20Sopenharmony_ci xfer[0].buf = (u8 *)&be_reg; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci /* Read data */ 898c2ecf20Sopenharmony_ci xfer[1].addr = client->addr; 908c2ecf20Sopenharmony_ci xfer[1].flags = I2C_M_RD; 918c2ecf20Sopenharmony_ci xfer[1].len = 4; 928c2ecf20Sopenharmony_ci xfer[1].buf = (u8 *)&buf; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci ret = i2c_transfer(client->adapter, xfer, 2); 958c2ecf20Sopenharmony_ci if (ret < 0) 968c2ecf20Sopenharmony_ci return ret; 978c2ecf20Sopenharmony_ci else if (ret != 2) 988c2ecf20Sopenharmony_ci return -EIO; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci *value = be32_to_cpu(buf); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci return 0; 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rl6347a_hw_read); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("RL6347A class device shared support"); 1078c2ecf20Sopenharmony_ciMODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>"); 1088c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 109