diff options
Diffstat (limited to 'drivers/mfd/ab3100-core.c')
-rw-r--r-- | drivers/mfd/ab3100-core.c | 929 |
1 files changed, 0 insertions, 929 deletions
diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c deleted file mode 100644 index ee71ae04b5e6..000000000000 --- a/drivers/mfd/ab3100-core.c +++ /dev/null @@ -1,929 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2007-2010 ST-Ericsson - * Low-level core for exclusive access to the AB3100 IC on the I2C bus - * and some basic chip-configuration. - * Author: Linus Walleij <linus.walleij@stericsson.com> - */ - -#include <linux/i2c.h> -#include <linux/mutex.h> -#include <linux/list.h> -#include <linux/notifier.h> -#include <linux/slab.h> -#include <linux/err.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/device.h> -#include <linux/interrupt.h> -#include <linux/random.h> -#include <linux/debugfs.h> -#include <linux/seq_file.h> -#include <linux/uaccess.h> -#include <linux/mfd/core.h> -#include <linux/mfd/ab3100.h> -#include <linux/mfd/abx500.h> - -/* These are the only registers inside AB3100 used in this main file */ - -/* Interrupt event registers */ -#define AB3100_EVENTA1 0x21 -#define AB3100_EVENTA2 0x22 -#define AB3100_EVENTA3 0x23 - -/* AB3100 DAC converter registers */ -#define AB3100_DIS 0x00 -#define AB3100_D0C 0x01 -#define AB3100_D1C 0x02 -#define AB3100_D2C 0x03 -#define AB3100_D3C 0x04 - -/* Chip ID register */ -#define AB3100_CID 0x20 - -/* AB3100 interrupt registers */ -#define AB3100_IMRA1 0x24 -#define AB3100_IMRA2 0x25 -#define AB3100_IMRA3 0x26 -#define AB3100_IMRB1 0x2B -#define AB3100_IMRB2 0x2C -#define AB3100_IMRB3 0x2D - -/* System Power Monitoring and control registers */ -#define AB3100_MCA 0x2E -#define AB3100_MCB 0x2F - -/* SIM power up */ -#define AB3100_SUP 0x50 - -/* - * I2C communication - * - * The AB3100 is usually assigned address 0x48 (7-bit) - * The chip is defined in the platform i2c_board_data section. - */ -static int ab3100_get_chip_id(struct device *dev) -{ - struct ab3100 *ab3100 = dev_get_drvdata(dev->parent); - - return (int)ab3100->chip_id; -} - -static int ab3100_set_register_interruptible(struct ab3100 *ab3100, - u8 reg, u8 regval) -{ - u8 regandval[2] = {reg, regval}; - int err; - - err = mutex_lock_interruptible(&ab3100->access_mutex); - if (err) - return err; - - /* - * A two-byte write message with the first byte containing the register - * number and the second byte containing the value to be written - * effectively sets a register in the AB3100. - */ - err = i2c_master_send(ab3100->i2c_client, regandval, 2); - if (err < 0) { - dev_err(ab3100->dev, - "write error (write register): %d\n", - err); - } else if (err != 2) { - dev_err(ab3100->dev, - "write error (write register)\n" - " %d bytes transferred (expected 2)\n", - err); - err = -EIO; - } else { - /* All is well */ - err = 0; - } - mutex_unlock(&ab3100->access_mutex); - return err; -} - -static int set_register_interruptible(struct device *dev, - u8 bank, u8 reg, u8 value) -{ - struct ab3100 *ab3100 = dev_get_drvdata(dev->parent); - - return ab3100_set_register_interruptible(ab3100, reg, value); -} - -/* - * The test registers exist at an I2C bus address up one - * from the ordinary base. They are not supposed to be used - * in production code, but sometimes you have to do that - * anyway. It's currently only used from this file so declare - * it static and do not export. - */ -static int ab3100_set_test_register_interruptible(struct ab3100 *ab3100, - u8 reg, u8 regval) -{ - u8 regandval[2] = {reg, regval}; - int err; - - err = mutex_lock_interruptible(&ab3100->access_mutex); - if (err) - return err; - - err = i2c_master_send(ab3100->testreg_client, regandval, 2); - if (err < 0) { - dev_err(ab3100->dev, - "write error (write test register): %d\n", - err); - } else if (err != 2) { - dev_err(ab3100->dev, - "write error (write test register)\n" - " %d bytes transferred (expected 2)\n", - err); - err = -EIO; - } else { - /* All is well */ - err = 0; - } - mutex_unlock(&ab3100->access_mutex); - - return err; -} - -static int ab3100_get_register_interruptible(struct ab3100 *ab3100, - u8 reg, u8 *regval) -{ - int err; - - err = mutex_lock_interruptible(&ab3100->access_mutex); - if (err) - return err; - - /* - * AB3100 require an I2C "stop" command between each message, else - * it will not work. The only way of achieveing this with the - * message transport layer is to send the read and write messages - * separately. - */ - err = i2c_master_send(ab3100->i2c_client, ®, 1); - if (err < 0) { - dev_err(ab3100->dev, - "write error (send register address): %d\n", - err); - goto get_reg_out_unlock; - } else if (err != 1) { - dev_err(ab3100->dev, - "write error (send register address)\n" - " %d bytes transferred (expected 1)\n", - err); - err = -EIO; - goto get_reg_out_unlock; - } else { - /* All is well */ - err = 0; - } - - err = i2c_master_recv(ab3100->i2c_client, regval, 1); - if (err < 0) { - dev_err(ab3100->dev, - "write error (read register): %d\n", - err); - goto get_reg_out_unlock; - } else if (err != 1) { - dev_err(ab3100->dev, - "write error (read register)\n" - " %d bytes transferred (expected 1)\n", - err); - err = -EIO; - goto get_reg_out_unlock; - } else { - /* All is well */ - err = 0; - } - - get_reg_out_unlock: - mutex_unlock(&ab3100->access_mutex); - return err; -} - -static int get_register_interruptible(struct device *dev, u8 bank, u8 reg, - u8 *value) -{ - struct ab3100 *ab3100 = dev_get_drvdata(dev->parent); - - return ab3100_get_register_interruptible(ab3100, reg, value); -} - -static int ab3100_get_register_page_interruptible(struct ab3100 *ab3100, - u8 first_reg, u8 *regvals, u8 numregs) -{ - int err; - - if (ab3100->chip_id == 0xa0 || - ab3100->chip_id == 0xa1) - /* These don't support paged reads */ - return -EIO; - - err = mutex_lock_interruptible(&ab3100->access_mutex); - if (err) - return err; - - /* - * Paged read also require an I2C "stop" command. - */ - err = i2c_master_send(ab3100->i2c_client, &first_reg, 1); - if (err < 0) { - dev_err(ab3100->dev, - "write error (send first register address): %d\n", - err); - goto get_reg_page_out_unlock; - } else if (err != 1) { - dev_err(ab3100->dev, - "write error (send first register address)\n" - " %d bytes transferred (expected 1)\n", - err); - err = -EIO; - goto get_reg_page_out_unlock; - } - - err = i2c_master_recv(ab3100->i2c_client, regvals, numregs); - if (err < 0) { - dev_err(ab3100->dev, - "write error (read register page): %d\n", - err); - goto get_reg_page_out_unlock; - } else if (err != numregs) { - dev_err(ab3100->dev, - "write error (read register page)\n" - " %d bytes transferred (expected %d)\n", - err, numregs); - err = -EIO; - goto get_reg_page_out_unlock; - } - - /* All is well */ - err = 0; - - get_reg_page_out_unlock: - mutex_unlock(&ab3100->access_mutex); - return err; -} - -static int get_register_page_interruptible(struct device *dev, u8 bank, - u8 first_reg, u8 *regvals, u8 numregs) -{ - struct ab3100 *ab3100 = dev_get_drvdata(dev->parent); - - return ab3100_get_register_page_interruptible(ab3100, - first_reg, regvals, numregs); -} - -static int ab3100_mask_and_set_register_interruptible(struct ab3100 *ab3100, - u8 reg, u8 andmask, u8 ormask) -{ - u8 regandval[2] = {reg, 0}; - int err; - - err = mutex_lock_interruptible(&ab3100->access_mutex); - if (err) - return err; - - /* First read out the target register */ - err = i2c_master_send(ab3100->i2c_client, ®, 1); - if (err < 0) { - dev_err(ab3100->dev, - "write error (maskset send address): %d\n", - err); - goto get_maskset_unlock; - } else if (err != 1) { - dev_err(ab3100->dev, - "write error (maskset send address)\n" - " %d bytes transferred (expected 1)\n", - err); - err = -EIO; - goto get_maskset_unlock; - } - - err = i2c_master_recv(ab3100->i2c_client, ®andval[1], 1); - if (err < 0) { - dev_err(ab3100->dev, - "write error (maskset read register): %d\n", - err); - goto get_maskset_unlock; - } else if (err != 1) { - dev_err(ab3100->dev, - "write error (maskset read register)\n" - " %d bytes transferred (expected 1)\n", - err); - err = -EIO; - goto get_maskset_unlock; - } - - /* Modify the register */ - regandval[1] &= andmask; - regandval[1] |= ormask; - - /* Write the register */ - err = i2c_master_send(ab3100->i2c_client, regandval, 2); - if (err < 0) { - dev_err(ab3100->dev, - "write error (write register): %d\n", - err); - goto get_maskset_unlock; - } else if (err != 2) { - dev_err(ab3100->dev, - "write error (write register)\n" - " %d bytes transferred (expected 2)\n", - err); - err = -EIO; - goto get_maskset_unlock; - } - - /* All is well */ - err = 0; - - get_maskset_unlock: - mutex_unlock(&ab3100->access_mutex); - return err; -} - -static int mask_and_set_register_interruptible(struct device *dev, u8 bank, - u8 reg, u8 bitmask, u8 bitvalues) -{ - struct ab3100 *ab3100 = dev_get_drvdata(dev->parent); - - return ab3100_mask_and_set_register_interruptible(ab3100, - reg, bitmask, (bitmask & bitvalues)); -} - -/* - * Register a simple callback for handling any AB3100 events. - */ -int ab3100_event_register(struct ab3100 *ab3100, - struct notifier_block *nb) -{ - return blocking_notifier_chain_register(&ab3100->event_subscribers, - nb); -} -EXPORT_SYMBOL(ab3100_event_register); - -/* - * Remove a previously registered callback. - */ -int ab3100_event_unregister(struct ab3100 *ab3100, - struct notifier_block *nb) -{ - return blocking_notifier_chain_unregister(&ab3100->event_subscribers, - nb); -} -EXPORT_SYMBOL(ab3100_event_unregister); - - -static int ab3100_event_registers_startup_state_get(struct device *dev, - u8 *event) -{ - struct ab3100 *ab3100 = dev_get_drvdata(dev->parent); - - if (!ab3100->startup_events_read) - return -EAGAIN; /* Try again later */ - memcpy(event, ab3100->startup_events, 3); - - return 0; -} - -static struct abx500_ops ab3100_ops = { - .get_chip_id = ab3100_get_chip_id, - .set_register = set_register_interruptible, - .get_register = get_register_interruptible, - .get_register_page = get_register_page_interruptible, - .set_register_page = NULL, - .mask_and_set_register = mask_and_set_register_interruptible, - .event_registers_startup_state_get = - ab3100_event_registers_startup_state_get, - .startup_irq_enabled = NULL, -}; - -/* - * This is a threaded interrupt handler so we can make some - * I2C calls etc. - */ -static irqreturn_t ab3100_irq_handler(int irq, void *data) -{ - struct ab3100 *ab3100 = data; - u8 event_regs[3]; - u32 fatevent; - int err; - - err = ab3100_get_register_page_interruptible(ab3100, AB3100_EVENTA1, - event_regs, 3); - if (err) - goto err_event; - - fatevent = (event_regs[0] << 16) | - (event_regs[1] << 8) | - event_regs[2]; - - if (!ab3100->startup_events_read) { - ab3100->startup_events[0] = event_regs[0]; - ab3100->startup_events[1] = event_regs[1]; - ab3100->startup_events[2] = event_regs[2]; - ab3100->startup_events_read = true; - } - /* - * The notified parties will have to mask out the events - * they're interested in and react to them. They will be - * notified on all events, then they use the fatevent value - * to determine if they're interested. - */ - blocking_notifier_call_chain(&ab3100->event_subscribers, - fatevent, NULL); - - dev_dbg(ab3100->dev, - "IRQ Event: 0x%08x\n", fatevent); - - return IRQ_HANDLED; - - err_event: - dev_dbg(ab3100->dev, - "error reading event status\n"); - return IRQ_HANDLED; -} - -#ifdef CONFIG_DEBUG_FS -/* - * Some debugfs entries only exposed if we're using debug - */ -static int ab3100_registers_print(struct seq_file *s, void *p) -{ - struct ab3100 *ab3100 = s->private; - u8 value; - u8 reg; - - seq_puts(s, "AB3100 registers:\n"); - - for (reg = 0; reg < 0xff; reg++) { - ab3100_get_register_interruptible(ab3100, reg, &value); - seq_printf(s, "[0x%x]: 0x%x\n", reg, value); - } - return 0; -} - -static int ab3100_registers_open(struct inode *inode, struct file *file) -{ - return single_open(file, ab3100_registers_print, inode->i_private); -} - -static const struct file_operations ab3100_registers_fops = { - .open = ab3100_registers_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -struct ab3100_get_set_reg_priv { - struct ab3100 *ab3100; - bool mode; -}; - -static ssize_t ab3100_get_set_reg(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ab3100_get_set_reg_priv *priv = file->private_data; - struct ab3100 *ab3100 = priv->ab3100; - char buf[32]; - ssize_t buf_size; - int regp; - u8 user_reg; - int err; - int i = 0; - - /* Get userspace string and assure termination */ - buf_size = min((ssize_t)count, (ssize_t)(sizeof(buf)-1)); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - buf[buf_size] = 0; - - /* - * The idea is here to parse a string which is either - * "0xnn" for reading a register, or "0xaa 0xbb" for - * writing 0xbb to the register 0xaa. First move past - * whitespace and then begin to parse the register. - */ - while ((i < buf_size) && (buf[i] == ' ')) - i++; - regp = i; - - /* - * Advance pointer to end of string then terminate - * the register string. This is needed to satisfy - * the kstrtou8() function. - */ - while ((i < buf_size) && (buf[i] != ' ')) - i++; - buf[i] = '\0'; - - err = kstrtou8(&buf[regp], 16, &user_reg); - if (err) - return err; - - /* Either we read or we write a register here */ - if (!priv->mode) { - /* Reading */ - u8 regvalue; - - ab3100_get_register_interruptible(ab3100, user_reg, ®value); - - dev_info(ab3100->dev, - "debug read AB3100 reg[0x%02x]: 0x%02x\n", - user_reg, regvalue); - } else { - int valp; - u8 user_value; - u8 regvalue; - - /* - * Writing, we need some value to write to - * the register so keep parsing the string - * from userspace. - */ - i++; - while ((i < buf_size) && (buf[i] == ' ')) - i++; - valp = i; - while ((i < buf_size) && (buf[i] != ' ')) - i++; - buf[i] = '\0'; - - err = kstrtou8(&buf[valp], 16, &user_value); - if (err) - return err; - - ab3100_set_register_interruptible(ab3100, user_reg, user_value); - ab3100_get_register_interruptible(ab3100, user_reg, ®value); - - dev_info(ab3100->dev, - "debug write reg[0x%02x]\n" - " with 0x%02x, after readback: 0x%02x\n", - user_reg, user_value, regvalue); - } - return buf_size; -} - -static const struct file_operations ab3100_get_set_reg_fops = { - .open = simple_open, - .write = ab3100_get_set_reg, - .llseek = noop_llseek, -}; - -static struct ab3100_get_set_reg_priv ab3100_get_priv; -static struct ab3100_get_set_reg_priv ab3100_set_priv; - -static void ab3100_setup_debugfs(struct ab3100 *ab3100) -{ - struct dentry *ab3100_dir; - - ab3100_dir = debugfs_create_dir("ab3100", NULL); - - debugfs_create_file("registers", S_IRUGO, ab3100_dir, ab3100, - &ab3100_registers_fops); - - ab3100_get_priv.ab3100 = ab3100; - ab3100_get_priv.mode = false; - debugfs_create_file("get_reg", S_IWUSR, ab3100_dir, &ab3100_get_priv, - &ab3100_get_set_reg_fops); - - ab3100_set_priv.ab3100 = ab3100; - ab3100_set_priv.mode = true; - debugfs_create_file("set_reg", S_IWUSR, ab3100_dir, &ab3100_set_priv, - &ab3100_get_set_reg_fops); -} -#else -static inline void ab3100_setup_debugfs(struct ab3100 *ab3100) -{ -} -#endif - -/* - * Basic set-up, datastructure creation/destruction and I2C interface. - * This sets up a default config in the AB3100 chip so that it - * will work as expected. - */ - -struct ab3100_init_setting { - u8 abreg; - u8 setting; -}; - -static const struct ab3100_init_setting ab3100_init_settings[] = { - { - .abreg = AB3100_MCA, - .setting = 0x01 - }, { - .abreg = AB3100_MCB, - .setting = 0x30 - }, { - .abreg = AB3100_IMRA1, - .setting = 0x00 - }, { - .abreg = AB3100_IMRA2, - .setting = 0xFF - }, { - .abreg = AB3100_IMRA3, - .setting = 0x01 - }, { - .abreg = AB3100_IMRB1, - .setting = 0xBF - }, { - .abreg = AB3100_IMRB2, - .setting = 0xFF - }, { - .abreg = AB3100_IMRB3, - .setting = 0xFF - }, { - .abreg = AB3100_SUP, - .setting = 0x00 - }, { - .abreg = AB3100_DIS, - .setting = 0xF0 - }, { - .abreg = AB3100_D0C, - .setting = 0x00 - }, { - .abreg = AB3100_D1C, - .setting = 0x00 - }, { - .abreg = AB3100_D2C, - .setting = 0x00 - }, { - .abreg = AB3100_D3C, - .setting = 0x00 - }, -}; - -static int ab3100_setup(struct ab3100 *ab3100) -{ - int err = 0; - int i; - - for (i = 0; i < ARRAY_SIZE(ab3100_init_settings); i++) { - err = ab3100_set_register_interruptible(ab3100, - ab3100_init_settings[i].abreg, - ab3100_init_settings[i].setting); - if (err) - goto exit_no_setup; - } - - /* - * Special trick to make the AB3100 use the 32kHz clock (RTC) - * bit 3 in test register 0x02 is a special, undocumented test - * register bit that only exist in AB3100 P1E - */ - if (ab3100->chip_id == 0xc4) { - dev_warn(ab3100->dev, - "AB3100 P1E variant detected forcing chip to 32KHz\n"); - err = ab3100_set_test_register_interruptible(ab3100, - 0x02, 0x08); - } - - exit_no_setup: - return err; -} - -/* The subdevices of the AB3100 */ -static struct mfd_cell ab3100_devs[] = { - { - .name = "ab3100-dac", - .id = -1, - }, - { - .name = "ab3100-leds", - .id = -1, - }, - { - .name = "ab3100-power", - .id = -1, - }, - { - .name = "ab3100-regulators", - .of_compatible = "stericsson,ab3100-regulators", - .id = -1, - }, - { - .name = "ab3100-sim", - .id = -1, - }, - { - .name = "ab3100-uart", - .id = -1, - }, - { - .name = "ab3100-rtc", - .id = -1, - }, - { - .name = "ab3100-charger", - .id = -1, - }, - { - .name = "ab3100-boost", - .id = -1, - }, - { - .name = "ab3100-adc", - .id = -1, - }, - { - .name = "ab3100-fuelgauge", - .id = -1, - }, - { - .name = "ab3100-vibrator", - .id = -1, - }, - { - .name = "ab3100-otp", - .id = -1, - }, - { - .name = "ab3100-codec", - .id = -1, - }, -}; - -struct ab_family_id { - u8 id; - char *name; -}; - -static const struct ab_family_id ids[] = { - /* AB3100 */ - { - .id = 0xc0, - .name = "P1A" - }, { - .id = 0xc1, - .name = "P1B" - }, { - .id = 0xc2, - .name = "P1C" - }, { - .id = 0xc3, - .name = "P1D" - }, { - .id = 0xc4, - .name = "P1E" - }, { - .id = 0xc5, - .name = "P1F/R1A" - }, { - .id = 0xc6, - .name = "P1G/R1A" - }, { - .id = 0xc7, - .name = "P2A/R2A" - }, { - .id = 0xc8, - .name = "P2B/R2B" - }, - /* AB3000 variants, not supported */ - { - .id = 0xa0 - }, { - .id = 0xa1 - }, { - .id = 0xa2 - }, { - .id = 0xa3 - }, { - .id = 0xa4 - }, { - .id = 0xa5 - }, { - .id = 0xa6 - }, { - .id = 0xa7 - }, - /* Terminator */ - { - .id = 0x00, - }, -}; - -static int ab3100_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct ab3100 *ab3100; - struct ab3100_platform_data *ab3100_plf_data = - dev_get_platdata(&client->dev); - int err; - int i; - - ab3100 = devm_kzalloc(&client->dev, sizeof(struct ab3100), GFP_KERNEL); - if (!ab3100) - return -ENOMEM; - - /* Initialize data structure */ - mutex_init(&ab3100->access_mutex); - BLOCKING_INIT_NOTIFIER_HEAD(&ab3100->event_subscribers); - - ab3100->i2c_client = client; - ab3100->dev = &ab3100->i2c_client->dev; - - i2c_set_clientdata(client, ab3100); - - /* Read chip ID register */ - err = ab3100_get_register_interruptible(ab3100, AB3100_CID, - &ab3100->chip_id); - if (err) { - dev_err(&client->dev, - "failed to communicate with AB3100 chip\n"); - goto exit_no_detect; - } - - for (i = 0; ids[i].id != 0x0; i++) { - if (ids[i].id == ab3100->chip_id) { - if (ids[i].name) - break; - - dev_err(&client->dev, "AB3000 is not supported\n"); - goto exit_no_detect; - } - } - - snprintf(&ab3100->chip_name[0], - sizeof(ab3100->chip_name) - 1, "AB3100 %s", ids[i].name); - - if (ids[i].id == 0x0) { - dev_err(&client->dev, "unknown analog baseband chip id: 0x%x\n", - ab3100->chip_id); - dev_err(&client->dev, - "accepting it anyway. Please update the driver.\n"); - goto exit_no_detect; - } - - dev_info(&client->dev, "Detected chip: %s\n", - &ab3100->chip_name[0]); - - /* Attach a second dummy i2c_client to the test register address */ - ab3100->testreg_client = i2c_new_dummy_device(client->adapter, - client->addr + 1); - if (IS_ERR(ab3100->testreg_client)) { - err = PTR_ERR(ab3100->testreg_client); - goto exit_no_testreg_client; - } - - err = ab3100_setup(ab3100); - if (err) - goto exit_no_setup; - - err = devm_request_threaded_irq(&client->dev, - client->irq, NULL, ab3100_irq_handler, - IRQF_ONESHOT, "ab3100-core", ab3100); - if (err) - goto exit_no_irq; - - err = abx500_register_ops(&client->dev, &ab3100_ops); - if (err) - goto exit_no_ops; - - /* Set up and register the platform devices. */ - for (i = 0; i < ARRAY_SIZE(ab3100_devs); i++) { - ab3100_devs[i].platform_data = ab3100_plf_data; - ab3100_devs[i].pdata_size = sizeof(struct ab3100_platform_data); - } - - err = mfd_add_devices(&client->dev, 0, ab3100_devs, - ARRAY_SIZE(ab3100_devs), NULL, 0, NULL); - - ab3100_setup_debugfs(ab3100); - - return 0; - - exit_no_ops: - exit_no_irq: - exit_no_setup: - i2c_unregister_device(ab3100->testreg_client); - exit_no_testreg_client: - exit_no_detect: - return err; -} - -static const struct i2c_device_id ab3100_id[] = { - { "ab3100", 0 }, - { } -}; - -static struct i2c_driver ab3100_driver = { - .driver = { - .name = "ab3100", - .suppress_bind_attrs = true, - }, - .id_table = ab3100_id, - .probe = ab3100_probe, -}; - -static int __init ab3100_i2c_init(void) -{ - return i2c_add_driver(&ab3100_driver); -} -subsys_initcall(ab3100_i2c_init); |