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