#ifdef CONFIG_IG69M
/* iWave board revision is combination of  pcb revsion and bom revision */
struct ig_board_rev_nr {
    char pcb_rev;
    char bom_rev;
};

unsigned int data;
int channel = 0, ret = 0;

static int ig_get_bom_revision(struct ig_board_rev_nr *board_rev,
                               unsigned int raw, int bom_rev_flag)
{
        if (!bom_rev_flag)
        {
                switch (raw) {
                        case 0 ... 100:
                                board_rev->bom_rev = '0';
                                break;
                        case 300 ... 450:
                                board_rev->bom_rev = '1';
                                break;
                        case 600 ... 850:
                                board_rev->bom_rev = '2';
                                break;
                        case 1150 ... 1450:
                                board_rev->bom_rev = '3';
                                break;
                        case 1500 ... 1800:
                                board_rev->bom_rev = '4';
                                break;
                        case 1900 ... 2200:
                                board_rev->bom_rev = '5';
                                break;
                        case 2300 ... 2600:
                                board_rev->bom_rev = '6';
                                break;
                        case 2650 ... 2950:
                                board_rev->bom_rev = '7';
                                break;
                        case 3200 ... 3450:
                                board_rev->bom_rev = '8';
                                break;
                        case 3500 ... 3650:
                                board_rev->bom_rev = '9';
                                break;
                        case 4000 ... 4150:
                                board_rev->bom_rev = 'A';
                                break;
                        default:
                                board_rev->bom_rev = 'x';
                }
        }
        else
        {
                switch (raw) {
                        case 0 ... 100:
                                board_rev->bom_rev = '0';
                                break;
                        case 300 ... 450:
                                board_rev->bom_rev = '1';
                                break;
                        case 600 ... 850:
                                board_rev->bom_rev = '2';
                                break;
                        case 1150 ... 1450:
                                board_rev->bom_rev = '3';
                                break;
                        case 1500 ... 1800:
                                board_rev->bom_rev = '4';
                                break;
                        case 1900 ... 2200:
                                board_rev->bom_rev = '5';
                                break;
                        case 2300 ... 2600:
                                board_rev->bom_rev = '6';
                                break;
                        case 2650 ... 2950:
                                board_rev->bom_rev = '7';
                                break;
                        case 3200 ... 3450:
                                board_rev->bom_rev = '8';
                                break;
                        case 3500 ... 3650:
                                board_rev->bom_rev = '9';
                                break;
                        case 4000 ... 4150:
                                board_rev->bom_rev = 'A';
                                break;
                        default:
                                board_rev->bom_rev = 'x';
                }
        }

        return 0;
}

/* Read the adc value based on the dts pin configuration */
static int adc_measurement(struct device_node *node, int adc_count,
                           struct ig_board_rev_nr *board_rev)
{
        struct of_phandle_args adc_args;
        struct device *adc_dev;
        struct iio_dev *indio_dev;
        struct iio_channel chan;
        unsigned int raw;
        int ret, uV;
        int i;
        int index;
        int bom_rev_flag = 0;

