blob: 99379169a1a3491e60f5119cd2d7eb037d3e9816 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001/*
2* All Rights Reserved
3*
4* MARVELL CONFIDENTIAL
5* Copyright 2012 Marvell International Ltd All Rights Reserved.
6* The source code contained or described herein and all documents related to
7* the source code ("Material") are owned by Marvell International Ltd or its
8* suppliers or licensors. Title to the Material remains with Marvell International Ltd
9* or its suppliers and licensors. The Material contains trade secrets and
10* proprietary and confidential information of Marvell or its suppliers and
11* licensors. The Material is protected by worldwide copyright and trade secret
12* laws and treaty provisions. No part of the Material may be used, copied,
13* reproduced, modified, published, uploaded, posted, transmitted, distributed,
14* or disclosed in any way without Marvell's prior express written permission.
15*
16* No license under any patent, copyright, trade secret or other intellectual
17* property right is granted to or conferred upon you by disclosure or delivery
18* of the Materials, either expressly, by implication, inducement, estoppel or
19* otherwise. Any license under such intellectual property rights must be
20* express and approved by Marvell in writing.
21*
22*/
23
24#define LOG_TAG "acm_ach_gelato"
25#define LOG_NDEBUG 0
26
27#define SYSCLK_DEV "/proc/driver/sspa_sysclk"
28
29#include <cutils/log.h>
30#include "acm_gelato.h"
31#include <sys/types.h>
32#include <sys/stat.h>
33#include <fcntl.h>
34
35int codec_reg_num = NUM_OF_REGS;
36
37static void CODEC_Enable(void);
38static void CODEC_Disable(void);
39static void CODEC_Reset(void);
40static void CODEC_GetTypeAndID(int *type, unsigned char *id);
41static ACH_ReturnCode CODEC_Handle(void *setting);
42
43ACH_ComponentHandler CODEC_handler = {
44 COMPONENT_INACTIVE,
45 0,
46 CODEC_Enable,
47 CODEC_Disable,
48 CODEC_Reset,
49 CODEC_GetTypeAndID,
50 CODEC_Handle,
51};
52
53extern void I2CWrite(unsigned char numid, unsigned short value);
54extern void I2CBurstWrite(unsigned char numid, unsigned char size, unsigned char *value);
55extern void I2CRead(unsigned char numid, unsigned char *value);
56extern void I2CBurstRead(unsigned char numid, unsigned char *value, unsigned char *size);
57
58static void CODEC_RegSet(unsigned char numid, unsigned char value) {
59#ifndef DEBUG_FAKE_ACH
60 I2CWrite(numid, value);
61#endif
62}
63
64static void CODEC_RegBurstSet(unsigned char numid, unsigned char size, unsigned char *value) {
65#ifndef DEBUG_FAKE_ACH
66 I2CBurstWrite(numid, size, value);
67#endif
68}
69
70void CODEC_RegGet(unsigned char numid, unsigned char *value) {
71#ifndef DEBUG_FAKE_ACH
72 I2CRead(numid, value);
73#endif
74}
75
76void CODEC_RegBurstGet(unsigned char numid, unsigned char *value, unsigned char *size) {
77#ifndef DEBUG_FAKE_ACH
78 I2CBurstRead(numid, value, size);
79#endif
80}
81
82static void CODEC_ResetRegCache() {
83 int size = sizeof(reg_cache) / sizeof(reg_cache[0]);
84 int i = 0;
85
86 for (i = 0; i < size; i++) {
87 reg_cache[i].reg_value = reg_cache[i].reg_default;
88 }
89}
90
91unsigned char CODEC_GetRegNumId(unsigned char reg_index) {
92 unsigned char i = 0;
93
94 for (i = 0; i < NUM_OF_REGS; i++) {
95 if (reg_cache[i].reg_index == reg_index) {
96 return REG_NUMID_BASE + i;
97 }
98 }
99
100 return 0;
101}
102
103//--------------------------------------------------------------
104//-------- External ACH APIs
105//--------------------------------------------------------------
106static void CODEC_Enable(void) {
107 int mDev;
108 LOGI(CODEC_Enable, "%s: enable gelato component", __FUNCTION__);
109
110 /* Open sysclk */
111 mDev = open(SYSCLK_DEV, O_RDWR);
112 if (mDev < 0) {
113 LOGE(CODEC_Enable1, "%s: Failed to open %s\n", __FUNCTION__, SYSCLK_DEV);
114 } else {
115 write(mDev, "1", 1);
116 mDev = -1;
117 LOGI(CODEC_Enable2, "%s: open sysclk\n", __FUNCTION__);
118 }
119
120 /* To be implemented after power control regiter is supported in GELATO production version */
121 //usleep(2000);
122 CODEC_RegSet(0x11, 0x00);
123 CODEC_RegSet(0x11, 0x01);
124 CODEC_ResetRegCache();
125
126 CODEC_RegSet(0xc8, 0x01);
127 CODEC_RegSet(0x25, 0x00);
128 CODEC_RegSet(0xd4, 0xff);
129 reg_cache[0xc8].reg_value = 0x01;
130 reg_cache[0x25].reg_value = 0x00;
131 reg_cache[0xd4].reg_value = 0xff;
132}
133
134static void CODEC_Disable(void) {
135 int mDev;
136 LOGI(CODEC_Disable, "%s: disable gelato component", __FUNCTION__);
137
138 /* disable sysclk */
139 mDev = open(SYSCLK_DEV, O_RDWR);
140 if (mDev < 0) {
141 LOGE(CODEC_Disable1, "%s: Failed to open %s\n", __FUNCTION__, SYSCLK_DEV);
142 } else {
143 /* now there's a work around, as EDEN Z1 use gelato to do HS detection, we cannot shut down its work clock, otherwise HS detection function will not work */
144 //write(mDev, "0", 1);
145 mDev = -1;
146 LOGI(CODEC_Disable2, "%s: disable sysclk\n", __FUNCTION__);
147 }
148
149 /* To be implemented after power control regiter is supported in GELATO production version */
150 //usleep(2000);
151
152 /* Should power down codec to save power here, but R26.3 GELATO cannot dectect plugged-in headset before power up, so we cannot disable codec now even at idle state, will refine this after GELATO improved its headset detection function */
153 //CODEC_RegSet(0x11, 0x31);
154 //reg_cache[0xc8].reg_value = 0x31;
155}
156
157static void CODEC_Reset(void) {
158 LOGI(CODEC_Reset, "%s: reset gelato component", __FUNCTION__);
159}
160
161static void CODEC_GetTypeAndID(int *type, unsigned char *id) {
162 LOGI(CODEC_GetTypeAndID, "%s: Get type and ID for gelato component", __FUNCTION__);
163 *type = COMPONENT_TYPE_CODEC;
164 //CODEC_RegGet(CODEC_ID_REG, id);
165 *id = 0x0;
166}
167
168static ACH_ReturnCode CODEC_Handle(void *setting) {
169 ACH_ComponentParameter *param = (ACH_ComponentParameter *)setting;
170 unsigned short i = 0;
171 unsigned char numid, value, cache_idx;
172
173 if (param && param->i2c.reg_value) {
174 numid = CODEC_GetRegNumId(param->i2c.reg_index);
175 if (numid > 0) {
176 if (param->i2c.length == 1) {
177 //compare with register cache
178 cache_idx = numid - REG_NUMID_BASE;
179 //value = (reg_cache[cache_idx].reg_value & ~param->i2c.reg_mask) | (*param->i2c.reg_value);
180 //if ((reg_cache[cache_idx].reg_value & param->i2c.reg_mask) != (*param->i2c.reg_value)) {
181 value = (((*param->i2c.reg_value) << param->i2c.reg_shift) & param->i2c.reg_mask);
182 if ((reg_cache[cache_idx].reg_value & param->i2c.reg_mask) != value) {
183#ifdef DEBUG_CODEC
184 LOGI(CODEC_Handle, "%s: set register 0x%02x [0x%02x --> 0x%02x]",
185 __FUNCTION__,
186 param->i2c.reg_index,
187 reg_cache[cache_idx].reg_value,
188 (reg_cache[cache_idx].reg_value & ~param->i2c.reg_mask) | value);
189#endif
190 //reg_cache[cache_idx].reg_value = value;
191 reg_cache[cache_idx].reg_value = (reg_cache[cache_idx].reg_value & ~param->i2c.reg_mask) | value;
192 CODEC_RegSet(numid, reg_cache[cache_idx].reg_value);
193 } else {
194#ifdef DEBUG_CODEC
195 LOGI(CODEC_Handle1, "%s: set register 0x%02x [0x%02x --> 0x%02x] (unchanged)",
196 __FUNCTION__,
197 param->i2c.reg_index,
198 reg_cache[cache_idx].reg_value,
199 reg_cache[cache_idx].reg_value);
200#endif
201 }
202 } else if (param->i2c.length > 1) {
203 //FIXME current no register cache is provided for mixer/eq configuration
204#ifdef DEBUG_CODEC
205 LOGI(CODEC_Handle2, "%s: set register 0x%02x values:", __FUNCTION__, param->i2c.reg_index);
206 for (i = 0; i < param->i2c.length; i++) {
207 LOGI(CODEC_Handle3, "%s: \t\t\t -->0x%02x", __FUNCTION__, param->i2c.reg_value[i]);
208 }
209#endif
210
211 CODEC_RegBurstSet(numid, param->i2c.length, param->i2c.reg_value);
212 }
213 }
214 }
215
216 return ACH_RC_OK;
217}