linux/sound/soc/codecs/rl6347a.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * rl6347a.c - RL6347A class device shared support
   4 *
   5 * Copyright 2015 Realtek Semiconductor Corp.
   6 *
   7 * Author: Oder Chiou <oder_chiou@realtek.com>
   8 */
   9
  10#include <linux/module.h>
  11#include <linux/i2c.h>
  12#include <linux/regmap.h>
  13
  14#include "rl6347a.h"
  15
  16int rl6347a_hw_write(void *context, unsigned int reg, unsigned int value)
  17{
  18        struct i2c_client *client = context;
  19        struct rl6347a_priv *rl6347a = i2c_get_clientdata(client);
  20        u8 data[4];
  21        int ret, i;
  22
  23        /* handle index registers */
  24        if (reg <= 0xff) {
  25                rl6347a_hw_write(client, RL6347A_COEF_INDEX, reg);
  26                for (i = 0; i < rl6347a->index_cache_size; i++) {
  27                        if (reg == rl6347a->index_cache[i].reg) {
  28                                rl6347a->index_cache[i].def = value;
  29                                break;
  30                        }
  31
  32                }
  33                reg = RL6347A_PROC_COEF;
  34        }
  35
  36        data[0] = (reg >> 24) & 0xff;
  37        data[1] = (reg >> 16) & 0xff;
  38        /*
  39         * 4 bit VID: reg should be 0
  40         * 12 bit VID: value should be 0
  41         * So we use an OR operator to handle it rather than use if condition.
  42         */
  43        data[2] = ((reg >> 8) & 0xff) | ((value >> 8) & 0xff);
  44        data[3] = value & 0xff;
  45
  46        ret = i2c_master_send(client, data, 4);
  47
  48        if (ret == 4)
  49                return 0;
  50        else
  51                dev_err(&client->dev, "I2C error %d\n", ret);
  52        if (ret < 0)
  53                return ret;
  54        else
  55                return -EIO;
  56}
  57EXPORT_SYMBOL_GPL(rl6347a_hw_write);
  58
  59int rl6347a_hw_read(void *context, unsigned int reg, unsigned int *value)
  60{
  61        struct i2c_client *client = context;
  62        struct i2c_msg xfer[2];
  63        int ret;
  64        __be32 be_reg, buf = 0x0;
  65        unsigned int index, vid;
  66
  67        /* handle index registers */
  68        if (reg <= 0xff) {
  69                rl6347a_hw_write(client, RL6347A_COEF_INDEX, reg);
  70                reg = RL6347A_PROC_COEF;
  71        }
  72
  73        reg = reg | 0x80000;
  74        vid = (reg >> 8) & 0xfff;
  75
  76        if (AC_VERB_GET_AMP_GAIN_MUTE == (vid & 0xf00)) {
  77                index = (reg >> 8) & 0xf;
  78                reg = (reg & ~0xf0f) | index;
  79        }
  80        be_reg = cpu_to_be32(reg);
  81
  82        /* Write register */
  83        xfer[0].addr = client->addr;
  84        xfer[0].flags = 0;
  85        xfer[0].len = 4;
  86        xfer[0].buf = (u8 *)&be_reg;
  87
  88        /* Read data */
  89        xfer[1].addr = client->addr;
  90        xfer[1].flags = I2C_M_RD;
  91        xfer[1].len = 4;
  92        xfer[1].buf = (u8 *)&buf;
  93
  94        ret = i2c_transfer(client->adapter, xfer, 2);
  95        if (ret < 0)
  96                return ret;
  97        else if (ret != 2)
  98                return -EIO;
  99
 100        *value = be32_to_cpu(buf);
 101
 102        return 0;
 103}
 104EXPORT_SYMBOL_GPL(rl6347a_hw_read);
 105
 106MODULE_DESCRIPTION("RL6347A class device shared support");
 107MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>");
 108MODULE_LICENSE("GPL v2");
 109