Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * drivers/mfd/si476x-prop.c -- Subroutines to access
0004  * properties of si476x chips
0005  *
0006  * Copyright (C) 2012 Innovative Converged Devices(ICD)
0007  * Copyright (C) 2013 Andrey Smirnov
0008  *
0009  * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
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);