Blame view

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