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