175 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * I2C driver for Marvell 88PM860x4 *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 15int 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->regmap19 : 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 else27 return (int)data;28}29EXPORT_SYMBOL(pm860x_reg_read);30 31int 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->regmap36 : chip->regmap_companion;37 int ret;38 39 ret = regmap_write(map, reg, data);40 return ret;41}42EXPORT_SYMBOL(pm860x_reg_write);43 44int 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->regmap49 : chip->regmap_companion;50 int ret;51 52 ret = regmap_raw_read(map, reg, buf, count);53 return ret;54}55EXPORT_SYMBOL(pm860x_bulk_read);56 57int 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->regmap62 : chip->regmap_companion;63 int ret;64 65 ret = regmap_raw_write(map, reg, buf, count);66 return ret;67}68EXPORT_SYMBOL(pm860x_bulk_write);69 70int 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->regmap75 : chip->regmap_companion;76 int ret;77 78 ret = regmap_update_bits(map, reg, mask, data);79 return ret;80}81EXPORT_SYMBOL(pm860x_set_bits);82 83static 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 = msgbuf095 },96 { .addr = i2c->addr,97 .flags = I2C_M_RD,98 .len = 0,99 .buf = msgbuf1100 },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 119static 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 140int 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}156EXPORT_SYMBOL(pm860x_page_reg_write);157 158int 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}174EXPORT_SYMBOL(pm860x_page_bulk_read);175