From 3466bd2273b81a0a29d0e134ba1c78b64b84f40b Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 19 Dec 2013 16:28:28 +0100 Subject: mfd: ti_am335x_tscadc: Make am335x_tsc_se_update() local Since the "recent" changes, am335x_tsc_se_update() has no longer any users outside of this file so make it local. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Lee Jones --- include/linux/mfd/ti_am335x_tscadc.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include/linux/mfd') diff --git a/include/linux/mfd/ti_am335x_tscadc.h b/include/linux/mfd/ti_am335x_tscadc.h index d498d98f0c2c..1fe72199e670 100644 --- a/include/linux/mfd/ti_am335x_tscadc.h +++ b/include/linux/mfd/ti_am335x_tscadc.h @@ -176,7 +176,6 @@ static inline struct ti_tscadc_dev *ti_tscadc_dev_get(struct platform_device *p) return *tscadc_dev; } -void am335x_tsc_se_update(struct ti_tscadc_dev *tsadc); void am335x_tsc_se_set(struct ti_tscadc_dev *tsadc, u32 val); void am335x_tsc_se_clr(struct ti_tscadc_dev *tsadc, u32 val); -- cgit v1.2.3 From 7e170c6e4f7501bea900aa66b2b27a6ce5001e25 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 19 Dec 2013 16:28:29 +0100 Subject: mfd: ti_am335x_tscadc: Don't read back REG_SE The purpose of reg_se_cache has been defeated. It should avoid the read-back of the register to avoid the latency and the fact that the bits are reset to 0 after the individual conversation took place. The reason why this is required like this to work, is that read-back of the register removes the bits of the ADC so they do not start another conversation after the register is re-written from the TSC side for the update. To avoid the not required read-back I introduce a "set once" variant which does not update the cache mask. After the conversation completes, the bit is removed from the SE register anyway and we don't plan a new conversation "any time soon". The current set function is renamed to set_cache to distinguish the two operations. This is a small preparation for a larger sync-rework. Signed-off-by: Sebastian Andrzej Siewior Acked-by: Dmitry Torokhov Acked-by: Jonathan Cameron Signed-off-by: Lee Jones --- drivers/iio/adc/ti_am335x_adc.c | 4 ++-- drivers/input/touchscreen/ti_am335x_tsc.c | 4 ++-- drivers/mfd/ti_am335x_tscadc.c | 16 ++++++++++++---- include/linux/mfd/ti_am335x_tscadc.h | 3 ++- 4 files changed, 18 insertions(+), 9 deletions(-) (limited to 'include/linux/mfd') diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c index ce8d03ac900f..95eef8e89979 100644 --- a/drivers/iio/adc/ti_am335x_adc.c +++ b/drivers/iio/adc/ti_am335x_adc.c @@ -181,7 +181,7 @@ static int tiadc_buffer_postenable(struct iio_dev *indio_dev) enb |= (get_adc_step_bit(adc_dev, bit) << 1); adc_dev->buffer_en_ch_steps = enb; - am335x_tsc_se_set(adc_dev->mfd_tscadc, enb); + am335x_tsc_se_set_cache(adc_dev->mfd_tscadc, enb); tiadc_writel(adc_dev, REG_IRQSTATUS, IRQENB_FIFO1THRES | IRQENB_FIFO1OVRRUN | IRQENB_FIFO1UNDRFLW); @@ -332,7 +332,7 @@ static int tiadc_read_raw(struct iio_dev *indio_dev, return -EBUSY; step_en = get_adc_step_mask(adc_dev); - am335x_tsc_se_set(adc_dev->mfd_tscadc, step_en); + am335x_tsc_se_set_once(adc_dev->mfd_tscadc, step_en); /* Wait for ADC sequencer to complete sampling */ while (tiadc_readl(adc_dev, REG_ADCFSM) & SEQ_STATUS) { diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c index 68beadaabceb..2ca5a7bee04e 100644 --- a/drivers/input/touchscreen/ti_am335x_tsc.c +++ b/drivers/input/touchscreen/ti_am335x_tsc.c @@ -198,7 +198,7 @@ static void titsc_step_config(struct titsc *ts_dev) /* The steps1 … end and bit 0 for TS_Charge */ stepenable = (1 << (end_step + 2)) - 1; ts_dev->step_mask = stepenable; - am335x_tsc_se_set(ts_dev->mfd_tscadc, ts_dev->step_mask); + am335x_tsc_se_set_cache(ts_dev->mfd_tscadc, ts_dev->step_mask); } static void titsc_read_coordinates(struct titsc *ts_dev, @@ -322,7 +322,7 @@ static irqreturn_t titsc_irq(int irq, void *dev) if (irqclr) { titsc_writel(ts_dev, REG_IRQSTATUS, irqclr); - am335x_tsc_se_set(ts_dev->mfd_tscadc, ts_dev->step_mask); + am335x_tsc_se_set_cache(ts_dev->mfd_tscadc, ts_dev->step_mask); return IRQ_HANDLED; } return IRQ_NONE; diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c index 67d0eb469a45..cb0c211fc7d8 100644 --- a/drivers/mfd/ti_am335x_tscadc.c +++ b/drivers/mfd/ti_am335x_tscadc.c @@ -53,24 +53,32 @@ static void am335x_tsc_se_update(struct ti_tscadc_dev *tsadc) tscadc_writel(tsadc, REG_SE, tsadc->reg_se_cache); } -void am335x_tsc_se_set(struct ti_tscadc_dev *tsadc, u32 val) +void am335x_tsc_se_set_cache(struct ti_tscadc_dev *tsadc, u32 val) { unsigned long flags; spin_lock_irqsave(&tsadc->reg_lock, flags); - tsadc->reg_se_cache = tscadc_readl(tsadc, REG_SE); tsadc->reg_se_cache |= val; am335x_tsc_se_update(tsadc); spin_unlock_irqrestore(&tsadc->reg_lock, flags); } -EXPORT_SYMBOL_GPL(am335x_tsc_se_set); +EXPORT_SYMBOL_GPL(am335x_tsc_se_set_cache); + +void am335x_tsc_se_set_once(struct ti_tscadc_dev *tsadc, u32 val) +{ + unsigned long flags; + + spin_lock_irqsave(&tsadc->reg_lock, flags); + tscadc_writel(tsadc, REG_SE, tsadc->reg_se_cache | val); + spin_unlock_irqrestore(&tsadc->reg_lock, flags); +} +EXPORT_SYMBOL_GPL(am335x_tsc_se_set_once); void am335x_tsc_se_clr(struct ti_tscadc_dev *tsadc, u32 val) { unsigned long flags; spin_lock_irqsave(&tsadc->reg_lock, flags); - tsadc->reg_se_cache = tscadc_readl(tsadc, REG_SE); tsadc->reg_se_cache &= ~val; am335x_tsc_se_update(tsadc); spin_unlock_irqrestore(&tsadc->reg_lock, flags); diff --git a/include/linux/mfd/ti_am335x_tscadc.h b/include/linux/mfd/ti_am335x_tscadc.h index 1fe72199e670..2fa9c0613da4 100644 --- a/include/linux/mfd/ti_am335x_tscadc.h +++ b/include/linux/mfd/ti_am335x_tscadc.h @@ -176,7 +176,8 @@ static inline struct ti_tscadc_dev *ti_tscadc_dev_get(struct platform_device *p) return *tscadc_dev; } -void am335x_tsc_se_set(struct ti_tscadc_dev *tsadc, u32 val); +void am335x_tsc_se_set_cache(struct ti_tscadc_dev *tsadc, u32 val); +void am335x_tsc_se_set_once(struct ti_tscadc_dev *tsadc, u32 val); void am335x_tsc_se_clr(struct ti_tscadc_dev *tsadc, u32 val); #endif -- cgit v1.2.3 From 7ca6740cd1cd410828a01151a044b51910d06eff Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 19 Dec 2013 16:28:31 +0100 Subject: mfd: input: iio: ti_amm335x: Rework TSC/ADC synchronization The ADC driver always programs all possible ADC values and discards them except for the value IIO asked for. On the am335x-evm the driver programs four values and it takes 500us to gather them. Reducing the number of conversations down to the (required) one also reduces the busy loop down to 125us. This leads to another error, namely the FIFOCOUNT register is sometimes (like one out of 10 attempts) not updated in time leading to EBUSY. The next read has the FIFOCOUNT register updated. Checking for the ADCSTAT register for being idle isn't a good choice either. The problem is that if TSC is used at the same time, the HW completes the conversation for ADC *and* before the driver noticed it, the HW begins to perform a TSC conversation and so the driver never seen the HW idle. The next time we would have two values in the FIFO but since the driver reads everything we always see the current one. So instead of polling for the IDLE bit in ADCStatus register, we should check the FIFOCOUNT register. It should be one instead of zero because we request one value. This change in turn leads to another error. Sometimes if TSC & ADC are used together the TSC starts generating interrupts even if nobody actually touched the touchscreen. The interrupts seem valid because TSC's FIFO is filled with values for each channel of the TSC. This condition stops after a few ADC reads but will occur again. Not good. On top of this (even without the changes I just mentioned) there is a ADC & TSC lockup condition which was reported to me by Jeff Lance including the following test case: A busy loop of "cat /sys/bus/iio/devices/iio\:device0/in_voltage4_raw" and a mug on touch screen. With this setup, the hardware will lockup after something between 20 minutes and it could take up to a couple of hours. During that lockup, the ADCSTAT register says 0x30 (or 0x70) which means STEP_ID = IDLE and FSM_BUSY = yes. That means the hardware says that it is idle and busy at the same time which is an invalid condition. For all this reasons I decided to rework this TSC/ADC part and add a handshake / synchronization here: First the ADC signals that it needs the HW and writes a 0 mask into the SE register. The HW (if active) will complete the current conversation and become idle. The TSC driver will gather the values from the FIFO (woken up by an interrupt) and won't "enable" another conversation. Instead it will wake up the ADC driver which is already waiting. The ADC driver will start "its" conversation and once it is done, it will enable the TSC steps so the TSC will work again. After this rework I haven't observed the lockup so far. Plus the busy loop has been reduced from 500us to 125us. The continues-read mode remains unchanged. Signed-off-by: Sebastian Andrzej Siewior Acked-by: Jonathan Cameron Signed-off-by: Lee Jones --- drivers/iio/adc/ti_am335x_adc.c | 64 ++++++++++++++++++++++++++---------- drivers/mfd/ti_am335x_tscadc.c | 63 +++++++++++++++++++++++++++++------ include/linux/mfd/ti_am335x_tscadc.h | 4 +++ 3 files changed, 103 insertions(+), 28 deletions(-) (limited to 'include/linux/mfd') diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c index e0dc2d0e7590..dff7343405e2 100644 --- a/drivers/iio/adc/ti_am335x_adc.c +++ b/drivers/iio/adc/ti_am335x_adc.c @@ -60,6 +60,24 @@ static u32 get_adc_step_mask(struct tiadc_device *adc_dev) return step_en; } +static u32 get_adc_chan_step_mask(struct tiadc_device *adc_dev, + struct iio_chan_spec const *chan) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(adc_dev->channel_step); i++) { + if (chan->channel == adc_dev->channel_line[i]) { + u32 step; + + step = adc_dev->channel_step[i]; + /* +1 for the charger */ + return 1 << (step + 1); + } + } + WARN_ON(1); + return 0; +} + static u32 get_adc_step_bit(struct tiadc_device *adc_dev, int chan) { return 1 << adc_dev->channel_step[chan]; @@ -326,34 +344,43 @@ static int tiadc_read_raw(struct iio_dev *indio_dev, unsigned int fifo1count, read, stepid; bool found = false; u32 step_en; - unsigned long timeout = jiffies + usecs_to_jiffies - (IDLE_TIMEOUT * adc_dev->channels); + unsigned long timeout; if (iio_buffer_enabled(indio_dev)) return -EBUSY; - step_en = get_adc_step_mask(adc_dev); + step_en = get_adc_chan_step_mask(adc_dev, chan); + if (!step_en) + return -EINVAL; + + fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT); + while (fifo1count--) + tiadc_readl(adc_dev, REG_FIFO1); + am335x_tsc_se_set_once(adc_dev->mfd_tscadc, step_en); - /* Wait for ADC sequencer to complete sampling */ - while (tiadc_readl(adc_dev, REG_ADCFSM) & SEQ_STATUS) { - if (time_after(jiffies, timeout)) + timeout = jiffies + usecs_to_jiffies + (IDLE_TIMEOUT * adc_dev->channels); + /* Wait for Fifo threshold interrupt */ + while (1) { + fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT); + if (fifo1count) + break; + + if (time_after(jiffies, timeout)) { + am335x_tsc_se_adc_done(adc_dev->mfd_tscadc); return -EAGAIN; + } } map_val = chan->channel + TOTAL_CHANNELS; /* - * When the sub-system is first enabled, - * the sequencer will always start with the - * lowest step (1) and continue until step (16). - * For ex: If we have enabled 4 ADC channels and - * currently use only 1 out of them, the - * sequencer still configures all the 4 steps, - * leading to 3 unwanted data. - * Hence we need to flush out this data. + * We check the complete FIFO. We programmed just one entry but in case + * something went wrong we left empty handed (-EAGAIN previously) and + * then the value apeared somehow in the FIFO we would have two entries. + * Therefore we read every item and keep only the latest version of the + * requested channel. */ - - fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT); for (i = 0; i < fifo1count; i++) { read = tiadc_readl(adc_dev, REG_FIFO1); stepid = read & FIFOREAD_CHNLID_MASK; @@ -365,6 +392,7 @@ static int tiadc_read_raw(struct iio_dev *indio_dev, *val = (u16) read; } } + am335x_tsc_se_adc_done(adc_dev->mfd_tscadc); if (found == false) return -EBUSY; @@ -492,8 +520,8 @@ static int tiadc_resume(struct device *dev) tiadc_writel(adc_dev, REG_CTRL, restore); tiadc_step_config(indio_dev); - am335x_tsc_se_set(adc_dev->mfd_tscadc, adc_dev->buffer_en_ch_steps); - + am335x_tsc_se_set_cache(adc_dev->mfd_tscadc, + adc_dev->buffer_en_ch_steps); return 0; } diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c index 157f5699a33c..d4e860413bb5 100644 --- a/drivers/mfd/ti_am335x_tscadc.c +++ b/drivers/mfd/ti_am335x_tscadc.c @@ -24,6 +24,7 @@ #include #include #include +#include #include @@ -48,31 +49,71 @@ static const struct regmap_config tscadc_regmap_config = { .val_bits = 32, }; -static void am335x_tsc_se_update(struct ti_tscadc_dev *tsadc) -{ - tscadc_writel(tsadc, REG_SE, tsadc->reg_se_cache); -} - void am335x_tsc_se_set_cache(struct ti_tscadc_dev *tsadc, u32 val) { unsigned long flags; spin_lock_irqsave(&tsadc->reg_lock, flags); - tsadc->reg_se_cache |= val; - am335x_tsc_se_update(tsadc); + tsadc->reg_se_cache = val; + if (tsadc->adc_waiting) + wake_up(&tsadc->reg_se_wait); + else if (!tsadc->adc_in_use) + tscadc_writel(tsadc, REG_SE, val); + spin_unlock_irqrestore(&tsadc->reg_lock, flags); } EXPORT_SYMBOL_GPL(am335x_tsc_se_set_cache); +static void am335x_tscadc_need_adc(struct ti_tscadc_dev *tsadc) +{ + DEFINE_WAIT(wait); + u32 reg; + + /* + * disable TSC steps so it does not run while the ADC is using it. If + * write 0 while it is running (it just started or was already running) + * then it completes all steps that were enabled and stops then. + */ + tscadc_writel(tsadc, REG_SE, 0); + reg = tscadc_readl(tsadc, REG_ADCFSM); + if (reg & SEQ_STATUS) { + tsadc->adc_waiting = true; + prepare_to_wait(&tsadc->reg_se_wait, &wait, + TASK_UNINTERRUPTIBLE); + spin_unlock_irq(&tsadc->reg_lock); + + schedule(); + + spin_lock_irq(&tsadc->reg_lock); + finish_wait(&tsadc->reg_se_wait, &wait); + + reg = tscadc_readl(tsadc, REG_ADCFSM); + WARN_ON(reg & SEQ_STATUS); + tsadc->adc_waiting = false; + } + tsadc->adc_in_use = true; +} + void am335x_tsc_se_set_once(struct ti_tscadc_dev *tsadc, u32 val) +{ + spin_lock_irq(&tsadc->reg_lock); + am335x_tscadc_need_adc(tsadc); + + tscadc_writel(tsadc, REG_SE, val); + spin_unlock_irq(&tsadc->reg_lock); +} +EXPORT_SYMBOL_GPL(am335x_tsc_se_set_once); + +void am335x_tsc_se_adc_done(struct ti_tscadc_dev *tsadc) { unsigned long flags; spin_lock_irqsave(&tsadc->reg_lock, flags); - tscadc_writel(tsadc, REG_SE, tsadc->reg_se_cache | val); + tsadc->adc_in_use = false; + tscadc_writel(tsadc, REG_SE, tsadc->reg_se_cache); spin_unlock_irqrestore(&tsadc->reg_lock, flags); } -EXPORT_SYMBOL_GPL(am335x_tsc_se_set_once); +EXPORT_SYMBOL_GPL(am335x_tsc_se_adc_done); void am335x_tsc_se_clr(struct ti_tscadc_dev *tsadc, u32 val) { @@ -80,7 +121,7 @@ void am335x_tsc_se_clr(struct ti_tscadc_dev *tsadc, u32 val) spin_lock_irqsave(&tsadc->reg_lock, flags); tsadc->reg_se_cache &= ~val; - am335x_tsc_se_update(tsadc); + tscadc_writel(tsadc, REG_SE, tsadc->reg_se_cache); spin_unlock_irqrestore(&tsadc->reg_lock, flags); } EXPORT_SYMBOL_GPL(am335x_tsc_se_clr); @@ -188,6 +229,8 @@ static int ti_tscadc_probe(struct platform_device *pdev) } spin_lock_init(&tscadc->reg_lock); + init_waitqueue_head(&tscadc->reg_se_wait); + pm_runtime_enable(&pdev->dev); pm_runtime_get_sync(&pdev->dev); diff --git a/include/linux/mfd/ti_am335x_tscadc.h b/include/linux/mfd/ti_am335x_tscadc.h index 2fa9c0613da4..fb96c84dada5 100644 --- a/include/linux/mfd/ti_am335x_tscadc.h +++ b/include/linux/mfd/ti_am335x_tscadc.h @@ -159,6 +159,9 @@ struct ti_tscadc_dev { int adc_cell; /* -1 if not used */ struct mfd_cell cells[TSCADC_CELLS]; u32 reg_se_cache; + bool adc_waiting; + bool adc_in_use; + wait_queue_head_t reg_se_wait; spinlock_t reg_lock; unsigned int clk_div; @@ -179,5 +182,6 @@ static inline struct ti_tscadc_dev *ti_tscadc_dev_get(struct platform_device *p) void am335x_tsc_se_set_cache(struct ti_tscadc_dev *tsadc, u32 val); void am335x_tsc_se_set_once(struct ti_tscadc_dev *tsadc, u32 val); void am335x_tsc_se_clr(struct ti_tscadc_dev *tsadc, u32 val); +void am335x_tsc_se_adc_done(struct ti_tscadc_dev *tsadc); #endif -- cgit v1.2.3 From 3008ddbe061b0f1d5c8ffbb599f105b67cf06637 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Fri, 22 Nov 2013 16:51:05 +0100 Subject: mfd: max14577: Add max14577 MFD driver core This patch adds max14577 core/irq driver to support MUIC(Micro USB IC) device and charger device and support irq domain method to control internal interrupt of max14577 device. Also, this patch supports DT binding with max14577_i2c_parse_dt(). The MAXIM 14577 chip contains Micro-USB Interface Circuit and Li+ Battery Charger. It contains accessory and USB charger detection logic. It supports USB 2.0 Hi-Speed, UART and stereo audio signals over Micro-USB connector. The battery charger is compliant with the USB Battery Charging Specification Revision 1.1. It has also SFOUT LDO output for powering USB devices. Reviewed-by: Mark Brown Signed-off-by: Chanwoo Choi Signed-off-by: Krzysztof Kozlowski Signed-off-by: Kyungmin Park Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 13 ++ drivers/mfd/Makefile | 1 + drivers/mfd/max14577.c | 243 ++++++++++++++++++++++++++ include/linux/mfd/max14577-private.h | 330 +++++++++++++++++++++++++++++++++++ include/linux/mfd/max14577.h | 69 ++++++++ 5 files changed, 656 insertions(+) create mode 100644 drivers/mfd/max14577.c create mode 100644 include/linux/mfd/max14577-private.h create mode 100644 include/linux/mfd/max14577.h (limited to 'include/linux/mfd') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index dd671582c9a1..e54a6fd2a5bd 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -321,6 +321,19 @@ config MFD_88PM860X select individual components like voltage regulators, RTC and battery-charger under the corresponding menus. +config MFD_MAX14577 + bool "Maxim Semiconductor MAX14577 MUIC + Charger Support" + depends on I2C=y + select MFD_CORE + select REGMAP_I2C + select IRQ_DOMAIN + help + Say yes here to support for Maxim Semiconductor MAX14577. + This is a Micro-USB IC with Charger controls on chip. + This driver provides common support for accessing the device; + additional drivers must be enabled in order to use the functionality + of the device. + config MFD_MAX77686 bool "Maxim Semiconductor MAX77686 PMIC Support" depends on I2C=y diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 8a28dc90fe78..2e18b05017d9 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -110,6 +110,7 @@ obj-$(CONFIG_MFD_DA9055) += da9055.o da9063-objs := da9063-core.o da9063-irq.o da9063-i2c.o obj-$(CONFIG_MFD_DA9063) += da9063.o +obj-$(CONFIG_MFD_MAX14577) += max14577.o obj-$(CONFIG_MFD_MAX77686) += max77686.o max77686-irq.o obj-$(CONFIG_MFD_MAX77693) += max77693.o max77693-irq.o obj-$(CONFIG_MFD_MAX8907) += max8907.o diff --git a/drivers/mfd/max14577.c b/drivers/mfd/max14577.c new file mode 100644 index 000000000000..94b766d8cb15 --- /dev/null +++ b/drivers/mfd/max14577.c @@ -0,0 +1,243 @@ +/* + * max14577.c - mfd core driver for the Maxim 14577 + * + * Copyright (C) 2013 Samsung Electrnoics + * Chanwoo Choi + * Krzysztof Kozlowski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This driver is based on max8997.c + */ + +#include +#include +#include +#include +#include + +static struct mfd_cell max14577_devs[] = { + { .name = "max14577-muic", }, + { .name = "max14577-regulator", }, + { .name = "max14577-charger", }, +}; + +static bool max14577_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX14577_REG_INT1 ... MAX14577_REG_STATUS3: + return true; + default: + break; + } + return false; +} + +static const struct regmap_config max14577_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .volatile_reg = max14577_volatile_reg, + .max_register = MAX14577_REG_END, +}; + +static const struct regmap_irq max14577_irqs[] = { + /* INT1 interrupts */ + { .reg_offset = 0, .mask = INT1_ADC_MASK, }, + { .reg_offset = 0, .mask = INT1_ADCLOW_MASK, }, + { .reg_offset = 0, .mask = INT1_ADCERR_MASK, }, + /* INT2 interrupts */ + { .reg_offset = 1, .mask = INT2_CHGTYP_MASK, }, + { .reg_offset = 1, .mask = INT2_CHGDETRUN_MASK, }, + { .reg_offset = 1, .mask = INT2_DCDTMR_MASK, }, + { .reg_offset = 1, .mask = INT2_DBCHG_MASK, }, + { .reg_offset = 1, .mask = INT2_VBVOLT_MASK, }, + /* INT3 interrupts */ + { .reg_offset = 2, .mask = INT3_EOC_MASK, }, + { .reg_offset = 2, .mask = INT3_CGMBC_MASK, }, + { .reg_offset = 2, .mask = INT3_OVP_MASK, }, + { .reg_offset = 2, .mask = INT3_MBCCHGERR_MASK, }, +}; + +static const struct regmap_irq_chip max14577_irq_chip = { + .name = "max14577", + .status_base = MAX14577_REG_INT1, + .mask_base = MAX14577_REG_INTMASK1, + .mask_invert = 1, + .num_regs = 3, + .irqs = max14577_irqs, + .num_irqs = ARRAY_SIZE(max14577_irqs), +}; + +static int max14577_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct max14577 *max14577; + struct max14577_platform_data *pdata = dev_get_platdata(&i2c->dev); + struct device_node *np = i2c->dev.of_node; + u8 reg_data; + int ret = 0; + + if (np) { + pdata = devm_kzalloc(&i2c->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + i2c->dev.platform_data = pdata; + } + + if (!pdata) { + dev_err(&i2c->dev, "No platform data found: %ld\n", + PTR_ERR(pdata)); + return -EINVAL; + } + + max14577 = devm_kzalloc(&i2c->dev, sizeof(*max14577), GFP_KERNEL); + if (!max14577) + return -ENOMEM; + + i2c_set_clientdata(i2c, max14577); + max14577->dev = &i2c->dev; + max14577->i2c = i2c; + max14577->irq = i2c->irq; + + max14577->regmap = devm_regmap_init_i2c(i2c, &max14577_regmap_config); + if (IS_ERR(max14577->regmap)) { + ret = PTR_ERR(max14577->regmap); + dev_err(max14577->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + ret = max14577_read_reg(max14577->regmap, MAX14577_REG_DEVICEID, + ®_data); + if (ret) { + dev_err(max14577->dev, "Device not found on this channel: %d\n", + ret); + return ret; + } + max14577->vendor_id = ((reg_data & DEVID_VENDORID_MASK) >> + DEVID_VENDORID_SHIFT); + max14577->device_id = ((reg_data & DEVID_DEVICEID_MASK) >> + DEVID_DEVICEID_SHIFT); + dev_info(max14577->dev, "Device ID: 0x%x, vendor: 0x%x\n", + max14577->device_id, max14577->vendor_id); + + ret = regmap_add_irq_chip(max14577->regmap, max14577->irq, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 0, + &max14577_irq_chip, + &max14577->irq_data); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n", + max14577->irq, ret); + return ret; + } + + ret = mfd_add_devices(max14577->dev, -1, max14577_devs, + ARRAY_SIZE(max14577_devs), NULL, 0, + regmap_irq_get_domain(max14577->irq_data)); + if (ret < 0) + goto err_mfd; + + device_init_wakeup(max14577->dev, 1); + + return 0; + +err_mfd: + regmap_del_irq_chip(max14577->irq, max14577->irq_data); + + return ret; +} + +static int max14577_i2c_remove(struct i2c_client *i2c) +{ + struct max14577 *max14577 = i2c_get_clientdata(i2c); + + mfd_remove_devices(max14577->dev); + regmap_del_irq_chip(max14577->irq, max14577->irq_data); + + return 0; +} + +static const struct i2c_device_id max14577_i2c_id[] = { + { "max14577", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max14577_i2c_id); + +static int max14577_suspend(struct device *dev) +{ + struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); + struct max14577 *max14577 = i2c_get_clientdata(i2c); + + if (device_may_wakeup(dev)) { + enable_irq_wake(max14577->irq); + /* + * MUIC IRQ must be disabled during suspend if this is + * a wake up source because it will be handled before + * resuming I2C. + * + * When device is woken up from suspend (e.g. by ADC change), + * an interrupt occurs before resuming I2C bus controller. + * Interrupt handler tries to read registers but this read + * will fail because I2C is still suspended. + */ + disable_irq(max14577->irq); + } + + return 0; +} + +static int max14577_resume(struct device *dev) +{ + struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); + struct max14577 *max14577 = i2c_get_clientdata(i2c); + + if (device_may_wakeup(dev)) { + disable_irq_wake(max14577->irq); + enable_irq(max14577->irq); + } + + return 0; +} + +static struct of_device_id max14577_dt_match[] = { + { .compatible = "maxim,max14577", }, + {}, +}; + +static SIMPLE_DEV_PM_OPS(max14577_pm, max14577_suspend, max14577_resume); + +static struct i2c_driver max14577_i2c_driver = { + .driver = { + .name = "max14577", + .owner = THIS_MODULE, + .pm = &max14577_pm, + .of_match_table = of_match_ptr(max14577_dt_match), + }, + .probe = max14577_i2c_probe, + .remove = max14577_i2c_remove, + .id_table = max14577_i2c_id, +}; + +static int __init max14577_i2c_init(void) +{ + return i2c_add_driver(&max14577_i2c_driver); +} +subsys_initcall(max14577_i2c_init); + +static void __exit max14577_i2c_exit(void) +{ + i2c_del_driver(&max14577_i2c_driver); +} +module_exit(max14577_i2c_exit); + +MODULE_AUTHOR("Chanwoo Choi , Krzysztof Kozlowski "); +MODULE_DESCRIPTION("MAXIM 14577 multi-function core driver"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/mfd/max14577-private.h b/include/linux/mfd/max14577-private.h new file mode 100644 index 000000000000..a3d0185196d3 --- /dev/null +++ b/include/linux/mfd/max14577-private.h @@ -0,0 +1,330 @@ +/* + * max14577-private.h - Common API for the Maxim 14577 internal sub chip + * + * Copyright (C) 2013 Samsung Electrnoics + * Chanwoo Choi + * Krzysztof Kozlowski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MAX14577_PRIVATE_H__ +#define __MAX14577_PRIVATE_H__ + +#include +#include + +#define MAX14577_REG_INVALID (0xff) + +/* Slave addr = 0x4A: Interrupt */ +enum max14577_reg { + MAX14577_REG_DEVICEID = 0x00, + MAX14577_REG_INT1 = 0x01, + MAX14577_REG_INT2 = 0x02, + MAX14577_REG_INT3 = 0x03, + MAX14577_REG_STATUS1 = 0x04, + MAX14577_REG_STATUS2 = 0x05, + MAX14577_REG_STATUS3 = 0x06, + MAX14577_REG_INTMASK1 = 0x07, + MAX14577_REG_INTMASK2 = 0x08, + MAX14577_REG_INTMASK3 = 0x09, + MAX14577_REG_CDETCTRL1 = 0x0A, + MAX14577_REG_RFU = 0x0B, + MAX14577_REG_CONTROL1 = 0x0C, + MAX14577_REG_CONTROL2 = 0x0D, + MAX14577_REG_CONTROL3 = 0x0E, + MAX14577_REG_CHGCTRL1 = 0x0F, + MAX14577_REG_CHGCTRL2 = 0x10, + MAX14577_REG_CHGCTRL3 = 0x11, + MAX14577_REG_CHGCTRL4 = 0x12, + MAX14577_REG_CHGCTRL5 = 0x13, + MAX14577_REG_CHGCTRL6 = 0x14, + MAX14577_REG_CHGCTRL7 = 0x15, + + MAX14577_REG_END, +}; + +/* Slave addr = 0x4A: MUIC */ +enum max14577_muic_reg { + MAX14577_MUIC_REG_STATUS1 = 0x04, + MAX14577_MUIC_REG_STATUS2 = 0x05, + MAX14577_MUIC_REG_CONTROL1 = 0x0C, + MAX14577_MUIC_REG_CONTROL3 = 0x0E, + + MAX14577_MUIC_REG_END, +}; + +enum max14577_muic_charger_type { + MAX14577_CHARGER_TYPE_NONE = 0, + MAX14577_CHARGER_TYPE_USB, + MAX14577_CHARGER_TYPE_DOWNSTREAM_PORT, + MAX14577_CHARGER_TYPE_DEDICATED_CHG, + MAX14577_CHARGER_TYPE_SPECIAL_500MA, + MAX14577_CHARGER_TYPE_SPECIAL_1A, + MAX14577_CHARGER_TYPE_RESERVED, + MAX14577_CHARGER_TYPE_DEAD_BATTERY = 7, +}; + +/* MAX14577 interrupts */ +#define INT1_ADC_MASK (0x1 << 0) +#define INT1_ADCLOW_MASK (0x1 << 1) +#define INT1_ADCERR_MASK (0x1 << 2) + +#define INT2_CHGTYP_MASK (0x1 << 0) +#define INT2_CHGDETRUN_MASK (0x1 << 1) +#define INT2_DCDTMR_MASK (0x1 << 2) +#define INT2_DBCHG_MASK (0x1 << 3) +#define INT2_VBVOLT_MASK (0x1 << 4) + +#define INT3_EOC_MASK (0x1 << 0) +#define INT3_CGMBC_MASK (0x1 << 1) +#define INT3_OVP_MASK (0x1 << 2) +#define INT3_MBCCHGERR_MASK (0x1 << 3) + +/* MAX14577 DEVICE ID register */ +#define DEVID_VENDORID_SHIFT 0 +#define DEVID_DEVICEID_SHIFT 3 +#define DEVID_VENDORID_MASK (0x07 << DEVID_VENDORID_SHIFT) +#define DEVID_DEVICEID_MASK (0x1f << DEVID_DEVICEID_SHIFT) + +/* MAX14577 STATUS1 register */ +#define STATUS1_ADC_SHIFT 0 +#define STATUS1_ADCLOW_SHIFT 5 +#define STATUS1_ADCERR_SHIFT 6 +#define STATUS1_ADC_MASK (0x1f << STATUS1_ADC_SHIFT) +#define STATUS1_ADCLOW_MASK (0x1 << STATUS1_ADCLOW_SHIFT) +#define STATUS1_ADCERR_MASK (0x1 << STATUS1_ADCERR_SHIFT) + +/* MAX14577 STATUS2 register */ +#define STATUS2_CHGTYP_SHIFT 0 +#define STATUS2_CHGDETRUN_SHIFT 3 +#define STATUS2_DCDTMR_SHIFT 4 +#define STATUS2_DBCHG_SHIFT 5 +#define STATUS2_VBVOLT_SHIFT 6 +#define STATUS2_CHGTYP_MASK (0x7 << STATUS2_CHGTYP_SHIFT) +#define STATUS2_CHGDETRUN_MASK (0x1 << STATUS2_CHGDETRUN_SHIFT) +#define STATUS2_DCDTMR_MASK (0x1 << STATUS2_DCDTMR_SHIFT) +#define STATUS2_DBCHG_MASK (0x1 << STATUS2_DBCHG_SHIFT) +#define STATUS2_VBVOLT_MASK (0x1 << STATUS2_VBVOLT_SHIFT) + +/* MAX14577 CONTROL1 register */ +#define COMN1SW_SHIFT 0 +#define COMP2SW_SHIFT 3 +#define MICEN_SHIFT 6 +#define IDBEN_SHIFT 7 +#define COMN1SW_MASK (0x7 << COMN1SW_SHIFT) +#define COMP2SW_MASK (0x7 << COMP2SW_SHIFT) +#define MICEN_MASK (0x1 << MICEN_SHIFT) +#define IDBEN_MASK (0x1 << IDBEN_SHIFT) +#define CLEAR_IDBEN_MICEN_MASK (COMN1SW_MASK | COMP2SW_MASK) +#define CTRL1_SW_USB ((1 << COMP2SW_SHIFT) \ + | (1 << COMN1SW_SHIFT)) +#define CTRL1_SW_AUDIO ((2 << COMP2SW_SHIFT) \ + | (2 << COMN1SW_SHIFT)) +#define CTRL1_SW_UART ((3 << COMP2SW_SHIFT) \ + | (3 << COMN1SW_SHIFT)) +#define CTRL1_SW_OPEN ((0 << COMP2SW_SHIFT) \ + | (0 << COMN1SW_SHIFT)) + +/* MAX14577 CONTROL2 register */ +#define CTRL2_LOWPWR_SHIFT (0) +#define CTRL2_ADCEN_SHIFT (1) +#define CTRL2_CPEN_SHIFT (2) +#define CTRL2_SFOUTASRT_SHIFT (3) +#define CTRL2_SFOUTORD_SHIFT (4) +#define CTRL2_ACCDET_SHIFT (5) +#define CTRL2_USBCPINT_SHIFT (6) +#define CTRL2_RCPS_SHIFT (7) +#define CTRL2_LOWPWR_MASK (0x1 << CTRL2_LOWPWR_SHIFT) +#define CTRL2_ADCEN_MASK (0x1 << CTRL2_ADCEN_SHIFT) +#define CTRL2_CPEN_MASK (0x1 << CTRL2_CPEN_SHIFT) +#define CTRL2_SFOUTASRT_MASK (0x1 << CTRL2_SFOUTASRT_SHIFT) +#define CTRL2_SFOUTORD_MASK (0x1 << CTRL2_SFOUTORD_SHIFT) +#define CTRL2_ACCDET_MASK (0x1 << CTRL2_ACCDET_SHIFT) +#define CTRL2_USBCPINT_MASK (0x1 << CTRL2_USBCPINT_SHIFT) +#define CTRL2_RCPS_MASK (0x1 << CTR2_RCPS_SHIFT) + +#define CTRL2_CPEN1_LOWPWR0 ((1 << CTRL2_CPEN_SHIFT) | \ + (0 << CTRL2_LOWPWR_SHIFT)) +#define CTRL2_CPEN0_LOWPWR1 ((0 << CTRL2_CPEN_SHIFT) | \ + (1 << CTRL2_LOWPWR_SHIFT)) + +/* MAX14577 CONTROL3 register */ +#define CTRL3_JIGSET_SHIFT 0 +#define CTRL3_BOOTSET_SHIFT 2 +#define CTRL3_ADCDBSET_SHIFT 4 +#define CTRL3_JIGSET_MASK (0x3 << CTRL3_JIGSET_SHIFT) +#define CTRL3_BOOTSET_MASK (0x3 << CTRL3_BOOTSET_SHIFT) +#define CTRL3_ADCDBSET_MASK (0x3 << CTRL3_ADCDBSET_SHIFT) + +/* Slave addr = 0x4A: Charger */ +enum max14577_charger_reg { + MAX14577_CHG_REG_STATUS3 = 0x06, + MAX14577_CHG_REG_CHG_CTRL1 = 0x0F, + MAX14577_CHG_REG_CHG_CTRL2 = 0x10, + MAX14577_CHG_REG_CHG_CTRL3 = 0x11, + MAX14577_CHG_REG_CHG_CTRL4 = 0x12, + MAX14577_CHG_REG_CHG_CTRL5 = 0x13, + MAX14577_CHG_REG_CHG_CTRL6 = 0x14, + MAX14577_CHG_REG_CHG_CTRL7 = 0x15, + + MAX14577_CHG_REG_END, +}; + +/* MAX14577 STATUS3 register */ +#define STATUS3_EOC_SHIFT 0 +#define STATUS3_CGMBC_SHIFT 1 +#define STATUS3_OVP_SHIFT 2 +#define STATUS3_MBCCHGERR_SHIFT 3 +#define STATUS3_EOC_MASK (0x1 << STATUS3_EOC_SHIFT) +#define STATUS3_CGMBC_MASK (0x1 << STATUS3_CGMBC_SHIFT) +#define STATUS3_OVP_MASK (0x1 << STATUS3_OVP_SHIFT) +#define STATUS3_MBCCHGERR_MASK (0x1 << STATUS3_MBCCHGERR_SHIFT) + +/* MAX14577 CDETCTRL1 register */ +#define CDETCTRL1_CHGDETEN_SHIFT 0 +#define CDETCTRL1_CHGTYPMAN_SHIFT 1 +#define CDETCTRL1_DCDEN_SHIFT 2 +#define CDETCTRL1_DCD2SCT_SHIFT 3 +#define CDETCTRL1_DCHKTM_SHIFT 4 +#define CDETCTRL1_DBEXIT_SHIFT 5 +#define CDETCTRL1_DBIDLE_SHIFT 6 +#define CDETCTRL1_CDPDET_SHIFT 7 +#define CDETCTRL1_CHGDETEN_MASK (0x1 << CDETCTRL1_CHGDETEN_SHIFT) +#define CDETCTRL1_CHGTYPMAN_MASK (0x1 << CDETCTRL1_CHGTYPMAN_SHIFT) +#define CDETCTRL1_DCDEN_MASK (0x1 << CDETCTRL1_DCDEN_SHIFT) +#define CDETCTRL1_DCD2SCT_MASK (0x1 << CDETCTRL1_DCD2SCT_SHIFT) +#define CDETCTRL1_DCHKTM_MASK (0x1 << CDETCTRL1_DCHKTM_SHIFT) +#define CDETCTRL1_DBEXIT_MASK (0x1 << CDETCTRL1_DBEXIT_SHIFT) +#define CDETCTRL1_DBIDLE_MASK (0x1 << CDETCTRL1_DBIDLE_SHIFT) +#define CDETCTRL1_CDPDET_MASK (0x1 << CDETCTRL1_CDPDET_SHIFT) + +/* MAX14577 CHGCTRL1 register */ +#define CHGCTRL1_TCHW_SHIFT 4 +#define CHGCTRL1_TCHW_MASK (0x7 << CHGCTRL1_TCHW_SHIFT) + +/* MAX14577 CHGCTRL2 register */ +#define CHGCTRL2_MBCHOSTEN_SHIFT 6 +#define CHGCTRL2_MBCHOSTEN_MASK (0x1 << CHGCTRL2_MBCHOSTEN_SHIFT) +#define CHGCTRL2_VCHGR_RC_SHIFT 7 +#define CHGCTRL2_VCHGR_RC_MASK (0x1 << CHGCTRL2_VCHGR_RC_SHIFT) + +/* MAX14577 CHGCTRL3 register */ +#define CHGCTRL3_MBCCVWRC_SHIFT 0 +#define CHGCTRL3_MBCCVWRC_MASK (0xf << CHGCTRL3_MBCCVWRC_SHIFT) + +/* MAX14577 CHGCTRL4 register */ +#define CHGCTRL4_MBCICHWRCH_SHIFT 0 +#define CHGCTRL4_MBCICHWRCH_MASK (0xf << CHGCTRL4_MBCICHWRCH_SHIFT) +#define CHGCTRL4_MBCICHWRCL_SHIFT 4 +#define CHGCTRL4_MBCICHWRCL_MASK (0x1 << CHGCTRL4_MBCICHWRCL_SHIFT) + +/* MAX14577 CHGCTRL5 register */ +#define CHGCTRL5_EOCS_SHIFT 0 +#define CHGCTRL5_EOCS_MASK (0xf << CHGCTRL5_EOCS_SHIFT) + +/* MAX14577 CHGCTRL6 register */ +#define CHGCTRL6_AUTOSTOP_SHIFT 5 +#define CHGCTRL6_AUTOSTOP_MASK (0x1 << CHGCTRL6_AUTOSTOP_SHIFT) + +/* MAX14577 CHGCTRL7 register */ +#define CHGCTRL7_OTPCGHCVS_SHIFT 0 +#define CHGCTRL7_OTPCGHCVS_MASK (0x3 << CHGCTRL7_OTPCGHCVS_SHIFT) + +/* MAX14577 regulator current limits (as in CHGCTRL4 register), uA */ +#define MAX14577_REGULATOR_CURRENT_LIMIT_MIN 90000 +#define MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START 200000 +#define MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP 50000 +#define MAX14577_REGULATOR_CURRENT_LIMIT_MAX 950000 + +/* MAX14577 regulator SFOUT LDO voltage, fixed, uV */ +#define MAX14577_REGULATOR_SAFEOUT_VOLTAGE 4900000 + +enum max14577_irq_source { + MAX14577_IRQ_INT1 = 0, + MAX14577_IRQ_INT2, + MAX14577_IRQ_INT3, + + MAX14577_IRQ_REGS_NUM, +}; + +enum max14577_irq { + /* INT1 */ + MAX14577_IRQ_INT1_ADC, + MAX14577_IRQ_INT1_ADCLOW, + MAX14577_IRQ_INT1_ADCERR, + + /* INT2 */ + MAX14577_IRQ_INT2_CHGTYP, + MAX14577_IRQ_INT2_CHGDETRUN, + MAX14577_IRQ_INT2_DCDTMR, + MAX14577_IRQ_INT2_DBCHG, + MAX14577_IRQ_INT2_VBVOLT, + + /* INT3 */ + MAX14577_IRQ_INT3_EOC, + MAX14577_IRQ_INT3_CGMBC, + MAX14577_IRQ_INT3_OVP, + MAX14577_IRQ_INT3_MBCCHGERR, + + MAX14577_IRQ_NUM, +}; + +struct max14577 { + struct device *dev; + struct i2c_client *i2c; /* Slave addr = 0x4A */ + + struct regmap *regmap; + + struct regmap_irq_chip_data *irq_data; + int irq; + + /* Device ID */ + u8 vendor_id; /* Vendor Identification */ + u8 device_id; /* Chip Version */ +}; + +/* MAX14577 shared regmap API function */ +static inline int max14577_read_reg(struct regmap *map, u8 reg, u8 *dest) +{ + unsigned int val; + int ret; + + ret = regmap_read(map, reg, &val); + *dest = val; + + return ret; +} + +static inline int max14577_bulk_read(struct regmap *map, u8 reg, u8 *buf, + int count) +{ + return regmap_bulk_read(map, reg, buf, count); +} + +static inline int max14577_write_reg(struct regmap *map, u8 reg, u8 value) +{ + return regmap_write(map, reg, value); +} + +static inline int max14577_bulk_write(struct regmap *map, u8 reg, u8 *buf, + int count) +{ + return regmap_bulk_write(map, reg, buf, count); +} + +static inline int max14577_update_reg(struct regmap *map, u8 reg, u8 mask, + u8 val) +{ + return regmap_update_bits(map, reg, mask, val); +} + +#endif /* __MAX14577_PRIVATE_H__ */ diff --git a/include/linux/mfd/max14577.h b/include/linux/mfd/max14577.h new file mode 100644 index 000000000000..247b021dfaaf --- /dev/null +++ b/include/linux/mfd/max14577.h @@ -0,0 +1,69 @@ +/* + * max14577.h - Driver for the Maxim 14577 + * + * Copyright (C) 2013 Samsung Electrnoics + * Chanwoo Choi + * Krzysztof Kozlowski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This driver is based on max8997.h + * + * MAX14577 has MUIC, Charger devices. + * The devices share the same I2C bus and interrupt line + * included in this mfd driver. + */ + +#ifndef __MAX14577_H__ +#define __MAX14577_H__ + +#include +#include + +/* + * MAX14577 Regulator + */ + +/* MAX14577 regulator IDs */ +enum max14577_regulators { + MAX14577_SAFEOUT = 0, + MAX14577_CHARGER, + + MAX14577_REG_MAX, +}; + +struct max14577_regulator_platform_data { + int id; + struct regulator_init_data *initdata; + struct device_node *of_node; +}; + +/* + * MAX14577 MFD platform data + */ +struct max14577_platform_data { + /* IRQ */ + int irq_base; + + /* current control GPIOs */ + int gpio_pogo_vbatt_en; + int gpio_pogo_vbus_en; + + /* current control GPIO control function */ + int (*set_gpio_pogo_vbatt_en) (int gpio_val); + int (*set_gpio_pogo_vbus_en) (int gpio_val); + + int (*set_gpio_pogo_cb) (int new_dev); + + struct max14577_regulator_platform_data *regulators; +}; + +#endif /* __MAX14577_H__ */ -- cgit v1.2.3 From 45e842235626fa4ff78d53aa92c45f8fbc9a69c4 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 3 Dec 2013 15:50:34 +0100 Subject: mfd: ab8500: Delete all GPIO platform data instances This deletes all instances where the AB8500 GPIO platform data is passed around. It is completely unused in the kernel now, so it does not hurt anyone. Signed-off-by: Linus Walleij Signed-off-by: Lee Jones --- include/linux/mfd/abx500/ab8500-gpio.h | 10 ---------- include/linux/mfd/abx500/ab8500.h | 2 -- 2 files changed, 12 deletions(-) (limited to 'include/linux/mfd') diff --git a/include/linux/mfd/abx500/ab8500-gpio.h b/include/linux/mfd/abx500/ab8500-gpio.h index 172b2f201ae0..ebef068cbb6f 100644 --- a/include/linux/mfd/abx500/ab8500-gpio.h +++ b/include/linux/mfd/abx500/ab8500-gpio.h @@ -8,16 +8,6 @@ #ifndef _AB8500_GPIO_H #define _AB8500_GPIO_H -/* - * Platform data to register a block: only the initial gpio/irq number. - * Array sizes are large enough to contain all AB8500 and AB9540 GPIO - * registers. - */ - -struct abx500_gpio_platform_data { - int gpio_base; -}; - enum abx500_gpio_pull_updown { ABX500_GPIO_PULL_DOWN = 0x0, ABX500_GPIO_PULL_NONE = 0x1, diff --git a/include/linux/mfd/abx500/ab8500.h b/include/linux/mfd/abx500/ab8500.h index f4acd898dac9..a86ca1406fb8 100644 --- a/include/linux/mfd/abx500/ab8500.h +++ b/include/linux/mfd/abx500/ab8500.h @@ -368,7 +368,6 @@ struct ab8500 { }; struct ab8500_regulator_platform_data; -struct ab8500_gpio_platform_data; struct ab8500_codec_platform_data; struct ab8500_sysctrl_platform_data; @@ -382,7 +381,6 @@ struct ab8500_platform_data { int irq_base; void (*init) (struct ab8500 *); struct ab8500_regulator_platform_data *regulator; - struct abx500_gpio_platform_data *gpio; struct ab8500_codec_platform_data *codec; struct ab8500_sysctrl_platform_data *sysctrl; }; -- cgit v1.2.3 From 97b583f3b491f75712b0edc89c26a112f3847ab3 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 3 Dec 2013 15:50:49 +0100 Subject: mfd/pinctrl: Delete platform data header This deletes the special AB8500 GPIO platform data passing header and merges the few remaining contents down into the abx500 pinctrl driver which handles the abx500 GPIO device. Signed-off-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/pinctrl/pinctrl-abx500.c | 1 - drivers/pinctrl/pinctrl-abx500.h | 12 ++++++++++++ include/linux/mfd/abx500/ab8500-gpio.h | 23 ----------------------- 3 files changed, 12 insertions(+), 24 deletions(-) delete mode 100644 include/linux/mfd/abx500/ab8500-gpio.h (limited to 'include/linux/mfd') diff --git a/drivers/pinctrl/pinctrl-abx500.c b/drivers/pinctrl/pinctrl-abx500.c index 62bd7cf79a3b..163da9c3ea0e 100644 --- a/drivers/pinctrl/pinctrl-abx500.c +++ b/drivers/pinctrl/pinctrl-abx500.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pinctrl/pinctrl-abx500.h b/drivers/pinctrl/pinctrl-abx500.h index 82293806e842..2beef3bfe9ca 100644 --- a/drivers/pinctrl/pinctrl-abx500.h +++ b/drivers/pinctrl/pinctrl-abx500.h @@ -15,6 +15,18 @@ enum abx500_pin_func { ABX500_ALT_C, }; +enum abx500_gpio_pull_updown { + ABX500_GPIO_PULL_DOWN = 0x0, + ABX500_GPIO_PULL_NONE = 0x1, + ABX500_GPIO_PULL_UP = 0x3, +}; + +enum abx500_gpio_vinsel { + ABX500_GPIO_VINSEL_VBAT = 0x0, + ABX500_GPIO_VINSEL_VIN_1V8 = 0x1, + ABX500_GPIO_VINSEL_VDD_BIF = 0x2, +}; + /** * struct abx500_function - ABx500 pinctrl mux function * @name: The name of the function, exported to pinctrl core. diff --git a/include/linux/mfd/abx500/ab8500-gpio.h b/include/linux/mfd/abx500/ab8500-gpio.h deleted file mode 100644 index ebef068cbb6f..000000000000 --- a/include/linux/mfd/abx500/ab8500-gpio.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright ST-Ericsson 2010. - * - * Author: Bibek Basu - * Licensed under GPLv2. - */ - -#ifndef _AB8500_GPIO_H -#define _AB8500_GPIO_H - -enum abx500_gpio_pull_updown { - ABX500_GPIO_PULL_DOWN = 0x0, - ABX500_GPIO_PULL_NONE = 0x1, - ABX500_GPIO_PULL_UP = 0x3, -}; - -enum abx500_gpio_vinsel { - ABX500_GPIO_VINSEL_VBAT = 0x0, - ABX500_GPIO_VINSEL_VIN_1V8 = 0x1, - ABX500_GPIO_VINSEL_VDD_BIF = 0x2, -}; - -#endif /* _AB8500_GPIO_H */ -- cgit v1.2.3 From 470eca47bded10f2e1a425b44d6f2b1418271a9f Mon Sep 17 00:00:00 2001 From: Milo Kim Date: Fri, 6 Dec 2013 11:18:41 +0900 Subject: mfd: Add LP3943 MFD driver LP3943 has 16 output pins which can be used as GPIO expander and PWM generator. * Regmap I2C interface for R/W LP3943 registers * Atomic operations for output pin assignment The driver should check whether requested pin is available or not. If the pin is already used, pin request returns as a failure. A driver data, 'pin_used' is checked when gpio_request() and pwm_request() are called. If the pin is available, then pin_used is set. And it is cleared when gpio_free() and pwm_free(). * Device tree support Compatible strings for GPIO and PWM driver. LP3943 platform data is PWM related, so parsing the device tree is implemented in the PWM driver. Signed-off-by: Milo Kim Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 11 +++ drivers/mfd/Makefile | 1 + drivers/mfd/lp3943.c | 167 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/mfd/lp3943.h | 114 +++++++++++++++++++++++++++++++ 4 files changed, 293 insertions(+) create mode 100644 drivers/mfd/lp3943.c create mode 100644 include/linux/mfd/lp3943.h (limited to 'include/linux/mfd') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index e54a6fd2a5bd..1c2a389e6dc2 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -738,6 +738,17 @@ config MFD_DM355EVM_MSP boards. MSP430 firmware manages resets and power sequencing, inputs from buttons and the IR remote, LEDs, an RTC, and more. +config MFD_LP3943 + tristate "TI/National Semiconductor LP3943 MFD Driver" + depends on I2C + select MFD_CORE + select REGMAP_I2C + help + Support for the TI/National Semiconductor LP3943. + This driver consists of GPIO and PWM drivers. + With these functionalities, it can be used for LED string control or + general usage such like a GPIO controller and a PWM controller. + config MFD_LP8788 bool "TI LP8788 Power Management Unit Driver" depends on I2C=y diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 2e18b05017d9..5aea5ef0a62f 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -102,6 +102,7 @@ obj-$(CONFIG_PMIC_DA9052) += da9052-core.o obj-$(CONFIG_MFD_DA9052_SPI) += da9052-spi.o obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.o +obj-$(CONFIG_MFD_LP3943) += lp3943.o obj-$(CONFIG_MFD_LP8788) += lp8788.o lp8788-irq.o da9055-objs := da9055-core.o da9055-i2c.o diff --git a/drivers/mfd/lp3943.c b/drivers/mfd/lp3943.c new file mode 100644 index 000000000000..e32226836fb4 --- /dev/null +++ b/drivers/mfd/lp3943.c @@ -0,0 +1,167 @@ +/* + * TI/National Semiconductor LP3943 MFD Core Driver + * + * Copyright 2013 Texas Instruments + * + * Author: Milo Kim + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Driver structure: + * LP3943 is an integrated device capable of driving 16 output channels. + * It can be used for a GPIO expander and PWM generators. + * + * LED control General usage for a device + * ___________ ____________________________ + * + * LP3943 MFD ---- GPIO expander leds-gpio eg) HW enable pin + * | + * --- PWM generator leds-pwm eg) PWM input + * + * Internal two PWM channels are used for LED dimming effect. + * And each output pin can be used as a GPIO as well. + * The LED functionality can work with GPIOs or PWMs. + * LEDs can be controlled with legacy leds-gpio(static brightness) or + * leds-pwm drivers(dynamic brightness control). + * Alternatively, it can be used for generic GPIO and PWM controller. + * For example, a GPIO is HW enable pin of a device. + * A PWM is input pin of a backlight device. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define LP3943_MAX_REGISTERS 0x09 + +/* Register configuration for pin MUX */ +static const struct lp3943_reg_cfg lp3943_mux_cfg[] = { + /* address, mask, shift */ + { LP3943_REG_MUX0, 0x03, 0 }, + { LP3943_REG_MUX0, 0x0C, 2 }, + { LP3943_REG_MUX0, 0x30, 4 }, + { LP3943_REG_MUX0, 0xC0, 6 }, + { LP3943_REG_MUX1, 0x03, 0 }, + { LP3943_REG_MUX1, 0x0C, 2 }, + { LP3943_REG_MUX1, 0x30, 4 }, + { LP3943_REG_MUX1, 0xC0, 6 }, + { LP3943_REG_MUX2, 0x03, 0 }, + { LP3943_REG_MUX2, 0x0C, 2 }, + { LP3943_REG_MUX2, 0x30, 4 }, + { LP3943_REG_MUX2, 0xC0, 6 }, + { LP3943_REG_MUX3, 0x03, 0 }, + { LP3943_REG_MUX3, 0x0C, 2 }, + { LP3943_REG_MUX3, 0x30, 4 }, + { LP3943_REG_MUX3, 0xC0, 6 }, +}; + +static struct mfd_cell lp3943_devs[] = { + { + .name = "lp3943-pwm", + .of_compatible = "ti,lp3943-pwm", + }, + { + .name = "lp3943-gpio", + .of_compatible = "ti,lp3943-gpio", + }, +}; + +int lp3943_read_byte(struct lp3943 *lp3943, u8 reg, u8 *read) +{ + int ret; + unsigned int val; + + ret = regmap_read(lp3943->regmap, reg, &val); + if (ret < 0) + return ret; + + *read = (u8)val; + return 0; +} +EXPORT_SYMBOL_GPL(lp3943_read_byte); + +int lp3943_write_byte(struct lp3943 *lp3943, u8 reg, u8 data) +{ + return regmap_write(lp3943->regmap, reg, data); +} +EXPORT_SYMBOL_GPL(lp3943_write_byte); + +int lp3943_update_bits(struct lp3943 *lp3943, u8 reg, u8 mask, u8 data) +{ + return regmap_update_bits(lp3943->regmap, reg, mask, data); +} +EXPORT_SYMBOL_GPL(lp3943_update_bits); + +static const struct regmap_config lp3943_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = LP3943_MAX_REGISTERS, +}; + +static int lp3943_probe(struct i2c_client *cl, const struct i2c_device_id *id) +{ + struct lp3943 *lp3943; + struct device *dev = &cl->dev; + + lp3943 = devm_kzalloc(dev, sizeof(*lp3943), GFP_KERNEL); + if (!lp3943) + return -ENOMEM; + + lp3943->regmap = devm_regmap_init_i2c(cl, &lp3943_regmap_config); + if (IS_ERR(lp3943->regmap)) + return PTR_ERR(lp3943->regmap); + + lp3943->pdata = dev_get_platdata(dev); + lp3943->dev = dev; + lp3943->mux_cfg = lp3943_mux_cfg; + i2c_set_clientdata(cl, lp3943); + + return mfd_add_devices(dev, -1, lp3943_devs, ARRAY_SIZE(lp3943_devs), + NULL, 0, NULL); +} + +static int lp3943_remove(struct i2c_client *cl) +{ + struct lp3943 *lp3943 = i2c_get_clientdata(cl); + + mfd_remove_devices(lp3943->dev); + return 0; +} + +static const struct i2c_device_id lp3943_ids[] = { + { "lp3943", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, lp3943_ids); + +#ifdef CONFIG_OF +static const struct of_device_id lp3943_of_match[] = { + { .compatible = "ti,lp3943", }, + { } +}; +MODULE_DEVICE_TABLE(of, lp3943_of_match); +#endif + +static struct i2c_driver lp3943_driver = { + .probe = lp3943_probe, + .remove = lp3943_remove, + .driver = { + .name = "lp3943", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(lp3943_of_match), + }, + .id_table = lp3943_ids, +}; + +module_i2c_driver(lp3943_driver); + +MODULE_DESCRIPTION("LP3943 MFD Core Driver"); +MODULE_AUTHOR("Milo Kim"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/mfd/lp3943.h b/include/linux/mfd/lp3943.h new file mode 100644 index 000000000000..3490db782988 --- /dev/null +++ b/include/linux/mfd/lp3943.h @@ -0,0 +1,114 @@ +/* + * TI/National Semiconductor LP3943 Device + * + * Copyright 2013 Texas Instruments + * + * Author: Milo Kim + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef __MFD_LP3943_H__ +#define __MFD_LP3943_H__ + +#include +#include +#include + +/* Registers */ +#define LP3943_REG_GPIO_A 0x00 +#define LP3943_REG_GPIO_B 0x01 +#define LP3943_REG_PRESCALE0 0x02 +#define LP3943_REG_PWM0 0x03 +#define LP3943_REG_PRESCALE1 0x04 +#define LP3943_REG_PWM1 0x05 +#define LP3943_REG_MUX0 0x06 +#define LP3943_REG_MUX1 0x07 +#define LP3943_REG_MUX2 0x08 +#define LP3943_REG_MUX3 0x09 + +/* Bit description for LP3943_REG_MUX0 ~ 3 */ +#define LP3943_GPIO_IN 0x00 +#define LP3943_GPIO_OUT_HIGH 0x00 +#define LP3943_GPIO_OUT_LOW 0x01 +#define LP3943_DIM_PWM0 0x02 +#define LP3943_DIM_PWM1 0x03 + +#define LP3943_NUM_PWMS 2 + +enum lp3943_pwm_output { + LP3943_PWM_OUT0, + LP3943_PWM_OUT1, + LP3943_PWM_OUT2, + LP3943_PWM_OUT3, + LP3943_PWM_OUT4, + LP3943_PWM_OUT5, + LP3943_PWM_OUT6, + LP3943_PWM_OUT7, + LP3943_PWM_OUT8, + LP3943_PWM_OUT9, + LP3943_PWM_OUT10, + LP3943_PWM_OUT11, + LP3943_PWM_OUT12, + LP3943_PWM_OUT13, + LP3943_PWM_OUT14, + LP3943_PWM_OUT15, +}; + +/* + * struct lp3943_pwm_map + * @output: Output pins which are mapped to each PWM channel + * @num_outputs: Number of outputs + */ +struct lp3943_pwm_map { + enum lp3943_pwm_output *output; + int num_outputs; +}; + +/* + * struct lp3943_platform_data + * @pwms: Output channel definitions for PWM channel 0 and 1 + */ +struct lp3943_platform_data { + struct lp3943_pwm_map *pwms[LP3943_NUM_PWMS]; +}; + +/* + * struct lp3943_reg_cfg + * @reg: Register address + * @mask: Register bit mask to be updated + * @shift: Register bit shift + */ +struct lp3943_reg_cfg { + u8 reg; + u8 mask; + u8 shift; +}; + +/* + * struct lp3943 + * @dev: Parent device pointer + * @regmap: Used for I2C communication on accessing registers + * @pdata: LP3943 platform specific data + * @mux_cfg: Register configuration for pin MUX + * @pin_used: Bit mask for output pin used. + * This bitmask is used for pin assignment management. + * 1 = pin used, 0 = available. + * Only LSB 16 bits are used, but it is unsigned long type + * for atomic bitwise operations. + */ +struct lp3943 { + struct device *dev; + struct regmap *regmap; + struct lp3943_platform_data *pdata; + const struct lp3943_reg_cfg *mux_cfg; + unsigned long pin_used; +}; + +int lp3943_read_byte(struct lp3943 *lp3943, u8 reg, u8 *read); +int lp3943_write_byte(struct lp3943 *lp3943, u8 reg, u8 data); +int lp3943_update_bits(struct lp3943 *lp3943, u8 reg, u8 mask, u8 data); +#endif -- cgit v1.2.3 From e0a3da80c65dc427c30829eb3e361507f843778f Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Fri, 6 Dec 2013 13:51:45 +0100 Subject: mfd: tps6586x: Add version detection Use the VERSIONCRC to determine the exact device version. According to the datasheet this register can be used as device identifier. The identification is needed since some tps6586x regulators use a different voltage table. Signed-off-by: Stefan Agner Reviewed-by: Thierry Reding Acked-by: Stephen Warren Signed-off-by: Lee Jones --- drivers/mfd/tps6586x.c | 50 +++++++++++++++++++++++++++++++++++++------- include/linux/mfd/tps6586x.h | 7 +++++++ 2 files changed, 49 insertions(+), 8 deletions(-) (limited to 'include/linux/mfd') diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index d0e57934370f..bbd54414a75d 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c @@ -124,6 +124,7 @@ struct tps6586x { struct device *dev; struct i2c_client *client; struct regmap *regmap; + int version; int irq; struct irq_chip irq_chip; @@ -208,6 +209,14 @@ int tps6586x_irq_get_virq(struct device *dev, int irq) } EXPORT_SYMBOL_GPL(tps6586x_irq_get_virq); +int tps6586x_get_version(struct device *dev) +{ + struct tps6586x *tps6586x = dev_get_drvdata(dev); + + return tps6586x->version; +} +EXPORT_SYMBOL_GPL(tps6586x_get_version); + static int __remove_subdev(struct device *dev, void *unused) { platform_device_unregister(to_platform_device(dev)); @@ -472,12 +481,38 @@ static void tps6586x_power_off(void) tps6586x_set_bits(tps6586x_dev, TPS6586X_SUPPLYENE, SLEEP_MODE_BIT); } +static void tps6586x_print_version(struct i2c_client *client, int version) +{ + const char *name; + + switch (version) { + case TPS658621A: + name = "TPS658621A"; + break; + case TPS658621CD: + name = "TPS658621C/D"; + break; + case TPS658623: + name = "TPS658623"; + break; + case TPS658643: + name = "TPS658643"; + break; + default: + name = "TPS6586X"; + break; + } + + dev_info(&client->dev, "Found %s, VERSIONCRC is %02x\n", name, version); +} + static int tps6586x_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct tps6586x_platform_data *pdata = dev_get_platdata(&client->dev); struct tps6586x *tps6586x; int ret; + int version; if (!pdata && client->dev.of_node) pdata = tps6586x_parse_dt(client); @@ -487,19 +522,18 @@ static int tps6586x_i2c_probe(struct i2c_client *client, return -ENOTSUPP; } - ret = i2c_smbus_read_byte_data(client, TPS6586X_VERSIONCRC); - if (ret < 0) { - dev_err(&client->dev, "Chip ID read failed: %d\n", ret); + version = i2c_smbus_read_byte_data(client, TPS6586X_VERSIONCRC); + if (version < 0) { + dev_err(&client->dev, "Chip ID read failed: %d\n", version); return -EIO; } - dev_info(&client->dev, "VERSIONCRC is %02x\n", ret); - tps6586x = devm_kzalloc(&client->dev, sizeof(*tps6586x), GFP_KERNEL); - if (tps6586x == NULL) { - dev_err(&client->dev, "memory for tps6586x alloc failed\n"); + if (!tps6586x) return -ENOMEM; - } + + tps6586x->version = version; + tps6586x_print_version(client, tps6586x->version); tps6586x->client = client; tps6586x->dev = &client->dev; diff --git a/include/linux/mfd/tps6586x.h b/include/linux/mfd/tps6586x.h index 87994542573b..cbecec2e353a 100644 --- a/include/linux/mfd/tps6586x.h +++ b/include/linux/mfd/tps6586x.h @@ -13,6 +13,12 @@ #define TPS6586X_SLEW_RATE_SET 0x08 #define TPS6586X_SLEW_RATE_MASK 0x07 +/* VERSION CRC */ +#define TPS658621A 0x15 +#define TPS658621CD 0x2c +#define TPS658623 0x1b +#define TPS658643 0x03 + enum { TPS6586X_ID_SYS, TPS6586X_ID_SM_0, @@ -97,5 +103,6 @@ extern int tps6586x_clr_bits(struct device *dev, int reg, uint8_t bit_mask); extern int tps6586x_update(struct device *dev, int reg, uint8_t val, uint8_t mask); extern int tps6586x_irq_get_virq(struct device *dev, int irq); +extern int tps6586x_get_version(struct device *dev); #endif /*__LINUX_MFD_TPS6586X_H */ -- cgit v1.2.3 From 03b1e3023b34dceedd882136f5a4c834e501fb39 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 14 Dec 2013 17:03:11 +0400 Subject: mfd: mc13xxx: Remove duplicate mc13xxx_get_flags() declaration mc13xxx_get_flags() declaration given twice. This patch removes this duplicate. Signed-off-by: Alexander Shiyan Signed-off-by: Lee Jones --- include/linux/mfd/mc13xxx.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include/linux/mfd') diff --git a/include/linux/mfd/mc13xxx.h b/include/linux/mfd/mc13xxx.h index 67c17b5a6f44..6156686bf108 100644 --- a/include/linux/mfd/mc13xxx.h +++ b/include/linux/mfd/mc13xxx.h @@ -21,8 +21,6 @@ int mc13xxx_reg_write(struct mc13xxx *mc13xxx, unsigned int offset, u32 val); int mc13xxx_reg_rmw(struct mc13xxx *mc13xxx, unsigned int offset, u32 mask, u32 val); -int mc13xxx_get_flags(struct mc13xxx *mc13xxx); - int mc13xxx_irq_request(struct mc13xxx *mc13xxx, int irq, irq_handler_t handler, const char *name, void *dev); int mc13xxx_irq_request_nounmask(struct mc13xxx *mc13xxx, int irq, -- cgit v1.2.3 From f876a975a05a2dffb4f1a4f07b81b212d9d8db01 Mon Sep 17 00:00:00 2001 From: Laszlo Papp Date: Thu, 19 Dec 2013 13:08:43 +0000 Subject: mfd: Represent correct filenames in file headers The original author(s) probably copy/pasted these headers from the existing public header files. Signed-off-by: Laszlo Papp Signed-off-by: Lee Jones --- include/linux/mfd/max77686-private.h | 2 +- include/linux/mfd/max8997-private.h | 2 +- include/linux/mfd/max8998-private.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'include/linux/mfd') diff --git a/include/linux/mfd/max77686-private.h b/include/linux/mfd/max77686-private.h index d327d4971e4f..8c75a9c8dfab 100644 --- a/include/linux/mfd/max77686-private.h +++ b/include/linux/mfd/max77686-private.h @@ -1,5 +1,5 @@ /* - * max77686.h - Voltage regulator driver for the Maxim 77686 + * max77686-private.h - Voltage regulator driver for the Maxim 77686 * * Copyright (C) 2012 Samsung Electrnoics * Chiwoong Byun diff --git a/include/linux/mfd/max8997-private.h b/include/linux/mfd/max8997-private.h index fb465dfbb59e..ad1ae7f345ad 100644 --- a/include/linux/mfd/max8997-private.h +++ b/include/linux/mfd/max8997-private.h @@ -1,5 +1,5 @@ /* - * max8997.h - Voltage regulator driver for the Maxim 8997 + * max8997-private.h - Voltage regulator driver for the Maxim 8997 * * Copyright (C) 2010 Samsung Electrnoics * MyungJoo Ham diff --git a/include/linux/mfd/max8998-private.h b/include/linux/mfd/max8998-private.h index 84844e0a5704..4ecb24b4b863 100644 --- a/include/linux/mfd/max8998-private.h +++ b/include/linux/mfd/max8998-private.h @@ -1,5 +1,5 @@ /* - * max8998.h - Voltage regulator driver for the Maxim 8998 + * max8998-private.h - Voltage regulator driver for the Maxim 8998 * * Copyright (C) 2009-2010 Samsung Electrnoics * Kyungmin Park -- cgit v1.2.3