brintos

brintos / linux-shallow public Read only

0
0
Text · 5.7 KiB · 9848b78 Raw
285 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * STK1160 driver4 *5 * Copyright (C) 2012 Ezequiel Garcia6 * <elezegarcia--a.t--gmail.com>7 *8 * Based on Easycap driver by R.M. Thomas9 *	Copyright (C) 2010 R.M. Thomas10 *	<rmthomas--a.t--sciolus.org>11 */12 13#include <linux/module.h>14#include <linux/usb.h>15#include <linux/i2c.h>16 17#include "stk1160.h"18#include "stk1160-reg.h"19 20static unsigned int i2c_debug;21module_param(i2c_debug, int, 0644);22MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");23 24#define dprintk_i2c(fmt, args...)				\25do {								\26	if (i2c_debug)						\27		printk(KERN_DEBUG fmt, ##args);			\28} while (0)29 30static int stk1160_i2c_busy_wait(struct stk1160 *dev, u8 wait_bit_mask)31{32	unsigned long end;33	u8 flag;34 35	/* Wait until read/write finish bit is set */36	end = jiffies + msecs_to_jiffies(STK1160_I2C_TIMEOUT);37	while (time_is_after_jiffies(end)) {38 39		stk1160_read_reg(dev, STK1160_SICTL+1, &flag);40		/* read/write done? */41		if (flag & wait_bit_mask)42			goto done;43 44		usleep_range(10 * USEC_PER_MSEC, 20 * USEC_PER_MSEC);45	}46 47	return -ETIMEDOUT;48 49done:50	return 0;51}52 53static int stk1160_i2c_write_reg(struct stk1160 *dev, u8 addr,54		u8 reg, u8 value)55{56	int rc;57 58	/* Set serial device address */59	rc = stk1160_write_reg(dev, STK1160_SICTL_SDA, addr);60	if (rc < 0)61		return rc;62 63	/* Set i2c device register sub-address */64	rc = stk1160_write_reg(dev, STK1160_SBUSW_WA, reg);65	if (rc < 0)66		return rc;67 68	/* Set i2c device register value */69	rc = stk1160_write_reg(dev, STK1160_SBUSW_WD, value);70	if (rc < 0)71		return rc;72 73	/* Start write now */74	rc = stk1160_write_reg(dev, STK1160_SICTL, 0x01);75	if (rc < 0)76		return rc;77 78	rc = stk1160_i2c_busy_wait(dev, 0x04);79	if (rc < 0)80		return rc;81 82	return 0;83}84 85static int stk1160_i2c_read_reg(struct stk1160 *dev, u8 addr,86		u8 reg, u8 *value)87{88	int rc;89 90	/* Set serial device address */91	rc = stk1160_write_reg(dev, STK1160_SICTL_SDA, addr);92	if (rc < 0)93		return rc;94 95	/* Set i2c device register sub-address */96	rc = stk1160_write_reg(dev, STK1160_SBUSR_RA, reg);97	if (rc < 0)98		return rc;99 100	/* Start read now */101	rc = stk1160_write_reg(dev, STK1160_SICTL, 0x20);102	if (rc < 0)103		return rc;104 105	rc = stk1160_i2c_busy_wait(dev, 0x01);106	if (rc < 0)107		return rc;108 109	rc = stk1160_read_reg(dev, STK1160_SBUSR_RD, value);110	if (rc < 0)111		return rc;112 113	return 0;114}115 116/*117 * stk1160_i2c_check_for_device()118 * check if there is a i2c_device at the supplied address119 */120static int stk1160_i2c_check_for_device(struct stk1160 *dev,121		unsigned char addr)122{123	int rc;124 125	/* Set serial device address */126	rc = stk1160_write_reg(dev, STK1160_SICTL_SDA, addr);127	if (rc < 0)128		return rc;129 130	/* Set device sub-address, we'll chip version reg */131	rc = stk1160_write_reg(dev, STK1160_SBUSR_RA, 0x00);132	if (rc < 0)133		return rc;134 135	/* Start read now */136	rc = stk1160_write_reg(dev, STK1160_SICTL, 0x20);137	if (rc < 0)138		return rc;139 140	rc = stk1160_i2c_busy_wait(dev, 0x01);141	if (rc < 0)142		return -ENODEV;143 144	return 0;145}146 147/*148 * stk1160_i2c_xfer()149 * the main i2c transfer function150 */151static int stk1160_i2c_xfer(struct i2c_adapter *i2c_adap,152			   struct i2c_msg msgs[], int num)153{154	struct stk1160 *dev = i2c_adap->algo_data;155	int addr, rc, i;156 157	for (i = 0; i < num; i++) {158		addr = msgs[i].addr << 1;159		dprintk_i2c("%s: addr=%x", __func__, addr);160 161		if (!msgs[i].len) {162			/* no len: check only for device presence */163			rc = stk1160_i2c_check_for_device(dev, addr);164			if (rc < 0) {165				dprintk_i2c(" no device\n");166				return rc;167			}168 169		} else if (msgs[i].flags & I2C_M_RD) {170			/* read request without preceding register selection */171			dprintk_i2c(" subaddr not selected");172			rc = -EOPNOTSUPP;173			goto err;174 175		} else if (i + 1 < num && msgs[i].len <= 2 &&176			   (msgs[i + 1].flags & I2C_M_RD) &&177			   msgs[i].addr == msgs[i + 1].addr) {178 179			if (msgs[i].len != 1 || msgs[i + 1].len != 1) {180				dprintk_i2c(" len not supported");181				rc = -EOPNOTSUPP;182				goto err;183			}184 185			dprintk_i2c(" subaddr=%x", msgs[i].buf[0]);186 187			rc = stk1160_i2c_read_reg(dev, addr, msgs[i].buf[0],188				msgs[i + 1].buf);189 190			dprintk_i2c(" read=%x", *msgs[i + 1].buf);191 192			/* consumed two msgs, so we skip one of them */193			i++;194 195		} else {196			if (msgs[i].len != 2) {197				dprintk_i2c(" len not supported");198				rc = -EOPNOTSUPP;199				goto err;200			}201 202			dprintk_i2c(" subaddr=%x write=%x",203				msgs[i].buf[0],  msgs[i].buf[1]);204 205			rc = stk1160_i2c_write_reg(dev, addr, msgs[i].buf[0],206				msgs[i].buf[1]);207		}208 209		if (rc < 0)210			goto err;211		dprintk_i2c(" OK\n");212	}213 214	return num;215err:216	dprintk_i2c(" ERROR: %d\n", rc);217	return num;218}219 220/*221 * functionality(), what da heck is this?222 */223static u32 functionality(struct i2c_adapter *adap)224{225	return I2C_FUNC_SMBUS_EMUL;226}227 228static const struct i2c_algorithm algo = {229	.master_xfer   = stk1160_i2c_xfer,230	.functionality = functionality,231};232 233static const struct i2c_adapter adap_template = {234	.owner = THIS_MODULE,235	.name = "stk1160",236	.algo = &algo,237};238 239static const struct i2c_client client_template = {240	.name = "stk1160 internal",241};242 243/*244 * stk1160_i2c_register()245 * register i2c bus246 */247int stk1160_i2c_register(struct stk1160 *dev)248{249	int rc;250 251	dev->i2c_adap = adap_template;252	dev->i2c_adap.dev.parent = dev->dev;253	strscpy(dev->i2c_adap.name, "stk1160", sizeof(dev->i2c_adap.name));254	dev->i2c_adap.algo_data = dev;255 256	i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);257 258	rc = i2c_add_adapter(&dev->i2c_adap);259	if (rc < 0) {260		stk1160_err("cannot add i2c adapter (%d)\n", rc);261		return rc;262	}263 264	dev->i2c_client = client_template;265	dev->i2c_client.adapter = &dev->i2c_adap;266 267	/* Set i2c clock divider device address */268	stk1160_write_reg(dev, STK1160_SICTL_CD,  0x0f);269 270	/* ??? */271	stk1160_write_reg(dev, STK1160_ASIC + 3,  0x00);272 273	return 0;274}275 276/*277 * stk1160_i2c_unregister()278 * unregister i2c_bus279 */280int stk1160_i2c_unregister(struct stk1160 *dev)281{282	i2c_del_adapter(&dev->i2c_adap);283	return 0;284}285