Loading drivers/mfd/Kconfig +3 −0 Original line number Diff line number Diff line Loading @@ -404,6 +404,7 @@ config MFD_WM831X_I2C bool "Support Wolfson Microelectronics WM831x/2x PMICs with I2C" select MFD_CORE select MFD_WM831X select REGMAP_I2C depends on I2C=y && GENERIC_HARDIRQS help Support for the Wolfson Microelecronics WM831x and WM832x PMICs Loading @@ -415,6 +416,7 @@ config MFD_WM831X_SPI bool "Support Wolfson Microelectronics WM831x/2x PMICs with SPI" select MFD_CORE select MFD_WM831X select REGMAP_SPI depends on SPI_MASTER && GENERIC_HARDIRQS help Support for the Wolfson Microelecronics WM831x and WM832x PMICs Loading Loading @@ -488,6 +490,7 @@ config MFD_WM8350_I2C config MFD_WM8994 bool "Support Wolfson Microelectronics WM8994" select MFD_CORE select REGMAP_I2C depends on I2C=y && GENERIC_HARDIRQS help The WM8994 is a highly integrated hi-fi CODEC designed for Loading drivers/mfd/wm831x-core.c +371 −53 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include <linux/delay.h> #include <linux/mfd/core.h> #include <linux/slab.h> #include <linux/err.h> #include <linux/mfd/wm831x/core.h> #include <linux/mfd/wm831x/pdata.h> Loading Loading @@ -160,27 +161,350 @@ int wm831x_reg_unlock(struct wm831x *wm831x) } EXPORT_SYMBOL_GPL(wm831x_reg_unlock); static int wm831x_read(struct wm831x *wm831x, unsigned short reg, int bytes, void *dest) static bool wm831x_reg_readable(struct device *dev, unsigned int reg) { int ret, i; u16 *buf = dest; BUG_ON(bytes % 2); BUG_ON(bytes <= 0); switch (reg) { case WM831X_RESET_ID: case WM831X_REVISION: case WM831X_PARENT_ID: case WM831X_SYSVDD_CONTROL: case WM831X_THERMAL_MONITORING: case WM831X_POWER_STATE: case WM831X_WATCHDOG: case WM831X_ON_PIN_CONTROL: case WM831X_RESET_CONTROL: case WM831X_CONTROL_INTERFACE: case WM831X_SECURITY_KEY: case WM831X_SOFTWARE_SCRATCH: case WM831X_OTP_CONTROL: case WM831X_GPIO_LEVEL: case WM831X_SYSTEM_STATUS: case WM831X_ON_SOURCE: case WM831X_OFF_SOURCE: case WM831X_SYSTEM_INTERRUPTS: case WM831X_INTERRUPT_STATUS_1: case WM831X_INTERRUPT_STATUS_2: case WM831X_INTERRUPT_STATUS_3: case WM831X_INTERRUPT_STATUS_4: case WM831X_INTERRUPT_STATUS_5: case WM831X_IRQ_CONFIG: case WM831X_SYSTEM_INTERRUPTS_MASK: case WM831X_INTERRUPT_STATUS_1_MASK: case WM831X_INTERRUPT_STATUS_2_MASK: case WM831X_INTERRUPT_STATUS_3_MASK: case WM831X_INTERRUPT_STATUS_4_MASK: case WM831X_INTERRUPT_STATUS_5_MASK: case WM831X_RTC_WRITE_COUNTER: case WM831X_RTC_TIME_1: case WM831X_RTC_TIME_2: case WM831X_RTC_ALARM_1: case WM831X_RTC_ALARM_2: case WM831X_RTC_CONTROL: case WM831X_RTC_TRIM: case WM831X_TOUCH_CONTROL_1: case WM831X_TOUCH_CONTROL_2: case WM831X_TOUCH_DATA_X: case WM831X_TOUCH_DATA_Y: case WM831X_TOUCH_DATA_Z: case WM831X_AUXADC_DATA: case WM831X_AUXADC_CONTROL: case WM831X_AUXADC_SOURCE: case WM831X_COMPARATOR_CONTROL: case WM831X_COMPARATOR_1: case WM831X_COMPARATOR_2: case WM831X_COMPARATOR_3: case WM831X_COMPARATOR_4: case WM831X_GPIO1_CONTROL: case WM831X_GPIO2_CONTROL: case WM831X_GPIO3_CONTROL: case WM831X_GPIO4_CONTROL: case WM831X_GPIO5_CONTROL: case WM831X_GPIO6_CONTROL: case WM831X_GPIO7_CONTROL: case WM831X_GPIO8_CONTROL: case WM831X_GPIO9_CONTROL: case WM831X_GPIO10_CONTROL: case WM831X_GPIO11_CONTROL: case WM831X_GPIO12_CONTROL: case WM831X_GPIO13_CONTROL: case WM831X_GPIO14_CONTROL: case WM831X_GPIO15_CONTROL: case WM831X_GPIO16_CONTROL: case WM831X_CHARGER_CONTROL_1: case WM831X_CHARGER_CONTROL_2: case WM831X_CHARGER_STATUS: case WM831X_BACKUP_CHARGER_CONTROL: case WM831X_STATUS_LED_1: case WM831X_STATUS_LED_2: case WM831X_CURRENT_SINK_1: case WM831X_CURRENT_SINK_2: case WM831X_DCDC_ENABLE: case WM831X_LDO_ENABLE: case WM831X_DCDC_STATUS: case WM831X_LDO_STATUS: case WM831X_DCDC_UV_STATUS: case WM831X_LDO_UV_STATUS: case WM831X_DC1_CONTROL_1: case WM831X_DC1_CONTROL_2: case WM831X_DC1_ON_CONFIG: case WM831X_DC1_SLEEP_CONTROL: case WM831X_DC1_DVS_CONTROL: case WM831X_DC2_CONTROL_1: case WM831X_DC2_CONTROL_2: case WM831X_DC2_ON_CONFIG: case WM831X_DC2_SLEEP_CONTROL: case WM831X_DC2_DVS_CONTROL: case WM831X_DC3_CONTROL_1: case WM831X_DC3_CONTROL_2: case WM831X_DC3_ON_CONFIG: case WM831X_DC3_SLEEP_CONTROL: case WM831X_DC4_CONTROL: case WM831X_DC4_SLEEP_CONTROL: case WM831X_EPE1_CONTROL: case WM831X_EPE2_CONTROL: case WM831X_LDO1_CONTROL: case WM831X_LDO1_ON_CONTROL: case WM831X_LDO1_SLEEP_CONTROL: case WM831X_LDO2_CONTROL: case WM831X_LDO2_ON_CONTROL: case WM831X_LDO2_SLEEP_CONTROL: case WM831X_LDO3_CONTROL: case WM831X_LDO3_ON_CONTROL: case WM831X_LDO3_SLEEP_CONTROL: case WM831X_LDO4_CONTROL: case WM831X_LDO4_ON_CONTROL: case WM831X_LDO4_SLEEP_CONTROL: case WM831X_LDO5_CONTROL: case WM831X_LDO5_ON_CONTROL: case WM831X_LDO5_SLEEP_CONTROL: case WM831X_LDO6_CONTROL: case WM831X_LDO6_ON_CONTROL: case WM831X_LDO6_SLEEP_CONTROL: case WM831X_LDO7_CONTROL: case WM831X_LDO7_ON_CONTROL: case WM831X_LDO7_SLEEP_CONTROL: case WM831X_LDO8_CONTROL: case WM831X_LDO8_ON_CONTROL: case WM831X_LDO8_SLEEP_CONTROL: case WM831X_LDO9_CONTROL: case WM831X_LDO9_ON_CONTROL: case WM831X_LDO9_SLEEP_CONTROL: case WM831X_LDO10_CONTROL: case WM831X_LDO10_ON_CONTROL: case WM831X_LDO10_SLEEP_CONTROL: case WM831X_LDO11_ON_CONTROL: case WM831X_LDO11_SLEEP_CONTROL: case WM831X_POWER_GOOD_SOURCE_1: case WM831X_POWER_GOOD_SOURCE_2: case WM831X_CLOCK_CONTROL_1: case WM831X_CLOCK_CONTROL_2: case WM831X_FLL_CONTROL_1: case WM831X_FLL_CONTROL_2: case WM831X_FLL_CONTROL_3: case WM831X_FLL_CONTROL_4: case WM831X_FLL_CONTROL_5: case WM831X_UNIQUE_ID_1: case WM831X_UNIQUE_ID_2: case WM831X_UNIQUE_ID_3: case WM831X_UNIQUE_ID_4: case WM831X_UNIQUE_ID_5: case WM831X_UNIQUE_ID_6: case WM831X_UNIQUE_ID_7: case WM831X_UNIQUE_ID_8: case WM831X_FACTORY_OTP_ID: case WM831X_FACTORY_OTP_1: case WM831X_FACTORY_OTP_2: case WM831X_FACTORY_OTP_3: case WM831X_FACTORY_OTP_4: case WM831X_FACTORY_OTP_5: case WM831X_CUSTOMER_OTP_ID: case WM831X_DC1_OTP_CONTROL: case WM831X_DC2_OTP_CONTROL: case WM831X_DC3_OTP_CONTROL: case WM831X_LDO1_2_OTP_CONTROL: case WM831X_LDO3_4_OTP_CONTROL: case WM831X_LDO5_6_OTP_CONTROL: case WM831X_LDO7_8_OTP_CONTROL: case WM831X_LDO9_10_OTP_CONTROL: case WM831X_LDO11_EPE_CONTROL: case WM831X_GPIO1_OTP_CONTROL: case WM831X_GPIO2_OTP_CONTROL: case WM831X_GPIO3_OTP_CONTROL: case WM831X_GPIO4_OTP_CONTROL: case WM831X_GPIO5_OTP_CONTROL: case WM831X_GPIO6_OTP_CONTROL: case WM831X_DBE_CHECK_DATA: return true; default: return false; } } ret = wm831x->read_dev(wm831x, reg, bytes, dest); if (ret < 0) return ret; static bool wm831x_reg_writeable(struct device *dev, unsigned int reg) { struct wm831x *wm831x = dev_get_drvdata(dev); for (i = 0; i < bytes / 2; i++) { buf[i] = be16_to_cpu(buf[i]); if (wm831x_reg_locked(wm831x, reg)) return false; dev_vdbg(wm831x->dev, "Read %04x from R%d(0x%x)\n", buf[i], reg + i, reg + i); switch (reg) { case WM831X_SYSVDD_CONTROL: case WM831X_THERMAL_MONITORING: case WM831X_POWER_STATE: case WM831X_WATCHDOG: case WM831X_ON_PIN_CONTROL: case WM831X_RESET_CONTROL: case WM831X_CONTROL_INTERFACE: case WM831X_SECURITY_KEY: case WM831X_SOFTWARE_SCRATCH: case WM831X_OTP_CONTROL: case WM831X_GPIO_LEVEL: case WM831X_INTERRUPT_STATUS_1: case WM831X_INTERRUPT_STATUS_2: case WM831X_INTERRUPT_STATUS_3: case WM831X_INTERRUPT_STATUS_4: case WM831X_INTERRUPT_STATUS_5: case WM831X_IRQ_CONFIG: case WM831X_SYSTEM_INTERRUPTS_MASK: case WM831X_INTERRUPT_STATUS_1_MASK: case WM831X_INTERRUPT_STATUS_2_MASK: case WM831X_INTERRUPT_STATUS_3_MASK: case WM831X_INTERRUPT_STATUS_4_MASK: case WM831X_INTERRUPT_STATUS_5_MASK: case WM831X_RTC_TIME_1: case WM831X_RTC_TIME_2: case WM831X_RTC_ALARM_1: case WM831X_RTC_ALARM_2: case WM831X_RTC_CONTROL: case WM831X_RTC_TRIM: case WM831X_TOUCH_CONTROL_1: case WM831X_TOUCH_CONTROL_2: case WM831X_AUXADC_CONTROL: case WM831X_AUXADC_SOURCE: case WM831X_COMPARATOR_CONTROL: case WM831X_COMPARATOR_1: case WM831X_COMPARATOR_2: case WM831X_COMPARATOR_3: case WM831X_COMPARATOR_4: case WM831X_GPIO1_CONTROL: case WM831X_GPIO2_CONTROL: case WM831X_GPIO3_CONTROL: case WM831X_GPIO4_CONTROL: case WM831X_GPIO5_CONTROL: case WM831X_GPIO6_CONTROL: case WM831X_GPIO7_CONTROL: case WM831X_GPIO8_CONTROL: case WM831X_GPIO9_CONTROL: case WM831X_GPIO10_CONTROL: case WM831X_GPIO11_CONTROL: case WM831X_GPIO12_CONTROL: case WM831X_GPIO13_CONTROL: case WM831X_GPIO14_CONTROL: case WM831X_GPIO15_CONTROL: case WM831X_GPIO16_CONTROL: case WM831X_CHARGER_CONTROL_1: case WM831X_CHARGER_CONTROL_2: case WM831X_CHARGER_STATUS: case WM831X_BACKUP_CHARGER_CONTROL: case WM831X_STATUS_LED_1: case WM831X_STATUS_LED_2: case WM831X_CURRENT_SINK_1: case WM831X_CURRENT_SINK_2: case WM831X_DCDC_ENABLE: case WM831X_LDO_ENABLE: case WM831X_DC1_CONTROL_1: case WM831X_DC1_CONTROL_2: case WM831X_DC1_ON_CONFIG: case WM831X_DC1_SLEEP_CONTROL: case WM831X_DC1_DVS_CONTROL: case WM831X_DC2_CONTROL_1: case WM831X_DC2_CONTROL_2: case WM831X_DC2_ON_CONFIG: case WM831X_DC2_SLEEP_CONTROL: case WM831X_DC2_DVS_CONTROL: case WM831X_DC3_CONTROL_1: case WM831X_DC3_CONTROL_2: case WM831X_DC3_ON_CONFIG: case WM831X_DC3_SLEEP_CONTROL: case WM831X_DC4_CONTROL: case WM831X_DC4_SLEEP_CONTROL: case WM831X_EPE1_CONTROL: case WM831X_EPE2_CONTROL: case WM831X_LDO1_CONTROL: case WM831X_LDO1_ON_CONTROL: case WM831X_LDO1_SLEEP_CONTROL: case WM831X_LDO2_CONTROL: case WM831X_LDO2_ON_CONTROL: case WM831X_LDO2_SLEEP_CONTROL: case WM831X_LDO3_CONTROL: case WM831X_LDO3_ON_CONTROL: case WM831X_LDO3_SLEEP_CONTROL: case WM831X_LDO4_CONTROL: case WM831X_LDO4_ON_CONTROL: case WM831X_LDO4_SLEEP_CONTROL: case WM831X_LDO5_CONTROL: case WM831X_LDO5_ON_CONTROL: case WM831X_LDO5_SLEEP_CONTROL: case WM831X_LDO6_CONTROL: case WM831X_LDO6_ON_CONTROL: case WM831X_LDO6_SLEEP_CONTROL: case WM831X_LDO7_CONTROL: case WM831X_LDO7_ON_CONTROL: case WM831X_LDO7_SLEEP_CONTROL: case WM831X_LDO8_CONTROL: case WM831X_LDO8_ON_CONTROL: case WM831X_LDO8_SLEEP_CONTROL: case WM831X_LDO9_CONTROL: case WM831X_LDO9_ON_CONTROL: case WM831X_LDO9_SLEEP_CONTROL: case WM831X_LDO10_CONTROL: case WM831X_LDO10_ON_CONTROL: case WM831X_LDO10_SLEEP_CONTROL: case WM831X_LDO11_ON_CONTROL: case WM831X_LDO11_SLEEP_CONTROL: case WM831X_POWER_GOOD_SOURCE_1: case WM831X_POWER_GOOD_SOURCE_2: case WM831X_CLOCK_CONTROL_1: case WM831X_CLOCK_CONTROL_2: case WM831X_FLL_CONTROL_1: case WM831X_FLL_CONTROL_2: case WM831X_FLL_CONTROL_3: case WM831X_FLL_CONTROL_4: case WM831X_FLL_CONTROL_5: return true; default: return false; } } return 0; static bool wm831x_reg_volatile(struct device *dev, unsigned int reg) { switch (reg) { case WM831X_SYSTEM_STATUS: case WM831X_ON_SOURCE: case WM831X_OFF_SOURCE: case WM831X_GPIO_LEVEL: case WM831X_SYSTEM_INTERRUPTS: case WM831X_INTERRUPT_STATUS_1: case WM831X_INTERRUPT_STATUS_2: case WM831X_INTERRUPT_STATUS_3: case WM831X_INTERRUPT_STATUS_4: case WM831X_INTERRUPT_STATUS_5: case WM831X_RTC_TIME_1: case WM831X_RTC_TIME_2: case WM831X_TOUCH_DATA_X: case WM831X_TOUCH_DATA_Y: case WM831X_TOUCH_DATA_Z: case WM831X_AUXADC_DATA: case WM831X_CHARGER_STATUS: case WM831X_DCDC_STATUS: case WM831X_LDO_STATUS: case WM831X_DCDC_UV_STATUS: case WM831X_LDO_UV_STATUS: return true; default: return false; } } /** Loading @@ -191,14 +515,10 @@ static int wm831x_read(struct wm831x *wm831x, unsigned short reg, */ int wm831x_reg_read(struct wm831x *wm831x, unsigned short reg) { unsigned short val; unsigned int val; int ret; mutex_lock(&wm831x->io_lock); ret = wm831x_read(wm831x, reg, 2, &val); mutex_unlock(&wm831x->io_lock); ret = regmap_read(wm831x->regmap, reg, &val); if (ret < 0) return ret; Loading @@ -218,15 +538,7 @@ EXPORT_SYMBOL_GPL(wm831x_reg_read); int wm831x_bulk_read(struct wm831x *wm831x, unsigned short reg, int count, u16 *buf) { int ret; mutex_lock(&wm831x->io_lock); ret = wm831x_read(wm831x, reg, count * 2, buf); mutex_unlock(&wm831x->io_lock); return ret; return regmap_bulk_read(wm831x->regmap, reg, buf, count); } EXPORT_SYMBOL_GPL(wm831x_bulk_read); Loading @@ -234,7 +546,7 @@ static int wm831x_write(struct wm831x *wm831x, unsigned short reg, int bytes, void *src) { u16 *buf = src; int i; int i, ret; BUG_ON(bytes % 2); BUG_ON(bytes <= 0); Loading @@ -245,11 +557,10 @@ static int wm831x_write(struct wm831x *wm831x, unsigned short reg, dev_vdbg(wm831x->dev, "Write %04x to R%d(0x%x)\n", buf[i], reg + i, reg + i); buf[i] = cpu_to_be16(buf[i]); ret = regmap_write(wm831x->regmap, reg + i, buf[i]); } return wm831x->write_dev(wm831x, reg, bytes, src); return 0; } /** Loading Loading @@ -286,20 +597,14 @@ int wm831x_set_bits(struct wm831x *wm831x, unsigned short reg, unsigned short mask, unsigned short val) { int ret; u16 r; mutex_lock(&wm831x->io_lock); ret = wm831x_read(wm831x, reg, 2, &r); if (ret < 0) goto out; r &= ~mask; r |= val & mask; ret = wm831x_write(wm831x, reg, 2, &r); if (!wm831x_reg_locked(wm831x, reg)) ret = regmap_update_bits(wm831x->regmap, reg, mask, val); else ret = -EPERM; out: mutex_unlock(&wm831x->io_lock); return ret; Loading Loading @@ -1292,6 +1597,17 @@ static struct mfd_cell backlight_devs[] = { }, }; struct regmap_config wm831x_regmap_config = { .reg_bits = 16, .val_bits = 16, .max_register = WM831X_DBE_CHECK_DATA, .readable_reg = wm831x_reg_readable, .writeable_reg = wm831x_reg_writeable, .volatile_reg = wm831x_reg_volatile, }; EXPORT_SYMBOL_GPL(wm831x_regmap_config); /* * Instantiate the generic non-control parts of the device. */ Loading @@ -1309,7 +1625,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) ret = wm831x_reg_read(wm831x, WM831X_PARENT_ID); if (ret < 0) { dev_err(wm831x->dev, "Failed to read parent ID: %d\n", ret); goto err; goto err_regmap; } switch (ret) { case 0x6204: Loading @@ -1318,20 +1634,20 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) default: dev_err(wm831x->dev, "Device is not a WM831x: ID %x\n", ret); ret = -EINVAL; goto err; goto err_regmap; } ret = wm831x_reg_read(wm831x, WM831X_REVISION); if (ret < 0) { dev_err(wm831x->dev, "Failed to read revision: %d\n", ret); goto err; goto err_regmap; } rev = (ret & WM831X_PARENT_REV_MASK) >> WM831X_PARENT_REV_SHIFT; ret = wm831x_reg_read(wm831x, WM831X_RESET_ID); if (ret < 0) { dev_err(wm831x->dev, "Failed to read device ID: %d\n", ret); goto err; goto err_regmap; } /* Some engineering samples do not have the ID set, rely on Loading Loading @@ -1406,7 +1722,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) default: dev_err(wm831x->dev, "Unknown WM831x device %04x\n", ret); ret = -EINVAL; goto err; goto err_regmap; } /* This will need revisiting in future but is OK for all Loading @@ -1420,7 +1736,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) ret = wm831x_reg_read(wm831x, WM831X_SECURITY_KEY); if (ret < 0) { dev_err(wm831x->dev, "Failed to read security key: %d\n", ret); goto err; goto err_regmap; } if (ret != 0) { dev_warn(wm831x->dev, "Security key had non-zero value %x\n", Loading @@ -1433,7 +1749,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) ret = pdata->pre_init(wm831x); if (ret != 0) { dev_err(wm831x->dev, "pre_init() failed: %d\n", ret); goto err; goto err_regmap; } } Loading @@ -1456,7 +1772,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) ret = wm831x_irq_init(wm831x, irq); if (ret != 0) goto err; goto err_regmap; wm831x_auxadc_init(wm831x); Loading Loading @@ -1552,8 +1868,9 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) err_irq: wm831x_irq_exit(wm831x); err: err_regmap: mfd_remove_devices(wm831x->dev); regmap_exit(wm831x->regmap); kfree(wm831x); return ret; } Loading @@ -1565,6 +1882,7 @@ void wm831x_device_exit(struct wm831x *wm831x) if (wm831x->irq_base) free_irq(wm831x->irq_base + WM831X_IRQ_AUXADC_DATA, wm831x); wm831x_irq_exit(wm831x); regmap_exit(wm831x->regmap); kfree(wm831x); } Loading drivers/mfd/wm831x-i2c.c +12 −56 Original line number Diff line number Diff line Loading @@ -18,67 +18,17 @@ #include <linux/delay.h> #include <linux/mfd/core.h> #include <linux/slab.h> #include <linux/err.h> #include <linux/regmap.h> #include <linux/mfd/wm831x/core.h> #include <linux/mfd/wm831x/pdata.h> static int wm831x_i2c_read_device(struct wm831x *wm831x, unsigned short reg, int bytes, void *dest) { struct i2c_client *i2c = wm831x->control_data; int ret; u16 r = cpu_to_be16(reg); ret = i2c_master_send(i2c, (unsigned char *)&r, 2); if (ret < 0) return ret; if (ret != 2) return -EIO; ret = i2c_master_recv(i2c, dest, bytes); if (ret < 0) return ret; if (ret != bytes) return -EIO; return 0; } /* Currently we allocate the write buffer on the stack; this is OK for * small writes - if we need to do large writes this will need to be * revised. */ static int wm831x_i2c_write_device(struct wm831x *wm831x, unsigned short reg, int bytes, void *src) { struct i2c_client *i2c = wm831x->control_data; struct i2c_msg xfer[2]; int ret; reg = cpu_to_be16(reg); xfer[0].addr = i2c->addr; xfer[0].flags = 0; xfer[0].len = 2; xfer[0].buf = (char *)® xfer[1].addr = i2c->addr; xfer[1].flags = I2C_M_NOSTART; xfer[1].len = bytes; xfer[1].buf = (char *)src; ret = i2c_transfer(i2c->adapter, xfer, 2); if (ret < 0) return ret; if (ret != 2) return -EIO; return 0; } static int wm831x_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct wm831x *wm831x; int ret; wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL); if (wm831x == NULL) Loading @@ -86,9 +36,15 @@ static int wm831x_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, wm831x); wm831x->dev = &i2c->dev; wm831x->control_data = i2c; wm831x->read_dev = wm831x_i2c_read_device; wm831x->write_dev = wm831x_i2c_write_device; wm831x->regmap = regmap_init_i2c(i2c, &wm831x_regmap_config); if (IS_ERR(wm831x->regmap)) { ret = PTR_ERR(wm831x->regmap); dev_err(wm831x->dev, "Failed to allocate register map: %d\n", ret); kfree(wm831x); return ret; } return wm831x_device_init(wm831x, id->driver_data, i2c->irq); } Loading drivers/mfd/wm831x-spi.c +30 −166 Original line number Diff line number Diff line Loading @@ -16,78 +16,19 @@ #include <linux/module.h> #include <linux/pm.h> #include <linux/spi/spi.h> #include <linux/regmap.h> #include <linux/err.h> #include <linux/mfd/wm831x/core.h> static int wm831x_spi_read_device(struct wm831x *wm831x, unsigned short reg, int bytes, void *dest) { u16 tx_val; u16 *d = dest; int r, ret; /* Go register at a time */ for (r = reg; r < reg + (bytes / 2); r++) { tx_val = r | 0x8000; ret = spi_write_then_read(wm831x->control_data, (u8 *)&tx_val, 2, (u8 *)d, 2); if (ret != 0) return ret; *d = be16_to_cpu(*d); d++; } return 0; } static int wm831x_spi_write_device(struct wm831x *wm831x, unsigned short reg, int bytes, void *src) { struct spi_device *spi = wm831x->control_data; u16 *s = src; u16 data[2]; int ret, r; /* Go register at a time */ for (r = reg; r < reg + (bytes / 2); r++) { data[0] = r; data[1] = *s++; ret = spi_write(spi, (char *)&data, sizeof(data)); if (ret != 0) return ret; } return 0; } static int __devinit wm831x_spi_probe(struct spi_device *spi) { const struct spi_device_id *id = spi_get_device_id(spi); struct wm831x *wm831x; enum wm831x_parent type; int ret; /* Currently SPI support for ID tables is unmerged, we're faking it */ if (strcmp(spi->modalias, "wm8310") == 0) type = WM8310; else if (strcmp(spi->modalias, "wm8311") == 0) type = WM8311; else if (strcmp(spi->modalias, "wm8312") == 0) type = WM8312; else if (strcmp(spi->modalias, "wm8320") == 0) type = WM8320; else if (strcmp(spi->modalias, "wm8321") == 0) type = WM8321; else if (strcmp(spi->modalias, "wm8325") == 0) type = WM8325; else if (strcmp(spi->modalias, "wm8326") == 0) type = WM8326; else { dev_err(&spi->dev, "Unknown device type\n"); return -EINVAL; } type = (enum wm831x_parent)id->driver_data; wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL); if (wm831x == NULL) Loading @@ -98,9 +39,15 @@ static int __devinit wm831x_spi_probe(struct spi_device *spi) dev_set_drvdata(&spi->dev, wm831x); wm831x->dev = &spi->dev; wm831x->control_data = spi; wm831x->read_dev = wm831x_spi_read_device; wm831x->write_dev = wm831x_spi_write_device; wm831x->regmap = regmap_init_spi(spi, &wm831x_regmap_config); if (IS_ERR(wm831x->regmap)) { ret = PTR_ERR(wm831x->regmap); dev_err(wm831x->dev, "Failed to allocate register map: %d\n", ret); kfree(wm831x); return ret; } return wm831x_device_init(wm831x, type, spi->irq); } Loading @@ -126,79 +73,26 @@ static const struct dev_pm_ops wm831x_spi_pm = { .suspend = wm831x_spi_suspend, }; static struct spi_driver wm8310_spi_driver = { .driver = { .name = "wm8310", .bus = &spi_bus_type, .owner = THIS_MODULE, .pm = &wm831x_spi_pm, }, .probe = wm831x_spi_probe, .remove = __devexit_p(wm831x_spi_remove), static const struct spi_device_id wm831x_spi_ids[] = { { "wm8310", WM8310 }, { "wm8311", WM8311 }, { "wm8312", WM8312 }, { "wm8320", WM8320 }, { "wm8321", WM8321 }, { "wm8325", WM8325 }, { "wm8326", WM8326 }, { }, }; MODULE_DEVICE_TABLE(spi, wm831x_spi_id); static struct spi_driver wm8311_spi_driver = { static struct spi_driver wm831x_spi_driver = { .driver = { .name = "wm8311", .bus = &spi_bus_type, .owner = THIS_MODULE, .pm = &wm831x_spi_pm, }, .probe = wm831x_spi_probe, .remove = __devexit_p(wm831x_spi_remove), }; static struct spi_driver wm8312_spi_driver = { .driver = { .name = "wm8312", .bus = &spi_bus_type, .owner = THIS_MODULE, .pm = &wm831x_spi_pm, }, .probe = wm831x_spi_probe, .remove = __devexit_p(wm831x_spi_remove), }; static struct spi_driver wm8320_spi_driver = { .driver = { .name = "wm8320", .bus = &spi_bus_type, .owner = THIS_MODULE, .pm = &wm831x_spi_pm, }, .probe = wm831x_spi_probe, .remove = __devexit_p(wm831x_spi_remove), }; static struct spi_driver wm8321_spi_driver = { .driver = { .name = "wm8321", .bus = &spi_bus_type, .owner = THIS_MODULE, .pm = &wm831x_spi_pm, }, .probe = wm831x_spi_probe, .remove = __devexit_p(wm831x_spi_remove), }; static struct spi_driver wm8325_spi_driver = { .driver = { .name = "wm8325", .bus = &spi_bus_type, .owner = THIS_MODULE, .pm = &wm831x_spi_pm, }, .probe = wm831x_spi_probe, .remove = __devexit_p(wm831x_spi_remove), }; static struct spi_driver wm8326_spi_driver = { .driver = { .name = "wm8326", .name = "wm831x", .bus = &spi_bus_type, .owner = THIS_MODULE, .pm = &wm831x_spi_pm, }, .id_table = wm831x_spi_ids, .probe = wm831x_spi_probe, .remove = __devexit_p(wm831x_spi_remove), }; Loading @@ -207,33 +101,9 @@ static int __init wm831x_spi_init(void) { int ret; ret = spi_register_driver(&wm8310_spi_driver); if (ret != 0) pr_err("Failed to register WM8310 SPI driver: %d\n", ret); ret = spi_register_driver(&wm8311_spi_driver); if (ret != 0) pr_err("Failed to register WM8311 SPI driver: %d\n", ret); ret = spi_register_driver(&wm8312_spi_driver); if (ret != 0) pr_err("Failed to register WM8312 SPI driver: %d\n", ret); ret = spi_register_driver(&wm8320_spi_driver); if (ret != 0) pr_err("Failed to register WM8320 SPI driver: %d\n", ret); ret = spi_register_driver(&wm8321_spi_driver); if (ret != 0) pr_err("Failed to register WM8321 SPI driver: %d\n", ret); ret = spi_register_driver(&wm8325_spi_driver); if (ret != 0) pr_err("Failed to register WM8325 SPI driver: %d\n", ret); ret = spi_register_driver(&wm8326_spi_driver); ret = spi_register_driver(&wm831x_spi_driver); if (ret != 0) pr_err("Failed to register WM8326 SPI driver: %d\n", ret); pr_err("Failed to register WM831x SPI driver: %d\n", ret); return 0; } Loading @@ -241,13 +111,7 @@ subsys_initcall(wm831x_spi_init); static void __exit wm831x_spi_exit(void) { spi_unregister_driver(&wm8326_spi_driver); spi_unregister_driver(&wm8325_spi_driver); spi_unregister_driver(&wm8321_spi_driver); spi_unregister_driver(&wm8320_spi_driver); spi_unregister_driver(&wm8312_spi_driver); spi_unregister_driver(&wm8311_spi_driver); spi_unregister_driver(&wm8310_spi_driver); spi_unregister_driver(&wm831x_spi_driver); } module_exit(wm831x_spi_exit); Loading drivers/mfd/wm8400-core.c +29 −77 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
drivers/mfd/Kconfig +3 −0 Original line number Diff line number Diff line Loading @@ -404,6 +404,7 @@ config MFD_WM831X_I2C bool "Support Wolfson Microelectronics WM831x/2x PMICs with I2C" select MFD_CORE select MFD_WM831X select REGMAP_I2C depends on I2C=y && GENERIC_HARDIRQS help Support for the Wolfson Microelecronics WM831x and WM832x PMICs Loading @@ -415,6 +416,7 @@ config MFD_WM831X_SPI bool "Support Wolfson Microelectronics WM831x/2x PMICs with SPI" select MFD_CORE select MFD_WM831X select REGMAP_SPI depends on SPI_MASTER && GENERIC_HARDIRQS help Support for the Wolfson Microelecronics WM831x and WM832x PMICs Loading Loading @@ -488,6 +490,7 @@ config MFD_WM8350_I2C config MFD_WM8994 bool "Support Wolfson Microelectronics WM8994" select MFD_CORE select REGMAP_I2C depends on I2C=y && GENERIC_HARDIRQS help The WM8994 is a highly integrated hi-fi CODEC designed for Loading
drivers/mfd/wm831x-core.c +371 −53 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include <linux/delay.h> #include <linux/mfd/core.h> #include <linux/slab.h> #include <linux/err.h> #include <linux/mfd/wm831x/core.h> #include <linux/mfd/wm831x/pdata.h> Loading Loading @@ -160,27 +161,350 @@ int wm831x_reg_unlock(struct wm831x *wm831x) } EXPORT_SYMBOL_GPL(wm831x_reg_unlock); static int wm831x_read(struct wm831x *wm831x, unsigned short reg, int bytes, void *dest) static bool wm831x_reg_readable(struct device *dev, unsigned int reg) { int ret, i; u16 *buf = dest; BUG_ON(bytes % 2); BUG_ON(bytes <= 0); switch (reg) { case WM831X_RESET_ID: case WM831X_REVISION: case WM831X_PARENT_ID: case WM831X_SYSVDD_CONTROL: case WM831X_THERMAL_MONITORING: case WM831X_POWER_STATE: case WM831X_WATCHDOG: case WM831X_ON_PIN_CONTROL: case WM831X_RESET_CONTROL: case WM831X_CONTROL_INTERFACE: case WM831X_SECURITY_KEY: case WM831X_SOFTWARE_SCRATCH: case WM831X_OTP_CONTROL: case WM831X_GPIO_LEVEL: case WM831X_SYSTEM_STATUS: case WM831X_ON_SOURCE: case WM831X_OFF_SOURCE: case WM831X_SYSTEM_INTERRUPTS: case WM831X_INTERRUPT_STATUS_1: case WM831X_INTERRUPT_STATUS_2: case WM831X_INTERRUPT_STATUS_3: case WM831X_INTERRUPT_STATUS_4: case WM831X_INTERRUPT_STATUS_5: case WM831X_IRQ_CONFIG: case WM831X_SYSTEM_INTERRUPTS_MASK: case WM831X_INTERRUPT_STATUS_1_MASK: case WM831X_INTERRUPT_STATUS_2_MASK: case WM831X_INTERRUPT_STATUS_3_MASK: case WM831X_INTERRUPT_STATUS_4_MASK: case WM831X_INTERRUPT_STATUS_5_MASK: case WM831X_RTC_WRITE_COUNTER: case WM831X_RTC_TIME_1: case WM831X_RTC_TIME_2: case WM831X_RTC_ALARM_1: case WM831X_RTC_ALARM_2: case WM831X_RTC_CONTROL: case WM831X_RTC_TRIM: case WM831X_TOUCH_CONTROL_1: case WM831X_TOUCH_CONTROL_2: case WM831X_TOUCH_DATA_X: case WM831X_TOUCH_DATA_Y: case WM831X_TOUCH_DATA_Z: case WM831X_AUXADC_DATA: case WM831X_AUXADC_CONTROL: case WM831X_AUXADC_SOURCE: case WM831X_COMPARATOR_CONTROL: case WM831X_COMPARATOR_1: case WM831X_COMPARATOR_2: case WM831X_COMPARATOR_3: case WM831X_COMPARATOR_4: case WM831X_GPIO1_CONTROL: case WM831X_GPIO2_CONTROL: case WM831X_GPIO3_CONTROL: case WM831X_GPIO4_CONTROL: case WM831X_GPIO5_CONTROL: case WM831X_GPIO6_CONTROL: case WM831X_GPIO7_CONTROL: case WM831X_GPIO8_CONTROL: case WM831X_GPIO9_CONTROL: case WM831X_GPIO10_CONTROL: case WM831X_GPIO11_CONTROL: case WM831X_GPIO12_CONTROL: case WM831X_GPIO13_CONTROL: case WM831X_GPIO14_CONTROL: case WM831X_GPIO15_CONTROL: case WM831X_GPIO16_CONTROL: case WM831X_CHARGER_CONTROL_1: case WM831X_CHARGER_CONTROL_2: case WM831X_CHARGER_STATUS: case WM831X_BACKUP_CHARGER_CONTROL: case WM831X_STATUS_LED_1: case WM831X_STATUS_LED_2: case WM831X_CURRENT_SINK_1: case WM831X_CURRENT_SINK_2: case WM831X_DCDC_ENABLE: case WM831X_LDO_ENABLE: case WM831X_DCDC_STATUS: case WM831X_LDO_STATUS: case WM831X_DCDC_UV_STATUS: case WM831X_LDO_UV_STATUS: case WM831X_DC1_CONTROL_1: case WM831X_DC1_CONTROL_2: case WM831X_DC1_ON_CONFIG: case WM831X_DC1_SLEEP_CONTROL: case WM831X_DC1_DVS_CONTROL: case WM831X_DC2_CONTROL_1: case WM831X_DC2_CONTROL_2: case WM831X_DC2_ON_CONFIG: case WM831X_DC2_SLEEP_CONTROL: case WM831X_DC2_DVS_CONTROL: case WM831X_DC3_CONTROL_1: case WM831X_DC3_CONTROL_2: case WM831X_DC3_ON_CONFIG: case WM831X_DC3_SLEEP_CONTROL: case WM831X_DC4_CONTROL: case WM831X_DC4_SLEEP_CONTROL: case WM831X_EPE1_CONTROL: case WM831X_EPE2_CONTROL: case WM831X_LDO1_CONTROL: case WM831X_LDO1_ON_CONTROL: case WM831X_LDO1_SLEEP_CONTROL: case WM831X_LDO2_CONTROL: case WM831X_LDO2_ON_CONTROL: case WM831X_LDO2_SLEEP_CONTROL: case WM831X_LDO3_CONTROL: case WM831X_LDO3_ON_CONTROL: case WM831X_LDO3_SLEEP_CONTROL: case WM831X_LDO4_CONTROL: case WM831X_LDO4_ON_CONTROL: case WM831X_LDO4_SLEEP_CONTROL: case WM831X_LDO5_CONTROL: case WM831X_LDO5_ON_CONTROL: case WM831X_LDO5_SLEEP_CONTROL: case WM831X_LDO6_CONTROL: case WM831X_LDO6_ON_CONTROL: case WM831X_LDO6_SLEEP_CONTROL: case WM831X_LDO7_CONTROL: case WM831X_LDO7_ON_CONTROL: case WM831X_LDO7_SLEEP_CONTROL: case WM831X_LDO8_CONTROL: case WM831X_LDO8_ON_CONTROL: case WM831X_LDO8_SLEEP_CONTROL: case WM831X_LDO9_CONTROL: case WM831X_LDO9_ON_CONTROL: case WM831X_LDO9_SLEEP_CONTROL: case WM831X_LDO10_CONTROL: case WM831X_LDO10_ON_CONTROL: case WM831X_LDO10_SLEEP_CONTROL: case WM831X_LDO11_ON_CONTROL: case WM831X_LDO11_SLEEP_CONTROL: case WM831X_POWER_GOOD_SOURCE_1: case WM831X_POWER_GOOD_SOURCE_2: case WM831X_CLOCK_CONTROL_1: case WM831X_CLOCK_CONTROL_2: case WM831X_FLL_CONTROL_1: case WM831X_FLL_CONTROL_2: case WM831X_FLL_CONTROL_3: case WM831X_FLL_CONTROL_4: case WM831X_FLL_CONTROL_5: case WM831X_UNIQUE_ID_1: case WM831X_UNIQUE_ID_2: case WM831X_UNIQUE_ID_3: case WM831X_UNIQUE_ID_4: case WM831X_UNIQUE_ID_5: case WM831X_UNIQUE_ID_6: case WM831X_UNIQUE_ID_7: case WM831X_UNIQUE_ID_8: case WM831X_FACTORY_OTP_ID: case WM831X_FACTORY_OTP_1: case WM831X_FACTORY_OTP_2: case WM831X_FACTORY_OTP_3: case WM831X_FACTORY_OTP_4: case WM831X_FACTORY_OTP_5: case WM831X_CUSTOMER_OTP_ID: case WM831X_DC1_OTP_CONTROL: case WM831X_DC2_OTP_CONTROL: case WM831X_DC3_OTP_CONTROL: case WM831X_LDO1_2_OTP_CONTROL: case WM831X_LDO3_4_OTP_CONTROL: case WM831X_LDO5_6_OTP_CONTROL: case WM831X_LDO7_8_OTP_CONTROL: case WM831X_LDO9_10_OTP_CONTROL: case WM831X_LDO11_EPE_CONTROL: case WM831X_GPIO1_OTP_CONTROL: case WM831X_GPIO2_OTP_CONTROL: case WM831X_GPIO3_OTP_CONTROL: case WM831X_GPIO4_OTP_CONTROL: case WM831X_GPIO5_OTP_CONTROL: case WM831X_GPIO6_OTP_CONTROL: case WM831X_DBE_CHECK_DATA: return true; default: return false; } } ret = wm831x->read_dev(wm831x, reg, bytes, dest); if (ret < 0) return ret; static bool wm831x_reg_writeable(struct device *dev, unsigned int reg) { struct wm831x *wm831x = dev_get_drvdata(dev); for (i = 0; i < bytes / 2; i++) { buf[i] = be16_to_cpu(buf[i]); if (wm831x_reg_locked(wm831x, reg)) return false; dev_vdbg(wm831x->dev, "Read %04x from R%d(0x%x)\n", buf[i], reg + i, reg + i); switch (reg) { case WM831X_SYSVDD_CONTROL: case WM831X_THERMAL_MONITORING: case WM831X_POWER_STATE: case WM831X_WATCHDOG: case WM831X_ON_PIN_CONTROL: case WM831X_RESET_CONTROL: case WM831X_CONTROL_INTERFACE: case WM831X_SECURITY_KEY: case WM831X_SOFTWARE_SCRATCH: case WM831X_OTP_CONTROL: case WM831X_GPIO_LEVEL: case WM831X_INTERRUPT_STATUS_1: case WM831X_INTERRUPT_STATUS_2: case WM831X_INTERRUPT_STATUS_3: case WM831X_INTERRUPT_STATUS_4: case WM831X_INTERRUPT_STATUS_5: case WM831X_IRQ_CONFIG: case WM831X_SYSTEM_INTERRUPTS_MASK: case WM831X_INTERRUPT_STATUS_1_MASK: case WM831X_INTERRUPT_STATUS_2_MASK: case WM831X_INTERRUPT_STATUS_3_MASK: case WM831X_INTERRUPT_STATUS_4_MASK: case WM831X_INTERRUPT_STATUS_5_MASK: case WM831X_RTC_TIME_1: case WM831X_RTC_TIME_2: case WM831X_RTC_ALARM_1: case WM831X_RTC_ALARM_2: case WM831X_RTC_CONTROL: case WM831X_RTC_TRIM: case WM831X_TOUCH_CONTROL_1: case WM831X_TOUCH_CONTROL_2: case WM831X_AUXADC_CONTROL: case WM831X_AUXADC_SOURCE: case WM831X_COMPARATOR_CONTROL: case WM831X_COMPARATOR_1: case WM831X_COMPARATOR_2: case WM831X_COMPARATOR_3: case WM831X_COMPARATOR_4: case WM831X_GPIO1_CONTROL: case WM831X_GPIO2_CONTROL: case WM831X_GPIO3_CONTROL: case WM831X_GPIO4_CONTROL: case WM831X_GPIO5_CONTROL: case WM831X_GPIO6_CONTROL: case WM831X_GPIO7_CONTROL: case WM831X_GPIO8_CONTROL: case WM831X_GPIO9_CONTROL: case WM831X_GPIO10_CONTROL: case WM831X_GPIO11_CONTROL: case WM831X_GPIO12_CONTROL: case WM831X_GPIO13_CONTROL: case WM831X_GPIO14_CONTROL: case WM831X_GPIO15_CONTROL: case WM831X_GPIO16_CONTROL: case WM831X_CHARGER_CONTROL_1: case WM831X_CHARGER_CONTROL_2: case WM831X_CHARGER_STATUS: case WM831X_BACKUP_CHARGER_CONTROL: case WM831X_STATUS_LED_1: case WM831X_STATUS_LED_2: case WM831X_CURRENT_SINK_1: case WM831X_CURRENT_SINK_2: case WM831X_DCDC_ENABLE: case WM831X_LDO_ENABLE: case WM831X_DC1_CONTROL_1: case WM831X_DC1_CONTROL_2: case WM831X_DC1_ON_CONFIG: case WM831X_DC1_SLEEP_CONTROL: case WM831X_DC1_DVS_CONTROL: case WM831X_DC2_CONTROL_1: case WM831X_DC2_CONTROL_2: case WM831X_DC2_ON_CONFIG: case WM831X_DC2_SLEEP_CONTROL: case WM831X_DC2_DVS_CONTROL: case WM831X_DC3_CONTROL_1: case WM831X_DC3_CONTROL_2: case WM831X_DC3_ON_CONFIG: case WM831X_DC3_SLEEP_CONTROL: case WM831X_DC4_CONTROL: case WM831X_DC4_SLEEP_CONTROL: case WM831X_EPE1_CONTROL: case WM831X_EPE2_CONTROL: case WM831X_LDO1_CONTROL: case WM831X_LDO1_ON_CONTROL: case WM831X_LDO1_SLEEP_CONTROL: case WM831X_LDO2_CONTROL: case WM831X_LDO2_ON_CONTROL: case WM831X_LDO2_SLEEP_CONTROL: case WM831X_LDO3_CONTROL: case WM831X_LDO3_ON_CONTROL: case WM831X_LDO3_SLEEP_CONTROL: case WM831X_LDO4_CONTROL: case WM831X_LDO4_ON_CONTROL: case WM831X_LDO4_SLEEP_CONTROL: case WM831X_LDO5_CONTROL: case WM831X_LDO5_ON_CONTROL: case WM831X_LDO5_SLEEP_CONTROL: case WM831X_LDO6_CONTROL: case WM831X_LDO6_ON_CONTROL: case WM831X_LDO6_SLEEP_CONTROL: case WM831X_LDO7_CONTROL: case WM831X_LDO7_ON_CONTROL: case WM831X_LDO7_SLEEP_CONTROL: case WM831X_LDO8_CONTROL: case WM831X_LDO8_ON_CONTROL: case WM831X_LDO8_SLEEP_CONTROL: case WM831X_LDO9_CONTROL: case WM831X_LDO9_ON_CONTROL: case WM831X_LDO9_SLEEP_CONTROL: case WM831X_LDO10_CONTROL: case WM831X_LDO10_ON_CONTROL: case WM831X_LDO10_SLEEP_CONTROL: case WM831X_LDO11_ON_CONTROL: case WM831X_LDO11_SLEEP_CONTROL: case WM831X_POWER_GOOD_SOURCE_1: case WM831X_POWER_GOOD_SOURCE_2: case WM831X_CLOCK_CONTROL_1: case WM831X_CLOCK_CONTROL_2: case WM831X_FLL_CONTROL_1: case WM831X_FLL_CONTROL_2: case WM831X_FLL_CONTROL_3: case WM831X_FLL_CONTROL_4: case WM831X_FLL_CONTROL_5: return true; default: return false; } } return 0; static bool wm831x_reg_volatile(struct device *dev, unsigned int reg) { switch (reg) { case WM831X_SYSTEM_STATUS: case WM831X_ON_SOURCE: case WM831X_OFF_SOURCE: case WM831X_GPIO_LEVEL: case WM831X_SYSTEM_INTERRUPTS: case WM831X_INTERRUPT_STATUS_1: case WM831X_INTERRUPT_STATUS_2: case WM831X_INTERRUPT_STATUS_3: case WM831X_INTERRUPT_STATUS_4: case WM831X_INTERRUPT_STATUS_5: case WM831X_RTC_TIME_1: case WM831X_RTC_TIME_2: case WM831X_TOUCH_DATA_X: case WM831X_TOUCH_DATA_Y: case WM831X_TOUCH_DATA_Z: case WM831X_AUXADC_DATA: case WM831X_CHARGER_STATUS: case WM831X_DCDC_STATUS: case WM831X_LDO_STATUS: case WM831X_DCDC_UV_STATUS: case WM831X_LDO_UV_STATUS: return true; default: return false; } } /** Loading @@ -191,14 +515,10 @@ static int wm831x_read(struct wm831x *wm831x, unsigned short reg, */ int wm831x_reg_read(struct wm831x *wm831x, unsigned short reg) { unsigned short val; unsigned int val; int ret; mutex_lock(&wm831x->io_lock); ret = wm831x_read(wm831x, reg, 2, &val); mutex_unlock(&wm831x->io_lock); ret = regmap_read(wm831x->regmap, reg, &val); if (ret < 0) return ret; Loading @@ -218,15 +538,7 @@ EXPORT_SYMBOL_GPL(wm831x_reg_read); int wm831x_bulk_read(struct wm831x *wm831x, unsigned short reg, int count, u16 *buf) { int ret; mutex_lock(&wm831x->io_lock); ret = wm831x_read(wm831x, reg, count * 2, buf); mutex_unlock(&wm831x->io_lock); return ret; return regmap_bulk_read(wm831x->regmap, reg, buf, count); } EXPORT_SYMBOL_GPL(wm831x_bulk_read); Loading @@ -234,7 +546,7 @@ static int wm831x_write(struct wm831x *wm831x, unsigned short reg, int bytes, void *src) { u16 *buf = src; int i; int i, ret; BUG_ON(bytes % 2); BUG_ON(bytes <= 0); Loading @@ -245,11 +557,10 @@ static int wm831x_write(struct wm831x *wm831x, unsigned short reg, dev_vdbg(wm831x->dev, "Write %04x to R%d(0x%x)\n", buf[i], reg + i, reg + i); buf[i] = cpu_to_be16(buf[i]); ret = regmap_write(wm831x->regmap, reg + i, buf[i]); } return wm831x->write_dev(wm831x, reg, bytes, src); return 0; } /** Loading Loading @@ -286,20 +597,14 @@ int wm831x_set_bits(struct wm831x *wm831x, unsigned short reg, unsigned short mask, unsigned short val) { int ret; u16 r; mutex_lock(&wm831x->io_lock); ret = wm831x_read(wm831x, reg, 2, &r); if (ret < 0) goto out; r &= ~mask; r |= val & mask; ret = wm831x_write(wm831x, reg, 2, &r); if (!wm831x_reg_locked(wm831x, reg)) ret = regmap_update_bits(wm831x->regmap, reg, mask, val); else ret = -EPERM; out: mutex_unlock(&wm831x->io_lock); return ret; Loading Loading @@ -1292,6 +1597,17 @@ static struct mfd_cell backlight_devs[] = { }, }; struct regmap_config wm831x_regmap_config = { .reg_bits = 16, .val_bits = 16, .max_register = WM831X_DBE_CHECK_DATA, .readable_reg = wm831x_reg_readable, .writeable_reg = wm831x_reg_writeable, .volatile_reg = wm831x_reg_volatile, }; EXPORT_SYMBOL_GPL(wm831x_regmap_config); /* * Instantiate the generic non-control parts of the device. */ Loading @@ -1309,7 +1625,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) ret = wm831x_reg_read(wm831x, WM831X_PARENT_ID); if (ret < 0) { dev_err(wm831x->dev, "Failed to read parent ID: %d\n", ret); goto err; goto err_regmap; } switch (ret) { case 0x6204: Loading @@ -1318,20 +1634,20 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) default: dev_err(wm831x->dev, "Device is not a WM831x: ID %x\n", ret); ret = -EINVAL; goto err; goto err_regmap; } ret = wm831x_reg_read(wm831x, WM831X_REVISION); if (ret < 0) { dev_err(wm831x->dev, "Failed to read revision: %d\n", ret); goto err; goto err_regmap; } rev = (ret & WM831X_PARENT_REV_MASK) >> WM831X_PARENT_REV_SHIFT; ret = wm831x_reg_read(wm831x, WM831X_RESET_ID); if (ret < 0) { dev_err(wm831x->dev, "Failed to read device ID: %d\n", ret); goto err; goto err_regmap; } /* Some engineering samples do not have the ID set, rely on Loading Loading @@ -1406,7 +1722,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) default: dev_err(wm831x->dev, "Unknown WM831x device %04x\n", ret); ret = -EINVAL; goto err; goto err_regmap; } /* This will need revisiting in future but is OK for all Loading @@ -1420,7 +1736,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) ret = wm831x_reg_read(wm831x, WM831X_SECURITY_KEY); if (ret < 0) { dev_err(wm831x->dev, "Failed to read security key: %d\n", ret); goto err; goto err_regmap; } if (ret != 0) { dev_warn(wm831x->dev, "Security key had non-zero value %x\n", Loading @@ -1433,7 +1749,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) ret = pdata->pre_init(wm831x); if (ret != 0) { dev_err(wm831x->dev, "pre_init() failed: %d\n", ret); goto err; goto err_regmap; } } Loading @@ -1456,7 +1772,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) ret = wm831x_irq_init(wm831x, irq); if (ret != 0) goto err; goto err_regmap; wm831x_auxadc_init(wm831x); Loading Loading @@ -1552,8 +1868,9 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) err_irq: wm831x_irq_exit(wm831x); err: err_regmap: mfd_remove_devices(wm831x->dev); regmap_exit(wm831x->regmap); kfree(wm831x); return ret; } Loading @@ -1565,6 +1882,7 @@ void wm831x_device_exit(struct wm831x *wm831x) if (wm831x->irq_base) free_irq(wm831x->irq_base + WM831X_IRQ_AUXADC_DATA, wm831x); wm831x_irq_exit(wm831x); regmap_exit(wm831x->regmap); kfree(wm831x); } Loading
drivers/mfd/wm831x-i2c.c +12 −56 Original line number Diff line number Diff line Loading @@ -18,67 +18,17 @@ #include <linux/delay.h> #include <linux/mfd/core.h> #include <linux/slab.h> #include <linux/err.h> #include <linux/regmap.h> #include <linux/mfd/wm831x/core.h> #include <linux/mfd/wm831x/pdata.h> static int wm831x_i2c_read_device(struct wm831x *wm831x, unsigned short reg, int bytes, void *dest) { struct i2c_client *i2c = wm831x->control_data; int ret; u16 r = cpu_to_be16(reg); ret = i2c_master_send(i2c, (unsigned char *)&r, 2); if (ret < 0) return ret; if (ret != 2) return -EIO; ret = i2c_master_recv(i2c, dest, bytes); if (ret < 0) return ret; if (ret != bytes) return -EIO; return 0; } /* Currently we allocate the write buffer on the stack; this is OK for * small writes - if we need to do large writes this will need to be * revised. */ static int wm831x_i2c_write_device(struct wm831x *wm831x, unsigned short reg, int bytes, void *src) { struct i2c_client *i2c = wm831x->control_data; struct i2c_msg xfer[2]; int ret; reg = cpu_to_be16(reg); xfer[0].addr = i2c->addr; xfer[0].flags = 0; xfer[0].len = 2; xfer[0].buf = (char *)® xfer[1].addr = i2c->addr; xfer[1].flags = I2C_M_NOSTART; xfer[1].len = bytes; xfer[1].buf = (char *)src; ret = i2c_transfer(i2c->adapter, xfer, 2); if (ret < 0) return ret; if (ret != 2) return -EIO; return 0; } static int wm831x_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct wm831x *wm831x; int ret; wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL); if (wm831x == NULL) Loading @@ -86,9 +36,15 @@ static int wm831x_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, wm831x); wm831x->dev = &i2c->dev; wm831x->control_data = i2c; wm831x->read_dev = wm831x_i2c_read_device; wm831x->write_dev = wm831x_i2c_write_device; wm831x->regmap = regmap_init_i2c(i2c, &wm831x_regmap_config); if (IS_ERR(wm831x->regmap)) { ret = PTR_ERR(wm831x->regmap); dev_err(wm831x->dev, "Failed to allocate register map: %d\n", ret); kfree(wm831x); return ret; } return wm831x_device_init(wm831x, id->driver_data, i2c->irq); } Loading
drivers/mfd/wm831x-spi.c +30 −166 Original line number Diff line number Diff line Loading @@ -16,78 +16,19 @@ #include <linux/module.h> #include <linux/pm.h> #include <linux/spi/spi.h> #include <linux/regmap.h> #include <linux/err.h> #include <linux/mfd/wm831x/core.h> static int wm831x_spi_read_device(struct wm831x *wm831x, unsigned short reg, int bytes, void *dest) { u16 tx_val; u16 *d = dest; int r, ret; /* Go register at a time */ for (r = reg; r < reg + (bytes / 2); r++) { tx_val = r | 0x8000; ret = spi_write_then_read(wm831x->control_data, (u8 *)&tx_val, 2, (u8 *)d, 2); if (ret != 0) return ret; *d = be16_to_cpu(*d); d++; } return 0; } static int wm831x_spi_write_device(struct wm831x *wm831x, unsigned short reg, int bytes, void *src) { struct spi_device *spi = wm831x->control_data; u16 *s = src; u16 data[2]; int ret, r; /* Go register at a time */ for (r = reg; r < reg + (bytes / 2); r++) { data[0] = r; data[1] = *s++; ret = spi_write(spi, (char *)&data, sizeof(data)); if (ret != 0) return ret; } return 0; } static int __devinit wm831x_spi_probe(struct spi_device *spi) { const struct spi_device_id *id = spi_get_device_id(spi); struct wm831x *wm831x; enum wm831x_parent type; int ret; /* Currently SPI support for ID tables is unmerged, we're faking it */ if (strcmp(spi->modalias, "wm8310") == 0) type = WM8310; else if (strcmp(spi->modalias, "wm8311") == 0) type = WM8311; else if (strcmp(spi->modalias, "wm8312") == 0) type = WM8312; else if (strcmp(spi->modalias, "wm8320") == 0) type = WM8320; else if (strcmp(spi->modalias, "wm8321") == 0) type = WM8321; else if (strcmp(spi->modalias, "wm8325") == 0) type = WM8325; else if (strcmp(spi->modalias, "wm8326") == 0) type = WM8326; else { dev_err(&spi->dev, "Unknown device type\n"); return -EINVAL; } type = (enum wm831x_parent)id->driver_data; wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL); if (wm831x == NULL) Loading @@ -98,9 +39,15 @@ static int __devinit wm831x_spi_probe(struct spi_device *spi) dev_set_drvdata(&spi->dev, wm831x); wm831x->dev = &spi->dev; wm831x->control_data = spi; wm831x->read_dev = wm831x_spi_read_device; wm831x->write_dev = wm831x_spi_write_device; wm831x->regmap = regmap_init_spi(spi, &wm831x_regmap_config); if (IS_ERR(wm831x->regmap)) { ret = PTR_ERR(wm831x->regmap); dev_err(wm831x->dev, "Failed to allocate register map: %d\n", ret); kfree(wm831x); return ret; } return wm831x_device_init(wm831x, type, spi->irq); } Loading @@ -126,79 +73,26 @@ static const struct dev_pm_ops wm831x_spi_pm = { .suspend = wm831x_spi_suspend, }; static struct spi_driver wm8310_spi_driver = { .driver = { .name = "wm8310", .bus = &spi_bus_type, .owner = THIS_MODULE, .pm = &wm831x_spi_pm, }, .probe = wm831x_spi_probe, .remove = __devexit_p(wm831x_spi_remove), static const struct spi_device_id wm831x_spi_ids[] = { { "wm8310", WM8310 }, { "wm8311", WM8311 }, { "wm8312", WM8312 }, { "wm8320", WM8320 }, { "wm8321", WM8321 }, { "wm8325", WM8325 }, { "wm8326", WM8326 }, { }, }; MODULE_DEVICE_TABLE(spi, wm831x_spi_id); static struct spi_driver wm8311_spi_driver = { static struct spi_driver wm831x_spi_driver = { .driver = { .name = "wm8311", .bus = &spi_bus_type, .owner = THIS_MODULE, .pm = &wm831x_spi_pm, }, .probe = wm831x_spi_probe, .remove = __devexit_p(wm831x_spi_remove), }; static struct spi_driver wm8312_spi_driver = { .driver = { .name = "wm8312", .bus = &spi_bus_type, .owner = THIS_MODULE, .pm = &wm831x_spi_pm, }, .probe = wm831x_spi_probe, .remove = __devexit_p(wm831x_spi_remove), }; static struct spi_driver wm8320_spi_driver = { .driver = { .name = "wm8320", .bus = &spi_bus_type, .owner = THIS_MODULE, .pm = &wm831x_spi_pm, }, .probe = wm831x_spi_probe, .remove = __devexit_p(wm831x_spi_remove), }; static struct spi_driver wm8321_spi_driver = { .driver = { .name = "wm8321", .bus = &spi_bus_type, .owner = THIS_MODULE, .pm = &wm831x_spi_pm, }, .probe = wm831x_spi_probe, .remove = __devexit_p(wm831x_spi_remove), }; static struct spi_driver wm8325_spi_driver = { .driver = { .name = "wm8325", .bus = &spi_bus_type, .owner = THIS_MODULE, .pm = &wm831x_spi_pm, }, .probe = wm831x_spi_probe, .remove = __devexit_p(wm831x_spi_remove), }; static struct spi_driver wm8326_spi_driver = { .driver = { .name = "wm8326", .name = "wm831x", .bus = &spi_bus_type, .owner = THIS_MODULE, .pm = &wm831x_spi_pm, }, .id_table = wm831x_spi_ids, .probe = wm831x_spi_probe, .remove = __devexit_p(wm831x_spi_remove), }; Loading @@ -207,33 +101,9 @@ static int __init wm831x_spi_init(void) { int ret; ret = spi_register_driver(&wm8310_spi_driver); if (ret != 0) pr_err("Failed to register WM8310 SPI driver: %d\n", ret); ret = spi_register_driver(&wm8311_spi_driver); if (ret != 0) pr_err("Failed to register WM8311 SPI driver: %d\n", ret); ret = spi_register_driver(&wm8312_spi_driver); if (ret != 0) pr_err("Failed to register WM8312 SPI driver: %d\n", ret); ret = spi_register_driver(&wm8320_spi_driver); if (ret != 0) pr_err("Failed to register WM8320 SPI driver: %d\n", ret); ret = spi_register_driver(&wm8321_spi_driver); if (ret != 0) pr_err("Failed to register WM8321 SPI driver: %d\n", ret); ret = spi_register_driver(&wm8325_spi_driver); if (ret != 0) pr_err("Failed to register WM8325 SPI driver: %d\n", ret); ret = spi_register_driver(&wm8326_spi_driver); ret = spi_register_driver(&wm831x_spi_driver); if (ret != 0) pr_err("Failed to register WM8326 SPI driver: %d\n", ret); pr_err("Failed to register WM831x SPI driver: %d\n", ret); return 0; } Loading @@ -241,13 +111,7 @@ subsys_initcall(wm831x_spi_init); static void __exit wm831x_spi_exit(void) { spi_unregister_driver(&wm8326_spi_driver); spi_unregister_driver(&wm8325_spi_driver); spi_unregister_driver(&wm8321_spi_driver); spi_unregister_driver(&wm8320_spi_driver); spi_unregister_driver(&wm8312_spi_driver); spi_unregister_driver(&wm8311_spi_driver); spi_unregister_driver(&wm8310_spi_driver); spi_unregister_driver(&wm831x_spi_driver); } module_exit(wm831x_spi_exit); Loading
drivers/mfd/wm8400-core.c +29 −77 File changed.Preview size limit exceeded, changes collapsed. Show changes