cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

wm8400-core.c (3850B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Core driver for WM8400.
      4 *
      5 * Copyright 2008 Wolfson Microelectronics PLC.
      6 *
      7 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
      8 */
      9
     10#include <linux/init.h>
     11#include <linux/bug.h>
     12#include <linux/err.h>
     13#include <linux/i2c.h>
     14#include <linux/kernel.h>
     15#include <linux/mfd/core.h>
     16#include <linux/mfd/wm8400-private.h>
     17#include <linux/mfd/wm8400-audio.h>
     18#include <linux/regmap.h>
     19#include <linux/slab.h>
     20
     21static bool wm8400_volatile(struct device *dev, unsigned int reg)
     22{
     23	switch (reg) {
     24	case WM8400_INTERRUPT_STATUS_1:
     25	case WM8400_INTERRUPT_LEVELS:
     26	case WM8400_SHUTDOWN_REASON:
     27		return true;
     28	default:
     29		return false;
     30	}
     31}
     32
     33static int wm8400_register_codec(struct wm8400 *wm8400)
     34{
     35	const struct mfd_cell cell = {
     36		.name = "wm8400-codec",
     37		.platform_data = wm8400,
     38		.pdata_size = sizeof(*wm8400),
     39	};
     40
     41	return devm_mfd_add_devices(wm8400->dev, -1, &cell, 1, NULL, 0, NULL);
     42}
     43
     44/*
     45 * wm8400_init - Generic initialisation
     46 *
     47 * The WM8400 can be configured as either an I2C or SPI device.  Probe
     48 * functions for each bus set up the accessors then call into this to
     49 * set up the device itself.
     50 */
     51static int wm8400_init(struct wm8400 *wm8400,
     52		       struct wm8400_platform_data *pdata)
     53{
     54	unsigned int reg;
     55	int ret;
     56
     57	dev_set_drvdata(wm8400->dev, wm8400);
     58
     59	/* Check that this is actually a WM8400 */
     60	ret = regmap_read(wm8400->regmap, WM8400_RESET_ID, &reg);
     61	if (ret != 0) {
     62		dev_err(wm8400->dev, "Chip ID register read failed\n");
     63		return -EIO;
     64	}
     65	if (reg != 0x6172) {
     66		dev_err(wm8400->dev, "Device is not a WM8400, ID is %x\n",
     67			reg);
     68		return -ENODEV;
     69	}
     70
     71	ret = regmap_read(wm8400->regmap, WM8400_ID, &reg);
     72	if (ret != 0) {
     73		dev_err(wm8400->dev, "ID register read failed: %d\n", ret);
     74		return ret;
     75	}
     76	reg = (reg & WM8400_CHIP_REV_MASK) >> WM8400_CHIP_REV_SHIFT;
     77	dev_info(wm8400->dev, "WM8400 revision %x\n", reg);
     78
     79	ret = wm8400_register_codec(wm8400);
     80	if (ret != 0) {
     81		dev_err(wm8400->dev, "Failed to register codec\n");
     82		return ret;
     83	}
     84
     85	if (pdata && pdata->platform_init) {
     86		ret = pdata->platform_init(wm8400->dev);
     87		if (ret != 0) {
     88			dev_err(wm8400->dev, "Platform init failed: %d\n",
     89				ret);
     90			return ret;
     91		}
     92	} else
     93		dev_warn(wm8400->dev, "No platform initialisation supplied\n");
     94
     95	return 0;
     96}
     97
     98static const struct regmap_config wm8400_regmap_config = {
     99	.reg_bits = 8,
    100	.val_bits = 16,
    101	.max_register = WM8400_REGISTER_COUNT - 1,
    102
    103	.volatile_reg = wm8400_volatile,
    104
    105	.cache_type = REGCACHE_RBTREE,
    106};
    107
    108/**
    109 * wm8400_reset_codec_reg_cache - Reset cached codec registers to
    110 * their default values.
    111 *
    112 * @wm8400: pointer to local driver data structure
    113 */
    114void wm8400_reset_codec_reg_cache(struct wm8400 *wm8400)
    115{
    116	regmap_reinit_cache(wm8400->regmap, &wm8400_regmap_config);
    117}
    118EXPORT_SYMBOL_GPL(wm8400_reset_codec_reg_cache);
    119
    120#if IS_ENABLED(CONFIG_I2C)
    121static int wm8400_i2c_probe(struct i2c_client *i2c,
    122			    const struct i2c_device_id *id)
    123{
    124	struct wm8400 *wm8400;
    125
    126	wm8400 = devm_kzalloc(&i2c->dev, sizeof(struct wm8400), GFP_KERNEL);
    127	if (!wm8400)
    128		return -ENOMEM;
    129
    130	wm8400->regmap = devm_regmap_init_i2c(i2c, &wm8400_regmap_config);
    131	if (IS_ERR(wm8400->regmap))
    132		return PTR_ERR(wm8400->regmap);
    133
    134	wm8400->dev = &i2c->dev;
    135	i2c_set_clientdata(i2c, wm8400);
    136
    137	return wm8400_init(wm8400, dev_get_platdata(&i2c->dev));
    138}
    139
    140static const struct i2c_device_id wm8400_i2c_id[] = {
    141       { "wm8400", 0 },
    142       { }
    143};
    144
    145static struct i2c_driver wm8400_i2c_driver = {
    146	.driver = {
    147		.name = "WM8400",
    148	},
    149	.probe    = wm8400_i2c_probe,
    150	.id_table = wm8400_i2c_id,
    151};
    152#endif
    153
    154static int __init wm8400_driver_init(void)
    155{
    156	int ret = -ENODEV;
    157
    158#if IS_ENABLED(CONFIG_I2C)
    159	ret = i2c_add_driver(&wm8400_i2c_driver);
    160	if (ret != 0)
    161		pr_err("Failed to register I2C driver: %d\n", ret);
    162#endif
    163
    164	return ret;
    165}
    166subsys_initcall(wm8400_driver_init);