diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2023-05-02 10:41:31 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2023-05-02 10:41:31 -0700 |
commit | 3af49062b0115b55a54615109172b44f618daf97 (patch) | |
tree | 54bc04f20c95dc27362978c04e7d00e2399f9904 /drivers | |
parent | c5eb8bf76718cf2e2f36aac216a99014f00927de (diff) | |
parent | 9e9ff39243ea8795a4833708613f884b39dc91f9 (diff) | |
download | lwn-3af49062b0115b55a54615109172b44f618daf97.tar.gz lwn-3af49062b0115b55a54615109172b44f618daf97.zip |
Merge tag 'mfd-next-6.4' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd
Pull MFD updates from Lee Jones:
"New Drivers:
- Add support for Renesas RZ/G2L MTU3
New Device Support:
- Add support for Lenovo Yoga Book X90F to Intel CHT WC
- Add support for MAX5970 and MAX5978 to Simple MFD (I2C)
- Add support for Meteor Lake PCH-S LPSS PCI to Intel LPSS PCI
- Add support for AXP15060 PMIC to X-Powers PMIC collection
Remove Device Support:
- Remove support for Samsung 5M8751 and S5M8763 PMIC devices
New Functionality:
- Convert deprecated QCOM IRQ Chip to config registers
- Add support for 32-bit address spaces to Renesas SMUs
Fix-ups:
- Make use of APIs / MACROs designed to simplify and demystify
- Add / improve Device Tree bindings
- Memory saving struct layout optimisations
- Remove old / deprecated functionality
- Factor out unassigned register addresses from ranges
- Trivial: Spelling fixes, renames and coding style fixes
- Rid 'defined but not used' warnings
- Remove ineffective casts and pointer stubs
Bug Fixes:
- Fix incorrectly non-inverted mask/unmask IRQs on QCOM platforms
- Remove MODULE_*() helpers from non-tristate drivers
- Do not attempt to use out-of-range memory addresses associated with io_base
- Provide missing export helpers
- Fix remap bulk read optimisation fallout
- Fix memory leak issues in error paths"
* tag 'mfd-next-6.4' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (88 commits)
dt-bindings: mfd: ti,j721e-system-controller: Add SoC chip ID
leds: bd2606mvv: Driver for the Rohm 6 Channel i2c LED driver
dt-bindings: mfd: qcom,spmi-pmic: Document flash LED controller
dt-bindings: mfd: x-powers,axp152: Document the AXP15060 variant
mfd: axp20x: Add support for AXP15060 PMIC
dt-bindings: mfd: x-powers,axp152: Document the AXP313a variant
counter: rz-mtu3-cnt: Unlock on error in rz_mtu3_count_ceiling_write()
dt-bindings: mfd: dlg,da9063: Document voltage monitoring
dt-bindings: mfd: stm32: Remove unnecessary blank lines
dt-bindings: mfd: qcom,spmi-pmic: Use generic ADC node name in examples
dt-bindings: mfd: syscon: Add nuvoton,ma35d1-sys compatible
MAINTAINERS: Add entries for Renesas RZ/G2L MTU3a counter driver
counter: Add Renesas RZ/G2L MTU3a counter driver
Documentation: ABI: sysfs-bus-counter: add cascade_counts_enable and external_input_phase_clock_select
mfd: Add Renesas RZ/G2L MTU3a core driver
dt-bindings: timer: Document RZ/G2L MTU3a bindings
mfd: rsmu_i2c: Convert to i2c's .probe_new() again
mfd: intel-lpss: Add Intel Meteor Lake PCH-S LPSS PCI IDs
mfd: dln2: Fix memory leak in dln2_probe()
mfd: axp20x: Fix axp288 writable-ranges
...
Diffstat (limited to 'drivers')
61 files changed, 2446 insertions, 634 deletions
diff --git a/drivers/counter/Kconfig b/drivers/counter/Kconfig index b5ba8fb02cf7..4228be917038 100644 --- a/drivers/counter/Kconfig +++ b/drivers/counter/Kconfig @@ -73,6 +73,17 @@ config MICROCHIP_TCB_CAPTURE To compile this driver as a module, choose M here: the module will be called microchip-tcb-capture. +config RZ_MTU3_CNT + tristate "Renesas RZ/G2L MTU3a counter driver" + depends on RZ_MTU3 || COMPILE_TEST + help + Enable support for MTU3a counter driver found on Renesas RZ/G2L alike + SoCs. This IP supports both 16-bit and 32-bit phase counting mode + support. + + To compile this driver as a module, choose M here: the + module will be called rz-mtu3-cnt. + config STM32_LPTIMER_CNT tristate "STM32 LP Timer encoder counter driver" depends on MFD_STM32_LPTIMER || COMPILE_TEST diff --git a/drivers/counter/Makefile b/drivers/counter/Makefile index b9a369e0d4fc..933fdd50b3e4 100644 --- a/drivers/counter/Makefile +++ b/drivers/counter/Makefile @@ -8,6 +8,7 @@ counter-y := counter-core.o counter-sysfs.o counter-chrdev.o obj-$(CONFIG_104_QUAD_8) += 104-quad-8.o obj-$(CONFIG_INTERRUPT_CNT) += interrupt-cnt.o +obj-$(CONFIG_RZ_MTU3_CNT) += rz-mtu3-cnt.o obj-$(CONFIG_STM32_TIMER_CNT) += stm32-timer-cnt.o obj-$(CONFIG_STM32_LPTIMER_CNT) += stm32-lptimer-cnt.o obj-$(CONFIG_TI_EQEP) += ti-eqep.o diff --git a/drivers/counter/rz-mtu3-cnt.c b/drivers/counter/rz-mtu3-cnt.c new file mode 100644 index 000000000000..48c83933aa2f --- /dev/null +++ b/drivers/counter/rz-mtu3-cnt.c @@ -0,0 +1,906 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas RZ/G2L MTU3a Counter driver + * + * Copyright (C) 2022 Renesas Electronics Corporation + */ + +#include <linux/clk.h> +#include <linux/counter.h> +#include <linux/mfd/rz-mtu3.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/types.h> + +/* + * Register descriptions + * TSR: Timer Status Register + * TMDR1: Timer Mode Register 1 + * TMDR3: Timer Mode Register 3 + * TIOR: Timer I/O Control Register + * TCR: Timer Control Register + * TCNT: Timer Counter + * TGRA: Timer general register A + * TCNTLW: Timer Longword Counter + * TGRALW: Timer longword general register A + */ + +#define RZ_MTU3_TSR_TCFD BIT(7) /* Count Direction Flag */ + +#define RZ_MTU3_TMDR1_PH_CNT_MODE_1 (4) /* Phase counting mode 1 */ +#define RZ_MTU3_TMDR1_PH_CNT_MODE_2 (5) /* Phase counting mode 2 */ +#define RZ_MTU3_TMDR1_PH_CNT_MODE_3 (6) /* Phase counting mode 3 */ +#define RZ_MTU3_TMDR1_PH_CNT_MODE_4 (7) /* Phase counting mode 4 */ +#define RZ_MTU3_TMDR1_PH_CNT_MODE_5 (9) /* Phase counting mode 5 */ +#define RZ_MTU3_TMDR1_PH_CNT_MODE_MASK (0xf) + +/* + * LWA: MTU1/MTU2 Combination Longword Access Control + * 0: 16-bit, 1: 32-bit + */ +#define RZ_MTU3_TMDR3_LWA (0) + +/* + * PHCKSEL: External Input Phase Clock Select + * 0: MTCLKA and MTCLKB, 1: MTCLKC and MTCLKD + */ +#define RZ_MTU3_TMDR3_PHCKSEL (1) + +#define RZ_MTU3_16_BIT_MTU1_CH (0) +#define RZ_MTU3_16_BIT_MTU2_CH (1) +#define RZ_MTU3_32_BIT_CH (2) + +#define RZ_MTU3_TIOR_NO_OUTPUT (0) /* Output prohibited */ +#define RZ_MTU3_TIOR_IC_BOTH (10) /* Input capture at both edges */ + +#define SIGNAL_A_ID (0) +#define SIGNAL_B_ID (1) +#define SIGNAL_C_ID (2) +#define SIGNAL_D_ID (3) + +#define RZ_MTU3_MAX_HW_CNTR_CHANNELS (2) +#define RZ_MTU3_MAX_LOGICAL_CNTR_CHANNELS (3) + +/** + * struct rz_mtu3_cnt - MTU3 counter private data + * + * @clk: MTU3 module clock + * @lock: Lock to prevent concurrent access for ceiling and count + * @ch: HW channels for the counters + * @count_is_enabled: Enabled state of Counter value channel + * @mtu_16bit_max: Cache for 16-bit counters + * @mtu_32bit_max: Cache for 32-bit counters + */ +struct rz_mtu3_cnt { + struct clk *clk; + struct mutex lock; + struct rz_mtu3_channel *ch; + bool count_is_enabled[RZ_MTU3_MAX_LOGICAL_CNTR_CHANNELS]; + union { + u16 mtu_16bit_max[RZ_MTU3_MAX_HW_CNTR_CHANNELS]; + u32 mtu_32bit_max; + }; +}; + +static const enum counter_function rz_mtu3_count_functions[] = { + COUNTER_FUNCTION_QUADRATURE_X4, + COUNTER_FUNCTION_PULSE_DIRECTION, + COUNTER_FUNCTION_QUADRATURE_X2_B, +}; + +static inline size_t rz_mtu3_get_hw_ch(const size_t id) +{ + return (id == RZ_MTU3_32_BIT_CH) ? 0 : id; +} + +static inline struct rz_mtu3_channel *rz_mtu3_get_ch(struct counter_device *counter, int id) +{ + struct rz_mtu3_cnt *const priv = counter_priv(counter); + const size_t ch_id = rz_mtu3_get_hw_ch(id); + + return &priv->ch[ch_id]; +} + +static bool rz_mtu3_is_counter_invalid(struct counter_device *counter, int id) +{ + struct rz_mtu3_cnt *const priv = counter_priv(counter); + unsigned long tmdr; + + pm_runtime_get_sync(priv->ch->dev); + tmdr = rz_mtu3_shared_reg_read(priv->ch, RZ_MTU3_TMDR3); + pm_runtime_put(priv->ch->dev); + + if (id == RZ_MTU3_32_BIT_CH && test_bit(RZ_MTU3_TMDR3_LWA, &tmdr)) + return false; + + if (id != RZ_MTU3_32_BIT_CH && !test_bit(RZ_MTU3_TMDR3_LWA, &tmdr)) + return false; + + return true; +} + +static int rz_mtu3_lock_if_counter_is_valid(struct counter_device *counter, + struct rz_mtu3_channel *const ch, + struct rz_mtu3_cnt *const priv, + int id) +{ + mutex_lock(&priv->lock); + + if (ch->is_busy && !priv->count_is_enabled[id]) { + mutex_unlock(&priv->lock); + return -EINVAL; + } + + if (rz_mtu3_is_counter_invalid(counter, id)) { + mutex_unlock(&priv->lock); + return -EBUSY; + } + + return 0; +} + +static int rz_mtu3_lock_if_count_is_enabled(struct rz_mtu3_channel *const ch, + struct rz_mtu3_cnt *const priv, + int id) +{ + mutex_lock(&priv->lock); + + if (ch->is_busy && !priv->count_is_enabled[id]) { + mutex_unlock(&priv->lock); + return -EINVAL; + } + + return 0; +} + +static int rz_mtu3_count_read(struct counter_device *counter, + struct counter_count *count, u64 *val) +{ + struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, count->id); + struct rz_mtu3_cnt *const priv = counter_priv(counter); + int ret; + + ret = rz_mtu3_lock_if_counter_is_valid(counter, ch, priv, count->id); + if (ret) + return ret; + + pm_runtime_get_sync(ch->dev); + if (count->id == RZ_MTU3_32_BIT_CH) + *val = rz_mtu3_32bit_ch_read(ch, RZ_MTU3_TCNTLW); + else + *val = rz_mtu3_16bit_ch_read(ch, RZ_MTU3_TCNT); + pm_runtime_put(ch->dev); + mutex_unlock(&priv->lock); + + return 0; +} + +static int rz_mtu3_count_write(struct counter_device *counter, + struct counter_count *count, const u64 val) +{ + struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, count->id); + struct rz_mtu3_cnt *const priv = counter_priv(counter); + int ret; + + ret = rz_mtu3_lock_if_counter_is_valid(counter, ch, priv, count->id); + if (ret) + return ret; + + pm_runtime_get_sync(ch->dev); + if (count->id == RZ_MTU3_32_BIT_CH) + rz_mtu3_32bit_ch_write(ch, RZ_MTU3_TCNTLW, val); + else + rz_mtu3_16bit_ch_write(ch, RZ_MTU3_TCNT, val); + pm_runtime_put(ch->dev); + mutex_unlock(&priv->lock); + + return 0; +} + +static int rz_mtu3_count_function_read_helper(struct rz_mtu3_channel *const ch, + struct rz_mtu3_cnt *const priv, + enum counter_function *function) +{ + u8 timer_mode; + + pm_runtime_get_sync(ch->dev); + timer_mode = rz_mtu3_8bit_ch_read(ch, RZ_MTU3_TMDR1); + pm_runtime_put(ch->dev); + + switch (timer_mode & RZ_MTU3_TMDR1_PH_CNT_MODE_MASK) { + case RZ_MTU3_TMDR1_PH_CNT_MODE_1: + *function = COUNTER_FUNCTION_QUADRATURE_X4; + return 0; + case RZ_MTU3_TMDR1_PH_CNT_MODE_2: + *function = COUNTER_FUNCTION_PULSE_DIRECTION; + return 0; + case RZ_MTU3_TMDR1_PH_CNT_MODE_4: + *function = COUNTER_FUNCTION_QUADRATURE_X2_B; + return 0; + default: + /* + * TODO: + * - need to add RZ_MTU3_TMDR1_PH_CNT_MODE_3 + * - need to add RZ_MTU3_TMDR1_PH_CNT_MODE_5 + */ + return -EINVAL; + } +} + +static int rz_mtu3_count_function_read(struct counter_device *counter, + struct counter_count *count, + enum counter_function *function) +{ + struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, count->id); + struct rz_mtu3_cnt *const priv = counter_priv(counter); + int ret; + + ret = rz_mtu3_lock_if_count_is_enabled(ch, priv, count->id); + if (ret) + return ret; + + ret = rz_mtu3_count_function_read_helper(ch, priv, function); + mutex_unlock(&priv->lock); + + return ret; +} + +static int rz_mtu3_count_function_write(struct counter_device *counter, + struct counter_count *count, + enum counter_function function) +{ + struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, count->id); + struct rz_mtu3_cnt *const priv = counter_priv(counter); + u8 timer_mode; + int ret; + + ret = rz_mtu3_lock_if_count_is_enabled(ch, priv, count->id); + if (ret) + return ret; + + switch (function) { + case COUNTER_FUNCTION_QUADRATURE_X4: + timer_mode = RZ_MTU3_TMDR1_PH_CNT_MODE_1; + break; + case COUNTER_FUNCTION_PULSE_DIRECTION: + timer_mode = RZ_MTU3_TMDR1_PH_CNT_MODE_2; + break; + case COUNTER_FUNCTION_QUADRATURE_X2_B: + timer_mode = RZ_MTU3_TMDR1_PH_CNT_MODE_4; + break; + default: + /* + * TODO: + * - need to add RZ_MTU3_TMDR1_PH_CNT_MODE_3 + * - need to add RZ_MTU3_TMDR1_PH_CNT_MODE_5 + */ + mutex_unlock(&priv->lock); + return -EINVAL; + } + + pm_runtime_get_sync(ch->dev); + rz_mtu3_8bit_ch_write(ch, RZ_MTU3_TMDR1, timer_mode); + pm_runtime_put(ch->dev); + mutex_unlock(&priv->lock); + + return 0; +} + +static int rz_mtu3_count_direction_read(struct counter_device *counter, + struct counter_count *count, + enum counter_count_direction *direction) +{ + struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, count->id); + struct rz_mtu3_cnt *const priv = counter_priv(counter); + int ret; + u8 tsr; + + ret = rz_mtu3_lock_if_count_is_enabled(ch, priv, count->id); + if (ret) + return ret; + + pm_runtime_get_sync(ch->dev); + tsr = rz_mtu3_8bit_ch_read(ch, RZ_MTU3_TSR); + pm_runtime_put(ch->dev); + + *direction = (tsr & RZ_MTU3_TSR_TCFD) ? + COUNTER_COUNT_DIRECTION_FORWARD : COUNTER_COUNT_DIRECTION_BACKWARD; + mutex_unlock(&priv->lock); + + return 0; +} + +static int rz_mtu3_count_ceiling_read(struct counter_device *counter, + struct counter_count *count, + u64 *ceiling) +{ + struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, count->id); + struct rz_mtu3_cnt *const priv = counter_priv(counter); + const size_t ch_id = rz_mtu3_get_hw_ch(count->id); + int ret; + + ret = rz_mtu3_lock_if_counter_is_valid(counter, ch, priv, count->id); + if (ret) + return ret; + + switch (count->id) { + case RZ_MTU3_16_BIT_MTU1_CH: + case RZ_MTU3_16_BIT_MTU2_CH: + *ceiling = priv->mtu_16bit_max[ch_id]; + break; + case RZ_MTU3_32_BIT_CH: + *ceiling = priv->mtu_32bit_max; + break; + default: + /* should never reach this path */ + mutex_unlock(&priv->lock); + return -EINVAL; + } + + mutex_unlock(&priv->lock); + return 0; +} + +static int rz_mtu3_count_ceiling_write(struct counter_device *counter, + struct counter_count *count, + u64 ceiling) +{ + struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, count->id); + struct rz_mtu3_cnt *const priv = counter_priv(counter); + const size_t ch_id = rz_mtu3_get_hw_ch(count->id); + int ret; + + ret = rz_mtu3_lock_if_counter_is_valid(counter, ch, priv, count->id); + if (ret) + return ret; + + switch (count->id) { + case RZ_MTU3_16_BIT_MTU1_CH: + case RZ_MTU3_16_BIT_MTU2_CH: + if (ceiling > U16_MAX) { + mutex_unlock(&priv->lock); + return -ERANGE; + } + priv->mtu_16bit_max[ch_id] = ceiling; + break; + case RZ_MTU3_32_BIT_CH: + if (ceiling > U32_MAX) { + mutex_unlock(&priv->lock); + return -ERANGE; + } + priv->mtu_32bit_max = ceiling; + break; + default: + /* should never reach this path */ + mutex_unlock(&priv->lock); + return -EINVAL; + } + + pm_runtime_get_sync(ch->dev); + if (count->id == RZ_MTU3_32_BIT_CH) + rz_mtu3_32bit_ch_write(ch, RZ_MTU3_TGRALW, ceiling); + else + rz_mtu3_16bit_ch_write(ch, RZ_MTU3_TGRA, ceiling); + + rz_mtu3_8bit_ch_write(ch, RZ_MTU3_TCR, RZ_MTU3_TCR_CCLR_TGRA); + pm_runtime_put(ch->dev); + mutex_unlock(&priv->lock); + + return 0; +} + +static void rz_mtu3_32bit_cnt_setting(struct counter_device *counter) +{ + struct rz_mtu3_channel *const ch1 = rz_mtu3_get_ch(counter, 0); + struct rz_mtu3_channel *const ch2 = rz_mtu3_get_ch(counter, 1); + + /* Phase counting mode 1 is used as default in initialization. */ + rz_mtu3_8bit_ch_write(ch1, RZ_MTU3_TMDR1, RZ_MTU3_TMDR1_PH_CNT_MODE_1); + + rz_mtu3_8bit_ch_write(ch1, RZ_MTU3_TCR, RZ_MTU3_TCR_CCLR_TGRA); + rz_mtu3_8bit_ch_write(ch1, RZ_MTU3_TIOR, RZ_MTU3_TIOR_IC_BOTH); + + rz_mtu3_enable(ch1); + rz_mtu3_enable(ch2); +} + +static void rz_mtu3_16bit_cnt_setting(struct counter_device *counter, int id) +{ + struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, id); + + /* Phase counting mode 1 is used as default in initialization. */ + rz_mtu3_8bit_ch_write(ch, RZ_MTU3_TMDR1, RZ_MTU3_TMDR1_PH_CNT_MODE_1); + + rz_mtu3_8bit_ch_write(ch, RZ_MTU3_TCR, RZ_MTU3_TCR_CCLR_TGRA); + rz_mtu3_8bit_ch_write(ch, RZ_MTU3_TIOR, RZ_MTU3_TIOR_NO_OUTPUT); + rz_mtu3_enable(ch); +} + +static int rz_mtu3_initialize_counter(struct counter_device *counter, int id) +{ + struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, id); + struct rz_mtu3_channel *const ch1 = rz_mtu3_get_ch(counter, 0); + struct rz_mtu3_channel *const ch2 = rz_mtu3_get_ch(counter, 1); + + switch (id) { + case RZ_MTU3_16_BIT_MTU1_CH: + case RZ_MTU3_16_BIT_MTU2_CH: + if (!rz_mtu3_request_channel(ch)) + return -EBUSY; + + rz_mtu3_16bit_cnt_setting(counter, id); + return 0; + case RZ_MTU3_32_BIT_CH: + /* + * 32-bit phase counting need MTU1 and MTU2 to create 32-bit + * cascade counter. + */ + if (!rz_mtu3_request_channel(ch1)) + return -EBUSY; + + if (!rz_mtu3_request_channel(ch2)) { + rz_mtu3_release_channel(ch1); + return -EBUSY; + } + + rz_mtu3_32bit_cnt_setting(counter); + return 0; + default: + /* should never reach this path */ + return -EINVAL; + } +} + +static void rz_mtu3_terminate_counter(struct counter_device *counter, int id) +{ + struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, id); + struct rz_mtu3_channel *const ch1 = rz_mtu3_get_ch(counter, 0); + struct rz_mtu3_channel *const ch2 = rz_mtu3_get_ch(counter, 1); + + if (id == RZ_MTU3_32_BIT_CH) { + rz_mtu3_release_channel(ch2); + rz_mtu3_release_channel(ch1); + rz_mtu3_disable(ch2); + rz_mtu3_disable(ch1); + } else { + rz_mtu3_release_channel(ch); + rz_mtu3_disable(ch); + } +} + +static int rz_mtu3_count_enable_read(struct counter_device *counter, + struct counter_count *count, u8 *enable) +{ + struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, count->id); + struct rz_mtu3_channel *const ch1 = rz_mtu3_get_ch(counter, 0); + struct rz_mtu3_channel *const ch2 = rz_mtu3_get_ch(counter, 1); + struct rz_mtu3_cnt *const priv = counter_priv(counter); + int ret; + + ret = rz_mtu3_lock_if_count_is_enabled(ch, priv, count->id); + if (ret) + return ret; + + if (count->id == RZ_MTU3_32_BIT_CH) + *enable = rz_mtu3_is_enabled(ch1) && rz_mtu3_is_enabled(ch2); + else + *enable = rz_mtu3_is_enabled(ch); + + mutex_unlock(&priv->lock); + + return 0; +} + +static int rz_mtu3_count_enable_write(struct counter_device *counter, + struct counter_count *count, u8 enable) +{ + struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, count->id); + struct rz_mtu3_cnt *const priv = counter_priv(counter); + int ret = 0; + + if (enable) { + pm_runtime_get_sync(ch->dev); + mutex_lock(&priv->lock); + ret = rz_mtu3_initialize_counter(counter, count->id); + if (ret == 0) + priv->count_is_enabled[count->id] = true; + mutex_unlock(&priv->lock); + } else { + mutex_lock(&priv->lock); + rz_mtu3_terminate_counter(counter, count->id); + priv->count_is_enabled[count->id] = false; + mutex_unlock(&priv->lock); + pm_runtime_put(ch->dev); + } + + return ret; +} + +static int rz_mtu3_lock_if_ch0_is_enabled(struct rz_mtu3_cnt *const priv) +{ + mutex_lock(&priv->lock); + if (priv->ch->is_busy && !(priv->count_is_enabled[RZ_MTU3_16_BIT_MTU1_CH] || + priv->count_is_enabled[RZ_MTU3_32_BIT_CH])) { + mutex_unlock(&priv->lock); + return -EINVAL; + } + + return 0; +} + +static int rz_mtu3_cascade_counts_enable_get(struct counter_device *counter, + u8 *cascade_enable) +{ + struct rz_mtu3_cnt *const priv = counter_priv(counter); + unsigned long tmdr; + int ret; + + ret = rz_mtu3_lock_if_ch0_is_enabled(priv); + if (ret) + return ret; + + pm_runtime_get_sync(priv->ch->dev); + tmdr = rz_mtu3_shared_reg_read(priv->ch, RZ_MTU3_TMDR3); + pm_runtime_put(priv->ch->dev); + *cascade_enable = test_bit(RZ_MTU3_TMDR3_LWA, &tmdr); + mutex_unlock(&priv->lock); + + return 0; +} + +static int rz_mtu3_cascade_counts_enable_set(struct counter_device *counter, + u8 cascade_enable) +{ + struct rz_mtu3_cnt *const priv = counter_priv(counter); + int ret; + + ret = rz_mtu3_lock_if_ch0_is_enabled(priv); + if (ret) + return ret; + + pm_runtime_get_sync(priv->ch->dev); + rz_mtu3_shared_reg_update_bit(priv->ch, RZ_MTU3_TMDR3, + RZ_MTU3_TMDR3_LWA, cascade_enable); + pm_runtime_put(priv->ch->dev); + mutex_unlock(&priv->lock); + + return 0; +} + +static int rz_mtu3_ext_input_phase_clock_select_get(struct counter_device *counter, + u32 *ext_input_phase_clock_select) +{ + struct rz_mtu3_cnt *const priv = counter_priv(counter); + unsigned long tmdr; + int ret; + + ret = rz_mtu3_lock_if_ch0_is_enabled(priv); + if (ret) + return ret; + + pm_runtime_get_sync(priv->ch->dev); + tmdr = rz_mtu3_shared_reg_read(priv->ch, RZ_MTU3_TMDR3); + pm_runtime_put(priv->ch->dev); + *ext_input_phase_clock_select = test_bit(RZ_MTU3_TMDR3_PHCKSEL, &tmdr); + mutex_unlock(&priv->lock); + + return 0; +} + +static int rz_mtu3_ext_input_phase_clock_select_set(struct counter_device *counter, + u32 ext_input_phase_clock_select) +{ + struct rz_mtu3_cnt *const priv = counter_priv(counter); + int ret; + + ret = rz_mtu3_lock_if_ch0_is_enabled(priv); + if (ret) + return ret; + + pm_runtime_get_sync(priv->ch->dev); + rz_mtu3_shared_reg_update_bit(priv->ch, RZ_MTU3_TMDR3, + RZ_MTU3_TMDR3_PHCKSEL, + ext_input_phase_clock_select); + pm_runtime_put(priv->ch->dev); + mutex_unlock(&priv->lock); + + return 0; +} + +static struct counter_comp rz_mtu3_count_ext[] = { + COUNTER_COMP_DIRECTION(rz_mtu3_count_direction_read), + COUNTER_COMP_ENABLE(rz_mtu3_count_enable_read, + rz_mtu3_count_enable_write), + COUNTER_COMP_CEILING(rz_mtu3_count_ceiling_read, + rz_mtu3_count_ceiling_write), +}; + +static const enum counter_synapse_action rz_mtu3_synapse_actions[] = { + COUNTER_SYNAPSE_ACTION_BOTH_EDGES, + COUNTER_SYNAPSE_ACTION_RISING_EDGE, + COUNTER_SYNAPSE_ACTION_NONE, +}; + +static int rz_mtu3_action_read(struct counter_device *counter, + struct counter_count *count, + struct counter_synapse *synapse, + enum counter_synapse_action *action) +{ + const bool is_signal_ab = (synapse->signal->id == SIGNAL_A_ID) || + (synapse->signal->id == SIGNAL_B_ID); + struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, count->id); + struct rz_mtu3_cnt *const priv = counter_priv(counter); + enum counter_function function; + bool mtclkc_mtclkd; + unsigned long tmdr; + int ret; + + ret = rz_mtu3_lock_if_count_is_enabled(ch, priv, count->id); + if (ret) + return ret; + + ret = rz_mtu3_count_function_read_helper(ch, priv, &function); + if (ret) { + mutex_unlock(&priv->lock); + return ret; + } + + /* Default action mode */ + *action = COUNTER_SYNAPSE_ACTION_NONE; + + if (count->id != RZ_MTU3_16_BIT_MTU1_CH) { + tmdr = rz_mtu3_shared_reg_read(priv->ch, RZ_MTU3_TMDR3); + mtclkc_mtclkd = test_bit(RZ_MTU3_TMDR3_PHCKSEL, &tmdr); + if ((mtclkc_mtclkd && is_signal_ab) || + (!mtclkc_mtclkd && !is_signal_ab)) { + mutex_unlock(&priv->lock); + return 0; + } + } + + switch (function) { + case COUNTER_FUNCTION_PULSE_DIRECTION: + /* + * Rising edges on signal A (signal C) updates the respective + * count. The input level of signal B (signal D) determines + * direction. + */ + if (synapse->signal->id == SIGNAL_A_ID || + synapse->signal->id == SIGNAL_C_ID) + *action = COUNTER_SYNAPSE_ACTION_RISING_EDGE; + break; + case COUNTER_FUNCTION_QUADRATURE_X2_B: + /* + * Any state transition on quadrature pair signal B (signal D) + * updates the respective count. + */ + if (synapse->signal->id == SIGNAL_B_ID || + synapse->signal->id == SIGNAL_D_ID) + *action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES; + break; + case COUNTER_FUNCTION_QUADRATURE_X4: + /* counts up/down on both edges of A (C) and B (D) signal */ + *action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES; + break; + default: + /* should never reach this path */ + mutex_unlock(&priv->lock); + return -EINVAL; + } + + mutex_unlock(&priv->lock); + + return 0; +} + +static const struct counter_ops rz_mtu3_cnt_ops = { + .count_read = rz_mtu3_count_read, + .count_write = rz_mtu3_count_write, + .function_read = rz_mtu3_count_function_read, + .function_write = rz_mtu3_count_function_write, + .action_read = rz_mtu3_action_read, +}; + +#define RZ_MTU3_PHASE_SIGNAL(_id, _name) { \ + .id = (_id), \ + .name = (_name), \ +} + +static struct counter_signal rz_mtu3_signals[] = { + RZ_MTU3_PHASE_SIGNAL(SIGNAL_A_ID, "MTU1 MTCLKA"), + RZ_MTU3_PHASE_SIGNAL(SIGNAL_B_ID, "MTU1 MTCLKB"), + RZ_MTU3_PHASE_SIGNAL(SIGNAL_C_ID, "MTU2 MTCLKC"), + RZ_MTU3_PHASE_SIGNAL(SIGNAL_D_ID, "MTU2 MTCLKD"), +}; + +static struct counter_synapse rz_mtu3_mtu1_count_synapses[] = { + { + .actions_list = rz_mtu3_synapse_actions, + .num_actions = ARRAY_SIZE(rz_mtu3_synapse_actions), + .signal = rz_mtu3_signals, + }, + { + .actions_list = rz_mtu3_synapse_actions, + .num_actions = ARRAY_SIZE(rz_mtu3_synapse_actions), + .signal = rz_mtu3_signals + 1, + } +}; + +static struct counter_synapse rz_mtu3_mtu2_count_synapses[] = { + { + .actions_list = rz_mtu3_synapse_actions, + .num_actions = ARRAY_SIZE(rz_mtu3_synapse_actions), + .signal = rz_mtu3_signals, + }, + { + .actions_list = rz_mtu3_synapse_actions, + .num_actions = ARRAY_SIZE(rz_mtu3_synapse_actions), + .signal = rz_mtu3_signals + 1, + }, + { + .actions_list = rz_mtu3_synapse_actions, + .num_actions = ARRAY_SIZE(rz_mtu3_synapse_actions), + .signal = rz_mtu3_signals + 2, + }, + { + .actions_list = rz_mtu3_synapse_actions, + .num_actions = ARRAY_SIZE(rz_mtu3_synapse_actions), + .signal = rz_mtu3_signals + 3, + } +}; + +static struct counter_count rz_mtu3_counts[] = { + { + .id = RZ_MTU3_16_BIT_MTU1_CH, + .name = "Channel 1 Count", + .functions_list = rz_mtu3_count_functions, + .num_functions = ARRAY_SIZE(rz_mtu3_count_functions), + .synapses = rz_mtu3_mtu1_count_synapses, + .num_synapses = ARRAY_SIZE(rz_mtu3_mtu1_count_synapses), + .ext = rz_mtu3_count_ext, + .num_ext = ARRAY_SIZE(rz_mtu3_count_ext), + }, + { + .id = RZ_MTU3_16_BIT_MTU2_CH, + .name = "Channel 2 Count", + .functions_list = rz_mtu3_count_functions, + .num_functions = ARRAY_SIZE(rz_mtu3_count_functions), + .synapses = rz_mtu3_mtu2_count_synapses, + .num_synapses = ARRAY_SIZE(rz_mtu3_mtu2_count_synapses), + .ext = rz_mtu3_count_ext, + .num_ext = ARRAY_SIZE(rz_mtu3_count_ext), + }, + { + .id = RZ_MTU3_32_BIT_CH, + .name = "Channel 1 and 2 (cascaded) Count", + .functions_list = rz_mtu3_count_functions, + .num_functions = ARRAY_SIZE(rz_mtu3_count_functions), + .synapses = rz_mtu3_mtu2_count_synapses, + .num_synapses = ARRAY_SIZE(rz_mtu3_mtu2_count_synapses), + .ext = rz_mtu3_count_ext, + .num_ext = ARRAY_SIZE(rz_mtu3_count_ext), + } +}; + +static const char *const rz_mtu3_ext_input_phase_clock_select[] = { + "MTCLKA-MTCLKB", + "MTCLKC-MTCLKD", +}; + +static DEFINE_COUNTER_ENUM(rz_mtu3_ext_input_phase_clock_select_enum, + rz_mtu3_ext_input_phase_clock_select); + +static struct counter_comp rz_mtu3_device_ext[] = { + COUNTER_COMP_DEVICE_BOOL("cascade_counts_enable", + rz_mtu3_cascade_counts_enable_get, + rz_mtu3_cascade_counts_enable_set), + COUNTER_COMP_DEVICE_ENUM("external_input_phase_clock_select", + rz_mtu3_ext_input_phase_clock_select_get, + rz_mtu3_ext_input_phase_clock_select_set, + rz_mtu3_ext_input_phase_clock_select_enum), +}; + +static int rz_mtu3_cnt_pm_runtime_suspend(struct device *dev) +{ + struct clk *const clk = dev_get_drvdata(dev); + + clk_disable_unprepare(clk); + + return 0; +} + +static int rz_mtu3_cnt_pm_runtime_resume(struct device *dev) +{ + struct clk *const clk = dev_get_drvdata(dev); + + clk_prepare_enable(clk); + + return 0; +} + +static DEFINE_RUNTIME_DEV_PM_OPS(rz_mtu3_cnt_pm_ops, + rz_mtu3_cnt_pm_runtime_suspend, + rz_mtu3_cnt_pm_runtime_resume, NULL); + +static void rz_mtu3_cnt_pm_disable(void *data) +{ + struct device *dev = data; + + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); +} + +static int rz_mtu3_cnt_probe(struct platform_device *pdev) +{ + struct rz_mtu3 *ddata = dev_get_drvdata(pdev->dev.parent); + struct device *dev = &pdev->dev; + struct counter_device *counter; + struct rz_mtu3_channel *ch; + struct rz_mtu3_cnt *priv; + unsigned int i; + int ret; + + counter = devm_counter_alloc(dev, sizeof(*priv)); + if (!counter) + return -ENOMEM; + + priv = counter_priv(counter); + priv->clk = ddata->clk; + priv->mtu_32bit_max = U32_MAX; + priv->ch = &ddata->channels[RZ_MTU3_CHAN_1]; + ch = &priv->ch[0]; + for (i = 0; i < RZ_MTU3_MAX_HW_CNTR_CHANNELS; i++) { + ch->dev = dev; + priv->mtu_16bit_max[i] = U16_MAX; + ch++; + } + + mutex_init(&priv->lock); + platform_set_drvdata(pdev, priv->clk); + clk_prepare_enable(priv->clk); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + ret = devm_add_action_or_reset(&pdev->dev, rz_mtu3_cnt_pm_disable, dev); + if (ret < 0) + goto disable_clock; + + counter->name = dev_name(dev); + counter->parent = dev; + counter->ops = &rz_mtu3_cnt_ops; + counter->counts = rz_mtu3_counts; + counter->num_counts = ARRAY_SIZE(rz_mtu3_counts); + counter->signals = rz_mtu3_signals; + counter->num_signals = ARRAY_SIZE(rz_mtu3_signals); + counter->ext = rz_mtu3_device_ext; + counter->num_ext = ARRAY_SIZE(rz_mtu3_device_ext); + + /* Register Counter device */ + ret = devm_counter_add(dev, counter); + if (ret < 0) { + dev_err_probe(dev, ret, "Failed to add counter\n"); + goto disable_clock; + } + + return 0; + +disable_clock: + clk_disable_unprepare(priv->clk); + + return ret; +} + +static struct platform_driver rz_mtu3_cnt_driver = { + .probe = rz_mtu3_cnt_probe, + .driver = { + .name = "rz-mtu3-counter", + .pm = pm_ptr(&rz_mtu3_cnt_pm_ops), + }, +}; +module_platform_driver(rz_mtu3_cnt_driver); + +MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>"); +MODULE_ALIAS("platform:rz-mtu3-counter"); +MODULE_DESCRIPTION("Renesas RZ/G2L MTU3a counter driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(COUNTER); diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index b81393072715..5521f060d58e 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1292,6 +1292,18 @@ config GPIO_KEMPLD This driver can also be built as a module. If so, the module will be called gpio-kempld. +config GPIO_LJCA + tristate "INTEL La Jolla Cove Adapter GPIO support" + depends on MFD_LJCA + select GPIOLIB_IRQCHIP + default MFD_LJCA + help + Select this option to enable GPIO driver for the INTEL + La Jolla Cove Adapter (LJCA) board. + + This driver can also be built as a module. If so, the module + will be called gpio-ljca. + config GPIO_LP3943 tristate "TI/National Semiconductor LP3943 GPIO expander" depends on MFD_LP3943 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 8309b4ff128b..20036af3acb1 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -79,6 +79,7 @@ obj-$(CONFIG_GPIO_IXP4XX) += gpio-ixp4xx.o obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o obj-$(CONFIG_GPIO_KEMPLD) += gpio-kempld.o obj-$(CONFIG_GPIO_LATCH) += gpio-latch.o +obj-$(CONFIG_GPIO_LJCA) += gpio-ljca.o obj-$(CONFIG_GPIO_LOGICVC) += gpio-logicvc.o obj-$(CONFIG_GPIO_LOONGSON1) += gpio-loongson1.o obj-$(CONFIG_GPIO_LOONGSON) += gpio-loongson.o diff --git a/drivers/gpio/gpio-ljca.c b/drivers/gpio/gpio-ljca.c new file mode 100644 index 000000000000..87863f0230f5 --- /dev/null +++ b/drivers/gpio/gpio-ljca.c @@ -0,0 +1,454 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Intel La Jolla Cove Adapter USB-GPIO driver + * + * Copyright (c) 2023, Intel Corporation. + */ + +#include <linux/acpi.h> +#include <linux/bitfield.h> +#include <linux/bitops.h> +#include <linux/dev_printk.h> +#include <linux/gpio/driver.h> +#include <linux/irq.h> +#include <linux/kernel.h> +#include <linux/kref.h> +#include <linux/mfd/ljca.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/types.h> + +/* GPIO commands */ +#define LJCA_GPIO_CONFIG 1 +#define LJCA_GPIO_READ 2 +#define LJCA_GPIO_WRITE 3 +#define LJCA_GPIO_INT_EVENT 4 +#define LJCA_GPIO_INT_MASK 5 +#define LJCA_GPIO_INT_UNMASK 6 + +#define LJCA_GPIO_CONF_DISABLE BIT(0) +#define LJCA_GPIO_CONF_INPUT BIT(1) +#define LJCA_GPIO_CONF_OUTPUT BIT(2) +#define LJCA_GPIO_CONF_PULLUP BIT(3) +#define LJCA_GPIO_CONF_PULLDOWN BIT(4) +#define LJCA_GPIO_CONF_DEFAULT BIT(5) +#define LJCA_GPIO_CONF_INTERRUPT BIT(6) +#define LJCA_GPIO_INT_TYPE BIT(7) + +#define LJCA_GPIO_CONF_EDGE FIELD_PREP(LJCA_GPIO_INT_TYPE, 1) +#define LJCA_GPIO_CONF_LEVEL FIELD_PREP(LJCA_GPIO_INT_TYPE, 0) + +/* Intentional overlap with PULLUP / PULLDOWN */ +#define LJCA_GPIO_CONF_SET BIT(3) +#define LJCA_GPIO_CONF_CLR BIT(4) + +struct gpio_op { + u8 index; + u8 value; +} __packed; + +struct gpio_packet { + u8 num; + struct gpio_op item[]; +} __packed; + +#define LJCA_GPIO_BUF_SIZE 60 +struct ljca_gpio_dev { + struct platform_device *pdev; + struct gpio_chip gc; + struct ljca_gpio_info *gpio_info; + DECLARE_BITMAP(unmasked_irqs, LJCA_MAX_GPIO_NUM); + DECLARE_BITMAP(enabled_irqs, LJCA_MAX_GPIO_NUM); + DECLARE_BITMAP(reenable_irqs, LJCA_MAX_GPIO_NUM); + u8 *connect_mode; + /* mutex to protect irq bus */ + struct mutex irq_lock; + struct work_struct work; + /* lock to protect package transfer to Hardware */ + struct mutex trans_lock; + + u8 obuf[LJCA_GPIO_BUF_SIZE]; + u8 ibuf[LJCA_GPIO_BUF_SIZE]; +}; + +static int gpio_config(struct ljca_gpio_dev *ljca_gpio, u8 gpio_id, u8 config) +{ + struct gpio_packet *packet = (struct gpio_packet *)ljca_gpio->obuf; + int ret; + + mutex_lock(&ljca_gpio->trans_lock); + packet->item[0].index = gpio_id; + packet->item[0].value = config | ljca_gpio->connect_mode[gpio_id]; + packet->num = 1; + + ret = ljca_transfer(ljca_gpio->gpio_info->ljca, LJCA_GPIO_CONFIG, packet, + struct_size(packet, item, packet->num), NULL, NULL); + mutex_unlock(&ljca_gpio->trans_lock); + return ret; +} + +static int ljca_gpio_read(struct ljca_gpio_dev *ljca_gpio, u8 gpio_id) +{ + struct gpio_packet *packet = (struct gpio_packet *)ljca_gpio->obuf; + struct gpio_packet *ack_packet = (struct gpio_packet *)ljca_gpio->ibuf; + unsigned int ibuf_len = LJCA_GPIO_BUF_SIZE; + int ret; + + mutex_lock(&ljca_gpio->trans_lock); + packet->num = 1; + packet->item[0].index = gpio_id; + ret = ljca_transfer(ljca_gpio->gpio_info->ljca, LJCA_GPIO_READ, packet, + struct_size(packet, item, packet->num), ljca_gpio->ibuf, &ibuf_len); + if (ret) + goto out_unlock; + + if (!ibuf_len || ack_packet->num != packet->num) { + dev_err(&ljca_gpio->pdev->dev, "failed gpio_id:%u %u", gpio_id, ack_packet->num); + ret = -EIO; + } + +out_unlock: + mutex_unlock(&ljca_gpio->trans_lock); + if (ret) + return ret; + return ack_packet->item[0].value > 0; +} + +static int ljca_gpio_write(struct ljca_gpio_dev *ljca_gpio, u8 gpio_id, + int value) +{ + struct gpio_packet *packet = (struct gpio_packet *)ljca_gpio->obuf; + int ret; + + mutex_lock(&ljca_gpio->trans_lock); + packet->num = 1; + packet->item[0].index = gpio_id; + packet->item[0].value = value & 1; + + ret = ljca_transfer(ljca_gpio->gpio_info->ljca, LJCA_GPIO_WRITE, packet, + struct_size(packet, item, packet->num), NULL, NULL); + mutex_unlock(&ljca_gpio->trans_lock); + return ret; +} + +static int ljca_gpio_get_value(struct gpio_chip *chip, unsigned int offset) +{ + struct ljca_gpio_dev *ljca_gpio = gpiochip_get_data(chip); + + return ljca_gpio_read(ljca_gpio, offset); +} + +static void ljca_gpio_set_value(struct gpio_chip *chip, unsigned int offset, + int val) +{ + struct ljca_gpio_dev *ljca_gpio = gpiochip_get_data(chip); + int ret; + + ret = ljca_gpio_write(ljca_gpio, offset, val); + if (ret) + dev_err(chip->parent, "offset:%u val:%d set value failed %d\n", offset, val, ret); +} + +static int ljca_gpio_direction_input(struct gpio_chip *chip, + unsigned int offset) +{ + struct ljca_gpio_dev *ljca_gpio = gpiochip_get_data(chip); + u8 config = LJCA_GPIO_CONF_INPUT | LJCA_GPIO_CONF_CLR; + + return gpio_config(ljca_gpio, offset, config); +} + +static int ljca_gpio_direction_output(struct gpio_chip *chip, + unsigned int offset, int val) +{ + struct ljca_gpio_dev *ljca_gpio = gpiochip_get_data(chip); + u8 config = LJCA_GPIO_CONF_OUTPUT | LJCA_GPIO_CONF_CLR; + int ret; + + ret = gpio_config(ljca_gpio, offset, config); + if (ret) + return ret; + + ljca_gpio_set_value(chip, offset, val); + return 0; +} + +static int ljca_gpio_set_config(struct gpio_chip *chip, unsigned int offset, + unsigned long config) +{ + struct ljca_gpio_dev *ljca_gpio = gpiochip_get_data(chip); + + ljca_gpio->connect_mode[offset] = 0; + switch (pinconf_to_config_param(config)) { + case PIN_CONFIG_BIAS_PULL_UP: + ljca_gpio->connect_mode[offset] |= LJCA_GPIO_CONF_PULLUP; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + ljca_gpio->connect_mode[offset] |= LJCA_GPIO_CONF_PULLDOWN; + break; + case PIN_CONFIG_DRIVE_PUSH_PULL: + case PIN_CONFIG_PERSIST_STATE: + break; + default: + return -ENOTSUPP; + } + + return 0; +} + +static int ljca_gpio_init_valid_mask(struct gpio_chip *chip, unsigned long *valid_mask, + unsigned int ngpios) +{ + struct ljca_gpio_dev *ljca_gpio = gpiochip_get_data(chip); + + WARN_ON_ONCE(ngpios != ljca_gpio->gpio_info->num); + bitmap_copy(valid_mask, ljca_gpio->gpio_info->valid_pin_map, ngpios); + + return 0; +} + +static void ljca_gpio_irq_init_valid_mask(struct gpio_chip *chip, unsigned long *valid_mask, + unsigned int ngpios) +{ + ljca_gpio_init_valid_mask(chip, valid_mask, ngpios); +} + +static int ljca_enable_irq(struct ljca_gpio_dev *ljca_gpio, int gpio_id, bool enable) +{ + struct gpio_packet *packet = (struct gpio_packet *)ljca_gpio->obuf; + int ret; + + mutex_lock(&ljca_gpio->trans_lock); + packet->num = 1; + packet->item[0].index = gpio_id; + packet->item[0].value = 0; + + ret = ljca_transfer(ljca_gpio->gpio_info->ljca, + enable ? LJCA_GPIO_INT_UNMASK : LJCA_GPIO_INT_MASK, packet, + struct_size(packet, item, packet->num), NULL, NULL); + mutex_unlock(&ljca_gpio->trans_lock); + return ret; +} + +static void ljca_gpio_async(struct work_struct *work) +{ + struct ljca_gpio_dev *ljca_gpio = container_of(work, struct ljca_gpio_dev, work); + int gpio_id; + int unmasked; + + for_each_set_bit(gpio_id, ljca_gpio->reenable_irqs, ljca_gpio->gc.ngpio) { + clear_bit(gpio_id, ljca_gpio->reenable_irqs); + unmasked = test_bit(gpio_id, ljca_gpio->unmasked_irqs); + if (unmasked) + ljca_enable_irq(ljca_gpio, gpio_id, true); + } +} + +static void ljca_gpio_event_cb(void *context, u8 cmd, const void *evt_data, int len) +{ + const struct gpio_packet *packet = evt_data; + struct ljca_gpio_dev *ljca_gpio = context; + int i; + int irq; + + if (cmd != LJCA_GPIO_INT_EVENT) + return; + + for (i = 0; i < packet->num; i++) { + irq = irq_find_mapping(ljca_gpio->gc.irq.domain, packet->item[i].index); + if (!irq) { + dev_err(ljca_gpio->gc.parent, "gpio_id %u does not mapped to IRQ yet\n", + packet->item[i].index); + return; + } + + generic_handle_domain_irq(ljca_gpio->gc.irq.domain, irq); + set_bit(packet->item[i].index, ljca_gpio->reenable_irqs); + } + + schedule_work(&ljca_gpio->work); +} + +static void ljca_irq_unmask(struct irq_data *irqd) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); + struct ljca_gpio_dev *ljca_gpio = gpiochip_get_data(gc); + int gpio_id = irqd_to_hwirq(irqd); + + gpiochip_enable_irq(gc, gpio_id); + set_bit(gpio_id, ljca_gpio->unmasked_irqs); +} + +static void ljca_irq_mask(struct irq_data *irqd) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); + struct ljca_gpio_dev *ljca_gpio = gpiochip_get_data(gc); + int gpio_id = irqd_to_hwirq(irqd); + + clear_bit(gpio_id, ljca_gpio->unmasked_irqs); + gpiochip_disable_irq(gc, gpio_id); +} + +static int ljca_irq_set_type(struct irq_data *irqd, unsigned int type) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); + struct ljca_gpio_dev *ljca_gpio = gpiochip_get_data(gc); + int gpio_id = irqd_to_hwirq(irqd); + + ljca_gpio->connect_mode[gpio_id] = LJCA_GPIO_CONF_INTERRUPT; + switch (type) { + case IRQ_TYPE_LEVEL_HIGH: + ljca_gpio->connect_mode[gpio_id] |= (LJCA_GPIO_CONF_LEVEL | LJCA_GPIO_CONF_PULLUP); + break; + case IRQ_TYPE_LEVEL_LOW: + ljca_gpio->connect_mode[gpio_id] |= (LJCA_GPIO_CONF_LEVEL | LJCA_GPIO_CONF_PULLDOWN); + break; + case IRQ_TYPE_EDGE_BOTH: + break; + case IRQ_TYPE_EDGE_RISING: + ljca_gpio->connect_mode[gpio_id] |= (LJCA_GPIO_CONF_EDGE | LJCA_GPIO_CONF_PULLUP); + break; + case IRQ_TYPE_EDGE_FALLING: + ljca_gpio->connect_mode[gpio_id] |= (LJCA_GPIO_CONF_EDGE | LJCA_GPIO_CONF_PULLDOWN); + break; + default: + return -EINVAL; + } + + return 0; +} + +static void ljca_irq_bus_lock(struct irq_data *irqd) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); + struct ljca_gpio_dev *ljca_gpio = gpiochip_get_data(gc); + + mutex_lock(&ljca_gpio->irq_lock); +} + +static void ljca_irq_bus_unlock(struct irq_data *irqd) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); + struct ljca_gpio_dev *ljca_gpio = gpiochip_get_data(gc); + int gpio_id = irqd_to_hwirq(irqd); + int enabled; + int unmasked; + + enabled = test_bit(gpio_id, ljca_gpio->enabled_irqs); + unmasked = test_bit(gpio_id, ljca_gpio->unmasked_irqs); + + if (enabled != unmasked) { + if (unmasked) { + gpio_config(ljca_gpio, gpio_id, 0); + ljca_enable_irq(ljca_gpio, gpio_id, true); + set_bit(gpio_id, ljca_gpio->enabled_irqs); + } else { + ljca_enable_irq(ljca_gpio, gpio_id, false); + clear_bit(gpio_id, ljca_gpio->enabled_irqs); + } + } + + mutex_unlock(&ljca_gpio->irq_lock); +} + +static const struct irq_chip ljca_gpio_irqchip = { + .name = "ljca-irq", + .irq_mask = ljca_irq_mask, + .irq_unmask = ljca_irq_unmask, + .irq_set_type = ljca_irq_set_type, + .irq_bus_lock = ljca_irq_bus_lock, + .irq_bus_sync_unlock = ljca_irq_bus_unlock, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + +static int ljca_gpio_probe(struct platform_device *pdev) +{ + struct ljca_gpio_dev *ljca_gpio; + struct gpio_irq_chip *girq; + int ret; + + ljca_gpio = devm_kzalloc(&pdev->dev, sizeof(*ljca_gpio), GFP_KERNEL); + if (!ljca_gpio) + return -ENOMEM; + + ljca_gpio->gpio_info = dev_get_platdata(&pdev->dev); + ljca_gpio->connect_mode = devm_kcalloc(&pdev->dev, ljca_gpio->gpio_info->num, + sizeof(*ljca_gpio->connect_mode), GFP_KERNEL); + if (!ljca_gpio->connect_mode) + return -ENOMEM; + + mutex_init(&ljca_gpio->irq_lock); + mutex_init(&ljca_gpio->trans_lock); + ljca_gpio->pdev = pdev; + ljca_gpio->gc.direction_input = ljca_gpio_direction_input; + ljca_gpio->gc.direction_output = ljca_gpio_direction_output; + ljca_gpio->gc.get = ljca_gpio_get_value; + ljca_gpio->gc.set = ljca_gpio_set_value; + ljca_gpio->gc.set_config = ljca_gpio_set_config; + ljca_gpio->gc.init_valid_mask = ljca_gpio_init_valid_mask; + ljca_gpio->gc.can_sleep = true; + ljca_gpio->gc.parent = &pdev->dev; + + ljca_gpio->gc.base = -1; + ljca_gpio->gc.ngpio = ljca_gpio->gpio_info->num; + ljca_gpio->gc.label = ACPI_COMPANION(&pdev->dev) ? + acpi_dev_name(ACPI_COMPANION(&pdev->dev)) : + dev_name(&pdev->dev); + ljca_gpio->gc.owner = THIS_MODULE; + + platform_set_drvdata(pdev, ljca_gpio); + ljca_register_event_cb(ljca_gpio->gpio_info->ljca, ljca_gpio_event_cb, ljca_gpio); + + girq = &ljca_gpio->gc.irq; + gpio_irq_chip_set_chip(girq, &ljca_gpio_irqchip); + girq->parent_handler = NULL; + girq->num_parents = 0; + girq->parents = NULL; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_simple_irq; + girq->init_valid_mask = ljca_gpio_irq_init_valid_mask; + + INIT_WORK(&ljca_gpio->work, ljca_gpio_async); + ret = gpiochip_add_data(&ljca_gpio->gc, ljca_gpio); + if (ret) { + ljca_unregister_event_cb(ljca_gpio->gpio_info->ljca); + mutex_destroy(&ljca_gpio->irq_lock); + mutex_destroy(&ljca_gpio->trans_lock); + } + + return ret; +} + +static int ljca_gpio_remove(struct platform_device *pdev) +{ + struct ljca_gpio_dev *ljca_gpio = platform_get_drvdata(pdev); + + gpiochip_remove(&ljca_gpio->gc); + ljca_unregister_event_cb(ljca_gpio->gpio_info->ljca); + mutex_destroy(&ljca_gpio->irq_lock); + mutex_destroy(&ljca_gpio->trans_lock); + return 0; +} + +#define LJCA_GPIO_DRV_NAME "ljca-gpio" +static const struct platform_device_id ljca_gpio_id[] = { + { LJCA_GPIO_DRV_NAME, 0 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, ljca_gpio_id); + +static struct platform_driver ljca_gpio_driver = { + .driver.name = LJCA_GPIO_DRV_NAME, + .probe = ljca_gpio_probe, + .remove = ljca_gpio_remove, +}; +module_platform_driver(ljca_gpio_driver); + +MODULE_AUTHOR("Ye Xiang <xiang.ye@intel.com>"); +MODULE_AUTHOR("Wang Zhifeng <zhifeng.wang@intel.com>"); +MODULE_AUTHOR("Zhang Lixu <lixu.zhang@intel.com>"); +MODULE_DESCRIPTION("Intel La Jolla Cove Adapter USB-GPIO driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(LJCA); diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 6ba7169cb953..aabac37c3502 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -1117,8 +1117,7 @@ static int pm860x_dt_init(struct device_node *np, { int ret; - if (of_get_property(np, "marvell,88pm860x-irq-read-clr", NULL)) - pdata->irq_mode = 1; + pdata->irq_mode = of_property_read_bool(np, "marvell,88pm860x-irq-read-clr"); ret = of_property_read_u32(np, "marvell,88pm860x-slave-addr", &pdata->companion_addr); if (ret) { @@ -1276,4 +1275,3 @@ module_exit(pm860x_i2c_exit); MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM860x"); MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index fcc141e067b9..e90463c4441c 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -266,6 +266,16 @@ config MFD_MADERA_SPI Support for the Cirrus Logic Madera platform audio SoC core functionality controlled via SPI. +config MFD_MAX597X + tristate "Maxim 597x power switch and monitor" + depends on (I2C && OF) + select MFD_SIMPLE_MFD_I2C + help + This driver controls a Maxim 5970/5978 switch via I2C bus. + The MAX5970/5978 is a smart switch with no output regulation, but + fault protection and voltage and current monitoring capabilities. + Also it supports upto 4 indication leds. + config MFD_CS47L15 bool "Cirrus Logic CS47L15" select PINCTRL_CS47L15 @@ -353,9 +363,6 @@ config MFD_DA9055 Additional drivers must be enabled in order to use the functionality of the device. - This driver can be built as a module. If built as a module it will be - called "da9055" - config MFD_DA9062 tristate "Dialog Semiconductor DA9062/61 PMIC Support" select MFD_CORE @@ -1308,6 +1315,16 @@ config MFD_SC27XX_PMIC This driver provides common support for accessing the SC27xx PMICs, and it also adds the irq_chip parts for handling the PMIC chip events. +config RZ_MTU3 + bool "Renesas RZ/G2L MTU3a core driver" + depends on (ARCH_RZG2L && OF) || COMPILE_TEST + help + Select this option to enable Renesas RZ/G2L MTU3a core driver for + the Multi-Function Timer Pulse Unit 3 (MTU3a) hardware available + on SoCs from Renesas. The core driver shares the clk and channel + register access for the other child devices like Counter, PWM, + Clock Source, and Clock event. + config ABX500_CORE bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions" depends on ARCH_U8500 || COMPILE_TEST diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 2f6c89d1e277..1d2392f06f78 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -174,6 +174,7 @@ pcf50633-objs := pcf50633-core.o pcf50633-irq.o obj-$(CONFIG_MFD_PCF50633) += pcf50633.o obj-$(CONFIG_PCF50633_ADC) += pcf50633-adc.o obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o +obj-$(CONFIG_RZ_MTU3) += rz-mtu3.o obj-$(CONFIG_ABX500_CORE) += abx500-core.o obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o # ab8500-core need to come after db8500-prcmu (which provides the channel) diff --git a/drivers/mfd/arizona-i2c.c b/drivers/mfd/arizona-i2c.c index b2301586adbc..43e393c8608d 100644 --- a/drivers/mfd/arizona-i2c.c +++ b/drivers/mfd/arizona-i2c.c @@ -112,6 +112,7 @@ static const struct of_device_id arizona_i2c_of_match[] = { { .compatible = "wlf,wm1814", .data = (void *)WM1814 }, {}, }; +MODULE_DEVICE_TABLE(of, arizona_i2c_of_match); #endif static struct i2c_driver arizona_i2c_driver = { diff --git a/drivers/mfd/arizona-spi.c b/drivers/mfd/arizona-spi.c index da05b966d48c..02cf4f3e91d7 100644 --- a/drivers/mfd/arizona-spi.c +++ b/drivers/mfd/arizona-spi.c @@ -277,6 +277,7 @@ static const struct of_device_id arizona_spi_of_match[] = { { .compatible = "cirrus,cs47l24", .data = (void *)CS47L24 }, {}, }; +MODULE_DEVICE_TABLE(of, arizona_spi_of_match); #endif static struct spi_driver arizona_spi_driver = { diff --git a/drivers/mfd/atc260x-i2c.c b/drivers/mfd/atc260x-i2c.c index 19e248ed7966..8e1491167160 100644 --- a/drivers/mfd/atc260x-i2c.c +++ b/drivers/mfd/atc260x-i2c.c @@ -51,7 +51,7 @@ MODULE_DEVICE_TABLE(of, atc260x_i2c_of_match); static struct i2c_driver atc260x_i2c_driver = { .driver = { .name = "atc260x", - .of_match_table = of_match_ptr(atc260x_i2c_of_match), + .of_match_table = atc260x_i2c_of_match, }, .probe_new = atc260x_i2c_probe, }; diff --git a/drivers/mfd/atmel-flexcom.c b/drivers/mfd/atmel-flexcom.c index 33caa4fba6af..b52f7ffdad35 100644 --- a/drivers/mfd/atmel-flexcom.c +++ b/drivers/mfd/atmel-flexcom.c @@ -37,7 +37,6 @@ struct atmel_flexcom { static int atmel_flexcom_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - struct resource *res; struct atmel_flexcom *ddata; int err; @@ -55,8 +54,7 @@ static int atmel_flexcom_probe(struct platform_device *pdev) ddata->opmode > ATMEL_FLEXCOM_MODE_TWI) return -EINVAL; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ddata->base = devm_ioremap_resource(&pdev->dev, res); + ddata->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); if (IS_ERR(ddata->base)) return PTR_ERR(ddata->base); diff --git a/drivers/mfd/atmel-smc.c b/drivers/mfd/atmel-smc.c index f3bad2b52f17..e560066e5885 100644 --- a/drivers/mfd/atmel-smc.c +++ b/drivers/mfd/atmel-smc.c @@ -323,7 +323,7 @@ static const struct atmel_hsmc_reg_layout sama5d2_reg_layout = { .timing_regs_offset = 0x700, }; -static const struct of_device_id atmel_smc_ids[] = { +static const struct of_device_id atmel_smc_ids[] __maybe_unused = { { .compatible = "atmel,at91sam9260-smc", .data = NULL }, { .compatible = "atmel,sama5d3-smc", .data = &sama5d3_reg_layout }, { .compatible = "atmel,sama5d2-smc", .data = &sama5d2_reg_layout }, diff --git a/drivers/mfd/axp20x-i2c.c b/drivers/mfd/axp20x-i2c.c index f49fbd307958..b4f5cb457117 100644 --- a/drivers/mfd/axp20x-i2c.c +++ b/drivers/mfd/axp20x-i2c.c @@ -65,6 +65,7 @@ static const struct of_device_id axp20x_i2c_of_match[] = { { .compatible = "x-powers,axp223", .data = (void *)AXP223_ID }, { .compatible = "x-powers,axp803", .data = (void *)AXP803_ID }, { .compatible = "x-powers,axp806", .data = (void *)AXP806_ID }, + { .compatible = "x-powers,axp15060", .data = (void *)AXP15060_ID }, { }, }; MODULE_DEVICE_TABLE(of, axp20x_i2c_of_match); @@ -78,6 +79,7 @@ static const struct i2c_device_id axp20x_i2c_id[] = { { "axp223", 0 }, { "axp803", 0 }, { "axp806", 0 }, + { "axp15060", 0 }, { }, }; MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id); diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c index 01a6bbb6d266..72b87aae60cc 100644 --- a/drivers/mfd/axp20x.c +++ b/drivers/mfd/axp20x.c @@ -43,6 +43,7 @@ static const char * const axp20x_model_names[] = { "AXP806", "AXP809", "AXP813", + "AXP15060", }; static const struct regmap_range axp152_writeable_ranges[] = { @@ -119,6 +120,7 @@ static const struct regmap_access_table axp22x_volatile_table = { /* AXP288 ranges are shared with the AXP803, as they cover the same range */ static const struct regmap_range axp288_writeable_ranges[] = { + regmap_reg_range(AXP288_POWER_REASON, AXP288_POWER_REASON), regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ6_STATE), regmap_reg_range(AXP20X_DCDC_MODE, AXP288_FG_TUNE5), }; @@ -168,6 +170,31 @@ static const struct regmap_access_table axp806_volatile_table = { .n_yes_ranges = ARRAY_SIZE(axp806_volatile_ranges), }; +static const struct regmap_range axp15060_writeable_ranges[] = { + regmap_reg_range(AXP15060_PWR_OUT_CTRL1, AXP15060_DCDC_MODE_CTRL2), + regmap_reg_range(AXP15060_OUTPUT_MONITOR_DISCHARGE, AXP15060_CPUSLDO_V_CTRL), + regmap_reg_range(AXP15060_PWR_WAKEUP_CTRL, AXP15060_PWR_DISABLE_DOWN_SEQ), + regmap_reg_range(AXP15060_PEK_KEY, AXP15060_PEK_KEY), + regmap_reg_range(AXP15060_IRQ1_EN, AXP15060_IRQ2_EN), + regmap_reg_range(AXP15060_IRQ1_STATE, AXP15060_IRQ2_STATE), +}; + +static const struct regmap_range axp15060_volatile_ranges[] = { + regmap_reg_range(AXP15060_STARTUP_SRC, AXP15060_STARTUP_SRC), + regmap_reg_range(AXP15060_PWR_WAKEUP_CTRL, AXP15060_PWR_DISABLE_DOWN_SEQ), + regmap_reg_range(AXP15060_IRQ1_STATE, AXP15060_IRQ2_STATE), +}; + +static const struct regmap_access_table axp15060_writeable_table = { + .yes_ranges = axp15060_writeable_ranges, + .n_yes_ranges = ARRAY_SIZE(axp15060_writeable_ranges), +}; + +static const struct regmap_access_table axp15060_volatile_table = { + .yes_ranges = axp15060_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(axp15060_volatile_ranges), +}; + static const struct resource axp152_pek_resources[] = { DEFINE_RES_IRQ_NAMED(AXP152_IRQ_PEK_RIS_EDGE, "PEK_DBR"), DEFINE_RES_IRQ_NAMED(AXP152_IRQ_PEK_FAL_EDGE, "PEK_DBF"), @@ -236,6 +263,11 @@ static const struct resource axp809_pek_resources[] = { DEFINE_RES_IRQ_NAMED(AXP809_IRQ_PEK_FAL_EDGE, "PEK_DBF"), }; +static const struct resource axp15060_pek_resources[] = { + DEFINE_RES_IRQ_NAMED(AXP15060_IRQ_PEK_RIS_EDGE, "PEK_DBR"), + DEFINE_RES_IRQ_NAMED(AXP15060_IRQ_PEK_FAL_EDGE, "PEK_DBF"), +}; + static const struct regmap_config axp152_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -281,6 +313,15 @@ static const struct regmap_config axp806_regmap_config = { .cache_type = REGCACHE_RBTREE, }; +static const struct regmap_config axp15060_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .wr_table = &axp15060_writeable_table, + .volatile_table = &axp15060_volatile_table, + .max_register = AXP15060_IRQ2_STATE, + .cache_type = REGCACHE_RBTREE, +}; + #define INIT_REGMAP_IRQ(_variant, _irq, _off, _mask) \ [_variant##_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) } @@ -502,6 +543,23 @@ static const struct regmap_irq axp809_regmap_irqs[] = { INIT_REGMAP_IRQ(AXP809, GPIO0_INPUT, 4, 0), }; +static const struct regmap_irq axp15060_regmap_irqs[] = { + INIT_REGMAP_IRQ(AXP15060, DIE_TEMP_HIGH_LV1, 0, 0), + INIT_REGMAP_IRQ(AXP15060, DIE_TEMP_HIGH_LV2, 0, 1), + INIT_REGMAP_IRQ(AXP15060, DCDC1_V_LOW, 0, 2), + INIT_REGMAP_IRQ(AXP15060, DCDC2_V_LOW, 0, 3), + INIT_REGMAP_IRQ(AXP15060, DCDC3_V_LOW, 0, 4), + INIT_REGMAP_IRQ(AXP15060, DCDC4_V_LOW, 0, 5), + INIT_REGMAP_IRQ(AXP15060, DCDC5_V_LOW, 0, 6), + INIT_REGMAP_IRQ(AXP15060, DCDC6_V_LOW, 0, 7), + INIT_REGMAP_IRQ(AXP15060, PEK_LONG, 1, 0), + INIT_REGMAP_IRQ(AXP15060, PEK_SHORT, 1, 1), + INIT_REGMAP_IRQ(AXP15060, GPIO1_INPUT, 1, 2), + INIT_REGMAP_IRQ(AXP15060, PEK_FAL_EDGE, 1, 3), + INIT_REGMAP_IRQ(AXP15060, PEK_RIS_EDGE, 1, 4), + INIT_REGMAP_IRQ(AXP15060, GPIO2_INPUT, 1, 5), +}; + static const struct regmap_irq_chip axp152_regmap_irq_chip = { .name = "axp152_irq_chip", .status_base = AXP152_IRQ1_STATE, @@ -581,6 +639,17 @@ static const struct regmap_irq_chip axp809_regmap_irq_chip = { .num_regs = 5, }; +static const struct regmap_irq_chip axp15060_regmap_irq_chip = { + .name = "axp15060", + .status_base = AXP15060_IRQ1_STATE, + .ack_base = AXP15060_IRQ1_STATE, + .unmask_base = AXP15060_IRQ1_EN, + .init_ack_masked = true, + .irqs = axp15060_regmap_irqs, + .num_irqs = ARRAY_SIZE(axp15060_regmap_irqs), + .num_regs = 2, +}; + static const struct mfd_cell axp20x_cells[] = { { .name = "axp20x-gpio", @@ -825,6 +894,23 @@ static const struct mfd_cell axp813_cells[] = { }, }; +static const struct mfd_cell axp15060_cells[] = { + { + .name = "axp221-pek", + .num_resources = ARRAY_SIZE(axp15060_pek_resources), + .resources = axp15060_pek_resources, + }, { + .name = "axp20x-regulator", + }, +}; + +/* For boards that don't have IRQ line connected to SOC. */ +static const struct mfd_cell axp_regulator_only_cells[] = { + { + .name = "axp20x-regulator", + }, +}; + static int axp20x_power_off(struct sys_off_data *data) { struct axp20x_dev *axp20x = data->cb_data; @@ -934,6 +1020,28 @@ int axp20x_match_device(struct axp20x_dev *axp20x) */ axp20x->regmap_irq_chip = &axp803_regmap_irq_chip; break; + case AXP15060_ID: + /* + * Don't register the power key part if there is no interrupt + * line. + * + * Since most use cases of AXP PMICs are Allwinner SOCs, board + * designers follow Allwinner's reference design and connects + * IRQ line to SOC, there's no need for those variants to deal + * with cases that IRQ isn't connected. However, AXP15660 is + * used by some other vendors' SOCs that didn't connect IRQ + * line, we need to deal with this case. + */ + if (axp20x->irq > 0) { + axp20x->nr_cells = ARRAY_SIZE(axp15060_cells); + axp20x->cells = axp15060_cells; + } else { + axp20x->nr_cells = ARRAY_SIZE(axp_regulator_only_cells); + axp20x->cells = axp_regulator_only_cells; + } + axp20x->regmap_cfg = &axp15060_regmap_config; + axp20x->regmap_irq_chip = &axp15060_regmap_irq_chip; + break; default: dev_err(dev, "unsupported AXP20X ID %lu\n", axp20x->variant); return -EINVAL; diff --git a/drivers/mfd/bcm2835-pm.c b/drivers/mfd/bcm2835-pm.c index 49cd1f03884a..3cb2b9423121 100644 --- a/drivers/mfd/bcm2835-pm.c +++ b/drivers/mfd/bcm2835-pm.c @@ -28,7 +28,7 @@ static const struct mfd_cell bcm2835_power_devs[] = { static int bcm2835_pm_get_pdata(struct platform_device *pdev, struct bcm2835_pm *pm) { - if (of_find_property(pm->dev->of_node, "reg-names", NULL)) { + if (of_property_present(pm->dev->of_node, "reg-names")) { struct resource *res; pm->base = devm_platform_ioremap_resource_byname(pdev, "pm"); @@ -123,4 +123,3 @@ module_platform_driver(bcm2835_pm_driver); MODULE_AUTHOR("Eric Anholt <eric@anholt.net>"); MODULE_DESCRIPTION("Driver for Broadcom BCM2835 PM MFD"); -MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/da903x.c b/drivers/mfd/da903x.c index 44a25d642ce9..6570b33a5a77 100644 --- a/drivers/mfd/da903x.c +++ b/drivers/mfd/da903x.c @@ -563,4 +563,3 @@ module_exit(da903x_exit); MODULE_DESCRIPTION("PMIC Driver for Dialog Semiconductor DA9034"); MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>"); MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/da9052-core.c b/drivers/mfd/da9052-core.c index 8b42d2f7024f..150448cd2eb0 100644 --- a/drivers/mfd/da9052-core.c +++ b/drivers/mfd/da9052-core.c @@ -653,4 +653,3 @@ void da9052_device_exit(struct da9052 *da9052) MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); MODULE_DESCRIPTION("DA9052 MFD Core"); -MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/da9052-i2c.c b/drivers/mfd/da9052-i2c.c index ecb8077cdaaf..03db7a2ccf7a 100644 --- a/drivers/mfd/da9052-i2c.c +++ b/drivers/mfd/da9052-i2c.c @@ -209,4 +209,3 @@ module_exit(da9052_i2c_exit); MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); MODULE_DESCRIPTION("I2C driver for Dialog DA9052 PMIC"); -MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/da9052-spi.c b/drivers/mfd/da9052-spi.c index b79a57b45c1e..be5f2b34e18a 100644 --- a/drivers/mfd/da9052-spi.c +++ b/drivers/mfd/da9052-spi.c @@ -102,4 +102,3 @@ module_exit(da9052_spi_exit); MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); MODULE_DESCRIPTION("SPI driver for Dialog DA9052 PMIC"); -MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/da9055-core.c b/drivers/mfd/da9055-core.c index c3bcbd8905c6..768302e05baa 100644 --- a/drivers/mfd/da9055-core.c +++ b/drivers/mfd/da9055-core.c @@ -398,5 +398,4 @@ void da9055_device_exit(struct da9055 *da9055) } MODULE_DESCRIPTION("Core support for the DA9055 PMIC"); -MODULE_LICENSE("GPL"); MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); diff --git a/drivers/mfd/da9055-i2c.c b/drivers/mfd/da9055-i2c.c index 702abff506a1..537fd5de3e6d 100644 --- a/drivers/mfd/da9055-i2c.c +++ b/drivers/mfd/da9055-i2c.c @@ -97,4 +97,3 @@ module_exit(da9055_i2c_exit); MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); MODULE_DESCRIPTION("I2C driver for Dialog DA9055 PMIC"); -MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/da9062-core.c b/drivers/mfd/da9062-core.c index 40cde51e5719..d073d5f106ec 100644 --- a/drivers/mfd/da9062-core.c +++ b/drivers/mfd/da9062-core.c @@ -181,35 +181,25 @@ static const struct resource da9061_onkey_resources[] = { DEFINE_RES_IRQ_NAMED(DA9061_IRQ_ONKEY, "ONKEY"), }; -static const struct mfd_cell da9061_devs[] = { - { - .name = "da9061-core", - .num_resources = ARRAY_SIZE(da9061_core_resources), - .resources = da9061_core_resources, - }, - { - .name = "da9062-regulators", - .num_resources = ARRAY_SIZE(da9061_regulators_resources), - .resources = da9061_regulators_resources, - }, - { - .name = "da9061-watchdog", - .num_resources = ARRAY_SIZE(da9061_wdt_resources), - .resources = da9061_wdt_resources, - .of_compatible = "dlg,da9061-watchdog", - }, - { - .name = "da9061-thermal", - .num_resources = ARRAY_SIZE(da9061_thermal_resources), - .resources = da9061_thermal_resources, - .of_compatible = "dlg,da9061-thermal", - }, - { - .name = "da9061-onkey", - .num_resources = ARRAY_SIZE(da9061_onkey_resources), - .resources = da9061_onkey_resources, - .of_compatible = "dlg,da9061-onkey", - }, +static const struct mfd_cell da9061_devs_irq[] = { + MFD_CELL_OF("da9061-core", da9061_core_resources, NULL, 0, 0, + NULL), + MFD_CELL_OF("da9062-regulators", da9061_regulators_resources, NULL, 0, 0, + NULL), + MFD_CELL_OF("da9061-watchdog", da9061_wdt_resources, NULL, 0, 0, + "dlg,da9061-watchdog"), + MFD_CELL_OF("da9061-thermal", da9061_thermal_resources, NULL, 0, 0, + "dlg,da9061-thermal"), + MFD_CELL_OF("da9061-onkey", da9061_onkey_resources, NULL, 0, 0, + "dlg,da9061-onkey"), +}; + +static const struct mfd_cell da9061_devs_noirq[] = { + MFD_CELL_OF("da9061-core", NULL, NULL, 0, 0, NULL), + MFD_CELL_OF("da9062-regulators", NULL, NULL, 0, 0, NULL), + MFD_CELL_OF("da9061-watchdog", NULL, NULL, 0, 0, "dlg,da9061-watchdog"), + MFD_CELL_OF("da9061-thermal", NULL, NULL, 0, 0, "dlg,da9061-thermal"), + MFD_CELL_OF("da9061-onkey", NULL, NULL, 0, 0, "dlg,da9061-onkey"), }; static const struct resource da9062_core_resources[] = { @@ -245,47 +235,31 @@ static const struct resource da9062_gpio_resources[] = { DEFINE_RES_NAMED(DA9062_IRQ_GPI4, 1, "GPI4", IORESOURCE_IRQ), }; -static const struct mfd_cell da9062_devs[] = { - { - .name = "da9062-core", - .num_resources = ARRAY_SIZE(da9062_core_resources), - .resources = da9062_core_resources, - }, - { - .name = "da9062-regulators", - .num_resources = ARRAY_SIZE(da9062_regulators_resources), - .resources = da9062_regulators_resources, - }, - { - .name = "da9062-watchdog", - .num_resources = ARRAY_SIZE(da9062_wdt_resources), - .resources = da9062_wdt_resources, - .of_compatible = "dlg,da9062-watchdog", - }, - { - .name = "da9062-thermal", - .num_resources = ARRAY_SIZE(da9062_thermal_resources), - .resources = da9062_thermal_resources, - .of_compatible = "dlg,da9062-thermal", - }, - { - .name = "da9062-rtc", - .num_resources = ARRAY_SIZE(da9062_rtc_resources), - .resources = da9062_rtc_resources, - .of_compatible = "dlg,da9062-rtc", - }, - { - .name = "da9062-onkey", - .num_resources = ARRAY_SIZE(da9062_onkey_resources), - .resources = da9062_onkey_resources, - .of_compatible = "dlg,da9062-onkey", - }, - { - .name = "da9062-gpio", - .num_resources = ARRAY_SIZE(da9062_gpio_resources), - .resources = da9062_gpio_resources, - .of_compatible = "dlg,da9062-gpio", - }, +static const struct mfd_cell da9062_devs_irq[] = { + MFD_CELL_OF("da9062-core", da9062_core_resources, NULL, 0, 0, + NULL), + MFD_CELL_OF("da9062-regulators", da9062_regulators_resources, NULL, 0, 0, + NULL), + MFD_CELL_OF("da9062-watchdog", da9062_wdt_resources, NULL, 0, 0, + "dlg,da9062-watchdog"), + MFD_CELL_OF("da9062-thermal", da9062_thermal_resources, NULL, 0, 0, + "dlg,da9062-thermal"), + MFD_CELL_OF("da9062-rtc", da9062_rtc_resources, NULL, 0, 0, + "dlg,da9062-rtc"), + MFD_CELL_OF("da9062-onkey", da9062_onkey_resources, NULL, 0, 0, + "dlg,da9062-onkey"), + MFD_CELL_OF("da9062-gpio", da9062_gpio_resources, NULL, 0, 0, + "dlg,da9062-gpio"), +}; + +static const struct mfd_cell da9062_devs_noirq[] = { + MFD_CELL_OF("da9062-core", NULL, NULL, 0, 0, NULL), + MFD_CELL_OF("da9062-regulators", NULL, NULL, 0, 0, NULL), + MFD_CELL_OF("da9062-watchdog", NULL, NULL, 0, 0, "dlg,da9062-watchdog"), + MFD_CELL_OF("da9062-thermal", NULL, NULL, 0, 0, "dlg,da9062-thermal"), + MFD_CELL_OF("da9062-rtc", NULL, NULL, 0, 0, "dlg,da9062-rtc"), + MFD_CELL_OF("da9062-onkey", NULL, NULL, 0, 0, "dlg,da9062-onkey"), + MFD_CELL_OF("da9062-gpio", NULL, NULL, 0, 0, "dlg,da9062-gpio"), }; static int da9062_clear_fault_log(struct da9062 *chip) @@ -625,7 +599,7 @@ static int da9062_i2c_probe(struct i2c_client *i2c) { const struct i2c_device_id *id = i2c_client_get_device_id(i2c); struct da9062 *chip; - unsigned int irq_base; + unsigned int irq_base = 0; const struct mfd_cell *cell; const struct regmap_irq_chip *irq_chip; const struct regmap_config *config; @@ -645,22 +619,16 @@ static int da9062_i2c_probe(struct i2c_client *i2c) i2c_set_clientdata(i2c, chip); chip->dev = &i2c->dev; - if (!i2c->irq) { - dev_err(chip->dev, "No IRQ configured\n"); - return -EINVAL; - } - + /* Start with a base configuration without IRQ */ switch (chip->chip_type) { case COMPAT_TYPE_DA9061: - cell = da9061_devs; - cell_num = ARRAY_SIZE(da9061_devs); - irq_chip = &da9061_irq_chip; + cell = da9061_devs_noirq; + cell_num = ARRAY_SIZE(da9061_devs_noirq); config = &da9061_regmap_config; break; case COMPAT_TYPE_DA9062: - cell = da9062_devs; - cell_num = ARRAY_SIZE(da9062_devs); - irq_chip = &da9062_irq_chip; + cell = da9062_devs_noirq; + cell_num = ARRAY_SIZE(da9062_devs_noirq); config = &da9062_regmap_config; break; default: @@ -695,29 +663,43 @@ static int da9062_i2c_probe(struct i2c_client *i2c) if (ret) return ret; - ret = da9062_configure_irq_type(chip, i2c->irq, &trigger_type); - if (ret < 0) { - dev_err(chip->dev, "Failed to configure IRQ type\n"); - return ret; - } + /* If IRQ is available, reconfigure it accordingly */ + if (i2c->irq) { + if (chip->chip_type == COMPAT_TYPE_DA9061) { + cell = da9061_devs_irq; + cell_num = ARRAY_SIZE(da9061_devs_irq); + irq_chip = &da9061_irq_chip; + } else { + cell = da9062_devs_irq; + cell_num = ARRAY_SIZE(da9062_devs_irq); + irq_chip = &da9062_irq_chip; + } - ret = regmap_add_irq_chip(chip->regmap, i2c->irq, - trigger_type | IRQF_SHARED | IRQF_ONESHOT, - -1, irq_chip, &chip->regmap_irq); - if (ret) { - dev_err(chip->dev, "Failed to request IRQ %d: %d\n", - i2c->irq, ret); - return ret; - } + ret = da9062_configure_irq_type(chip, i2c->irq, &trigger_type); + if (ret < 0) { + dev_err(chip->dev, "Failed to configure IRQ type\n"); + return ret; + } - irq_base = regmap_irq_chip_get_base(chip->regmap_irq); + ret = regmap_add_irq_chip(chip->regmap, i2c->irq, + trigger_type | IRQF_SHARED | IRQF_ONESHOT, + -1, irq_chip, &chip->regmap_irq); + if (ret) { + dev_err(chip->dev, "Failed to request IRQ %d: %d\n", + i2c->irq, ret); + return ret; + } + + irq_base = regmap_irq_chip_get_base(chip->regmap_irq); + } ret = mfd_add_devices(chip->dev, PLATFORM_DEVID_NONE, cell, cell_num, NULL, irq_base, NULL); if (ret) { dev_err(chip->dev, "Cannot register child devices\n"); - regmap_del_irq_chip(i2c->irq, chip->regmap_irq); + if (i2c->irq) + regmap_del_irq_chip(i2c->irq, chip->regmap_irq); return ret; } diff --git a/drivers/mfd/dln2.c b/drivers/mfd/dln2.c index 6cd0b0c752d6..c3149729cec2 100644 --- a/drivers/mfd/dln2.c +++ b/drivers/mfd/dln2.c @@ -827,6 +827,7 @@ out_stop_rx: dln2_stop_rx_urbs(dln2); out_free: + usb_put_dev(dln2->usb_dev); dln2_free(dln2); return ret; diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c index 3d5ce18aa9ae..8d006f6be48c 100644 --- a/drivers/mfd/ezx-pcap.c +++ b/drivers/mfd/ezx-pcap.c @@ -528,7 +528,6 @@ static void __exit ezx_pcap_exit(void) subsys_initcall(ezx_pcap_init); module_exit(ezx_pcap_exit); -MODULE_LICENSE("GPL"); MODULE_AUTHOR("Daniel Ribeiro / Harald Welte"); MODULE_DESCRIPTION("Motorola PCAP2 ASIC Driver"); MODULE_ALIAS("spi:ezx-pcap"); diff --git a/drivers/mfd/hi6421-pmic-core.c b/drivers/mfd/hi6421-pmic-core.c index eba88b80d969..cb5cf4a81c06 100644 --- a/drivers/mfd/hi6421-pmic-core.c +++ b/drivers/mfd/hi6421-pmic-core.c @@ -50,7 +50,6 @@ MODULE_DEVICE_TABLE(of, of_hi6421_pmic_match); static int hi6421_pmic_probe(struct platform_device *pdev) { struct hi6421_pmic *pmic; - struct resource *res; const struct of_device_id *id; const struct mfd_cell *subdevs; enum hi6421_type type; @@ -66,8 +65,7 @@ static int hi6421_pmic_probe(struct platform_device *pdev) if (!pmic) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); if (IS_ERR(base)) return PTR_ERR(base); diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c index dde31c50a632..699f44ffff0e 100644 --- a/drivers/mfd/intel-lpss-pci.c +++ b/drivers/mfd/intel-lpss-pci.c @@ -447,6 +447,21 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x7e79), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x7e7a), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x7e7b), (kernel_ulong_t)&bxt_i2c_info }, + /* MTP-S */ + { PCI_VDEVICE(INTEL, 0x7f28), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0x7f29), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0x7f2a), (kernel_ulong_t)&tgl_info }, + { PCI_VDEVICE(INTEL, 0x7f2b), (kernel_ulong_t)&tgl_info }, + { PCI_VDEVICE(INTEL, 0x7f4c), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x7f4d), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x7f4e), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x7f4f), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x7f5c), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0x7f5d), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0x7f5e), (kernel_ulong_t)&tgl_info }, + { PCI_VDEVICE(INTEL, 0x7f5f), (kernel_ulong_t)&tgl_info }, + { PCI_VDEVICE(INTEL, 0x7f7a), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x7f7b), (kernel_ulong_t)&bxt_i2c_info }, /* LKF */ { PCI_VDEVICE(INTEL, 0x98a8), (kernel_ulong_t)&bxt_uart_info }, { PCI_VDEVICE(INTEL, 0x98a9), (kernel_ulong_t)&bxt_uart_info }, diff --git a/drivers/mfd/intel_soc_pmic_chtwc.c b/drivers/mfd/intel_soc_pmic_chtwc.c index d53dae255490..871776d511e3 100644 --- a/drivers/mfd/intel_soc_pmic_chtwc.c +++ b/drivers/mfd/intel_soc_pmic_chtwc.c @@ -159,11 +159,19 @@ static const struct dmi_system_id cht_wc_model_dmi_ids[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Mipad2"), }, }, { - /* Lenovo Yoga Book X90F / X91F / X91L */ + /* Lenovo Yoga Book X90F / X90L */ .driver_data = (void *)(long)INTEL_CHT_WC_LENOVO_YOGABOOK1, .matches = { - /* Non exact match to match all versions */ - DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X9"), + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"), + DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "YETI-11"), + }, + }, { + /* Lenovo Yoga Book X91F / X91L */ + .driver_data = (void *)(long)INTEL_CHT_WC_LENOVO_YOGABOOK1, + .matches = { + /* Non exact match to match F + L versions */ + DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X91"), }, }, { /* Lenovo Yoga Tab 3 Pro YT3-X90F */ diff --git a/drivers/mfd/intel_soc_pmic_crc.c b/drivers/mfd/intel_soc_pmic_crc.c index b1548a933dc3..b745ace46e5b 100644 --- a/drivers/mfd/intel_soc_pmic_crc.c +++ b/drivers/mfd/intel_soc_pmic_crc.c @@ -271,6 +271,5 @@ static struct i2c_driver crystal_cove_i2c_driver = { module_i2c_driver(crystal_cove_i2c_driver); MODULE_DESCRIPTION("I2C driver for Intel SoC PMIC"); -MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Yang, Bin <bin.yang@intel.com>"); MODULE_AUTHOR("Zhu, Lejun <lejun.zhu@linux.intel.com>"); diff --git a/drivers/mfd/ipaq-micro.c b/drivers/mfd/ipaq-micro.c index 4cd5ecc72211..6d3968458e81 100644 --- a/drivers/mfd/ipaq-micro.c +++ b/drivers/mfd/ipaq-micro.c @@ -381,7 +381,6 @@ static int __maybe_unused micro_resume(struct device *dev) static int __init micro_probe(struct platform_device *pdev) { struct ipaq_micro *micro; - struct resource *res; int ret; int irq; @@ -391,8 +390,7 @@ static int __init micro_probe(struct platform_device *pdev) micro->dev = &pdev->dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - micro->base = devm_ioremap_resource(&pdev->dev, res); + micro->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); if (IS_ERR(micro->base)) return PTR_ERR(micro->base); diff --git a/drivers/mfd/khadas-mcu.c b/drivers/mfd/khadas-mcu.c index 7338cc16f327..1c807c0e6d25 100644 --- a/drivers/mfd/khadas-mcu.c +++ b/drivers/mfd/khadas-mcu.c @@ -112,7 +112,7 @@ static int khadas_mcu_probe(struct i2c_client *client) if (ret) return ret; - if (of_find_property(dev->of_node, "#cooling-cells", NULL)) + if (of_property_present(dev->of_node, "#cooling-cells")) return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, khadas_mcu_fan_cells, ARRAY_SIZE(khadas_mcu_fan_cells), diff --git a/drivers/mfd/lp8788.c b/drivers/mfd/lp8788.c index fe809b64147e..18583addaae2 100644 --- a/drivers/mfd/lp8788.c +++ b/drivers/mfd/lp8788.c @@ -244,4 +244,3 @@ module_exit(lp8788_exit); MODULE_DESCRIPTION("TI LP8788 MFD Driver"); MODULE_AUTHOR("Milo Kim"); -MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 16d1861e9682..695d50b3bac6 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -33,32 +33,6 @@ static struct device_type mfd_dev_type = { .name = "mfd_device", }; -int mfd_cell_enable(struct platform_device *pdev) -{ - const struct mfd_cell *cell = mfd_get_cell(pdev); - - if (!cell->enable) { - dev_dbg(&pdev->dev, "No .enable() call-back registered\n"); - return 0; - } - - return cell->enable(pdev); -} -EXPORT_SYMBOL(mfd_cell_enable); - -int mfd_cell_disable(struct platform_device *pdev) -{ - const struct mfd_cell *cell = mfd_get_cell(pdev); - - if (!cell->disable) { - dev_dbg(&pdev->dev, "No .disable() call-back registered\n"); - return 0; - } - - return cell->disable(pdev); -} -EXPORT_SYMBOL(mfd_cell_disable); - #if IS_ENABLED(CONFIG_ACPI) struct match_ids_walk_data { struct acpi_device_id *ids; diff --git a/drivers/mfd/ocelot-spi.c b/drivers/mfd/ocelot-spi.c index 2d1349a10ca9..94f82677675b 100644 --- a/drivers/mfd/ocelot-spi.c +++ b/drivers/mfd/ocelot-spi.c @@ -130,6 +130,7 @@ static const struct regmap_config ocelot_spi_regmap_config = { .write_flag_mask = 0x80, + .use_single_read = true, .use_single_write = true, .can_multi_write = false, diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 787d2ae86375..7f5775109593 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -853,7 +853,6 @@ static struct platform_driver usbhs_omap_driver = { MODULE_AUTHOR("Keshava Munegowda <keshava_mgowda@ti.com>"); MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>"); MODULE_ALIAS("platform:" USBHS_DRIVER_NAME); -MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("usb host common core driver for omap EHCI and OHCI"); static int omap_usbhs_drvinit(void) diff --git a/drivers/mfd/omap-usb-tll.c b/drivers/mfd/omap-usb-tll.c index 080d7970a377..69cbc2097911 100644 --- a/drivers/mfd/omap-usb-tll.c +++ b/drivers/mfd/omap-usb-tll.c @@ -125,11 +125,6 @@ static inline void usbtll_writeb(void __iomem *base, u32 reg, u8 val) writeb_relaxed(val, base + reg); } -static inline u8 usbtll_readb(void __iomem *base, u32 reg) -{ - return readb_relaxed(base + reg); -} - /*-------------------------------------------------------------------------*/ static bool is_ohci_port(enum usbhs_omap_port_mode pmode) @@ -450,7 +445,6 @@ EXPORT_SYMBOL_GPL(omap_tll_disable); MODULE_AUTHOR("Keshava Munegowda <keshava_mgowda@ti.com>"); MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>"); -MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("usb tll driver for TI OMAP EHCI and OHCI controllers"); static int __init omap_usbtll_drvinit(void) diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c index 9f3c4a01b4c1..837246aab4ac 100644 --- a/drivers/mfd/qcom-pm8008.c +++ b/drivers/mfd/qcom-pm8008.c @@ -44,37 +44,16 @@ enum { #define PM8008_GPIO1_ADDR PM8008_PERIPH_2_BASE #define PM8008_GPIO2_ADDR PM8008_PERIPH_3_BASE -#define PM8008_STATUS_BASE (PM8008_PERIPH_0_BASE | INT_LATCHED_STS_OFFSET) -#define PM8008_MASK_BASE (PM8008_PERIPH_0_BASE | INT_EN_SET_OFFSET) -#define PM8008_UNMASK_BASE (PM8008_PERIPH_0_BASE | INT_EN_CLR_OFFSET) -#define PM8008_TYPE_BASE (PM8008_PERIPH_0_BASE | INT_SET_TYPE_OFFSET) -#define PM8008_ACK_BASE (PM8008_PERIPH_0_BASE | INT_LATCHED_CLR_OFFSET) -#define PM8008_POLARITY_HI_BASE (PM8008_PERIPH_0_BASE | INT_POL_HIGH_OFFSET) -#define PM8008_POLARITY_LO_BASE (PM8008_PERIPH_0_BASE | INT_POL_LOW_OFFSET) - -#define PM8008_PERIPH_OFFSET(paddr) (paddr - PM8008_PERIPH_0_BASE) - -static unsigned int p0_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_0_BASE)}; -static unsigned int p1_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_1_BASE)}; -static unsigned int p2_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_2_BASE)}; -static unsigned int p3_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_3_BASE)}; - -static struct regmap_irq_sub_irq_map pm8008_sub_reg_offsets[] = { - REGMAP_IRQ_MAIN_REG_OFFSET(p0_offs), - REGMAP_IRQ_MAIN_REG_OFFSET(p1_offs), - REGMAP_IRQ_MAIN_REG_OFFSET(p2_offs), - REGMAP_IRQ_MAIN_REG_OFFSET(p3_offs), -}; - -static unsigned int pm8008_virt_regs[] = { - PM8008_POLARITY_HI_BASE, - PM8008_POLARITY_LO_BASE, -}; - enum { + SET_TYPE_INDEX, POLARITY_HI_INDEX, POLARITY_LO_INDEX, - PM8008_NUM_VIRT_REGS, +}; + +static unsigned int pm8008_config_regs[] = { + INT_SET_TYPE_OFFSET, + INT_POL_HIGH_OFFSET, + INT_POL_LOW_OFFSET, }; static struct regmap_irq pm8008_irqs[] = { @@ -88,32 +67,54 @@ static struct regmap_irq pm8008_irqs[] = { REGMAP_IRQ_REG(PM8008_IRQ_GPIO2, PM8008_GPIO2, BIT(0)), }; -static int pm8008_set_type_virt(unsigned int **virt_buf, - unsigned int type, unsigned long hwirq, - int reg) +static const unsigned int pm8008_periph_base[] = { + PM8008_PERIPH_0_BASE, + PM8008_PERIPH_1_BASE, + PM8008_PERIPH_2_BASE, + PM8008_PERIPH_3_BASE, +}; + +static unsigned int pm8008_get_irq_reg(struct regmap_irq_chip_data *data, + unsigned int base, int index) +{ + /* Simple linear addressing for the main status register */ + if (base == I2C_INTR_STATUS_BASE) + return base + index; + + return pm8008_periph_base[index] + base; +} + +static int pm8008_set_type_config(unsigned int **buf, unsigned int type, + const struct regmap_irq *irq_data, int idx, + void *irq_drv_data) { switch (type) { case IRQ_TYPE_EDGE_FALLING: case IRQ_TYPE_LEVEL_LOW: - virt_buf[POLARITY_HI_INDEX][reg] &= ~pm8008_irqs[hwirq].mask; - virt_buf[POLARITY_LO_INDEX][reg] |= pm8008_irqs[hwirq].mask; + buf[POLARITY_HI_INDEX][idx] &= ~irq_data->mask; + buf[POLARITY_LO_INDEX][idx] |= irq_data->mask; break; case IRQ_TYPE_EDGE_RISING: case IRQ_TYPE_LEVEL_HIGH: - virt_buf[POLARITY_HI_INDEX][reg] |= pm8008_irqs[hwirq].mask; - virt_buf[POLARITY_LO_INDEX][reg] &= ~pm8008_irqs[hwirq].mask; + buf[POLARITY_HI_INDEX][idx] |= irq_data->mask; + buf[POLARITY_LO_INDEX][idx] &= ~irq_data->mask; break; case IRQ_TYPE_EDGE_BOTH: - virt_buf[POLARITY_HI_INDEX][reg] |= pm8008_irqs[hwirq].mask; - virt_buf[POLARITY_LO_INDEX][reg] |= pm8008_irqs[hwirq].mask; + buf[POLARITY_HI_INDEX][idx] |= irq_data->mask; + buf[POLARITY_LO_INDEX][idx] |= irq_data->mask; break; default: return -EINVAL; } + if (type & IRQ_TYPE_EDGE_BOTH) + buf[SET_TYPE_INDEX][idx] |= irq_data->mask; + else + buf[SET_TYPE_INDEX][idx] &= ~irq_data->mask; + return 0; } @@ -121,20 +122,19 @@ static struct regmap_irq_chip pm8008_irq_chip = { .name = "pm8008_irq", .main_status = I2C_INTR_STATUS_BASE, .num_main_regs = 1, - .num_virt_regs = PM8008_NUM_VIRT_REGS, .irqs = pm8008_irqs, .num_irqs = ARRAY_SIZE(pm8008_irqs), .num_regs = PM8008_NUM_PERIPHS, - .not_fixed_stride = true, - .sub_reg_offsets = pm8008_sub_reg_offsets, - .set_type_virt = pm8008_set_type_virt, - .status_base = PM8008_STATUS_BASE, - .mask_base = PM8008_MASK_BASE, - .unmask_base = PM8008_UNMASK_BASE, - .type_base = PM8008_TYPE_BASE, - .ack_base = PM8008_ACK_BASE, - .virt_reg_base = pm8008_virt_regs, - .num_type_reg = PM8008_NUM_PERIPHS, + .status_base = INT_LATCHED_STS_OFFSET, + .mask_base = INT_EN_CLR_OFFSET, + .unmask_base = INT_EN_SET_OFFSET, + .mask_unmask_non_inverted = true, + .ack_base = INT_LATCHED_CLR_OFFSET, + .config_base = pm8008_config_regs, + .num_config_bases = ARRAY_SIZE(pm8008_config_regs), + .num_config_regs = PM8008_NUM_PERIPHS, + .set_type_config = pm8008_set_type_config, + .get_irq_reg = pm8008_get_irq_reg, }; static struct regmap_config qcom_mfd_regmap_cfg = { @@ -143,30 +143,6 @@ static struct regmap_config qcom_mfd_regmap_cfg = { .max_register = 0xFFFF, }; -static int pm8008_init(struct regmap *regmap) -{ - int rc; - - /* - * Set TEMP_ALARM peripheral's TYPE so that the regmap-irq framework - * reads this as the default value instead of zero, the HW default. - * This is required to enable the writing of TYPE registers in - * regmap_irq_sync_unlock(). - */ - rc = regmap_write(regmap, (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET), BIT(0)); - if (rc) - return rc; - - /* Do the same for GPIO1 and GPIO2 peripherals */ - rc = regmap_write(regmap, (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0)); - if (rc) - return rc; - - rc = regmap_write(regmap, (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0)); - - return rc; -} - static int pm8008_probe_irq_peripherals(struct device *dev, struct regmap *regmap, int client_irq) @@ -175,20 +151,10 @@ static int pm8008_probe_irq_peripherals(struct device *dev, struct regmap_irq_type *type; struct regmap_irq_chip_data *irq_data; - rc = pm8008_init(regmap); - if (rc) { - dev_err(dev, "Init failed: %d\n", rc); - return rc; - } - for (i = 0; i < ARRAY_SIZE(pm8008_irqs); i++) { type = &pm8008_irqs[i].type; - type->type_reg_offset = pm8008_irqs[i].reg_offset; - type->type_rising_val = pm8008_irqs[i].mask; - type->type_falling_val = pm8008_irqs[i].mask; - type->type_level_high_val = 0; - type->type_level_low_val = 0; + type->type_reg_offset = pm8008_irqs[i].reg_offset; if (type->type_reg_offset == PM8008_MISC) type->types_supported = IRQ_TYPE_EDGE_RISING; diff --git a/drivers/mfd/qcom_rpm.c b/drivers/mfd/qcom_rpm.c index 8fea0e511550..086611322874 100644 --- a/drivers/mfd/qcom_rpm.c +++ b/drivers/mfd/qcom_rpm.c @@ -530,7 +530,6 @@ static int qcom_rpm_probe(struct platform_device *pdev) { const struct of_device_id *match; struct device_node *syscon_np; - struct resource *res; struct qcom_rpm *rpm; u32 fw_version[3]; int irq_wakeup; @@ -576,8 +575,7 @@ static int qcom_rpm_probe(struct platform_device *pdev) return -ENODEV; rpm->data = match->data; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - rpm->status_regs = devm_ioremap_resource(&pdev->dev, res); + rpm->status_regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); if (IS_ERR(rpm->status_regs)) return PTR_ERR(rpm->status_regs); rpm->ctrl_regs = rpm->status_regs + 0x400; diff --git a/drivers/mfd/rsmu.h b/drivers/mfd/rsmu.h index bb88597d189f..1bb04cafa45d 100644 --- a/drivers/mfd/rsmu.h +++ b/drivers/mfd/rsmu.h @@ -10,6 +10,8 @@ #include <linux/mfd/rsmu.h> +#define RSMU_CM_SCSR_BASE 0x20100000 + int rsmu_core_init(struct rsmu_ddata *rsmu); void rsmu_core_exit(struct rsmu_ddata *rsmu); diff --git a/drivers/mfd/rsmu_i2c.c b/drivers/mfd/rsmu_i2c.c index 15d25b081434..807c32101460 100644 --- a/drivers/mfd/rsmu_i2c.c +++ b/drivers/mfd/rsmu_i2c.c @@ -18,11 +18,12 @@ #include "rsmu.h" /* - * 16-bit register address: the lower 8 bits of the register address come - * from the offset addr byte and the upper 8 bits come from the page register. + * 32-bit register address: the lower 8 bits of the register address come + * from the offset addr byte and the upper 24 bits come from the page register. */ -#define RSMU_CM_PAGE_ADDR 0xFD -#define RSMU_CM_PAGE_WINDOW 256 +#define RSMU_CM_PAGE_ADDR 0xFC +#define RSMU_CM_PAGE_MASK 0xFFFFFF00 +#define RSMU_CM_ADDRESS_MASK 0x000000FF /* * 15-bit register address: the lower 7 bits of the register address come @@ -31,18 +32,6 @@ #define RSMU_SABRE_PAGE_ADDR 0x7F #define RSMU_SABRE_PAGE_WINDOW 128 -static const struct regmap_range_cfg rsmu_cm_range_cfg[] = { - { - .range_min = 0, - .range_max = 0xD000, - .selector_reg = RSMU_CM_PAGE_ADDR, - .selector_mask = 0xFF, - .selector_shift = 0, - .window_start = 0, - .window_len = RSMU_CM_PAGE_WINDOW, - } -}; - static const struct regmap_range_cfg rsmu_sabre_range_cfg[] = { { .range_min = 0, @@ -55,35 +44,141 @@ static const struct regmap_range_cfg rsmu_sabre_range_cfg[] = { } }; -static bool rsmu_cm_volatile_reg(struct device *dev, unsigned int reg) +static bool rsmu_sabre_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { - case RSMU_CM_PAGE_ADDR: + case RSMU_SABRE_PAGE_ADDR: return false; default: return true; } } -static bool rsmu_sabre_volatile_reg(struct device *dev, unsigned int reg) +static int rsmu_read_device(struct rsmu_ddata *rsmu, u8 reg, u8 *buf, u16 bytes) { - switch (reg) { - case RSMU_SABRE_PAGE_ADDR: - return false; - default: - return true; + struct i2c_client *client = to_i2c_client(rsmu->dev); + struct i2c_msg msg[2]; + int cnt; + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = 1; + msg[0].buf = ® + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = bytes; + msg[1].buf = buf; + + cnt = i2c_transfer(client->adapter, msg, 2); + + if (cnt < 0) { + dev_err(rsmu->dev, "i2c_transfer failed at addr: %04x!", reg); + return cnt; + } else if (cnt != 2) { + dev_err(rsmu->dev, + "i2c_transfer sent only %d of 2 messages", cnt); + return -EIO; + } + + return 0; +} + +static int rsmu_write_device(struct rsmu_ddata *rsmu, u8 reg, u8 *buf, u16 bytes) +{ + struct i2c_client *client = to_i2c_client(rsmu->dev); + u8 msg[RSMU_MAX_WRITE_COUNT + 1]; /* 1 Byte added for the device register */ + int cnt; + + if (bytes > RSMU_MAX_WRITE_COUNT) + return -EINVAL; + + msg[0] = reg; + memcpy(&msg[1], buf, bytes); + + cnt = i2c_master_send(client, msg, bytes + 1); + + if (cnt < 0) { + dev_err(&client->dev, + "i2c_master_send failed at addr: %04x!", reg); + return cnt; } + + return 0; +} + +static int rsmu_write_page_register(struct rsmu_ddata *rsmu, u32 reg) +{ + u32 page = reg & RSMU_CM_PAGE_MASK; + u8 buf[4]; + int err; + + /* Do not modify offset register for none-scsr registers */ + if (reg < RSMU_CM_SCSR_BASE) + return 0; + + /* Simply return if we are on the same page */ + if (rsmu->page == page) + return 0; + + buf[0] = 0x0; + buf[1] = (u8)((page >> 8) & 0xFF); + buf[2] = (u8)((page >> 16) & 0xFF); + buf[3] = (u8)((page >> 24) & 0xFF); + + err = rsmu_write_device(rsmu, RSMU_CM_PAGE_ADDR, buf, sizeof(buf)); + if (err) + dev_err(rsmu->dev, "Failed to set page offset 0x%x\n", page); + else + /* Remember the last page */ + rsmu->page = page; + + return err; +} + +static int rsmu_reg_read(void *context, unsigned int reg, unsigned int *val) +{ + struct rsmu_ddata *rsmu = i2c_get_clientdata((struct i2c_client *)context); + u8 addr = (u8)(reg & RSMU_CM_ADDRESS_MASK); + int err; + + err = rsmu_write_page_register(rsmu, reg); + if (err) + return err; + + err = rsmu_read_device(rsmu, addr, (u8 *)val, 1); + if (err) + dev_err(rsmu->dev, "Failed to read offset address 0x%x\n", addr); + + return err; +} + +static int rsmu_reg_write(void *context, unsigned int reg, unsigned int val) +{ + struct rsmu_ddata *rsmu = i2c_get_clientdata((struct i2c_client *)context); + u8 addr = (u8)(reg & RSMU_CM_ADDRESS_MASK); + u8 data = (u8)val; + int err; + + err = rsmu_write_page_register(rsmu, reg); + if (err) + return err; + + err = rsmu_write_device(rsmu, addr, &data, 1); + if (err) + dev_err(rsmu->dev, + "Failed to write offset address 0x%x\n", addr); + + return err; } static const struct regmap_config rsmu_cm_regmap_config = { - .reg_bits = 8, + .reg_bits = 32, .val_bits = 8, - .max_register = 0xD000, - .ranges = rsmu_cm_range_cfg, - .num_ranges = ARRAY_SIZE(rsmu_cm_range_cfg), - .volatile_reg = rsmu_cm_volatile_reg, - .cache_type = REGCACHE_RBTREE, - .can_multi_write = true, + .max_register = 0x20120000, + .reg_read = rsmu_reg_read, + .reg_write = rsmu_reg_write, + .cache_type = REGCACHE_NONE, }; static const struct regmap_config rsmu_sabre_regmap_config = { @@ -101,7 +196,7 @@ static const struct regmap_config rsmu_sl_regmap_config = { .reg_bits = 16, .val_bits = 8, .reg_format_endian = REGMAP_ENDIAN_BIG, - .max_register = 0x339, + .max_register = 0x340, .cache_type = REGCACHE_NONE, .can_multi_write = true, }; @@ -136,7 +231,11 @@ static int rsmu_i2c_probe(struct i2c_client *client) dev_err(rsmu->dev, "Unsupported RSMU device type: %d\n", rsmu->type); return -ENODEV; } - rsmu->regmap = devm_regmap_init_i2c(client, cfg); + + if (rsmu->type == RSMU_CM) + rsmu->regmap = devm_regmap_init(&client->dev, NULL, client, cfg); + else + rsmu->regmap = devm_regmap_init_i2c(client, cfg); if (IS_ERR(rsmu->regmap)) { ret = PTR_ERR(rsmu->regmap); dev_err(rsmu->dev, "Failed to allocate register map: %d\n", ret); diff --git a/drivers/mfd/rsmu_spi.c b/drivers/mfd/rsmu_spi.c index d2f3d8f1e05a..a4a595bb8d0d 100644 --- a/drivers/mfd/rsmu_spi.c +++ b/drivers/mfd/rsmu_spi.c @@ -19,19 +19,21 @@ #define RSMU_CM_PAGE_ADDR 0x7C #define RSMU_SABRE_PAGE_ADDR 0x7F -#define RSMU_HIGHER_ADDR_MASK 0xFF80 -#define RSMU_HIGHER_ADDR_SHIFT 7 -#define RSMU_LOWER_ADDR_MASK 0x7F +#define RSMU_PAGE_MASK 0xFFFFFF80 +#define RSMU_ADDR_MASK 0x7F static int rsmu_read_device(struct rsmu_ddata *rsmu, u8 reg, u8 *buf, u16 bytes) { struct spi_device *client = to_spi_device(rsmu->dev); struct spi_transfer xfer = {0}; struct spi_message msg; - u8 cmd[256] = {0}; - u8 rsp[256] = {0}; + u8 cmd[RSMU_MAX_READ_COUNT + 1] = {0}; + u8 rsp[RSMU_MAX_READ_COUNT + 1] = {0}; int ret; + if (bytes > RSMU_MAX_READ_COUNT) + return -EINVAL; + cmd[0] = reg | 0x80; xfer.rx_buf = rsp; xfer.len = bytes + 1; @@ -66,7 +68,10 @@ static int rsmu_write_device(struct rsmu_ddata *rsmu, u8 reg, u8 *buf, u16 bytes struct spi_device *client = to_spi_device(rsmu->dev); struct spi_transfer xfer = {0}; struct spi_message msg; - u8 cmd[256] = {0}; + u8 cmd[RSMU_MAX_WRITE_COUNT + 1] = {0}; + + if (bytes > RSMU_MAX_WRITE_COUNT) + return -EINVAL; cmd[0] = reg; memcpy(&cmd[1], buf, bytes); @@ -86,26 +91,35 @@ static int rsmu_write_device(struct rsmu_ddata *rsmu, u8 reg, u8 *buf, u16 bytes * 16-bit register address: the lower 7 bits of the register address come * from the offset addr byte and the upper 9 bits come from the page register. */ -static int rsmu_write_page_register(struct rsmu_ddata *rsmu, u16 reg) +static int rsmu_write_page_register(struct rsmu_ddata *rsmu, u32 reg) { u8 page_reg; - u8 buf[2]; + u8 buf[4]; u16 bytes; - u16 page; + u32 page; int err; switch (rsmu->type) { case RSMU_CM: + /* Do not modify page register for none-scsr registers */ + if (reg < RSMU_CM_SCSR_BASE) + return 0; page_reg = RSMU_CM_PAGE_ADDR; - page = reg & RSMU_HIGHER_ADDR_MASK; + page = reg & RSMU_PAGE_MASK; buf[0] = (u8)(page & 0xff); buf[1] = (u8)((page >> 8) & 0xff); - bytes = 2; + buf[2] = (u8)((page >> 16) & 0xff); + buf[3] = (u8)((page >> 24) & 0xff); + bytes = 4; break; case RSMU_SABRE: + /* Do not modify page register if reg is page register itself */ + if ((reg & RSMU_ADDR_MASK) == RSMU_ADDR_MASK) + return 0; page_reg = RSMU_SABRE_PAGE_ADDR; - page = reg >> RSMU_HIGHER_ADDR_SHIFT; - buf[0] = (u8)(page & 0xff); + page = reg & RSMU_PAGE_MASK; + /* The three page bits are located in the single Page Register */ + buf[0] = (u8)((page >> 7) & 0x7); bytes = 1; break; default: @@ -130,7 +144,7 @@ static int rsmu_write_page_register(struct rsmu_ddata *rsmu, u16 reg) static int rsmu_reg_read(void *context, unsigned int reg, unsigned int *val) { struct rsmu_ddata *rsmu = spi_get_drvdata((struct spi_device *)context); - u8 addr = (u8)(reg & RSMU_LOWER_ADDR_MASK); + u8 addr = (u8)(reg & RSMU_ADDR_MASK); int err; err = rsmu_write_page_register(rsmu, reg); @@ -147,7 +161,7 @@ static int rsmu_reg_read(void *context, unsigned int reg, unsigned int *val) static int rsmu_reg_write(void *context, unsigned int reg, unsigned int val) { struct rsmu_ddata *rsmu = spi_get_drvdata((struct spi_device *)context); - u8 addr = (u8)(reg & RSMU_LOWER_ADDR_MASK); + u8 addr = (u8)(reg & RSMU_ADDR_MASK); u8 data = (u8)val; int err; @@ -164,9 +178,9 @@ static int rsmu_reg_write(void *context, unsigned int reg, unsigned int val) } static const struct regmap_config rsmu_cm_regmap_config = { - .reg_bits = 16, + .reg_bits = 32, .val_bits = 8, - .max_register = 0xD000, + .max_register = 0x20120000, .reg_read = rsmu_reg_read, .reg_write = rsmu_reg_write, .cache_type = REGCACHE_NONE, diff --git a/drivers/mfd/rz-mtu3.c b/drivers/mfd/rz-mtu3.c new file mode 100644 index 000000000000..04006f4aa702 --- /dev/null +++ b/drivers/mfd/rz-mtu3.c @@ -0,0 +1,391 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas RZ/G2L Multi-Function Timer Pulse Unit 3(MTU3a) Core driver + * + * Copyright (C) 2023 Renesas Electronics Corporation + */ + +#include <linux/bitfield.h> +#include <linux/clk.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/mfd/core.h> +#include <linux/mfd/rz-mtu3.h> +#include <linux/of_platform.h> +#include <linux/reset.h> +#include <linux/spinlock.h> + +#include "rz-mtu3.h" + +struct rz_mtu3_priv { + void __iomem *mmio; + struct reset_control *rstc; + raw_spinlock_t lock; +}; + +/******* MTU3 registers (original offset is +0x1200) *******/ +static const unsigned long rz_mtu3_8bit_ch_reg_offs[][13] = { + [RZ_MTU3_CHAN_0] = MTU_8BIT_CH_0(0x104, 0x090, 0x100, 0x128, 0x101, 0x102, 0x103, 0x126), + [RZ_MTU3_CHAN_1] = MTU_8BIT_CH_1_2(0x184, 0x091, 0x185, 0x180, 0x194, 0x181, 0x182), + [RZ_MTU3_CHAN_2] = MTU_8BIT_CH_1_2(0x204, 0x092, 0x205, 0x200, 0x20c, 0x201, 0x202), + [RZ_MTU3_CHAN_3] = MTU_8BIT_CH_3_4_6_7(0x008, 0x093, 0x02c, 0x000, 0x04c, 0x002, 0x004, 0x005, 0x038), + [RZ_MTU3_CHAN_4] = MTU_8BIT_CH_3_4_6_7(0x009, 0x094, 0x02d, 0x001, 0x04d, 0x003, 0x006, 0x007, 0x039), + [RZ_MTU3_CHAN_5] = MTU_8BIT_CH_5(0xab2, 0x1eb, 0xab4, 0xab6, 0xa84, 0xa85, 0xa86, 0xa94, 0xa95, 0xa96, 0xaa4, 0xaa5, 0xaa6), + [RZ_MTU3_CHAN_6] = MTU_8BIT_CH_3_4_6_7(0x808, 0x893, 0x82c, 0x800, 0x84c, 0x802, 0x804, 0x805, 0x838), + [RZ_MTU3_CHAN_7] = MTU_8BIT_CH_3_4_6_7(0x809, 0x894, 0x82d, 0x801, 0x84d, 0x803, 0x806, 0x807, 0x839), + [RZ_MTU3_CHAN_8] = MTU_8BIT_CH_8(0x404, 0x098, 0x400, 0x406, 0x401, 0x402, 0x403) +}; + +static const unsigned long rz_mtu3_16bit_ch_reg_offs[][12] = { + [RZ_MTU3_CHAN_0] = MTU_16BIT_CH_0(0x106, 0x108, 0x10a, 0x10c, 0x10e, 0x120, 0x122), + [RZ_MTU3_CHAN_1] = MTU_16BIT_CH_1_2(0x186, 0x188, 0x18a), + [RZ_MTU3_CHAN_2] = MTU_16BIT_CH_1_2(0x206, 0x208, 0x20a), + [RZ_MTU3_CHAN_3] = MTU_16BIT_CH_3_6(0x010, 0x018, 0x01a, 0x024, 0x026, 0x072), + [RZ_MTU3_CHAN_4] = MTU_16BIT_CH_4_7(0x012, 0x01c, 0x01e, 0x028, 0x2a, 0x074, 0x076, 0x040, 0x044, 0x046, 0x048, 0x04a), + [RZ_MTU3_CHAN_5] = MTU_16BIT_CH_5(0xa80, 0xa82, 0xa90, 0xa92, 0xaa0, 0xaa2), + [RZ_MTU3_CHAN_6] = MTU_16BIT_CH_3_6(0x810, 0x818, 0x81a, 0x824, 0x826, 0x872), + [RZ_MTU3_CHAN_7] = MTU_16BIT_CH_4_7(0x812, 0x81c, 0x81e, 0x828, 0x82a, 0x874, 0x876, 0x840, 0x844, 0x846, 0x848, 0x84a) +}; + +static const unsigned long rz_mtu3_32bit_ch_reg_offs[][5] = { + [RZ_MTU3_CHAN_1] = MTU_32BIT_CH_1(0x1a0, 0x1a4, 0x1a8), + [RZ_MTU3_CHAN_8] = MTU_32BIT_CH_8(0x408, 0x40c, 0x410, 0x414, 0x418) +}; + +static bool rz_mtu3_is_16bit_shared_reg(u16 offset) +{ + return (offset == RZ_MTU3_TDDRA || offset == RZ_MTU3_TDDRB || + offset == RZ_MTU3_TCDRA || offset == RZ_MTU3_TCDRB || + offset == RZ_MTU3_TCBRA || offset == RZ_MTU3_TCBRB || + offset == RZ_MTU3_TCNTSA || offset == RZ_MTU3_TCNTSB); +} + +u16 rz_mtu3_shared_reg_read(struct rz_mtu3_channel *ch, u16 offset) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent); + struct rz_mtu3_priv *priv = mtu->priv_data; + + if (rz_mtu3_is_16bit_shared_reg(offset)) + return readw(priv->mmio + offset); + else + return readb(priv->mmio + offset); +} +EXPORT_SYMBOL_GPL(rz_mtu3_shared_reg_read); + +u8 rz_mtu3_8bit_ch_read(struct rz_mtu3_channel *ch, u16 offset) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent); + struct rz_mtu3_priv *priv = mtu->priv_data; + u16 ch_offs; + + ch_offs = rz_mtu3_8bit_ch_reg_offs[ch->channel_number][offset]; + + return readb(priv->mmio + ch_offs); +} +EXPORT_SYMBOL_GPL(rz_mtu3_8bit_ch_read); + +u16 rz_mtu3_16bit_ch_read(struct rz_mtu3_channel *ch, u16 offset) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent); + struct rz_mtu3_priv *priv = mtu->priv_data; + u16 ch_offs; + + /* MTU8 doesn't have 16-bit registers */ + if (ch->channel_number == RZ_MTU3_CHAN_8) + return 0; + + ch_offs = rz_mtu3_16bit_ch_reg_offs[ch->channel_number][offset]; + + return readw(priv->mmio + ch_offs); +} +EXPORT_SYMBOL_GPL(rz_mtu3_16bit_ch_read); + +u32 rz_mtu3_32bit_ch_read(struct rz_mtu3_channel *ch, u16 offset) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent); + struct rz_mtu3_priv *priv = mtu->priv_data; + u16 ch_offs; + + if (ch->channel_number != RZ_MTU3_CHAN_1 && ch->channel_number != RZ_MTU3_CHAN_8) + return 0; + + ch_offs = rz_mtu3_32bit_ch_reg_offs[ch->channel_number][offset]; + + return readl(priv->mmio + ch_offs); +} +EXPORT_SYMBOL_GPL(rz_mtu3_32bit_ch_read); + +void rz_mtu3_8bit_ch_write(struct rz_mtu3_channel *ch, u16 offset, u8 val) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent); + struct rz_mtu3_priv *priv = mtu->priv_data; + u16 ch_offs; + + ch_offs = rz_mtu3_8bit_ch_reg_offs[ch->channel_number][offset]; + writeb(val, priv->mmio + ch_offs); +} +EXPORT_SYMBOL_GPL(rz_mtu3_8bit_ch_write); + +void rz_mtu3_16bit_ch_write(struct rz_mtu3_channel *ch, u16 offset, u16 val) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent); + struct rz_mtu3_priv *priv = mtu->priv_data; + u16 ch_offs; + + /* MTU8 doesn't have 16-bit registers */ + if (ch->channel_number == RZ_MTU3_CHAN_8) + return; + + ch_offs = rz_mtu3_16bit_ch_reg_offs[ch->channel_number][offset]; + writew(val, priv->mmio + ch_offs); +} +EXPORT_SYMBOL_GPL(rz_mtu3_16bit_ch_write); + +void rz_mtu3_32bit_ch_write(struct rz_mtu3_channel *ch, u16 offset, u32 val) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent); + struct rz_mtu3_priv *priv = mtu->priv_data; + u16 ch_offs; + + if (ch->channel_number != RZ_MTU3_CHAN_1 && ch->channel_number != RZ_MTU3_CHAN_8) + return; + + ch_offs = rz_mtu3_32bit_ch_reg_offs[ch->channel_number][offset]; + writel(val, priv->mmio + ch_offs); +} +EXPORT_SYMBOL_GPL(rz_mtu3_32bit_ch_write); + +void rz_mtu3_shared_reg_write(struct rz_mtu3_channel *ch, u16 offset, u16 value) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent); + struct rz_mtu3_priv *priv = mtu->priv_data; + + if (rz_mtu3_is_16bit_shared_reg(offset)) + writew(value, priv->mmio + offset); + else + writeb((u8)value, priv->mmio + offset); +} +EXPORT_SYMBOL_GPL(rz_mtu3_shared_reg_write); + +void rz_mtu3_shared_reg_update_bit(struct rz_mtu3_channel *ch, u16 offset, + u16 pos, u8 val) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent); + struct rz_mtu3_priv *priv = mtu->priv_data; + unsigned long tmdr, flags; + + raw_spin_lock_irqsave(&priv->lock, flags); + tmdr = rz_mtu3_shared_reg_read(ch, offset); + __assign_bit(pos, &tmdr, !!val); + rz_mtu3_shared_reg_write(ch, offset, tmdr); + raw_spin_unlock_irqrestore(&priv->lock, flags); +} +EXPORT_SYMBOL_GPL(rz_mtu3_shared_reg_update_bit); + +static u16 rz_mtu3_get_tstr_offset(struct rz_mtu3_channel *ch) +{ + u16 offset; + + switch (ch->channel_number) { + case RZ_MTU3_CHAN_0: + case RZ_MTU3_CHAN_1: + case RZ_MTU3_CHAN_2: + case RZ_MTU3_CHAN_3: + case RZ_MTU3_CHAN_4: + case RZ_MTU3_CHAN_8: + offset = RZ_MTU3_TSTRA; + break; + case RZ_MTU3_CHAN_5: + offset = RZ_MTU3_TSTR; + break; + case RZ_MTU3_CHAN_6: + case RZ_MTU3_CHAN_7: + offset = RZ_MTU3_TSTRB; + break; + default: + offset = 0; + break; + } + + return offset; +} + +static u8 rz_mtu3_get_tstr_bit_pos(struct rz_mtu3_channel *ch) +{ + u8 bitpos; + + switch (ch->channel_number) { + case RZ_MTU3_CHAN_0: + case RZ_MTU3_CHAN_1: + case RZ_MTU3_CHAN_2: + case RZ_MTU3_CHAN_6: + case RZ_MTU3_CHAN_7: + bitpos = ch->channel_number; + break; + case RZ_MTU3_CHAN_3: + bitpos = 6; + break; + case RZ_MTU3_CHAN_4: + bitpos = 7; + break; + case RZ_MTU3_CHAN_5: + bitpos = 2; + break; + case RZ_MTU3_CHAN_8: + bitpos = 3; + break; + default: + bitpos = 0; + break; + } + + return bitpos; +} + +static void rz_mtu3_start_stop_ch(struct rz_mtu3_channel *ch, bool start) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent); + struct rz_mtu3_priv *priv = mtu->priv_data; + unsigned long flags, tstr; + u16 offset; + u8 bitpos; + + /* start stop register shared by multiple timer channels */ + raw_spin_lock_irqsave(&priv->lock, flags); + + offset = rz_mtu3_get_tstr_offset(ch); + bitpos = rz_mtu3_get_tstr_bit_pos(ch); + tstr = rz_mtu3_shared_reg_read(ch, offset); + __assign_bit(bitpos, &tstr, start); + rz_mtu3_shared_reg_write(ch, offset, tstr); + + raw_spin_unlock_irqrestore(&priv->lock, flags); +} + +bool rz_mtu3_is_enabled(struct rz_mtu3_channel *ch) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent); + struct rz_mtu3_priv *priv = mtu->priv_data; + unsigned long flags, tstr; + bool ret = false; + u16 offset; + u8 bitpos; + + /* start stop register shared by multiple timer channels */ + raw_spin_lock_irqsave(&priv->lock, flags); + + offset = rz_mtu3_get_tstr_offset(ch); + bitpos = rz_mtu3_get_tstr_bit_pos(ch); + tstr = rz_mtu3_shared_reg_read(ch, offset); + ret = tstr & BIT(bitpos); + + raw_spin_unlock_irqrestore(&priv->lock, flags); + + return ret; +} +EXPORT_SYMBOL_GPL(rz_mtu3_is_enabled); + +int rz_mtu3_enable(struct rz_mtu3_channel *ch) +{ + /* enable channel */ + rz_mtu3_start_stop_ch(ch, true); + + return 0; +} +EXPORT_SYMBOL_GPL(rz_mtu3_enable); + +void rz_mtu3_disable(struct rz_mtu3_channel *ch) +{ + /* disable channel */ + rz_mtu3_start_stop_ch(ch, false); +} +EXPORT_SYMBOL_GPL(rz_mtu3_disable); + +static void rz_mtu3_reset_assert(void *data) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(data); + struct rz_mtu3_priv *priv = mtu->priv_data; + + mfd_remove_devices(data); + reset_control_assert(priv->rstc); +} + +static const struct mfd_cell rz_mtu3_devs[] = { + { + .name = "rz-mtu3-counter", + }, + { + .name = "pwm-rz-mtu3", + }, +}; + +static int rz_mtu3_probe(struct platform_device *pdev) +{ + struct rz_mtu3_priv *priv; + struct rz_mtu3 *ddata; + unsigned int i; + int ret; + + ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); + if (!ddata) + return -ENOMEM; + + ddata->priv_data = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!ddata->priv_data) + return -ENOMEM; + + priv = ddata->priv_data; + + priv->mmio = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->mmio)) + return PTR_ERR(priv->mmio); + + priv->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); + if (IS_ERR(priv->rstc)) + return PTR_ERR(priv->rstc); + + ddata->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(ddata->clk)) + return PTR_ERR(ddata->clk); + + reset_control_deassert(priv->rstc); + raw_spin_lock_init(&priv->lock); + platform_set_drvdata(pdev, ddata); + + for (i = 0; i < RZ_MTU_NUM_CHANNELS; i++) { + ddata->channels[i].channel_number = i; + ddata->channels[i].is_busy = false; + mutex_init(&ddata->channels[i].lock); + } + + ret = mfd_add_devices(&pdev->dev, 0, rz_mtu3_devs, + ARRAY_SIZE(rz_mtu3_devs), NULL, 0, NULL); + if (ret < 0) + goto err_assert; + + return devm_add_action_or_reset(&pdev->dev, rz_mtu3_reset_assert, + &pdev->dev); + +err_assert: + reset_control_assert(priv->rstc); + return ret; +} + +static const struct of_device_id rz_mtu3_of_match[] = { + { .compatible = "renesas,rz-mtu3", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rz_mtu3_of_match); + +static struct platform_driver rz_mtu3_driver = { + .probe = rz_mtu3_probe, + .driver = { + .name = "rz-mtu3", + .of_match_table = rz_mtu3_of_match, + }, +}; +module_platform_driver(rz_mtu3_driver); + +MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>"); +MODULE_DESCRIPTION("Renesas RZ/G2L MTU3a Core Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/rz-mtu3.h b/drivers/mfd/rz-mtu3.h new file mode 100644 index 000000000000..51a1298b0613 --- /dev/null +++ b/drivers/mfd/rz-mtu3.h @@ -0,0 +1,147 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * MFD internals for Renesas RZ/G2L MTU3 Core driver + * + * Copyright (C) 2023 Renesas Electronics Corporation + */ + +#ifndef RZ_MTU3_MFD_H +#define RZ_MTU3_MFD_H + +#define MTU_8BIT_CH_0(_tier, _nfcr, _tcr, _tcr2, _tmdr1, _tiorh, _tiorl, _tbtm) \ + { \ + [RZ_MTU3_TIER] = _tier, \ + [RZ_MTU3_NFCR] = _nfcr, \ + [RZ_MTU3_TCR] = _tcr, \ + [RZ_MTU3_TCR2] = _tcr2, \ + [RZ_MTU3_TMDR1] = _tmdr1, \ + [RZ_MTU3_TIORH] = _tiorh, \ + [RZ_MTU3_TIORL] = _tiorl, \ + [RZ_MTU3_TBTM] = _tbtm \ + } + +#define MTU_8BIT_CH_1_2(_tier, _nfcr, _tsr, _tcr, _tcr2, _tmdr1, _tior) \ + { \ + [RZ_MTU3_TIER] = _tier, \ + [RZ_MTU3_NFCR] = _nfcr, \ + [RZ_MTU3_TSR] = _tsr, \ + [RZ_MTU3_TCR] = _tcr, \ + [RZ_MTU3_TCR2] = _tcr2, \ + [RZ_MTU3_TMDR1] = _tmdr1, \ + [RZ_MTU3_TIOR] = _tior \ + } \ + +#define MTU_8BIT_CH_3_4_6_7(_tier, _nfcr, _tsr, _tcr, _tcr2, _tmdr1, _tiorh, _tiorl, _tbtm) \ + { \ + [RZ_MTU3_TIER] = _tier, \ + [RZ_MTU3_NFCR] = _nfcr, \ + [RZ_MTU3_TSR] = _tsr, \ + [RZ_MTU3_TCR] = _tcr, \ + [RZ_MTU3_TCR2] = _tcr2, \ + [RZ_MTU3_TMDR1] = _tmdr1, \ + [RZ_MTU3_TIORH] = _tiorh, \ + [RZ_MTU3_TIORL] = _tiorl, \ + [RZ_MTU3_TBTM] = _tbtm \ + } \ + +#define MTU_8BIT_CH_5(_tier, _nfcr, _tstr, _tcntcmpclr, _tcru, _tcr2u, _tioru, \ + _tcrv, _tcr2v, _tiorv, _tcrw, _tcr2w, _tiorw) \ + { \ + [RZ_MTU3_TIER] = _tier, \ + [RZ_MTU3_NFCR] = _nfcr, \ + [RZ_MTU3_TSTR] = _tstr, \ + [RZ_MTU3_TCNTCMPCLR] = _tcntcmpclr, \ + [RZ_MTU3_TCRU] = _tcru, \ + [RZ_MTU3_TCR2U] = _tcr2u, \ + [RZ_MTU3_TIORU] = _tioru, \ + [RZ_MTU3_TCRV] = _tcrv, \ + [RZ_MTU3_TCR2V] = _tcr2v, \ + [RZ_MTU3_TIORV] = _tiorv, \ + [RZ_MTU3_TCRW] = _tcrw, \ + [RZ_MTU3_TCR2W] = _tcr2w, \ + [RZ_MTU3_TIORW] = _tiorw \ + } \ + +#define MTU_8BIT_CH_8(_tier, _nfcr, _tcr, _tcr2, _tmdr1, _tiorh, _tiorl) \ + { \ + [RZ_MTU3_TIER] = _tier, \ + [RZ_MTU3_NFCR] = _nfcr, \ + [RZ_MTU3_TCR] = _tcr, \ + [RZ_MTU3_TCR2] = _tcr2, \ + [RZ_MTU3_TMDR1] = _tmdr1, \ + [RZ_MTU3_TIORH] = _tiorh, \ + [RZ_MTU3_TIORL] = _tiorl \ + } \ + +#define MTU_16BIT_CH_0(_tcnt, _tgra, _tgrb, _tgrc, _tgrd, _tgre, _tgrf) \ + { \ + [RZ_MTU3_TCNT] = _tcnt, \ + [RZ_MTU3_TGRA] = _tgra, \ + [RZ_MTU3_TGRB] = _tgrb, \ + [RZ_MTU3_TGRC] = _tgrc, \ + [RZ_MTU3_TGRD] = _tgrd, \ + [RZ_MTU3_TGRE] = _tgre, \ + [RZ_MTU3_TGRF] = _tgrf \ + } + +#define MTU_16BIT_CH_1_2(_tcnt, _tgra, _tgrb) \ + { \ + [RZ_MTU3_TCNT] = _tcnt, \ + [RZ_MTU3_TGRA] = _tgra, \ + [RZ_MTU3_TGRB] = _tgrb \ + } + +#define MTU_16BIT_CH_3_6(_tcnt, _tgra, _tgrb, _tgrc, _tgrd, _tgre) \ + { \ + [RZ_MTU3_TCNT] = _tcnt, \ + [RZ_MTU3_TGRA] = _tgra, \ + [RZ_MTU3_TGRB] = _tgrb, \ + [RZ_MTU3_TGRC] = _tgrc, \ + [RZ_MTU3_TGRD] = _tgrd, \ + [RZ_MTU3_TGRE] = _tgre \ + } + +#define MTU_16BIT_CH_4_7(_tcnt, _tgra, _tgrb, _tgrc, _tgrd, _tgre, _tgrf, \ + _tadcr, _tadcora, _tadcorb, _tadcobra, _tadcobrb) \ + { \ + [RZ_MTU3_TCNT] = _tcnt, \ + [RZ_MTU3_TGRA] = _tgra, \ + [RZ_MTU3_TGRB] = _tgrb, \ + [RZ_MTU3_TGRC] = _tgrc, \ + [RZ_MTU3_TGRD] = _tgrd, \ + [RZ_MTU3_TGRE] = _tgre, \ + [RZ_MTU3_TGRF] = _tgrf, \ + [RZ_MTU3_TADCR] = _tadcr, \ + [RZ_MTU3_TADCORA] = _tadcora, \ + [RZ_MTU3_TADCORB] = _tadcorb, \ + [RZ_MTU3_TADCOBRA] = _tadcobra, \ + [RZ_MTU3_TADCOBRB] = _tadcobrb \ + } + +#define MTU_16BIT_CH_5(_tcntu, _tgru, _tcntv, _tgrv, _tcntw, _tgrw) \ + { \ + [RZ_MTU3_TCNTU] = _tcntu, \ + [RZ_MTU3_TGRU] = _tgru, \ + [RZ_MTU3_TCNTV] = _tcntv, \ + [RZ_MTU3_TGRV] = _tgrv, \ + [RZ_MTU3_TCNTW] = _tcntw, \ + [RZ_MTU3_TGRW] = _tgrw \ + } + +#define MTU_32BIT_CH_1(_tcntlw, _tgralw, _tgrblw) \ + { \ + [RZ_MTU3_TCNTLW] = _tcntlw, \ + [RZ_MTU3_TGRALW] = _tgralw, \ + [RZ_MTU3_TGRBLW] = _tgrblw \ + } + +#define MTU_32BIT_CH_8(_tcnt, _tgra, _tgrb, _tgrc, _tgrd) \ + { \ + [RZ_MTU3_TCNT] = _tcnt, \ + [RZ_MTU3_TGRA] = _tgra, \ + [RZ_MTU3_TGRB] = _tgrb, \ + [RZ_MTU3_TGRC] = _tgrc, \ + [RZ_MTU3_TGRD] = _tgrd \ + } + +#endif diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c index b03edda56009..c2d0ed496959 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c @@ -24,22 +24,9 @@ #include <linux/mfd/samsung/s2mps14.h> #include <linux/mfd/samsung/s2mps15.h> #include <linux/mfd/samsung/s2mpu02.h> -#include <linux/mfd/samsung/s5m8763.h> #include <linux/mfd/samsung/s5m8767.h> #include <linux/regmap.h> -static const struct mfd_cell s5m8751_devs[] = { - { .name = "s5m8751-pmic", }, - { .name = "s5m-charger", }, - { .name = "s5m8751-codec", }, -}; - -static const struct mfd_cell s5m8763_devs[] = { - { .name = "s5m8763-pmic", }, - { .name = "s5m-rtc", }, - { .name = "s5m-charger", }, -}; - static const struct mfd_cell s5m8767_devs[] = { { .name = "s5m8767-pmic", }, { .name = "s5m-rtc", }, @@ -158,19 +145,6 @@ static bool s2mpu02_volatile(struct device *dev, unsigned int reg) } } -static bool s5m8763_volatile(struct device *dev, unsigned int reg) -{ - switch (reg) { - case S5M8763_REG_IRQM1: - case S5M8763_REG_IRQM2: - case S5M8763_REG_IRQM3: - case S5M8763_REG_IRQM4: - return false; - default: - return true; - } -} - static const struct regmap_config sec_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -230,15 +204,6 @@ static const struct regmap_config s2mpu02_regmap_config = { .cache_type = REGCACHE_FLAT, }; -static const struct regmap_config s5m8763_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - - .max_register = S5M8763_REG_LBCNFG2, - .volatile_reg = s5m8763_volatile, - .cache_type = REGCACHE_FLAT, -}; - static const struct regmap_config s5m8767_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -348,9 +313,6 @@ static int sec_pmic_probe(struct i2c_client *i2c) case S2MPS15X: regmap = &s2mps15_regmap_config; break; - case S5M8763X: - regmap = &s5m8763_regmap_config; - break; case S5M8767X: regmap = &s5m8767_regmap_config; break; @@ -375,14 +337,6 @@ static int sec_pmic_probe(struct i2c_client *i2c) pm_runtime_set_active(sec_pmic->dev); switch (sec_pmic->device_type) { - case S5M8751X: - sec_devs = s5m8751_devs; - num_sec_devs = ARRAY_SIZE(s5m8751_devs); - break; - case S5M8763X: - sec_devs = s5m8763_devs; - num_sec_devs = ARRAY_SIZE(s5m8763_devs); - break; case S5M8767X: sec_devs = s5m8767_devs; num_sec_devs = ARRAY_SIZE(s5m8767_devs); diff --git a/drivers/mfd/sec-irq.c b/drivers/mfd/sec-irq.c index f5f59fdc72fe..e191aeb0c07c 100644 --- a/drivers/mfd/sec-irq.c +++ b/drivers/mfd/sec-irq.c @@ -14,7 +14,6 @@ #include <linux/mfd/samsung/s2mps11.h> #include <linux/mfd/samsung/s2mps14.h> #include <linux/mfd/samsung/s2mpu02.h> -#include <linux/mfd/samsung/s5m8763.h> #include <linux/mfd/samsung/s5m8767.h> static const struct regmap_irq s2mps11_irqs[] = { @@ -297,81 +296,6 @@ static const struct regmap_irq s5m8767_irqs[] = { }, }; -static const struct regmap_irq s5m8763_irqs[] = { - [S5M8763_IRQ_DCINF] = { - .reg_offset = 0, - .mask = S5M8763_IRQ_DCINF_MASK, - }, - [S5M8763_IRQ_DCINR] = { - .reg_offset = 0, - .mask = S5M8763_IRQ_DCINR_MASK, - }, - [S5M8763_IRQ_JIGF] = { - .reg_offset = 0, - .mask = S5M8763_IRQ_JIGF_MASK, - }, - [S5M8763_IRQ_JIGR] = { - .reg_offset = 0, - .mask = S5M8763_IRQ_JIGR_MASK, - }, - [S5M8763_IRQ_PWRONF] = { - .reg_offset = 0, - .mask = S5M8763_IRQ_PWRONF_MASK, - }, - [S5M8763_IRQ_PWRONR] = { - .reg_offset = 0, - .mask = S5M8763_IRQ_PWRONR_MASK, - }, - [S5M8763_IRQ_WTSREVNT] = { - .reg_offset = 1, - .mask = S5M8763_IRQ_WTSREVNT_MASK, - }, - [S5M8763_IRQ_SMPLEVNT] = { - .reg_offset = 1, - .mask = S5M8763_IRQ_SMPLEVNT_MASK, - }, - [S5M8763_IRQ_ALARM1] = { - .reg_offset = 1, - .mask = S5M8763_IRQ_ALARM1_MASK, - }, - [S5M8763_IRQ_ALARM0] = { - .reg_offset = 1, - .mask = S5M8763_IRQ_ALARM0_MASK, - }, - [S5M8763_IRQ_ONKEY1S] = { - .reg_offset = 2, - .mask = S5M8763_IRQ_ONKEY1S_MASK, - }, - [S5M8763_IRQ_TOPOFFR] = { - .reg_offset = 2, - .mask = S5M8763_IRQ_TOPOFFR_MASK, - }, - [S5M8763_IRQ_DCINOVPR] = { - .reg_offset = 2, - .mask = S5M8763_IRQ_DCINOVPR_MASK, - }, - [S5M8763_IRQ_CHGRSTF] = { - .reg_offset = 2, - .mask = S5M8763_IRQ_CHGRSTF_MASK, - }, - [S5M8763_IRQ_DONER] = { - .reg_offset = 2, - .mask = S5M8763_IRQ_DONER_MASK, - }, - [S5M8763_IRQ_CHGFAULT] = { - .reg_offset = 2, - .mask = S5M8763_IRQ_CHGFAULT_MASK, - }, - [S5M8763_IRQ_LOBAT1] = { - .reg_offset = 3, - .mask = S5M8763_IRQ_LOBAT1_MASK, - }, - [S5M8763_IRQ_LOBAT2] = { - .reg_offset = 3, - .mask = S5M8763_IRQ_LOBAT2_MASK, - }, -}; - static const struct regmap_irq_chip s2mps11_irq_chip = { .name = "s2mps11", .irqs = s2mps11_irqs, @@ -425,16 +349,6 @@ static const struct regmap_irq_chip s5m8767_irq_chip = { .ack_base = S5M8767_REG_INT1, }; -static const struct regmap_irq_chip s5m8763_irq_chip = { - .name = "s5m8763", - .irqs = s5m8763_irqs, - .num_irqs = ARRAY_SIZE(s5m8763_irqs), - .num_regs = 4, - .status_base = S5M8763_REG_IRQ1, - .mask_base = S5M8763_REG_IRQM1, - .ack_base = S5M8763_REG_IRQ1, -}; - int sec_irq_init(struct sec_pmic_dev *sec_pmic) { int ret = 0; @@ -448,9 +362,6 @@ int sec_irq_init(struct sec_pmic_dev *sec_pmic) } switch (type) { - case S5M8763X: - sec_irq_chip = &s5m8763_irq_chip; - break; case S5M8767X: sec_irq_chip = &s5m8767_irq_chip; break; diff --git a/drivers/mfd/si476x-cmd.c b/drivers/mfd/si476x-cmd.c index f32f1fb93e37..c9a0ec084aa8 100644 --- a/drivers/mfd/si476x-cmd.c +++ b/drivers/mfd/si476x-cmd.c @@ -251,7 +251,7 @@ static int si476x_core_parse_and_nag_about_error(struct si476x_core *core) * @usecs: amount of time to wait before reading the response (in * usecs) * - * Function returns 0 on succsess and negative error code on + * Function returns 0 on success and negative error code on * failure */ static int si476x_core_send_command(struct si476x_core *core, @@ -398,7 +398,7 @@ static int si476x_cmd_tune_seek_freq(struct si476x_core *core, * The command requests the firmware and patch version for currently * loaded firmware (dependent on the function of the device FM/AM/WB) * - * Function returns 0 on succsess and negative error code on + * Function returns 0 on success and negative error code on * failure */ int si476x_core_cmd_func_info(struct si476x_core *core, @@ -429,7 +429,7 @@ EXPORT_SYMBOL_GPL(si476x_core_cmd_func_info); * @property: property address * @value: property value * - * Function returns 0 on succsess and negative error code on + * Function returns 0 on success and negative error code on * failure */ int si476x_core_cmd_set_property(struct si476x_core *core, @@ -545,13 +545,13 @@ EXPORT_SYMBOL_GPL(si476x_core_cmd_dig_audio_pin_cfg); * SI476X_IQCLK_NOOP - do not modify the behaviour * SI476X_IQCLK_TRISTATE - put the pin in tristate condition, * enable 1MOhm pulldown - * SI476X_IQCLK_IQ - set pin to be a part of I/Q interace + * SI476X_IQCLK_IQ - set pin to be a part of I/Q interface * in master mode * @iqfs: - IQFS pin function configuration: * SI476X_IQFS_NOOP - do not modify the behaviour * SI476X_IQFS_TRISTATE - put the pin in tristate condition, * enable 1MOhm pulldown - * SI476X_IQFS_IQ - set pin to be a part of I/Q interace + * SI476X_IQFS_IQ - set pin to be a part of I/Q interface * in master mode * @iout: - IOUT pin function configuration: * SI476X_IOUT_NOOP - do not modify the behaviour @@ -589,7 +589,7 @@ EXPORT_SYMBOL_GPL(si476x_core_cmd_zif_pin_cfg); /** * si476x_core_cmd_ic_link_gpo_ctl_pin_cfg - send - * 'IC_LINK_GPIO_CTL_PIN_CFG' comand to the device + * 'IC_LINK_GPIO_CTL_PIN_CFG' command to the device * @core: - device to send the command to * @icin: - ICIN pin function configuration: * SI476X_ICIN_NOOP - do not modify the behaviour @@ -1014,7 +1014,7 @@ EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_phase_diversity); * NOTE caller must hold core lock * * Function returns the value of the status bit in case of success and - * negative error code in case of failre. + * negative error code in case of failure. */ int si476x_core_cmd_fm_phase_div_status(struct si476x_core *core) { diff --git a/drivers/mfd/simple-mfd-i2c.c b/drivers/mfd/simple-mfd-i2c.c index e31f13fd6a79..20782b4dd172 100644 --- a/drivers/mfd/simple-mfd-i2c.c +++ b/drivers/mfd/simple-mfd-i2c.c @@ -72,9 +72,22 @@ static const struct simple_mfd_data silergy_sy7636a = { .mfd_cell_size = ARRAY_SIZE(sy7636a_cells), }; +static const struct mfd_cell max597x_cells[] = { + { .name = "max597x-regulator", }, + { .name = "max597x-iio", }, + { .name = "max597x-led", }, +}; + +static const struct simple_mfd_data maxim_max597x = { + .mfd_cell = max597x_cells, + .mfd_cell_size = ARRAY_SIZE(max597x_cells), +}; + static const struct of_device_id simple_mfd_i2c_of_match[] = { { .compatible = "kontron,sl28cpld" }, { .compatible = "silergy,sy7636a", .data = &silergy_sy7636a}, + { .compatible = "maxim,max5970", .data = &maxim_max597x}, + { .compatible = "maxim,max5978", .data = &maxim_max597x}, {} }; MODULE_DEVICE_TABLE(of, simple_mfd_i2c_of_match); diff --git a/drivers/mfd/ssbi.c b/drivers/mfd/ssbi.c index 94f60df0decd..dee89db3471d 100644 --- a/drivers/mfd/ssbi.c +++ b/drivers/mfd/ssbi.c @@ -262,7 +262,6 @@ EXPORT_SYMBOL_GPL(ssbi_write); static int ssbi_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - struct resource *mem_res; struct ssbi *ssbi; const char *type; @@ -270,8 +269,7 @@ static int ssbi_probe(struct platform_device *pdev) if (!ssbi) return -ENOMEM; - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ssbi->base = devm_ioremap_resource(&pdev->dev, mem_res); + ssbi->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); if (IS_ERR(ssbi->base)) return PTR_ERR(ssbi->base); diff --git a/drivers/mfd/stmpe-i2c.c b/drivers/mfd/stmpe-i2c.c index d4944fc1feb1..7998e0db1e15 100644 --- a/drivers/mfd/stmpe-i2c.c +++ b/drivers/mfd/stmpe-i2c.c @@ -135,6 +135,5 @@ static void __exit stmpe_exit(void) } module_exit(stmpe_exit); -MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("STMPE MFD I2C Interface Driver"); MODULE_AUTHOR("Rabin Vincent <rabin.vincent@stericsson.com>"); diff --git a/drivers/mfd/stmpe-spi.c b/drivers/mfd/stmpe-spi.c index e9cbf33502b3..792236f56399 100644 --- a/drivers/mfd/stmpe-spi.c +++ b/drivers/mfd/stmpe-spi.c @@ -154,6 +154,5 @@ static void __exit stmpe_exit(void) } module_exit(stmpe_exit); -MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("STMPE MFD SPI Interface Driver"); MODULE_AUTHOR("Viresh Kumar <vireshk@kernel.org>"); diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index c304d20bb988..a92301dfc712 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c @@ -1378,7 +1378,7 @@ int stmpe_probe(struct stmpe_client_info *ci, enum stmpe_partnum partnum) stmpe_of_probe(pdata, np); - if (of_find_property(np, "interrupts", NULL) == NULL) + if (!of_property_present(np, "interrupts")) ci->irq = -1; stmpe = devm_kzalloc(ci->dev, sizeof(struct stmpe), GFP_KERNEL); diff --git a/drivers/mfd/sun4i-gpadc.c b/drivers/mfd/sun4i-gpadc.c index edc180d83a4b..d1cbea27b136 100644 --- a/drivers/mfd/sun4i-gpadc.c +++ b/drivers/mfd/sun4i-gpadc.c @@ -93,7 +93,6 @@ MODULE_DEVICE_TABLE(of, sun4i_gpadc_of_match); static int sun4i_gpadc_probe(struct platform_device *pdev) { struct sun4i_gpadc_dev *dev; - struct resource *mem; const struct of_device_id *of_id; const struct mfd_cell *cells; unsigned int irq, size; @@ -124,8 +123,7 @@ static int sun4i_gpadc_probe(struct platform_device *pdev) if (!dev) return -ENOMEM; - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dev->base = devm_ioremap_resource(&pdev->dev, mem); + dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); if (IS_ERR(dev->base)) return PTR_ERR(dev->base); diff --git a/drivers/mfd/tc3589x.c b/drivers/mfd/tc3589x.c index 1f6e0d682cd9..cbfe19d1b145 100644 --- a/drivers/mfd/tc3589x.c +++ b/drivers/mfd/tc3589x.c @@ -502,6 +502,5 @@ static void __exit tc3589x_exit(void) } module_exit(tc3589x_exit); -MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("TC3589x MFD core driver"); MODULE_AUTHOR("Hanumath Prasad, Rabin Vincent"); diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index 2d947f3f606a..90e23232b6b0 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c @@ -638,4 +638,3 @@ module_exit(tps6586x_exit); MODULE_DESCRIPTION("TPS6586X core driver"); MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/tqmx86.c b/drivers/mfd/tqmx86.c index 7ae906ff8e35..fac02875fe7d 100644 --- a/drivers/mfd/tqmx86.c +++ b/drivers/mfd/tqmx86.c @@ -16,8 +16,8 @@ #include <linux/platform_data/i2c-ocores.h> #include <linux/platform_device.h> -#define TQMX86_IOBASE 0x160 -#define TQMX86_IOSIZE 0x3f +#define TQMX86_IOBASE 0x180 +#define TQMX86_IOSIZE 0x20 #define TQMX86_IOBASE_I2C 0x1a0 #define TQMX86_IOSIZE_I2C 0xa #define TQMX86_IOBASE_WATCHDOG 0x18b @@ -25,14 +25,14 @@ #define TQMX86_IOBASE_GPIO 0x18d #define TQMX86_IOSIZE_GPIO 0x4 -#define TQMX86_REG_BOARD_ID 0x20 +#define TQMX86_REG_BOARD_ID 0x00 #define TQMX86_REG_BOARD_ID_E38M 1 #define TQMX86_REG_BOARD_ID_50UC 2 #define TQMX86_REG_BOARD_ID_E38C 3 #define TQMX86_REG_BOARD_ID_60EB 4 -#define TQMX86_REG_BOARD_ID_E39M 5 -#define TQMX86_REG_BOARD_ID_E39C 6 -#define TQMX86_REG_BOARD_ID_E39x 7 +#define TQMX86_REG_BOARD_ID_E39MS 5 +#define TQMX86_REG_BOARD_ID_E39C1 6 +#define TQMX86_REG_BOARD_ID_E39C2 7 #define TQMX86_REG_BOARD_ID_70EB 8 #define TQMX86_REG_BOARD_ID_80UC 9 #define TQMX86_REG_BOARD_ID_110EB 11 @@ -40,18 +40,18 @@ #define TQMX86_REG_BOARD_ID_E40S 13 #define TQMX86_REG_BOARD_ID_E40C1 14 #define TQMX86_REG_BOARD_ID_E40C2 15 -#define TQMX86_REG_BOARD_REV 0x21 -#define TQMX86_REG_IO_EXT_INT 0x26 +#define TQMX86_REG_BOARD_REV 0x01 +#define TQMX86_REG_IO_EXT_INT 0x06 #define TQMX86_REG_IO_EXT_INT_NONE 0 #define TQMX86_REG_IO_EXT_INT_7 1 #define TQMX86_REG_IO_EXT_INT_9 2 #define TQMX86_REG_IO_EXT_INT_12 3 #define TQMX86_REG_IO_EXT_INT_MASK 0x3 #define TQMX86_REG_IO_EXT_INT_GPIO_SHIFT 4 +#define TQMX86_REG_SAUC 0x17 -#define TQMX86_REG_I2C_DETECT 0x47 +#define TQMX86_REG_I2C_DETECT 0x1a7 #define TQMX86_REG_I2C_DETECT_SOFT 0xa5 -#define TQMX86_REG_I2C_INT_EN 0x49 static uint gpio_irq; module_param(gpio_irq, uint, 0); @@ -111,7 +111,7 @@ static const struct mfd_cell tqmx86_devs[] = { }, }; -static const char *tqmx86_board_id_to_name(u8 board_id) +static const char *tqmx86_board_id_to_name(u8 board_id, u8 sauc) { switch (board_id) { case TQMX86_REG_BOARD_ID_E38M: @@ -122,12 +122,12 @@ static const char *tqmx86_board_id_to_name(u8 board_id) return "TQMxE38C"; case TQMX86_REG_BOARD_ID_60EB: return "TQMx60EB"; - case TQMX86_REG_BOARD_ID_E39M: - return "TQMxE39M"; - case TQMX86_REG_BOARD_ID_E39C: - return "TQMxE39C"; - case TQMX86_REG_BOARD_ID_E39x: - return "TQMxE39x"; + case TQMX86_REG_BOARD_ID_E39MS: + return (sauc == 0xff) ? "TQMxE39M" : "TQMxE39S"; + case TQMX86_REG_BOARD_ID_E39C1: + return "TQMxE39C1"; + case TQMX86_REG_BOARD_ID_E39C2: + return "TQMxE39C2"; case TQMX86_REG_BOARD_ID_70EB: return "TQMx70EB"; case TQMX86_REG_BOARD_ID_80UC: @@ -160,9 +160,9 @@ static int tqmx86_board_id_to_clk_rate(struct device *dev, u8 board_id) case TQMX86_REG_BOARD_ID_E40C1: case TQMX86_REG_BOARD_ID_E40C2: return 24000; - case TQMX86_REG_BOARD_ID_E39M: - case TQMX86_REG_BOARD_ID_E39C: - case TQMX86_REG_BOARD_ID_E39x: + case TQMX86_REG_BOARD_ID_E39MS: + case TQMX86_REG_BOARD_ID_E39C1: + case TQMX86_REG_BOARD_ID_E39C2: return 25000; case TQMX86_REG_BOARD_ID_E38M: case TQMX86_REG_BOARD_ID_E38C: @@ -176,7 +176,7 @@ static int tqmx86_board_id_to_clk_rate(struct device *dev, u8 board_id) static int tqmx86_probe(struct platform_device *pdev) { - u8 board_id, rev, i2c_det, io_ext_int_val; + u8 board_id, sauc, rev, i2c_det, io_ext_int_val; struct device *dev = &pdev->dev; u8 gpio_irq_cfg, readback; const char *board_name; @@ -206,14 +206,20 @@ static int tqmx86_probe(struct platform_device *pdev) return -ENOMEM; board_id = ioread8(io_base + TQMX86_REG_BOARD_ID); - board_name = tqmx86_board_id_to_name(board_id); + sauc = ioread8(io_base + TQMX86_REG_SAUC); + board_name = tqmx86_board_id_to_name(board_id, sauc); rev = ioread8(io_base + TQMX86_REG_BOARD_REV); dev_info(dev, "Found %s - Board ID %d, PCB Revision %d, PLD Revision %d\n", board_name, board_id, rev >> 4, rev & 0xf); - i2c_det = ioread8(io_base + TQMX86_REG_I2C_DETECT); + /* + * The I2C_DETECT register is in the range assigned to the I2C driver + * later, so we don't extend TQMX86_IOSIZE. Use inb() for this one-off + * access instead of ioport_map + unmap. + */ + i2c_det = inb(TQMX86_REG_I2C_DETECT); if (gpio_irq_cfg) { io_ext_int_val = diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index e2d9a93be43b..e801b7ce010f 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -594,71 +594,6 @@ int twl_get_hfclk_rate(void) } EXPORT_SYMBOL_GPL(twl_get_hfclk_rate); -static struct device * -add_numbered_child(unsigned mod_no, const char *name, int num, - void *pdata, unsigned pdata_len, - bool can_wakeup, int irq0, int irq1) -{ - struct platform_device *pdev; - struct twl_client *twl; - int status, sid; - - if (unlikely(mod_no >= twl_get_last_module())) { - pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); - return ERR_PTR(-EPERM); - } - sid = twl_priv->twl_map[mod_no].sid; - twl = &twl_priv->twl_modules[sid]; - - pdev = platform_device_alloc(name, num); - if (!pdev) - return ERR_PTR(-ENOMEM); - - pdev->dev.parent = &twl->client->dev; - - if (pdata) { - status = platform_device_add_data(pdev, pdata, pdata_len); - if (status < 0) { - dev_dbg(&pdev->dev, "can't add platform_data\n"); - goto put_device; - } - } - - if (irq0) { - struct resource r[2] = { - { .start = irq0, .flags = IORESOURCE_IRQ, }, - { .start = irq1, .flags = IORESOURCE_IRQ, }, - }; - - status = platform_device_add_resources(pdev, r, irq1 ? 2 : 1); - if (status < 0) { - dev_dbg(&pdev->dev, "can't add irqs\n"); - goto put_device; - } - } - - status = platform_device_add(pdev); - if (status) - goto put_device; - - device_init_wakeup(&pdev->dev, can_wakeup); - - return &pdev->dev; - -put_device: - platform_device_put(pdev); - dev_err(&twl->client->dev, "failed to add device %s\n", name); - return ERR_PTR(status); -} - -static inline struct device *add_child(unsigned mod_no, const char *name, - void *pdata, unsigned pdata_len, - bool can_wakeup, int irq0, int irq1) -{ - return add_numbered_child(mod_no, name, -1, pdata, pdata_len, - can_wakeup, irq0, irq1); -} - /*----------------------------------------------------------------------*/ /* diff --git a/drivers/mfd/twl4030-audio.c b/drivers/mfd/twl4030-audio.c index 4536d829b43e..88002f8941e5 100644 --- a/drivers/mfd/twl4030-audio.c +++ b/drivers/mfd/twl4030-audio.c @@ -285,5 +285,4 @@ module_platform_driver(twl4030_audio_driver); MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>"); MODULE_DESCRIPTION("TWL4030 audio block MFD driver"); -MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:twl4030-audio"); diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c index fc97fa5a2d0c..e982119bbefa 100644 --- a/drivers/mfd/twl6040.c +++ b/drivers/mfd/twl6040.c @@ -839,4 +839,3 @@ module_i2c_driver(twl6040_driver); MODULE_DESCRIPTION("TWL6040 MFD"); MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>"); MODULE_AUTHOR("Jorge Eduardo Candelaria <jorge.candelaria@ti.com>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index a89221bffde5..c419ab0c0eae 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -279,20 +279,11 @@ static int wm8994_set_pdata_from_of(struct wm8994 *wm8994) of_property_read_u32_array(np, "wlf,micbias-cfg", pdata->micbias, ARRAY_SIZE(pdata->micbias)); - pdata->lineout1_diff = true; - pdata->lineout2_diff = true; - if (of_find_property(np, "wlf,lineout1-se", NULL)) - pdata->lineout1_diff = false; - if (of_find_property(np, "wlf,lineout2-se", NULL)) - pdata->lineout2_diff = false; - - if (of_find_property(np, "wlf,lineout1-feedback", NULL)) - pdata->lineout1fb = true; - if (of_find_property(np, "wlf,lineout2-feedback", NULL)) - pdata->lineout2fb = true; - - if (of_find_property(np, "wlf,ldoena-always-driven", NULL)) - pdata->lineout2fb = true; + pdata->lineout1_diff = !of_property_read_bool(np, "wlf,lineout1-se"); + pdata->lineout2_diff = !of_property_read_bool(np, "wlf,lineout2-se"); + pdata->lineout1fb = of_property_read_bool(np, "wlf,lineout1-feedback"); + pdata->lineout2fb = of_property_read_bool(np, "wlf,lineout2-feedback") || + of_property_read_bool(np, "wlf,ldoena-always-driven"); pdata->spkmode_pu = of_property_read_bool(np, "wlf,spkmode-pu"); diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index 4243fe6d3842..dad294a0ce2a 100644 --- a/drivers/rtc/rtc-s5m.c +++ b/drivers/rtc/rtc-s5m.c @@ -85,7 +85,7 @@ struct s5m_rtc_reg_config { unsigned int write_alarm_udr_mask; }; -/* Register map for S5M8763 and S5M8767 */ +/* Register map for S5M8767 */ static const struct s5m_rtc_reg_config s5m_rtc_regs = { .regs_count = 8, .time = S5M_RTC_SEC, @@ -236,7 +236,6 @@ static int s5m_check_peding_alarm_interrupt(struct s5m_rtc_info *info, switch (info->device_type) { case S5M8767X: - case S5M8763X: ret = regmap_read(info->regmap, S5M_RTC_STATUS, &val); val &= S5M_ALARM0_STATUS; break; @@ -299,7 +298,6 @@ static int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info) data |= info->regs->write_alarm_udr_mask; switch (info->device_type) { - case S5M8763X: case S5M8767X: data &= ~S5M_RTC_TIME_EN_MASK; break; @@ -329,38 +327,6 @@ static int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info) return ret; } -static void s5m8763_data_to_tm(u8 *data, struct rtc_time *tm) -{ - tm->tm_sec = bcd2bin(data[RTC_SEC]); - tm->tm_min = bcd2bin(data[RTC_MIN]); - - if (data[RTC_HOUR] & HOUR_12) { - tm->tm_hour = bcd2bin(data[RTC_HOUR] & 0x1f); - if (data[RTC_HOUR] & HOUR_PM) - tm->tm_hour += 12; - } else { - tm->tm_hour = bcd2bin(data[RTC_HOUR] & 0x3f); - } - - tm->tm_wday = data[RTC_WEEKDAY] & 0x07; - tm->tm_mday = bcd2bin(data[RTC_DATE]); - tm->tm_mon = bcd2bin(data[RTC_MONTH]); - tm->tm_year = bcd2bin(data[RTC_YEAR1]) + bcd2bin(data[RTC_YEAR2]) * 100; - tm->tm_year -= 1900; -} - -static void s5m8763_tm_to_data(struct rtc_time *tm, u8 *data) -{ - data[RTC_SEC] = bin2bcd(tm->tm_sec); - data[RTC_MIN] = bin2bcd(tm->tm_min); - data[RTC_HOUR] = bin2bcd(tm->tm_hour); - data[RTC_WEEKDAY] = tm->tm_wday; - data[RTC_DATE] = bin2bcd(tm->tm_mday); - data[RTC_MONTH] = bin2bcd(tm->tm_mon); - data[RTC_YEAR1] = bin2bcd(tm->tm_year % 100); - data[RTC_YEAR2] = bin2bcd((tm->tm_year + 1900) / 100); -} - static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct s5m_rtc_info *info = dev_get_drvdata(dev); @@ -385,10 +351,6 @@ static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm) return ret; switch (info->device_type) { - case S5M8763X: - s5m8763_data_to_tm(data, tm); - break; - case S5M8767X: case S2MPS15X: case S2MPS14X: @@ -412,9 +374,6 @@ static int s5m_rtc_set_time(struct device *dev, struct rtc_time *tm) int ret = 0; switch (info->device_type) { - case S5M8763X: - s5m8763_tm_to_data(tm, data); - break; case S5M8767X: case S2MPS15X: case S2MPS14X: @@ -444,7 +403,6 @@ static int s5m_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) { struct s5m_rtc_info *info = dev_get_drvdata(dev); u8 data[RTC_MAX_NUM_TIME_REGS]; - unsigned int val; int ret, i; ret = regmap_bulk_read(info->regmap, info->regs->alarm0, data, @@ -453,15 +411,6 @@ static int s5m_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) return ret; switch (info->device_type) { - case S5M8763X: - s5m8763_data_to_tm(data, &alrm->time); - ret = regmap_read(info->regmap, S5M_ALARM0_CONF, &val); - if (ret < 0) - return ret; - - alrm->enabled = !!val; - break; - case S5M8767X: case S2MPS15X: case S2MPS14X: @@ -500,10 +449,6 @@ static int s5m_rtc_stop_alarm(struct s5m_rtc_info *info) dev_dbg(info->dev, "%s: %ptR(%d)\n", __func__, &tm, tm.tm_wday); switch (info->device_type) { - case S5M8763X: - ret = regmap_write(info->regmap, S5M_ALARM0_CONF, 0); - break; - case S5M8767X: case S2MPS15X: case S2MPS14X: @@ -531,7 +476,6 @@ static int s5m_rtc_start_alarm(struct s5m_rtc_info *info) { int ret; u8 data[RTC_MAX_NUM_TIME_REGS]; - u8 alarm0_conf; struct rtc_time tm; ret = regmap_bulk_read(info->regmap, info->regs->alarm0, data, @@ -543,11 +487,6 @@ static int s5m_rtc_start_alarm(struct s5m_rtc_info *info) dev_dbg(info->dev, "%s: %ptR(%d)\n", __func__, &tm, tm.tm_wday); switch (info->device_type) { - case S5M8763X: - alarm0_conf = 0x77; - ret = regmap_write(info->regmap, S5M_ALARM0_CONF, alarm0_conf); - break; - case S5M8767X: case S2MPS15X: case S2MPS14X: @@ -585,10 +524,6 @@ static int s5m_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) int ret; switch (info->device_type) { - case S5M8763X: - s5m8763_tm_to_data(&alrm->time, data); - break; - case S5M8767X: case S2MPS15X: case S2MPS14X: @@ -655,7 +590,6 @@ static int s5m8767_rtc_init_reg(struct s5m_rtc_info *info) int ret; switch (info->device_type) { - case S5M8763X: case S5M8767X: /* UDR update time. Default of 7.32 ms is too long. */ ret = regmap_update_bits(info->regmap, S5M_RTC_UDR_CON, @@ -729,11 +663,6 @@ static int s5m_rtc_probe(struct platform_device *pdev) info->regs = &s2mps13_rtc_regs; alarm_irq = S2MPS14_IRQ_RTCA0; break; - case S5M8763X: - regmap_cfg = &s5m_rtc_regmap_config; - info->regs = &s5m_rtc_regs; - alarm_irq = S5M8763_IRQ_ALARM0; - break; case S5M8767X: regmap_cfg = &s5m_rtc_regmap_config; info->regs = &s5m_rtc_regs; @@ -786,13 +715,8 @@ static int s5m_rtc_probe(struct platform_device *pdev) info->rtc_dev->ops = &s5m_rtc_ops; - if (info->device_type == S5M8763X) { - info->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_0000; - info->rtc_dev->range_max = RTC_TIMESTAMP_END_9999; - } else { - info->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_2000; - info->rtc_dev->range_max = RTC_TIMESTAMP_END_2099; - } + info->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_2000; + info->rtc_dev->range_max = RTC_TIMESTAMP_END_2099; if (!info->irq) { clear_bit(RTC_FEATURE_ALARM, info->rtc_dev->features); |