1 // SPDX-License-Identifier: GPL-2.0-only 1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 2 /* 3 * rl6347a.c - RL6347A class device shared sup 3 * rl6347a.c - RL6347A class device shared support 4 * 4 * 5 * Copyright 2015 Realtek Semiconductor Corp. 5 * Copyright 2015 Realtek Semiconductor Corp. 6 * 6 * 7 * Author: Oder Chiou <oder_chiou@realtek.com> 7 * Author: Oder Chiou <oder_chiou@realtek.com> 8 */ 8 */ 9 9 10 #include <linux/module.h> 10 #include <linux/module.h> 11 #include <linux/i2c.h> 11 #include <linux/i2c.h> 12 #include <linux/regmap.h> 12 #include <linux/regmap.h> 13 13 14 #include "rl6347a.h" 14 #include "rl6347a.h" 15 15 16 int rl6347a_hw_write(void *context, unsigned i 16 int rl6347a_hw_write(void *context, unsigned int reg, unsigned int value) 17 { 17 { 18 struct i2c_client *client = context; 18 struct i2c_client *client = context; 19 struct rl6347a_priv *rl6347a = i2c_get 19 struct rl6347a_priv *rl6347a = i2c_get_clientdata(client); 20 u8 data[4]; 20 u8 data[4]; 21 int ret, i; 21 int ret, i; 22 22 23 /* handle index registers */ 23 /* handle index registers */ 24 if (reg <= 0xff) { 24 if (reg <= 0xff) { 25 rl6347a_hw_write(client, RL634 25 rl6347a_hw_write(client, RL6347A_COEF_INDEX, reg); 26 for (i = 0; i < rl6347a->index 26 for (i = 0; i < rl6347a->index_cache_size; i++) { 27 if (reg == rl6347a->in 27 if (reg == rl6347a->index_cache[i].reg) { 28 rl6347a->index 28 rl6347a->index_cache[i].def = value; 29 break; 29 break; 30 } 30 } 31 31 32 } 32 } 33 reg = RL6347A_PROC_COEF; 33 reg = RL6347A_PROC_COEF; 34 } 34 } 35 35 36 data[0] = (reg >> 24) & 0xff; 36 data[0] = (reg >> 24) & 0xff; 37 data[1] = (reg >> 16) & 0xff; 37 data[1] = (reg >> 16) & 0xff; 38 /* 38 /* 39 * 4 bit VID: reg should be 0 39 * 4 bit VID: reg should be 0 40 * 12 bit VID: value should be 0 40 * 12 bit VID: value should be 0 41 * So we use an OR operator to handle 41 * So we use an OR operator to handle it rather than use if condition. 42 */ 42 */ 43 data[2] = ((reg >> 8) & 0xff) | ((valu 43 data[2] = ((reg >> 8) & 0xff) | ((value >> 8) & 0xff); 44 data[3] = value & 0xff; 44 data[3] = value & 0xff; 45 45 46 ret = i2c_master_send(client, data, 4) 46 ret = i2c_master_send(client, data, 4); 47 47 48 if (ret == 4) 48 if (ret == 4) 49 return 0; 49 return 0; 50 else 50 else 51 dev_err(&client->dev, "I2C err 51 dev_err(&client->dev, "I2C error %d\n", ret); 52 if (ret < 0) 52 if (ret < 0) 53 return ret; 53 return ret; 54 else 54 else 55 return -EIO; 55 return -EIO; 56 } 56 } 57 EXPORT_SYMBOL_GPL(rl6347a_hw_write); 57 EXPORT_SYMBOL_GPL(rl6347a_hw_write); 58 58 59 int rl6347a_hw_read(void *context, unsigned in 59 int rl6347a_hw_read(void *context, unsigned int reg, unsigned int *value) 60 { 60 { 61 struct i2c_client *client = context; 61 struct i2c_client *client = context; 62 struct i2c_msg xfer[2]; 62 struct i2c_msg xfer[2]; 63 int ret; 63 int ret; 64 __be32 be_reg, buf = 0x0; 64 __be32 be_reg, buf = 0x0; 65 unsigned int index, vid; 65 unsigned int index, vid; 66 66 67 /* handle index registers */ 67 /* handle index registers */ 68 if (reg <= 0xff) { 68 if (reg <= 0xff) { 69 rl6347a_hw_write(client, RL634 69 rl6347a_hw_write(client, RL6347A_COEF_INDEX, reg); 70 reg = RL6347A_PROC_COEF; 70 reg = RL6347A_PROC_COEF; 71 } 71 } 72 72 73 reg = reg | 0x80000; 73 reg = reg | 0x80000; 74 vid = (reg >> 8) & 0xfff; 74 vid = (reg >> 8) & 0xfff; 75 75 76 if (AC_VERB_GET_AMP_GAIN_MUTE == (vid 76 if (AC_VERB_GET_AMP_GAIN_MUTE == (vid & 0xf00)) { 77 index = (reg >> 8) & 0xf; 77 index = (reg >> 8) & 0xf; 78 reg = (reg & ~0xf0f) | index; 78 reg = (reg & ~0xf0f) | index; 79 } 79 } 80 be_reg = cpu_to_be32(reg); 80 be_reg = cpu_to_be32(reg); 81 81 82 /* Write register */ 82 /* Write register */ 83 xfer[0].addr = client->addr; 83 xfer[0].addr = client->addr; 84 xfer[0].flags = 0; 84 xfer[0].flags = 0; 85 xfer[0].len = 4; 85 xfer[0].len = 4; 86 xfer[0].buf = (u8 *)&be_reg; 86 xfer[0].buf = (u8 *)&be_reg; 87 87 88 /* Read data */ 88 /* Read data */ 89 xfer[1].addr = client->addr; 89 xfer[1].addr = client->addr; 90 xfer[1].flags = I2C_M_RD; 90 xfer[1].flags = I2C_M_RD; 91 xfer[1].len = 4; 91 xfer[1].len = 4; 92 xfer[1].buf = (u8 *)&buf; 92 xfer[1].buf = (u8 *)&buf; 93 93 94 ret = i2c_transfer(client->adapter, xf 94 ret = i2c_transfer(client->adapter, xfer, 2); 95 if (ret < 0) 95 if (ret < 0) 96 return ret; 96 return ret; 97 else if (ret != 2) 97 else if (ret != 2) 98 return -EIO; 98 return -EIO; 99 99 100 *value = be32_to_cpu(buf); 100 *value = be32_to_cpu(buf); 101 101 102 return 0; 102 return 0; 103 } 103 } 104 EXPORT_SYMBOL_GPL(rl6347a_hw_read); 104 EXPORT_SYMBOL_GPL(rl6347a_hw_read); 105 105 106 MODULE_DESCRIPTION("RL6347A class device share 106 MODULE_DESCRIPTION("RL6347A class device shared support"); 107 MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek. 107 MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>"); 108 MODULE_LICENSE("GPL v2"); 108 MODULE_LICENSE("GPL v2"); 109 109
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.