1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19#include <linux/module.h>
20#include <linux/types.h>
21#include <linux/slab.h>
22#include <linux/ioctl.h>
23#include <linux/uaccess.h>
24#include <linux/i2c.h>
25#include <linux/videodev2.h>
26#include <media/i2c/m52790.h>
27#include <media/v4l2-device.h>
28
29MODULE_DESCRIPTION("i2c device driver for m52790 A/V switch");
30MODULE_AUTHOR("Hans Verkuil");
31MODULE_LICENSE("GPL");
32
33
34struct m52790_state {
35 struct v4l2_subdev sd;
36 u16 input;
37 u16 output;
38};
39
40static inline struct m52790_state *to_state(struct v4l2_subdev *sd)
41{
42 return container_of(sd, struct m52790_state, sd);
43}
44
45
46
47static int m52790_write(struct v4l2_subdev *sd)
48{
49 struct m52790_state *state = to_state(sd);
50 struct i2c_client *client = v4l2_get_subdevdata(sd);
51
52 u8 sw1 = (state->input | state->output) & 0xff;
53 u8 sw2 = (state->input | state->output) >> 8;
54
55 return i2c_smbus_write_byte_data(client, sw1, sw2);
56}
57
58
59
60
61
62
63
64
65
66static int m52790_s_routing(struct v4l2_subdev *sd,
67 u32 input, u32 output, u32 config)
68{
69 struct m52790_state *state = to_state(sd);
70
71 state->input = input;
72 state->output = output;
73 m52790_write(sd);
74 return 0;
75}
76
77#ifdef CONFIG_VIDEO_ADV_DEBUG
78static int m52790_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
79{
80 struct m52790_state *state = to_state(sd);
81
82 if (reg->reg != 0)
83 return -EINVAL;
84 reg->size = 1;
85 reg->val = state->input | state->output;
86 return 0;
87}
88
89static int m52790_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
90{
91 struct m52790_state *state = to_state(sd);
92
93 if (reg->reg != 0)
94 return -EINVAL;
95 state->input = reg->val & 0x0303;
96 state->output = reg->val & ~0x0303;
97 m52790_write(sd);
98 return 0;
99}
100#endif
101
102static int m52790_log_status(struct v4l2_subdev *sd)
103{
104 struct m52790_state *state = to_state(sd);
105
106 v4l2_info(sd, "Switch 1: %02x\n",
107 (state->input | state->output) & 0xff);
108 v4l2_info(sd, "Switch 2: %02x\n",
109 (state->input | state->output) >> 8);
110 return 0;
111}
112
113
114
115static const struct v4l2_subdev_core_ops m52790_core_ops = {
116 .log_status = m52790_log_status,
117#ifdef CONFIG_VIDEO_ADV_DEBUG
118 .g_register = m52790_g_register,
119 .s_register = m52790_s_register,
120#endif
121};
122
123static const struct v4l2_subdev_audio_ops m52790_audio_ops = {
124 .s_routing = m52790_s_routing,
125};
126
127static const struct v4l2_subdev_video_ops m52790_video_ops = {
128 .s_routing = m52790_s_routing,
129};
130
131static const struct v4l2_subdev_ops m52790_ops = {
132 .core = &m52790_core_ops,
133 .audio = &m52790_audio_ops,
134 .video = &m52790_video_ops,
135};
136
137
138
139
140
141static int m52790_probe(struct i2c_client *client,
142 const struct i2c_device_id *id)
143{
144 struct m52790_state *state;
145 struct v4l2_subdev *sd;
146
147
148 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
149 return -EIO;
150
151 v4l_info(client, "chip found @ 0x%x (%s)\n",
152 client->addr << 1, client->adapter->name);
153
154 state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
155 if (state == NULL)
156 return -ENOMEM;
157
158 sd = &state->sd;
159 v4l2_i2c_subdev_init(sd, client, &m52790_ops);
160 state->input = M52790_IN_TUNER;
161 state->output = M52790_OUT_STEREO;
162 m52790_write(sd);
163 return 0;
164}
165
166static int m52790_remove(struct i2c_client *client)
167{
168 struct v4l2_subdev *sd = i2c_get_clientdata(client);
169
170 v4l2_device_unregister_subdev(sd);
171 return 0;
172}
173
174
175
176static const struct i2c_device_id m52790_id[] = {
177 { "m52790", 0 },
178 { }
179};
180MODULE_DEVICE_TABLE(i2c, m52790_id);
181
182static struct i2c_driver m52790_driver = {
183 .driver = {
184 .name = "m52790",
185 },
186 .probe = m52790_probe,
187 .remove = m52790_remove,
188 .id_table = m52790_id,
189};
190
191module_i2c_driver(m52790_driver);
192