18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci tuner-i2c.h - i2c interface for different tuners 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci Copyright (C) 2007 Michael Krufky (mkrufky@linuxtv.org) 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci*/ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#ifndef __TUNER_I2C_H__ 108c2ecf20Sopenharmony_ci#define __TUNER_I2C_H__ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/i2c.h> 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistruct tuner_i2c_props { 168c2ecf20Sopenharmony_ci u8 addr; 178c2ecf20Sopenharmony_ci struct i2c_adapter *adap; 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci /* used for tuner instance management */ 208c2ecf20Sopenharmony_ci int count; 218c2ecf20Sopenharmony_ci char *name; 228c2ecf20Sopenharmony_ci}; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic inline int tuner_i2c_xfer_send(struct tuner_i2c_props *props, 258c2ecf20Sopenharmony_ci unsigned char *buf, int len) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci struct i2c_msg msg = { .addr = props->addr, .flags = 0, 288c2ecf20Sopenharmony_ci .buf = buf, .len = len }; 298c2ecf20Sopenharmony_ci int ret = i2c_transfer(props->adap, &msg, 1); 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci return (ret == 1) ? len : ret; 328c2ecf20Sopenharmony_ci} 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic inline int tuner_i2c_xfer_recv(struct tuner_i2c_props *props, 358c2ecf20Sopenharmony_ci unsigned char *buf, int len) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci struct i2c_msg msg = { .addr = props->addr, .flags = I2C_M_RD, 388c2ecf20Sopenharmony_ci .buf = buf, .len = len }; 398c2ecf20Sopenharmony_ci int ret = i2c_transfer(props->adap, &msg, 1); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci return (ret == 1) ? len : ret; 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic inline int tuner_i2c_xfer_send_recv(struct tuner_i2c_props *props, 458c2ecf20Sopenharmony_ci unsigned char *obuf, int olen, 468c2ecf20Sopenharmony_ci unsigned char *ibuf, int ilen) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci struct i2c_msg msg[2] = { { .addr = props->addr, .flags = 0, 498c2ecf20Sopenharmony_ci .buf = obuf, .len = olen }, 508c2ecf20Sopenharmony_ci { .addr = props->addr, .flags = I2C_M_RD, 518c2ecf20Sopenharmony_ci .buf = ibuf, .len = ilen } }; 528c2ecf20Sopenharmony_ci int ret = i2c_transfer(props->adap, msg, 2); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci return (ret == 2) ? ilen : ret; 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/* Callers must declare as a global for the module: 588c2ecf20Sopenharmony_ci * 598c2ecf20Sopenharmony_ci * static LIST_HEAD(hybrid_tuner_instance_list); 608c2ecf20Sopenharmony_ci * 618c2ecf20Sopenharmony_ci * hybrid_tuner_instance_list should be the third argument 628c2ecf20Sopenharmony_ci * passed into hybrid_tuner_request_state(). 638c2ecf20Sopenharmony_ci * 648c2ecf20Sopenharmony_ci * state structure must contain the following: 658c2ecf20Sopenharmony_ci * 668c2ecf20Sopenharmony_ci * struct list_head hybrid_tuner_instance_list; 678c2ecf20Sopenharmony_ci * struct tuner_i2c_props i2c_props; 688c2ecf20Sopenharmony_ci * 698c2ecf20Sopenharmony_ci * hybrid_tuner_instance_list (both within state structure and globally) 708c2ecf20Sopenharmony_ci * is only required if the driver is using hybrid_tuner_request_state 718c2ecf20Sopenharmony_ci * and hybrid_tuner_release_state to manage state sharing between 728c2ecf20Sopenharmony_ci * multiple instances of hybrid tuners. 738c2ecf20Sopenharmony_ci */ 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci#define tuner_printk(kernlvl, i2cprops, fmt, arg...) do { \ 768c2ecf20Sopenharmony_ci printk(kernlvl "%s %d-%04x: " fmt, i2cprops.name, \ 778c2ecf20Sopenharmony_ci i2cprops.adap ? \ 788c2ecf20Sopenharmony_ci i2c_adapter_id(i2cprops.adap) : -1, \ 798c2ecf20Sopenharmony_ci i2cprops.addr, ##arg); \ 808c2ecf20Sopenharmony_ci } while (0) 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci/* TO DO: convert all callers of these macros to pass in 838c2ecf20Sopenharmony_ci * struct tuner_i2c_props, then remove the macro wrappers */ 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci#define __tuner_warn(i2cprops, fmt, arg...) do { \ 868c2ecf20Sopenharmony_ci tuner_printk(KERN_WARNING, i2cprops, fmt, ##arg); \ 878c2ecf20Sopenharmony_ci } while (0) 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci#define __tuner_info(i2cprops, fmt, arg...) do { \ 908c2ecf20Sopenharmony_ci tuner_printk(KERN_INFO, i2cprops, fmt, ##arg); \ 918c2ecf20Sopenharmony_ci } while (0) 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci#define __tuner_err(i2cprops, fmt, arg...) do { \ 948c2ecf20Sopenharmony_ci tuner_printk(KERN_ERR, i2cprops, fmt, ##arg); \ 958c2ecf20Sopenharmony_ci } while (0) 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci#define __tuner_dbg(i2cprops, fmt, arg...) do { \ 988c2ecf20Sopenharmony_ci if ((debug)) \ 998c2ecf20Sopenharmony_ci tuner_printk(KERN_DEBUG, i2cprops, fmt, ##arg); \ 1008c2ecf20Sopenharmony_ci } while (0) 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci#define tuner_warn(fmt, arg...) __tuner_warn(priv->i2c_props, fmt, ##arg) 1038c2ecf20Sopenharmony_ci#define tuner_info(fmt, arg...) __tuner_info(priv->i2c_props, fmt, ##arg) 1048c2ecf20Sopenharmony_ci#define tuner_err(fmt, arg...) __tuner_err(priv->i2c_props, fmt, ##arg) 1058c2ecf20Sopenharmony_ci#define tuner_dbg(fmt, arg...) __tuner_dbg(priv->i2c_props, fmt, ##arg) 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci/****************************************************************************/ 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci/* The return value of hybrid_tuner_request_state indicates the number of 1108c2ecf20Sopenharmony_ci * instances using this tuner object. 1118c2ecf20Sopenharmony_ci * 1128c2ecf20Sopenharmony_ci * 0 - no instances, indicates an error - kzalloc must have failed 1138c2ecf20Sopenharmony_ci * 1148c2ecf20Sopenharmony_ci * 1 - one instance, indicates that the tuner object was created successfully 1158c2ecf20Sopenharmony_ci * 1168c2ecf20Sopenharmony_ci * 2 (or more) instances, indicates that an existing tuner object was found 1178c2ecf20Sopenharmony_ci */ 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci#define hybrid_tuner_request_state(type, state, list, i2cadap, i2caddr, devname)\ 1208c2ecf20Sopenharmony_ci({ \ 1218c2ecf20Sopenharmony_ci int __ret = 0; \ 1228c2ecf20Sopenharmony_ci list_for_each_entry(state, &list, hybrid_tuner_instance_list) { \ 1238c2ecf20Sopenharmony_ci if (((i2cadap) && (state->i2c_props.adap)) && \ 1248c2ecf20Sopenharmony_ci ((i2c_adapter_id(state->i2c_props.adap) == \ 1258c2ecf20Sopenharmony_ci i2c_adapter_id(i2cadap)) && \ 1268c2ecf20Sopenharmony_ci (i2caddr == state->i2c_props.addr))) { \ 1278c2ecf20Sopenharmony_ci __tuner_info(state->i2c_props, \ 1288c2ecf20Sopenharmony_ci "attaching existing instance\n"); \ 1298c2ecf20Sopenharmony_ci state->i2c_props.count++; \ 1308c2ecf20Sopenharmony_ci __ret = state->i2c_props.count; \ 1318c2ecf20Sopenharmony_ci break; \ 1328c2ecf20Sopenharmony_ci } \ 1338c2ecf20Sopenharmony_ci } \ 1348c2ecf20Sopenharmony_ci if (0 == __ret) { \ 1358c2ecf20Sopenharmony_ci state = kzalloc(sizeof(type), GFP_KERNEL); \ 1368c2ecf20Sopenharmony_ci if (NULL == state) \ 1378c2ecf20Sopenharmony_ci goto __fail; \ 1388c2ecf20Sopenharmony_ci state->i2c_props.addr = i2caddr; \ 1398c2ecf20Sopenharmony_ci state->i2c_props.adap = i2cadap; \ 1408c2ecf20Sopenharmony_ci state->i2c_props.name = devname; \ 1418c2ecf20Sopenharmony_ci __tuner_info(state->i2c_props, \ 1428c2ecf20Sopenharmony_ci "creating new instance\n"); \ 1438c2ecf20Sopenharmony_ci list_add_tail(&state->hybrid_tuner_instance_list, &list);\ 1448c2ecf20Sopenharmony_ci state->i2c_props.count++; \ 1458c2ecf20Sopenharmony_ci __ret = state->i2c_props.count; \ 1468c2ecf20Sopenharmony_ci } \ 1478c2ecf20Sopenharmony_ci__fail: \ 1488c2ecf20Sopenharmony_ci __ret; \ 1498c2ecf20Sopenharmony_ci}) 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci#define hybrid_tuner_release_state(state) \ 1528c2ecf20Sopenharmony_ci({ \ 1538c2ecf20Sopenharmony_ci int __ret; \ 1548c2ecf20Sopenharmony_ci state->i2c_props.count--; \ 1558c2ecf20Sopenharmony_ci __ret = state->i2c_props.count; \ 1568c2ecf20Sopenharmony_ci if (!state->i2c_props.count) { \ 1578c2ecf20Sopenharmony_ci __tuner_info(state->i2c_props, "destroying instance\n");\ 1588c2ecf20Sopenharmony_ci list_del(&state->hybrid_tuner_instance_list); \ 1598c2ecf20Sopenharmony_ci kfree(state); \ 1608c2ecf20Sopenharmony_ci } \ 1618c2ecf20Sopenharmony_ci __ret; \ 1628c2ecf20Sopenharmony_ci}) 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci#define hybrid_tuner_report_instance_count(state) \ 1658c2ecf20Sopenharmony_ci({ \ 1668c2ecf20Sopenharmony_ci int __ret = 0; \ 1678c2ecf20Sopenharmony_ci if (state) \ 1688c2ecf20Sopenharmony_ci __ret = state->i2c_props.count; \ 1698c2ecf20Sopenharmony_ci __ret; \ 1708c2ecf20Sopenharmony_ci}) 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci#endif /* __TUNER_I2C_H__ */ 173