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