linux/drivers/media/tuners/tuner-i2c.h
<<
>>
Prefs
   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
  27struct 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
  36static 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
  46static 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
  56static 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