        for (i = 0; i < adc_count; i++) {
                ret = of_parse_phandle_with_args(node, "ig69m-adc",
                                                 "#io-channel-cells", i,
                                                 &adc_args);
                if (ret) {
                        pr_err("can't find /config/ig,adc_som_rev\n");
                        return 0;
                }

                /* Resolve the phandle's device_node to its iio_dev.
                 * "ig69m-adc" is a custom property name (not the
                 * standard "io-channels"/"io-channel-names" pair), so
                 * the public fwnode_iio_channel_get_by_name()/
                 * iio_channel_get() consumer APIs cannot be used here -
                 * neither accepts an arbitrary property name + index.
                 * bus_find_device_by_of_node() + dev_to_iio_dev() is
                 * the same resolution path IIO's own (non-exported)
                 * of_iio_channel_get() uses internally. */
                adc_dev = bus_find_device_by_of_node(&iio_bus_type,
                                                     adc_args.np);
                of_node_put(adc_args.np);

                if (!adc_dev) {
                        pr_err("Can't get adc device for channel %d\n", i);
                        return -ENODEV;
                }

                indio_dev = dev_to_iio_dev(adc_dev);

                index = adc_args.args_count ? adc_args.args[0] : 0;
                if (index >= indio_dev->num_channels) {
                        pr_err("ADC channel index %d out of range for %s\n",
                               index, dev_name(adc_dev));
                        put_device(adc_dev);
                        return -EINVAL;
                }

                chan.indio_dev = indio_dev;
                chan.channel = &indio_dev->channels[index];
                chan.data = NULL;

                ret = iio_read_channel_raw(&chan, (int *)&raw);
                if (ret) {
                        pr_err("single shot failed for ADC[%d]!\n", index);
                        put_device(adc_dev);
                        return ret;
                }

                /* Convert to uV */
                ret = iio_read_channel_processed(&chan, &uV);

                if (ret >= 0) {
                        if (i == 0)
                        {
                                switch (raw) {
                                        case 0 ... 100:
                                                board_rev->pcb_rev = '1';
                                                bom_rev_flag = 0;
                                                break;
                                        case 300 ... 450:
                                                board_rev->pcb_rev = '1';
                                                bom_rev_flag = 1;
                                                break;
                                        case 600 ... 850:
                                                board_rev->pcb_rev = '2';
                                                bom_rev_flag = 0;
                                                break;
                                        case 1150 ... 1450:
                                                board_rev->pcb_rev = '2';
                                                bom_rev_flag = 1;
                                                break;
                                        case 1500 ... 1800:
                                                board_rev->pcb_rev = '3';
                                                bom_rev_flag = 0;
                                                break;
                                        case 1900 ... 2200:
                                                board_rev->pcb_rev = '3';
                                                bom_rev_flag = 1;
                                                break;
                                        case 2300 ... 2600:
                                                board_rev->pcb_rev = '4';
                                                bom_rev_flag = 0;
                                                break;
                                        case 2650 ... 2950:
                                                board_rev->pcb_rev = '4';
                                                bom_rev_flag = 1;
                                                break;
                                        case 3200 ... 3450:
                                                board_rev->pcb_rev = '5';
                                                bom_rev_flag = 0;
                                                break;
                                        case 3500 ... 3650:
                                                board_rev->pcb_rev = '5';
                                                bom_rev_flag = 1;
                                                break;
                                        case 3950 ... 4150:
                                                board_rev->pcb_rev = '6';
                                                bom_rev_flag = 0;
                                                break;
                                        default:
                                                board_rev->pcb_rev = 'x';
                                }
                        }
                        else {
                                ig_get_bom_revision(board_rev, raw,
                                                    bom_rev_flag);
                        }
                }
                else {
                        pr_err("Can't get uV value for ADC[%d]\n", index);
                }

                put_device(adc_dev);
        }

        return 0;
}

static int board_get_som_revision(struct ig_board_rev_nr *board_rev)
{
        struct device_node *node;
        int adc_count, ret;

        node = of_find_node_by_path("/config");
        if (!node) {
                pr_err("no /config node?\n");
                return -ENOENT;
        }

        /*
         * Retrieve the ADC channels devices and get measurement
         * for each of them
         */
        adc_count = of_count_phandle_with_args(node,
                                       "ig69m-adc",
                                       "#io-channel-cells");
        if (adc_count < 0) {
                of_node_put(node);
                if (adc_count == -ENOENT)
                        return 0;

                pr_err("Can't find adc channel (%d)\n", adc_count);

                return adc_count;
        }

        ret = adc_measurement(node, adc_count, board_rev);
        of_node_put(node);

        if (ret)
                return ret;

        return 0;
}

static void print_board_info (void)
{
        struct ig_board_rev_nr *board_rev1;
        int ret;

        board_rev1 = kzalloc(sizeof(struct ig_board_rev_nr), GFP_KERNEL);
        if (!board_rev1) {
                pr_err("Failed to allocate board_rev\n");
                return;
        }

        /* IG69M: Get board revision */
        ret = board_get_som_revision(board_rev1);
        if (ret) {
                pr_err("Failed to read SOM revision (%d)\n", ret);
                kfree(board_rev1);
                return;
        }

        pr_info("\nBoard Info:\n");
        pr_info("\tSOM Version       : iG-PRJRZ-AP-01-R%c.%c\n",
                board_rev1->pcb_rev, board_rev1->bom_rev);

        kfree(board_rev1);
}
#endif

