1 // SPDX-License-Identifier: GPL-2.0-only
3 * drivers/mfd/si476x-prop.c -- Subroutines to access
4 * properties of si476x chips
6 * Copyright (C) 2012 Innovative Converged Devices(ICD)
7 * Copyright (C) 2013 Andrey Smirnov
9 * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
11 #include <linux/module.h>
13 #include <linux/mfd/si476x-core.h>
15 struct si476x_property_range {
19 static bool si476x_core_element_is_in_array(u16 element,
25 for (i = 0; i < size; i++)
26 if (element == array[i])
32 static bool si476x_core_element_is_in_range(u16 element,
33 const struct si476x_property_range range[],
38 for (i = 0; i < size; i++)
39 if (element <= range[i].high && element >= range[i].low)
45 static bool si476x_core_is_valid_property_a10(struct si476x_core *core,
48 static const u16 valid_properties[] = {
52 0x0709, 0x070C, 0x070D, 0x70E, 0x710,
59 static const struct si476x_property_range valid_ranges[] = {
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));
86 static bool si476x_core_is_valid_property_a20(struct si476x_core *core,
89 static const u16 valid_properties[] = {
96 static const struct si476x_property_range valid_ranges[] = {
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));
107 static bool si476x_core_is_valid_property_a30(struct si476x_core *core,
110 static const u16 valid_properties[] = {
119 static const struct si476x_property_range valid_ranges[] = {
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));
133 typedef bool (*valid_property_pred_t) (struct si476x_core *, u16);
135 static bool si476x_core_is_valid_property(struct si476x_core *core,
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,
144 BUG_ON(core->revision > SI476X_REVISION_A30 ||
145 core->revision == -1);
146 return is_valid_property[core->revision](core, property);
150 static bool si476x_core_is_readonly_property(struct si476x_core *core,
153 BUG_ON(core->revision > SI476X_REVISION_A30 ||
154 core->revision == -1);
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 ||
163 case SI476X_REVISION_A30:
170 static bool si476x_core_regmap_readable_register(struct device *dev,
173 struct i2c_client *client = to_i2c_client(dev);
174 struct si476x_core *core = i2c_get_clientdata(client);
176 return si476x_core_is_valid_property(core, (u16) reg);
180 static bool si476x_core_regmap_writable_register(struct device *dev,
183 struct i2c_client *client = to_i2c_client(dev);
184 struct si476x_core *core = i2c_get_clientdata(client);
186 return si476x_core_is_valid_property(core, (u16) reg) &&
187 !si476x_core_is_readonly_property(core, (u16) reg);
191 static int si476x_core_regmap_write(void *context, unsigned int reg,
194 return si476x_core_cmd_set_property(context, reg, val);
197 static int si476x_core_regmap_read(void *context, unsigned int reg,
200 struct si476x_core *core = context;
203 err = si476x_core_cmd_get_property(core, reg);
213 static const struct regmap_config si476x_regmap_config = {
217 .max_register = 0x4003,
219 .writeable_reg = si476x_core_regmap_writable_register,
220 .readable_reg = si476x_core_regmap_readable_register,
222 .reg_read = si476x_core_regmap_read,
223 .reg_write = si476x_core_regmap_write,
225 .cache_type = REGCACHE_RBTREE,
228 struct regmap *devm_regmap_init_si476x(struct si476x_core *core)
230 return devm_regmap_init(&core->client->dev, NULL,
231 core, &si476x_regmap_config);
233 EXPORT_SYMBOL_GPL(devm_regmap_init_si476x);