1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * I2C driver for Marvell 88PM860x 4 * 5 * Copyright (C) 2009 Marvell International Ltd. 6 * 7 * Author: Haojian Zhuang <haojian.zhuang@marvell.com> 8 */ 9 #include <linux/kernel.h> 10 #include <linux/module.h> 11 #include <linux/i2c.h> 12 #include <linux/regmap.h> 13 #include <linux/mfd/88pm860x.h> 14 15 int pm860x_reg_read(struct i2c_client *i2c, int reg) 16 { 17 struct pm860x_chip *chip = i2c_get_clientdata(i2c); 18 struct regmap *map = (i2c == chip->client) ? chip->regmap 19 : chip->regmap_companion; 20 unsigned int data; 21 int ret; 22 23 ret = regmap_read(map, reg, &data); 24 if (ret < 0) 25 return ret; 26 else 27 return (int)data; 28 } 29 EXPORT_SYMBOL(pm860x_reg_read); 30 31 int pm860x_reg_write(struct i2c_client *i2c, int reg, 32 unsigned char data) 33 { 34 struct pm860x_chip *chip = i2c_get_clientdata(i2c); 35 struct regmap *map = (i2c == chip->client) ? chip->regmap 36 : chip->regmap_companion; 37 int ret; 38 39 ret = regmap_write(map, reg, data); 40 return ret; 41 } 42 EXPORT_SYMBOL(pm860x_reg_write); 43 44 int pm860x_bulk_read(struct i2c_client *i2c, int reg, 45 int count, unsigned char *buf) 46 { 47 struct pm860x_chip *chip = i2c_get_clientdata(i2c); 48 struct regmap *map = (i2c == chip->client) ? chip->regmap 49 : chip->regmap_companion; 50 int ret; 51 52 ret = regmap_raw_read(map, reg, buf, count); 53 return ret; 54 } 55 EXPORT_SYMBOL(pm860x_bulk_read); 56 57 int pm860x_bulk_write(struct i2c_client *i2c, int reg, 58 int count, unsigned char *buf) 59 { 60 struct pm860x_chip *chip = i2c_get_clientdata(i2c); 61 struct regmap *map = (i2c == chip->client) ? chip->regmap 62 : chip->regmap_companion; 63 int ret; 64 65 ret = regmap_raw_write(map, reg, buf, count); 66 return ret; 67 } 68 EXPORT_SYMBOL(pm860x_bulk_write); 69 70 int pm860x_set_bits(struct i2c_client *i2c, int reg, 71 unsigned char mask, unsigned char data) 72 { 73 struct pm860x_chip *chip = i2c_get_clientdata(i2c); 74 struct regmap *map = (i2c == chip->client) ? chip->regmap 75 : chip->regmap_companion; 76 int ret; 77 78 ret = regmap_update_bits(map, reg, mask, data); 79 return ret; 80 } 81 EXPORT_SYMBOL(pm860x_set_bits); 82 83 static int read_device(struct i2c_client *i2c, int reg, 84 int bytes, void *dest) 85 { 86 unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX + 3]; 87 unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX + 2]; 88 struct i2c_adapter *adap = i2c->adapter; 89 struct i2c_msg msg[2] = { 90 { 91 .addr = i2c->addr, 92 .flags = 0, 93 .len = 1, 94 .buf = msgbuf0 95 }, 96 { .addr = i2c->addr, 97 .flags = I2C_M_RD, 98 .len = 0, 99 .buf = msgbuf1 100 }, 101 }; 102 int num = 1, ret = 0; 103 104 if (dest == NULL) 105 return -EINVAL; 106 msgbuf0[0] = (unsigned char)reg; /* command */ 107 msg[1].len = bytes; 108 109 /* if data needs to read back, num should be 2 */ 110 if (bytes > 0) 111 num = 2; 112 ret = adap->algo->master_xfer(adap, msg, num); 113 memcpy(dest, msgbuf1, bytes); 114 if (ret < 0) 115 return ret; 116 return 0; 117 } 118 119 static int write_device(struct i2c_client *i2c, int reg, 120 int bytes, void *src) 121 { 122 unsigned char buf[2]; 123 struct i2c_adapter *adap = i2c->adapter; 124 struct i2c_msg msg; 125 int ret; 126 127 buf[0] = (unsigned char)reg; 128 memcpy(&buf[1], src, bytes); 129 msg.addr = i2c->addr; 130 msg.flags = 0; 131 msg.len = bytes + 1; 132 msg.buf = buf; 133 134 ret = adap->algo->master_xfer(adap, &msg, 1); 135 if (ret < 0) 136 return ret; 137 return 0; 138 } 139 140 int pm860x_page_reg_write(struct i2c_client *i2c, int reg, 141 unsigned char data) 142 { 143 unsigned char zero; 144 int ret; 145 146 i2c_lock_bus(i2c->adapter, I2C_LOCK_SEGMENT); 147 read_device(i2c, 0xFA, 0, &zero); 148 read_device(i2c, 0xFB, 0, &zero); 149 read_device(i2c, 0xFF, 0, &zero); 150 ret = write_device(i2c, reg, 1, &data); 151 read_device(i2c, 0xFE, 0, &zero); 152 read_device(i2c, 0xFC, 0, &zero); 153 i2c_unlock_bus(i2c->adapter, I2C_LOCK_SEGMENT); 154 return ret; 155 } 156 EXPORT_SYMBOL(pm860x_page_reg_write); 157 158 int pm860x_page_bulk_read(struct i2c_client *i2c, int reg, 159 int count, unsigned char *buf) 160 { 161 unsigned char zero = 0; 162 int ret; 163 164 i2c_lock_bus(i2c->adapter, I2C_LOCK_SEGMENT); 165 read_device(i2c, 0xfa, 0, &zero); 166 read_device(i2c, 0xfb, 0, &zero); 167 read_device(i2c, 0xff, 0, &zero); 168 ret = read_device(i2c, reg, count, buf); 169 read_device(i2c, 0xFE, 0, &zero); 170 read_device(i2c, 0xFC, 0, &zero); 171 i2c_unlock_bus(i2c->adapter, I2C_LOCK_SEGMENT); 172 return ret; 173 } 174 EXPORT_SYMBOL(pm860x_page_bulk_read); 175