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