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