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

si476x-prop.c (5497B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * drivers/mfd/si476x-prop.c -- Subroutines to access
      4 * properties of si476x chips
      5 *
      6 * Copyright (C) 2012 Innovative Converged Devices(ICD)
      7 * Copyright (C) 2013 Andrey Smirnov
      8 *
      9 * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
     10 */
     11#include <linux/module.h>
     12
     13#include <linux/mfd/si476x-core.h>
     14
     15struct si476x_property_range {
     16	u16 low, high;
     17};
     18
     19static bool si476x_core_element_is_in_array(u16 element,
     20					    const u16 array[],
     21					    size_t size)
     22{
     23	int i;
     24
     25	for (i = 0; i < size; i++)
     26		if (element == array[i])
     27			return true;
     28
     29	return false;
     30}
     31
     32static bool si476x_core_element_is_in_range(u16 element,
     33					    const struct si476x_property_range range[],
     34					    size_t size)
     35{
     36	int i;
     37
     38	for (i = 0; i < size; i++)
     39		if (element <= range[i].high && element >= range[i].low)
     40			return true;
     41
     42	return false;
     43}
     44
     45static bool si476x_core_is_valid_property_a10(struct si476x_core *core,
     46					      u16 property)
     47{
     48	static const u16 valid_properties[] = {
     49		0x0000,
     50		0x0500, 0x0501,
     51		0x0600,
     52		0x0709, 0x070C, 0x070D, 0x70E, 0x710,
     53		0x0718,
     54		0x1207, 0x1208,
     55		0x2007,
     56		0x2300,
     57	};
     58
     59	static const struct si476x_property_range valid_ranges[] = {
     60		{ 0x0200, 0x0203 },
     61		{ 0x0300, 0x0303 },
     62		{ 0x0400, 0x0404 },
     63		{ 0x0700, 0x0707 },
     64		{ 0x1100, 0x1102 },
     65		{ 0x1200, 0x1204 },
     66		{ 0x1300, 0x1306 },
     67		{ 0x2000, 0x2005 },
     68		{ 0x2100, 0x2104 },
     69		{ 0x2106, 0x2106 },
     70		{ 0x2200, 0x220E },
     71		{ 0x3100, 0x3104 },
     72		{ 0x3207, 0x320F },
     73		{ 0x3300, 0x3304 },
     74		{ 0x3500, 0x3517 },
     75		{ 0x3600, 0x3617 },
     76		{ 0x3700, 0x3717 },
     77		{ 0x4000, 0x4003 },
     78	};
     79
     80	return	si476x_core_element_is_in_range(property, valid_ranges,
     81						ARRAY_SIZE(valid_ranges)) ||
     82		si476x_core_element_is_in_array(property, valid_properties,
     83						ARRAY_SIZE(valid_properties));
     84}
     85
     86static bool si476x_core_is_valid_property_a20(struct si476x_core *core,
     87					      u16 property)
     88{
     89	static const u16 valid_properties[] = {
     90		0x071B,
     91		0x1006,
     92		0x2210,
     93		0x3401,
     94	};
     95
     96	static const struct si476x_property_range valid_ranges[] = {
     97		{ 0x2215, 0x2219 },
     98	};
     99
    100	return	si476x_core_is_valid_property_a10(core, property) ||
    101		si476x_core_element_is_in_range(property, valid_ranges,
    102						ARRAY_SIZE(valid_ranges))  ||
    103		si476x_core_element_is_in_array(property, valid_properties,
    104						ARRAY_SIZE(valid_properties));
    105}
    106
    107static bool si476x_core_is_valid_property_a30(struct si476x_core *core,
    108					      u16 property)
    109{
    110	static const u16 valid_properties[] = {
    111		0x071C, 0x071D,
    112		0x1007, 0x1008,
    113		0x220F, 0x2214,
    114		0x2301,
    115		0x3105, 0x3106,
    116		0x3402,
    117	};
    118
    119	static const struct si476x_property_range valid_ranges[] = {
    120		{ 0x0405, 0x0411 },
    121		{ 0x2008, 0x200B },
    122		{ 0x2220, 0x2223 },
    123		{ 0x3100, 0x3106 },
    124	};
    125
    126	return	si476x_core_is_valid_property_a20(core, property) ||
    127		si476x_core_element_is_in_range(property, valid_ranges,
    128						ARRAY_SIZE(valid_ranges)) ||
    129		si476x_core_element_is_in_array(property, valid_properties,
    130						ARRAY_SIZE(valid_properties));
    131}
    132
    133typedef bool (*valid_property_pred_t) (struct si476x_core *, u16);
    134
    135static bool si476x_core_is_valid_property(struct si476x_core *core,
    136					  u16 property)
    137{
    138	static const valid_property_pred_t is_valid_property[] = {
    139		[SI476X_REVISION_A10] = si476x_core_is_valid_property_a10,
    140		[SI476X_REVISION_A20] = si476x_core_is_valid_property_a20,
    141		[SI476X_REVISION_A30] = si476x_core_is_valid_property_a30,
    142	};
    143
    144	BUG_ON(core->revision > SI476X_REVISION_A30 ||
    145	       core->revision == -1);
    146	return is_valid_property[core->revision](core, property);
    147}
    148
    149
    150static bool si476x_core_is_readonly_property(struct si476x_core *core,
    151					     u16 property)
    152{
    153	BUG_ON(core->revision > SI476X_REVISION_A30 ||
    154	       core->revision == -1);
    155
    156	switch (core->revision) {
    157	case SI476X_REVISION_A10:
    158		return (property == 0x3200);
    159	case SI476X_REVISION_A20:
    160		return (property == 0x1006 ||
    161			property == 0x2210 ||
    162			property == 0x3200);
    163	case SI476X_REVISION_A30:
    164		return false;
    165	}
    166
    167	return false;
    168}
    169
    170static bool si476x_core_regmap_readable_register(struct device *dev,
    171						 unsigned int reg)
    172{
    173	struct i2c_client *client = to_i2c_client(dev);
    174	struct si476x_core *core = i2c_get_clientdata(client);
    175
    176	return si476x_core_is_valid_property(core, (u16) reg);
    177
    178}
    179
    180static bool si476x_core_regmap_writable_register(struct device *dev,
    181						 unsigned int reg)
    182{
    183	struct i2c_client *client = to_i2c_client(dev);
    184	struct si476x_core *core = i2c_get_clientdata(client);
    185
    186	return si476x_core_is_valid_property(core, (u16) reg) &&
    187		!si476x_core_is_readonly_property(core, (u16) reg);
    188}
    189
    190
    191static int si476x_core_regmap_write(void *context, unsigned int reg,
    192				    unsigned int val)
    193{
    194	return si476x_core_cmd_set_property(context, reg, val);
    195}
    196
    197static int si476x_core_regmap_read(void *context, unsigned int reg,
    198				   unsigned *val)
    199{
    200	struct si476x_core *core = context;
    201	int err;
    202
    203	err = si476x_core_cmd_get_property(core, reg);
    204	if (err < 0)
    205		return err;
    206
    207	*val = err;
    208
    209	return 0;
    210}
    211
    212
    213static const struct regmap_config si476x_regmap_config = {
    214	.reg_bits = 16,
    215	.val_bits = 16,
    216
    217	.max_register = 0x4003,
    218
    219	.writeable_reg = si476x_core_regmap_writable_register,
    220	.readable_reg = si476x_core_regmap_readable_register,
    221
    222	.reg_read = si476x_core_regmap_read,
    223	.reg_write = si476x_core_regmap_write,
    224
    225	.cache_type = REGCACHE_RBTREE,
    226};
    227
    228struct regmap *devm_regmap_init_si476x(struct si476x_core *core)
    229{
    230	return devm_regmap_init(&core->client->dev, NULL,
    231				core, &si476x_regmap_config);
    232}
    233EXPORT_SYMBOL_GPL(devm_regmap_init_si476x);