root/drivers/video/fbdev/mb862xx/mb862xx-i2c.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mb862xx_i2c_wait_event
  2. mb862xx_i2c_do_address
  3. mb862xx_i2c_write_byte
  4. mb862xx_i2c_read_byte
  5. mb862xx_i2c_stop
  6. mb862xx_i2c_read
  7. mb862xx_i2c_write
  8. mb862xx_xfer
  9. mb862xx_func
  10. mb862xx_i2c_init
  11. mb862xx_i2c_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Coral-P(A)/Lime I2C adapter driver
   4  *
   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 
  17 static 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 
  32 static 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 
  45 static 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 
  56 static 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 
  67 static 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 
  76 static 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 
  90 static 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 
 103 static 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                 else
 129                         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 
 138 static u32 mb862xx_func(struct i2c_adapter *adap)
 139 {
 140         return I2C_FUNC_SMBUS_BYTE_DATA;
 141 }
 142 
 143 static const struct i2c_algorithm mb862xx_algo = {
 144         .master_xfer    = mb862xx_xfer,
 145         .functionality  = mb862xx_func,
 146 };
 147 
 148 static struct i2c_adapter mb862xx_i2c_adapter = {
 149         .name           = "MB862xx I2C adapter",
 150         .algo           = &mb862xx_algo,
 151         .owner          = THIS_MODULE,
 152 };
 153 
 154 int 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 
 162 void mb862xx_i2c_exit(struct mb862xxfb_par *par)
 163 {
 164         if (par->adap) {
 165                 i2c_del_adapter(par->adap);
 166                 par->adap = NULL;
 167         }
 168 }

/* [<][>][^][v][top][bottom][index][help] */