Commit | Line | Data |
---|---|---|
bc08f96b OC |
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"); |