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
16int 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}
57EXPORT_SYMBOL_GPL(rl6347a_hw_write);
58
59int 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}
104EXPORT_SYMBOL_GPL(rl6347a_hw_read);
105
106MODULE_DESCRIPTION("RL6347A class device shared support");
107MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>");
108MODULE_LICENSE("GPL v2");
109