0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/module.h>
0012
0013 #include <linux/mfd/si476x-core.h>
0014
0015 struct si476x_property_range {
0016 u16 low, high;
0017 };
0018
0019 static bool si476x_core_element_is_in_array(u16 element,
0020 const u16 array[],
0021 size_t size)
0022 {
0023 int i;
0024
0025 for (i = 0; i < size; i++)
0026 if (element == array[i])
0027 return true;
0028
0029 return false;
0030 }
0031
0032 static bool si476x_core_element_is_in_range(u16 element,
0033 const struct si476x_property_range range[],
0034 size_t size)
0035 {
0036 int i;
0037
0038 for (i = 0; i < size; i++)
0039 if (element <= range[i].high && element >= range[i].low)
0040 return true;
0041
0042 return false;
0043 }
0044
0045 static bool si476x_core_is_valid_property_a10(struct si476x_core *core,
0046 u16 property)
0047 {
0048 static const u16 valid_properties[] = {
0049 0x0000,
0050 0x0500, 0x0501,
0051 0x0600,
0052 0x0709, 0x070C, 0x070D, 0x70E, 0x710,
0053 0x0718,
0054 0x1207, 0x1208,
0055 0x2007,
0056 0x2300,
0057 };
0058
0059 static const struct si476x_property_range valid_ranges[] = {
0060 { 0x0200, 0x0203 },
0061 { 0x0300, 0x0303 },
0062 { 0x0400, 0x0404 },
0063 { 0x0700, 0x0707 },
0064 { 0x1100, 0x1102 },
0065 { 0x1200, 0x1204 },
0066 { 0x1300, 0x1306 },
0067 { 0x2000, 0x2005 },
0068 { 0x2100, 0x2104 },
0069 { 0x2106, 0x2106 },
0070 { 0x2200, 0x220E },
0071 { 0x3100, 0x3104 },
0072 { 0x3207, 0x320F },
0073 { 0x3300, 0x3304 },
0074 { 0x3500, 0x3517 },
0075 { 0x3600, 0x3617 },
0076 { 0x3700, 0x3717 },
0077 { 0x4000, 0x4003 },
0078 };
0079
0080 return si476x_core_element_is_in_range(property, valid_ranges,
0081 ARRAY_SIZE(valid_ranges)) ||
0082 si476x_core_element_is_in_array(property, valid_properties,
0083 ARRAY_SIZE(valid_properties));
0084 }
0085
0086 static bool si476x_core_is_valid_property_a20(struct si476x_core *core,
0087 u16 property)
0088 {
0089 static const u16 valid_properties[] = {
0090 0x071B,
0091 0x1006,
0092 0x2210,
0093 0x3401,
0094 };
0095
0096 static const struct si476x_property_range valid_ranges[] = {
0097 { 0x2215, 0x2219 },
0098 };
0099
0100 return si476x_core_is_valid_property_a10(core, property) ||
0101 si476x_core_element_is_in_range(property, valid_ranges,
0102 ARRAY_SIZE(valid_ranges)) ||
0103 si476x_core_element_is_in_array(property, valid_properties,
0104 ARRAY_SIZE(valid_properties));
0105 }
0106
0107 static bool si476x_core_is_valid_property_a30(struct si476x_core *core,
0108 u16 property)
0109 {
0110 static const u16 valid_properties[] = {
0111 0x071C, 0x071D,
0112 0x1007, 0x1008,
0113 0x220F, 0x2214,
0114 0x2301,
0115 0x3105, 0x3106,
0116 0x3402,
0117 };
0118
0119 static const struct si476x_property_range valid_ranges[] = {
0120 { 0x0405, 0x0411 },
0121 { 0x2008, 0x200B },
0122 { 0x2220, 0x2223 },
0123 { 0x3100, 0x3106 },
0124 };
0125
0126 return si476x_core_is_valid_property_a20(core, property) ||
0127 si476x_core_element_is_in_range(property, valid_ranges,
0128 ARRAY_SIZE(valid_ranges)) ||
0129 si476x_core_element_is_in_array(property, valid_properties,
0130 ARRAY_SIZE(valid_properties));
0131 }
0132
0133 typedef bool (*valid_property_pred_t) (struct si476x_core *, u16);
0134
0135 static bool si476x_core_is_valid_property(struct si476x_core *core,
0136 u16 property)
0137 {
0138 static const valid_property_pred_t is_valid_property[] = {
0139 [SI476X_REVISION_A10] = si476x_core_is_valid_property_a10,
0140 [SI476X_REVISION_A20] = si476x_core_is_valid_property_a20,
0141 [SI476X_REVISION_A30] = si476x_core_is_valid_property_a30,
0142 };
0143
0144 BUG_ON(core->revision > SI476X_REVISION_A30 ||
0145 core->revision == -1);
0146 return is_valid_property[core->revision](core, property);
0147 }
0148
0149
0150 static bool si476x_core_is_readonly_property(struct si476x_core *core,
0151 u16 property)
0152 {
0153 BUG_ON(core->revision > SI476X_REVISION_A30 ||
0154 core->revision == -1);
0155
0156 switch (core->revision) {
0157 case SI476X_REVISION_A10:
0158 return (property == 0x3200);
0159 case SI476X_REVISION_A20:
0160 return (property == 0x1006 ||
0161 property == 0x2210 ||
0162 property == 0x3200);
0163 case SI476X_REVISION_A30:
0164 return false;
0165 }
0166
0167 return false;
0168 }
0169
0170 static bool si476x_core_regmap_readable_register(struct device *dev,
0171 unsigned int reg)
0172 {
0173 struct i2c_client *client = to_i2c_client(dev);
0174 struct si476x_core *core = i2c_get_clientdata(client);
0175
0176 return si476x_core_is_valid_property(core, (u16) reg);
0177
0178 }
0179
0180 static bool si476x_core_regmap_writable_register(struct device *dev,
0181 unsigned int reg)
0182 {
0183 struct i2c_client *client = to_i2c_client(dev);
0184 struct si476x_core *core = i2c_get_clientdata(client);
0185
0186 return si476x_core_is_valid_property(core, (u16) reg) &&
0187 !si476x_core_is_readonly_property(core, (u16) reg);
0188 }
0189
0190
0191 static int si476x_core_regmap_write(void *context, unsigned int reg,
0192 unsigned int val)
0193 {
0194 return si476x_core_cmd_set_property(context, reg, val);
0195 }
0196
0197 static int si476x_core_regmap_read(void *context, unsigned int reg,
0198 unsigned *val)
0199 {
0200 struct si476x_core *core = context;
0201 int err;
0202
0203 err = si476x_core_cmd_get_property(core, reg);
0204 if (err < 0)
0205 return err;
0206
0207 *val = err;
0208
0209 return 0;
0210 }
0211
0212
0213 static const struct regmap_config si476x_regmap_config = {
0214 .reg_bits = 16,
0215 .val_bits = 16,
0216
0217 .max_register = 0x4003,
0218
0219 .writeable_reg = si476x_core_regmap_writable_register,
0220 .readable_reg = si476x_core_regmap_readable_register,
0221
0222 .reg_read = si476x_core_regmap_read,
0223 .reg_write = si476x_core_regmap_write,
0224
0225 .cache_type = REGCACHE_RBTREE,
0226 };
0227
0228 struct regmap *devm_regmap_init_si476x(struct si476x_core *core)
0229 {
0230 return devm_regmap_init(&core->client->dev, NULL,
0231 core, &si476x_regmap_config);
0232 }
0233 EXPORT_SYMBOL_GPL(devm_regmap_init_si476x);