xref: /openbmc/linux/drivers/media/tuners/tuner-i2c.h (revision 9cfc5c90)
1 /*
2     tuner-i2c.h - i2c interface for different tuners
3 
4     Copyright (C) 2007 Michael Krufky (mkrufky@linuxtv.org)
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20 
21 #ifndef __TUNER_I2C_H__
22 #define __TUNER_I2C_H__
23 
24 #include <linux/i2c.h>
25 #include <linux/slab.h>
26 
27 struct tuner_i2c_props {
28 	u8 addr;
29 	struct i2c_adapter *adap;
30 
31 	/* used for tuner instance management */
32 	int count;
33 	char *name;
34 };
35 
36 static inline int tuner_i2c_xfer_send(struct tuner_i2c_props *props,
37 				      unsigned char *buf, int len)
38 {
39 	struct i2c_msg msg = { .addr = props->addr, .flags = 0,
40 			       .buf = buf, .len = len };
41 	int ret = i2c_transfer(props->adap, &msg, 1);
42 
43 	return (ret == 1) ? len : ret;
44 }
45 
46 static inline int tuner_i2c_xfer_recv(struct tuner_i2c_props *props,
47 				      unsigned char *buf, int len)
48 {
49 	struct i2c_msg msg = { .addr = props->addr, .flags = I2C_M_RD,
50 			       .buf = buf, .len = len };
51 	int ret = i2c_transfer(props->adap, &msg, 1);
52 
53 	return (ret == 1) ? len : ret;
54 }
55 
56 static inline int tuner_i2c_xfer_send_recv(struct tuner_i2c_props *props,
57 					   unsigned char *obuf, int olen,
58 					   unsigned char *ibuf, int ilen)
59 {
60 	struct i2c_msg msg[2] = { { .addr = props->addr, .flags = 0,
61 				    .buf = obuf, .len = olen },
62 				  { .addr = props->addr, .flags = I2C_M_RD,
63 				    .buf = ibuf, .len = ilen } };
64 	int ret = i2c_transfer(props->adap, msg, 2);
65 
66 	return (ret == 2) ? ilen : ret;
67 }
68 
69 /* Callers must declare as a global for the module:
70  *
71  * static LIST_HEAD(hybrid_tuner_instance_list);
72  *
73  * hybrid_tuner_instance_list should be the third argument
74  * passed into hybrid_tuner_request_state().
75  *
76  * state structure must contain the following:
77  *
78  * 	struct list_head	hybrid_tuner_instance_list;
79  *	struct tuner_i2c_props	i2c_props;
80  *
81  * hybrid_tuner_instance_list (both within state structure and globally)
82  * is only required if the driver is using hybrid_tuner_request_state
83  * and hybrid_tuner_release_state to manage state sharing between
84  * multiple instances of hybrid tuners.
85  */
86 
87 #define tuner_printk(kernlvl, i2cprops, fmt, arg...) do {		\
88 	printk(kernlvl "%s %d-%04x: " fmt, i2cprops.name,		\
89 			i2cprops.adap ?					\
90 				i2c_adapter_id(i2cprops.adap) : -1,	\
91 			i2cprops.addr, ##arg);				\
92 	 } while (0)
93 
94 /* TO DO: convert all callers of these macros to pass in
95  * struct tuner_i2c_props, then remove the macro wrappers */
96 
97 #define __tuner_warn(i2cprops, fmt, arg...) do {			\
98 	tuner_printk(KERN_WARNING, i2cprops, fmt, ##arg);		\
99 	} while (0)
100 
101 #define __tuner_info(i2cprops, fmt, arg...) do {			\
102 	tuner_printk(KERN_INFO, i2cprops, fmt, ##arg);			\
103 	} while (0)
104 
105 #define __tuner_err(i2cprops, fmt, arg...) do {				\
106 	tuner_printk(KERN_ERR, i2cprops, fmt, ##arg);			\
107 	} while (0)
108 
109 #define __tuner_dbg(i2cprops, fmt, arg...) do {				\
110 	if ((debug))							\
111 		tuner_printk(KERN_DEBUG, i2cprops, fmt, ##arg);		\
112 	} while (0)
113 
114 #define tuner_warn(fmt, arg...) __tuner_warn(priv->i2c_props, fmt, ##arg)
115 #define tuner_info(fmt, arg...) __tuner_info(priv->i2c_props, fmt, ##arg)
116 #define tuner_err(fmt, arg...) __tuner_err(priv->i2c_props, fmt, ##arg)
117 #define tuner_dbg(fmt, arg...) __tuner_dbg(priv->i2c_props, fmt, ##arg)
118 
119 /****************************************************************************/
120 
121 /* The return value of hybrid_tuner_request_state indicates the number of
122  * instances using this tuner object.
123  *
124  * 0 - no instances, indicates an error - kzalloc must have failed
125  *
126  * 1 - one instance, indicates that the tuner object was created successfully
127  *
128  * 2 (or more) instances, indicates that an existing tuner object was found
129  */
130 
131 #define hybrid_tuner_request_state(type, state, list, i2cadap, i2caddr, devname)\
132 ({									\
133 	int __ret = 0;							\
134 	list_for_each_entry(state, &list, hybrid_tuner_instance_list) {	\
135 		if (((i2cadap) && (state->i2c_props.adap)) &&		\
136 		    ((i2c_adapter_id(state->i2c_props.adap) ==		\
137 		      i2c_adapter_id(i2cadap)) &&			\
138 		     (i2caddr == state->i2c_props.addr))) {		\
139 			__tuner_info(state->i2c_props,			\
140 				     "attaching existing instance\n");	\
141 			state->i2c_props.count++;			\
142 			__ret = state->i2c_props.count;			\
143 			break;						\
144 		}							\
145 	}								\
146 	if (0 == __ret) {						\
147 		state = kzalloc(sizeof(type), GFP_KERNEL);		\
148 		if (NULL == state)					\
149 			goto __fail;					\
150 		state->i2c_props.addr = i2caddr;			\
151 		state->i2c_props.adap = i2cadap;			\
152 		state->i2c_props.name = devname;			\
153 		__tuner_info(state->i2c_props,				\
154 			     "creating new instance\n");		\
155 		list_add_tail(&state->hybrid_tuner_instance_list, &list);\
156 		state->i2c_props.count++;				\
157 		__ret = state->i2c_props.count;				\
158 	}								\
159 __fail:									\
160 	__ret;								\
161 })
162 
163 #define hybrid_tuner_release_state(state)				\
164 ({									\
165 	int __ret;							\
166 	state->i2c_props.count--;					\
167 	__ret = state->i2c_props.count;					\
168 	if (!state->i2c_props.count) {					\
169 		__tuner_info(state->i2c_props, "destroying instance\n");\
170 		list_del(&state->hybrid_tuner_instance_list);		\
171 		kfree(state);						\
172 	}								\
173 	__ret;								\
174 })
175 
176 #define hybrid_tuner_report_instance_count(state)			\
177 ({									\
178 	int __ret = 0;							\
179 	if (state)							\
180 		__ret = state->i2c_props.count;				\
181 	__ret;								\
182 })
183 
184 #endif /* __TUNER_I2C_H__ */
185