brintos

brintos / linux-shallow public Read only

0
0
Text · 3.5 KiB · ffdb159 Raw
169 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Coral-P(A)/Lime I2C adapter driver4 *5 * (C) 2011 DENX Software Engineering, Anatolij Gustschin <agust@denx.de>6 */7 8#include <linux/fb.h>9#include <linux/i2c.h>10#include <linux/io.h>11#include <linux/delay.h>12#include <linux/export.h>13 14#include "mb862xxfb.h"15#include "mb862xx_reg.h"16 17static int mb862xx_i2c_wait_event(struct i2c_adapter *adap)18{19	struct mb862xxfb_par *par = adap->algo_data;20	u32 reg;21 22	do {23		udelay(10);24		reg = inreg(i2c, GC_I2C_BCR);25		if (reg & (I2C_INT | I2C_BER))26			break;27	} while (1);28 29	return (reg & I2C_BER) ? 0 : 1;30}31 32static int mb862xx_i2c_do_address(struct i2c_adapter *adap, int addr)33{34	struct mb862xxfb_par *par = adap->algo_data;35 36	outreg(i2c, GC_I2C_DAR, addr);37	outreg(i2c, GC_I2C_CCR, I2C_CLOCK_AND_ENABLE);38	outreg(i2c, GC_I2C_BCR, par->i2c_rs ? I2C_REPEATED_START : I2C_START);39	if (!mb862xx_i2c_wait_event(adap))40		return -EIO;41	par->i2c_rs = !(inreg(i2c, GC_I2C_BSR) & I2C_LRB);42	return par->i2c_rs;43}44 45static int mb862xx_i2c_write_byte(struct i2c_adapter *adap, u8 byte)46{47	struct mb862xxfb_par *par = adap->algo_data;48 49	outreg(i2c, GC_I2C_DAR, byte);50	outreg(i2c, GC_I2C_BCR, I2C_START);51	if (!mb862xx_i2c_wait_event(adap))52		return -EIO;53	return !(inreg(i2c, GC_I2C_BSR) & I2C_LRB);54}55 56static int mb862xx_i2c_read_byte(struct i2c_adapter *adap, u8 *byte, int last)57{58	struct mb862xxfb_par *par = adap->algo_data;59 60	outreg(i2c, GC_I2C_BCR, I2C_START | (last ? 0 : I2C_ACK));61	if (!mb862xx_i2c_wait_event(adap))62		return 0;63	*byte = inreg(i2c, GC_I2C_DAR);64	return 1;65}66 67static void mb862xx_i2c_stop(struct i2c_adapter *adap)68{69	struct mb862xxfb_par *par = adap->algo_data;70 71	outreg(i2c, GC_I2C_BCR, I2C_STOP);72	outreg(i2c, GC_I2C_CCR, I2C_DISABLE);73	par->i2c_rs = 0;74}75 76static int mb862xx_i2c_read(struct i2c_adapter *adap, struct i2c_msg *m)77{78	int i, ret = 0;79	int last = m->len - 1;80 81	for (i = 0; i < m->len; i++) {82		if (!mb862xx_i2c_read_byte(adap, &m->buf[i], i == last)) {83			ret = -EIO;84			break;85		}86	}87	return ret;88}89 90static int mb862xx_i2c_write(struct i2c_adapter *adap, struct i2c_msg *m)91{92	int i, ret = 0;93 94	for (i = 0; i < m->len; i++) {95		if (!mb862xx_i2c_write_byte(adap, m->buf[i])) {96			ret = -EIO;97			break;98		}99	}100	return ret;101}102 103static int mb862xx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,104			int num)105{106	struct mb862xxfb_par *par = adap->algo_data;107	struct i2c_msg *m;108	int addr;109	int i = 0, err = 0;110 111	dev_dbg(par->dev, "%s: %d msgs\n", __func__, num);112 113	for (i = 0; i < num; i++) {114		m = &msgs[i];115		if (!m->len) {116			dev_dbg(par->dev, "%s: null msgs\n", __func__);117			continue;118		}119		addr = m->addr;120		if (m->flags & I2C_M_RD)121			addr |= 1;122 123		err = mb862xx_i2c_do_address(adap, addr);124		if (err < 0)125			break;126		if (m->flags & I2C_M_RD)127			err = mb862xx_i2c_read(adap, m);128		else129			err = mb862xx_i2c_write(adap, m);130	}131 132	if (i)133		mb862xx_i2c_stop(adap);134 135	return (err < 0) ? err : i;136}137 138static u32 mb862xx_func(struct i2c_adapter *adap)139{140	return I2C_FUNC_SMBUS_BYTE_DATA;141}142 143static const struct i2c_algorithm mb862xx_algo = {144	.master_xfer	= mb862xx_xfer,145	.functionality	= mb862xx_func,146};147 148static struct i2c_adapter mb862xx_i2c_adapter = {149	.name		= "MB862xx I2C adapter",150	.algo		= &mb862xx_algo,151	.owner		= THIS_MODULE,152};153 154int mb862xx_i2c_init(struct mb862xxfb_par *par)155{156	mb862xx_i2c_adapter.algo_data = par;157	par->adap = &mb862xx_i2c_adapter;158 159	return i2c_add_adapter(par->adap);160}161 162void mb862xx_i2c_exit(struct mb862xxfb_par *par)163{164	if (par->adap) {165		i2c_del_adapter(par->adap);166		par->adap = NULL;167	}168}169