linux/drivers/mfd/88pm860x-i2c.c
<<
>>
Prefs
   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
  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->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}
  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->regmap
  36                                : 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->regmap
  49                                : 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->regmap
  62                                : 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->regmap
  75                                : 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 = 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
 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