diff options
Diffstat (limited to 'drivers')
81 files changed, 1926 insertions, 322 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index dda2405780..0b87c2af2a 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -13,6 +13,7 @@ source "drivers/mtd/Kconfig" source "drivers/ata/Kconfig" source "drivers/usb/Kconfig" source "drivers/video/Kconfig" +source "drivers/sound/Kconfig" source "drivers/mci/Kconfig" source "drivers/clk/Kconfig" source "drivers/clocksource/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 5a03bdceab..fab3790288 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -43,3 +43,4 @@ obj-y += soc/imx/ obj-y += nvme/ obj-y += ddr/ obj-y += power/ +obj-$(CONFIG_SOUND) += sound/ diff --git a/drivers/aiodev/Kconfig b/drivers/aiodev/Kconfig index 5fb445c096..88d013aad0 100644 --- a/drivers/aiodev/Kconfig +++ b/drivers/aiodev/Kconfig @@ -43,4 +43,11 @@ config AM335X_ADC rather than continuous sampling with DMA, etc. ADC channels should be configured via device tree, using the kernel bindings. +config STM32_ADC + tristate "STM32 ADC driver" + depends on ARCH_STM32MP || COMPILE_TEST + help + Support for ADC on STM32. Supports simple one-shot readings + rather than continuous sampling with DMA, etc. ADC channels should be + configured via device tree, using the kernel bindings. endif diff --git a/drivers/aiodev/Makefile b/drivers/aiodev/Makefile index 5f48b2022a..52652f67b7 100644 --- a/drivers/aiodev/Makefile +++ b/drivers/aiodev/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_LM75) += lm75.o obj-$(CONFIG_MC13XXX_ADC) += mc13xxx_adc.o obj-$(CONFIG_QORIQ_THERMAL) += qoriq_thermal.o obj-$(CONFIG_AM335X_ADC) += am335x_adc.o +obj-$(CONFIG_STM32_ADC) += stm32-adc.o stm32-adc-core.o diff --git a/drivers/aiodev/stm32-adc-core.c b/drivers/aiodev/stm32-adc-core.c new file mode 100644 index 0000000000..410e2a894e --- /dev/null +++ b/drivers/aiodev/stm32-adc-core.c @@ -0,0 +1,211 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + * Author: Fabrice Gasnier <fabrice.gasnier@st.com> + * + * Originally based on the Linux kernel v4.18 drivers/iio/adc/stm32-adc-core.c. + */ + +#include <common.h> +#include <linux/clk.h> +#include <regulator.h> +#include <linux/bitops.h> +#include "stm32-adc-core.h" + +/* STM32H7 - common registers for all ADC instances */ +#define STM32H7_ADC_CCR (STM32_ADCX_COMN_OFFSET + 0x08) + +/* STM32H7_ADC_CCR - bit fields */ +#define STM32H7_PRESC_SHIFT 18 +#define STM32H7_PRESC_MASK GENMASK(21, 18) +#define STM32H7_CKMODE_SHIFT 16 +#define STM32H7_CKMODE_MASK GENMASK(17, 16) + +/* STM32 H7 maximum analog clock rate (from datasheet) */ +#define STM32H7_ADC_MAX_CLK_RATE 36000000 + +/** + * struct stm32h7_adc_ck_spec - specification for stm32h7 adc clock + * @ckmode: ADC clock mode, Async or sync with prescaler. + * @presc: prescaler bitfield for async clock mode + * @div: prescaler division ratio + */ +struct stm32h7_adc_ck_spec { + u32 ckmode; + u32 presc; + int div; +}; + +static const struct stm32h7_adc_ck_spec stm32h7_adc_ckmodes_spec[] = { + /* 00: CK_ADC[1..3]: Asynchronous clock modes */ + { 0, 0, 1 }, + { 0, 1, 2 }, + { 0, 2, 4 }, + { 0, 3, 6 }, + { 0, 4, 8 }, + { 0, 5, 10 }, + { 0, 6, 12 }, + { 0, 7, 16 }, + { 0, 8, 32 }, + { 0, 9, 64 }, + { 0, 10, 128 }, + { 0, 11, 256 }, + /* HCLK used: Synchronous clock modes (1, 2 or 4 prescaler) */ + { 1, 0, 1 }, + { 2, 0, 2 }, + { 3, 0, 4 }, +}; + +static int stm32h7_adc_clk_sel(struct device_d *dev, + struct stm32_adc_common *common) +{ + u32 ckmode, presc; + unsigned long rate; + unsigned int i; + int div; + + /* stm32h7 bus clock is common for all ADC instances (mandatory) */ + if (!common->bclk) { + dev_err(dev, "No bclk clock found\n"); + return -ENOENT; + } + + /* + * stm32h7 can use either 'bus' or 'adc' clock for analog circuitry. + * So, choice is to have bus clock mandatory and adc clock optional. + * If optional 'adc' clock has been found, then try to use it first. + */ + if (common->aclk) { + /* + * Asynchronous clock modes (e.g. ckmode == 0) + * From spec: PLL output musn't exceed max rate + */ + rate = clk_get_rate(common->aclk); + if (!rate) { + dev_err(dev, "Invalid aclk rate: 0\n"); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(stm32h7_adc_ckmodes_spec); i++) { + ckmode = stm32h7_adc_ckmodes_spec[i].ckmode; + presc = stm32h7_adc_ckmodes_spec[i].presc; + div = stm32h7_adc_ckmodes_spec[i].div; + + if (ckmode) + continue; + + if ((rate / div) <= STM32H7_ADC_MAX_CLK_RATE) + goto out; + } + } + + /* Synchronous clock modes (e.g. ckmode is 1, 2 or 3) */ + rate = clk_get_rate(common->bclk); + if (!rate) { + dev_err(dev, "Invalid bus clock rate: 0\n"); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(stm32h7_adc_ckmodes_spec); i++) { + ckmode = stm32h7_adc_ckmodes_spec[i].ckmode; + presc = stm32h7_adc_ckmodes_spec[i].presc; + div = stm32h7_adc_ckmodes_spec[i].div; + + if (!ckmode) + continue; + + if ((rate / div) <= STM32H7_ADC_MAX_CLK_RATE) + goto out; + } + + dev_err(dev, "clk selection failed\n"); + return -EINVAL; + +out: + /* rate used later by each ADC instance to control BOOST mode */ + common->rate = rate / div; + + /* Set common clock mode and prescaler */ + clrsetbits_le32(common->base + STM32H7_ADC_CCR, + STM32H7_CKMODE_MASK | STM32H7_PRESC_MASK, + ckmode << STM32H7_CKMODE_SHIFT | + presc << STM32H7_PRESC_SHIFT); + + dev_dbg(dev, "Using %s clock/%d source at %ld kHz\n", + ckmode ? "bus" : "adc", div, common->rate / 1000); + + return 0; +} + +static int stm32_adc_core_probe(struct device_d *dev) +{ + struct stm32_adc_common *common; + int ret; + + common = xzalloc(sizeof(*common)); + + common->vref = regulator_get(dev, "vref"); + if (IS_ERR(common->vref)) { + dev_err(dev, "can't get vref-supply: %pe\n", common->vref); + return PTR_ERR(common->vref); + } + + ret = regulator_get_voltage(common->vref); + if (ret < 0) { + dev_err(dev, "can't get vref-supply value: %d\n", ret); + return ret; + } + common->vref_uv = ret; + + common->aclk = clk_get(dev, "adc"); + if (!IS_ERR(common->aclk)) { + ret = clk_enable(common->aclk); + if (ret) { + dev_err(dev, "Can't enable aclk: %d\n", ret); + return ret; + } + } + + common->bclk = clk_get(dev, "bus"); + if (!IS_ERR(common->bclk)) { + ret = clk_enable(common->bclk); + if (ret) { + dev_err(dev, "Can't enable bclk: %d\n", ret); + goto err_aclk_disable; + } + } + + common->base = dev_request_mem_region(dev, 0); + if (IS_ERR(common->base)) { + dev_err(dev, "can't get address\n"); + return -ENOENT; + } + + ret = stm32h7_adc_clk_sel(dev, common); + if (ret) + goto err_bclk_disable; + + dev->priv = common; + return of_platform_populate(dev->device_node, NULL, dev); + +err_bclk_disable: + clk_disable(common->bclk); + +err_aclk_disable: + clk_disable(common->aclk); + + return ret; +} + +static const struct of_device_id stm32_adc_core_ids[] = { + { .compatible = "st,stm32h7-adc-core" }, + { .compatible = "st,stm32mp1-adc-core" }, + {} +}; + +static struct driver_d stm32_adc_core_driver = { + .name = "stm32-adc-core", + .probe = stm32_adc_core_probe, + .of_compatible = DRV_OF_COMPAT(stm32_adc_core_ids), +}; +device_platform_driver(stm32_adc_core_driver); diff --git a/drivers/aiodev/stm32-adc-core.h b/drivers/aiodev/stm32-adc-core.h new file mode 100644 index 0000000000..de6c0b9495 --- /dev/null +++ b/drivers/aiodev/stm32-adc-core.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + * Author: Fabrice Gasnier <fabrice.gasnier@st.com>. + * + * Originally based on the Linux kernel v4.18 drivers/iio/adc/stm32-adc-core.h. + */ + +#ifndef __STM32_ADC_H +#define __STM32_ADC_H + +/* + * STM32 - ADC global register map + * ________________________________________________________ + * | Offset | Register | + * -------------------------------------------------------- + * | 0x000 | Master ADC1 | + * -------------------------------------------------------- + * | 0x100 | Slave ADC2 | + * -------------------------------------------------------- + * | 0x200 | Slave ADC3 | + * -------------------------------------------------------- + * | 0x300 | Master & Slave common regs | + * -------------------------------------------------------- + */ +#define STM32_ADC_MAX_ADCS 3 +#define STM32_ADCX_COMN_OFFSET 0x300 + +#include <linux/types.h> + +struct regulator; +struct clk; + +/** + * struct stm32_adc_common - stm32 ADC driver common data (for all instances) + * @base: control registers base cpu addr + * @rate: clock rate used for analog circuitry + * @aclk: clock for the analog circuitry + * @bclk: bus clock common for all ADCs + * @vref: regulator reference + * @vref_uv: reference supply voltage (uV) + */ +struct stm32_adc_common { + void __iomem *base; + unsigned long rate; + struct clk *aclk; + struct clk *bclk; + struct regulator *vref; + int vref_uv; +}; + +#endif diff --git a/drivers/aiodev/stm32-adc.c b/drivers/aiodev/stm32-adc.c new file mode 100644 index 0000000000..c99b995eaf --- /dev/null +++ b/drivers/aiodev/stm32-adc.c @@ -0,0 +1,374 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + * Author: Fabrice Gasnier <fabrice.gasnier@st.com> + * + * Originally based on the Linux kernel v4.18 drivers/iio/adc/stm32-adc.c. + */ + +#include <common.h> +#include <linux/bitops.h> +#include <linux/iopoll.h> +#include <aiodev.h> +#include <regulator.h> +#include <linux/math64.h> +#include "stm32-adc-core.h" + +/* STM32H7 - Registers for each ADC instance */ +#define STM32H7_ADC_ISR 0x00 +#define STM32H7_ADC_CR 0x08 +#define STM32H7_ADC_CFGR 0x0C +#define STM32H7_ADC_SMPR1 0x14 +#define STM32H7_ADC_SMPR2 0x18 +#define STM32H7_ADC_PCSEL 0x1C +#define STM32H7_ADC_SQR1 0x30 +#define STM32H7_ADC_DR 0x40 +#define STM32H7_ADC_DIFSEL 0xC0 + +/* STM32H7_ADC_ISR - bit fields */ +#define STM32MP1_VREGREADY BIT(12) +#define STM32H7_EOC BIT(2) +#define STM32H7_ADRDY BIT(0) + +/* STM32H7_ADC_CR - bit fields */ +#define STM32H7_DEEPPWD BIT(29) +#define STM32H7_ADVREGEN BIT(28) +#define STM32H7_BOOST BIT(8) +#define STM32H7_ADSTART BIT(2) +#define STM32H7_ADDIS BIT(1) +#define STM32H7_ADEN BIT(0) + +/* STM32H7_ADC_CFGR bit fields */ +#define STM32H7_EXTEN GENMASK(11, 10) +#define STM32H7_DMNGT GENMASK(1, 0) + +/* STM32H7_ADC_SQR1 - bit fields */ +#define STM32H7_SQ1_SHIFT 6 + +/* BOOST bit must be set on STM32H7 when ADC clock is above 20MHz */ +#define STM32H7_BOOST_CLKRATE 20000000UL + +#define STM32_ADC_CH_MAX 20 /* max number of channels */ +#define STM32_ADC_MAX_SMP 7 /* SMPx range is [0..7] */ +#define STM32_ADC_TIMEOUT_US 100000 + +struct stm32_adc_regs { + int reg; + int mask; + int shift; +}; + +struct stm32_adc_cfg { + unsigned int max_channels; + unsigned int num_bits; + bool has_vregready; + const struct stm32_adc_regs *smp_bits; + const unsigned int *smp_cycles; +}; + +struct stm32_adc { + struct stm32_adc_common *common; + void __iomem *regs; + const struct stm32_adc_cfg *cfg; + u32 channel_mask; + u32 data_mask; + struct aiodevice aiodev; + void __iomem *base; + struct aiochannel *channels; + u32 *channel_map; + u32 smpr_val[2]; +}; + +static void stm32_adc_stop(struct stm32_adc *adc) +{ + setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADDIS); + clrbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_BOOST); + /* Setting DEEPPWD disables ADC vreg and clears ADVREGEN */ + setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_DEEPPWD); + + regulator_disable(adc->common->vref); +} + +static int stm32_adc_start_channel(struct stm32_adc *adc, int channel) +{ + struct device_d *dev = adc->aiodev.hwdev; + struct stm32_adc_common *common = adc->common; + int ret; + u32 val; + + ret = regulator_enable(common->vref); + if (ret) + return ret; + + /* Exit deep power down, then enable ADC voltage regulator */ + clrbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_DEEPPWD); + setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADVREGEN); + if (common->rate > STM32H7_BOOST_CLKRATE) + setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_BOOST); + + /* Wait for startup time */ + if (!adc->cfg->has_vregready) { + udelay(20); + } else { + ret = readl_poll_timeout(adc->regs + STM32H7_ADC_ISR, val, + val & STM32MP1_VREGREADY, + STM32_ADC_TIMEOUT_US); + if (ret < 0) { + stm32_adc_stop(adc); + dev_err(dev, "Failed to enable vreg: %d\n", ret); + return ret; + } + } + + /* Only use single ended channels */ + writel(0, adc->regs + STM32H7_ADC_DIFSEL); + + /* Enable ADC, Poll for ADRDY to be set (after adc startup time) */ + setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADEN); + ret = readl_poll_timeout(adc->regs + STM32H7_ADC_ISR, val, + val & STM32H7_ADRDY, STM32_ADC_TIMEOUT_US); + if (ret < 0) { + stm32_adc_stop(adc); + dev_err(dev, "Failed to enable ADC: %d\n", ret); + return ret; + } + + /* Preselect channels */ + writel(adc->channel_mask, adc->regs + STM32H7_ADC_PCSEL); + + /* Apply sampling time settings */ + writel(adc->smpr_val[0], adc->regs + STM32H7_ADC_SMPR1); + writel(adc->smpr_val[1], adc->regs + STM32H7_ADC_SMPR2); + + /* Program regular sequence: chan in SQ1 & len = 0 for one channel */ + writel(channel << STM32H7_SQ1_SHIFT, adc->regs + STM32H7_ADC_SQR1); + + /* Trigger detection disabled (conversion can be launched in SW) */ + clrbits_le32(adc->regs + STM32H7_ADC_CFGR, STM32H7_EXTEN | + STM32H7_DMNGT); + + return 0; +} + +static int stm32_adc_channel_data(struct stm32_adc *adc, int channel, + int *data) +{ + struct device_d *dev = &adc->aiodev.dev; + int ret; + u32 val; + + setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADSTART); + ret = readl_poll_timeout(adc->regs + STM32H7_ADC_ISR, val, + val & STM32H7_EOC, STM32_ADC_TIMEOUT_US); + if (ret < 0) { + dev_err(dev, "conversion timed out: %d\n", ret); + return ret; + } + + *data = readl(adc->regs + STM32H7_ADC_DR); + + return 0; +} + +static int stm32_adc_channel_single_shot(struct aiochannel *chan, int *data) +{ + struct stm32_adc *adc = container_of(chan->aiodev, struct stm32_adc, aiodev); + int ret, index; + s64 raw64; + + index = adc->channel_map[chan->index]; + + ret = stm32_adc_start_channel(adc, index); + if (ret) + return ret; + + ret = stm32_adc_channel_data(adc, index, data); + if (ret) + return ret; + + raw64 = *data; + raw64 *= adc->common->vref_uv; + *data = div_s64(raw64, adc->data_mask); + + return 0; +} + +static void stm32_adc_smpr_init(struct stm32_adc *adc, int channel, u32 smp_ns) +{ + const struct stm32_adc_regs *smpr = &adc->cfg->smp_bits[channel]; + u32 period_ns, shift = smpr->shift, mask = smpr->mask; + unsigned int smp, r = smpr->reg; + + /* Determine sampling time (ADC clock cycles) */ + period_ns = NSEC_PER_SEC / adc->common->rate; + for (smp = 0; smp <= STM32_ADC_MAX_SMP; smp++) + if ((period_ns * adc->cfg->smp_cycles[smp]) >= smp_ns) + break; + if (smp > STM32_ADC_MAX_SMP) + smp = STM32_ADC_MAX_SMP; + + /* pre-build sampling time registers (e.g. smpr1, smpr2) */ + adc->smpr_val[r] = (adc->smpr_val[r] & ~mask) | (smp << shift); +} + +static int stm32_adc_chan_of_init(struct device_d *dev, struct stm32_adc *adc) +{ + unsigned int i; + int num_channels = 0, num_times = 0; + u32 smp = 0xffffffff; /* Set sampling time to max value by default */ + int ret; + + /* Retrieve single ended channels listed in device tree */ + of_get_property(dev->device_node, "st,adc-channels", &num_channels); + num_channels /= sizeof(__be32); + + if (num_channels > adc->cfg->max_channels) { + dev_err(dev, "too many st,adc-channels: %d\n", num_channels); + return -EINVAL; + } + + /* Optional sample time is provided either for each, or all channels */ + of_get_property(dev->device_node, "st,min-sample-time-nsecs", &num_times); + num_times /= sizeof(__be32); + if (num_times > 1 && num_times != num_channels) { + dev_err(dev, "Invalid st,min-sample-time-nsecs\n"); + return -EINVAL; + } + + adc->channels = calloc(sizeof(*adc->channels), num_channels); + if (!adc->channels) + return -ENOMEM; + + adc->aiodev.channels = calloc(sizeof(*adc->aiodev.channels), num_channels); + if (!adc->aiodev.channels) + return -ENOMEM; + + adc->channel_map = calloc(sizeof(u32), num_channels); + + adc->aiodev.num_channels = num_channels; + adc->aiodev.hwdev = dev; + adc->aiodev.read = stm32_adc_channel_single_shot; + + for (i = 0; i < num_channels; i++) { + u32 chan; + + ret = of_property_read_u32_index(dev->device_node, "st,adc-channels", i, &chan); + if (ret) + return ret; + + if (chan >= adc->cfg->max_channels) { + dev_err(dev, "bad channel %u\n", chan); + return -EINVAL; + } + + adc->channel_mask |= 1 << chan; + + adc->aiodev.channels[i] = &adc->channels[i]; + adc->channels[i].unit = "uV"; + adc->channel_map[i] = chan; + + /* + * Using of_property_read_u32_index(), smp value will only be + * modified if valid u32 value can be decoded. This allows to + * get either no value, 1 shared value for all indexes, or one + * value per channel. + */ + of_property_read_u32_index(dev->device_node, "st,min-sample-time-nsecs", + i, &smp); + /* Prepare sampling time settings */ + stm32_adc_smpr_init(adc, chan, smp); + } + + adc->data_mask = (1 << adc->cfg->num_bits) - 1; + + ret = aiodevice_register(&adc->aiodev); + if (ret < 0) + dev_err(dev, "Failed to register aiodev\n"); + + return ret; +} + +static int stm32_adc_probe(struct device_d *dev) +{ + struct stm32_adc_common *common = dev->parent->priv; + struct stm32_adc *adc; + u32 offset; + int ret; + + ret = of_property_read_u32(dev->device_node, "reg", &offset); + if (ret) { + dev_err(dev, "Can't read reg property\n"); + return ret; + } + + adc = xzalloc(sizeof(*adc)); + + adc->regs = common->base + offset; + adc->cfg = device_get_match_data(dev); + adc->common = common; + + return stm32_adc_chan_of_init(dev, adc); +} + +/* + * stm32h7_smp_bits - describe sampling time register index & bit fields + * Sorted so it can be indexed by channel number. + */ +static const struct stm32_adc_regs stm32h7_smp_bits[] = { + /* STM32H7_ADC_SMPR1, smpr[] index, mask, shift for SMP0 to SMP9 */ + { 0, GENMASK(2, 0), 0 }, + { 0, GENMASK(5, 3), 3 }, + { 0, GENMASK(8, 6), 6 }, + { 0, GENMASK(11, 9), 9 }, + { 0, GENMASK(14, 12), 12 }, + { 0, GENMASK(17, 15), 15 }, + { 0, GENMASK(20, 18), 18 }, + { 0, GENMASK(23, 21), 21 }, + { 0, GENMASK(26, 24), 24 }, + { 0, GENMASK(29, 27), 27 }, + /* STM32H7_ADC_SMPR2, smpr[] index, mask, shift for SMP10 to SMP19 */ + { 1, GENMASK(2, 0), 0 }, + { 1, GENMASK(5, 3), 3 }, + { 1, GENMASK(8, 6), 6 }, + { 1, GENMASK(11, 9), 9 }, + { 1, GENMASK(14, 12), 12 }, + { 1, GENMASK(17, 15), 15 }, + { 1, GENMASK(20, 18), 18 }, + { 1, GENMASK(23, 21), 21 }, + { 1, GENMASK(26, 24), 24 }, + { 1, GENMASK(29, 27), 27 }, +}; + +/* STM32H7 programmable sampling time (ADC clock cycles, rounded down) */ +static const unsigned int stm32h7_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = { + 1, 2, 8, 16, 32, 64, 387, 810, +}; + +static const struct stm32_adc_cfg stm32h7_adc_cfg = { + .num_bits = 16, + .max_channels = STM32_ADC_CH_MAX, + .smp_bits = stm32h7_smp_bits, + .smp_cycles = stm32h7_adc_smp_cycles, +}; + + +static const struct stm32_adc_cfg stm32mp1_adc_cfg = { + .num_bits = 16, + .max_channels = STM32_ADC_CH_MAX, + .smp_bits = stm32h7_smp_bits, + .smp_cycles = stm32h7_adc_smp_cycles, + .has_vregready = true, +}; + +static const struct of_device_id stm32_adc_match[] = { + { .compatible = "st,stm32h7-adc", .data = &stm32h7_adc_cfg }, + { .compatible = "st,stm32mp1-adc", .data = &stm32mp1_adc_cfg }, + {} +}; + +static struct driver_d stm32_adc_driver = { + .name = "stm32-adc", + .probe = stm32_adc_probe, + .of_compatible = DRV_OF_COMPAT(stm32_adc_match), +}; +device_platform_driver(stm32_adc_driver); diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 049a36bb44..6d251f248a 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -215,7 +215,7 @@ static int ahci_read_id(struct ata_port *ata, void *buf) } static int ahci_rw(struct ata_port *ata, void *rbuf, const void *wbuf, - unsigned int block, int num_blocks) + sector_t block, blkcnt_t num_blocks) { struct ahci_port *ahci = container_of(ata, struct ahci_port, ata); u8 fis[20]; @@ -237,7 +237,7 @@ static int ahci_rw(struct ata_port *ata, void *rbuf, const void *wbuf, while (num_blocks) { int now; - now = min(MAX_SATA_BLOCKS_READ_WRITE, num_blocks); + now = min_t(blkcnt_t, MAX_SATA_BLOCKS_READ_WRITE, num_blocks); fis[4] = (block >> 0) & 0xff; fis[5] = (block >> 8) & 0xff; @@ -270,14 +270,14 @@ static int ahci_rw(struct ata_port *ata, void *rbuf, const void *wbuf, return 0; } -static int ahci_read(struct ata_port *ata, void *buf, unsigned int block, - int num_blocks) +static int ahci_read(struct ata_port *ata, void *buf, sector_t block, + blkcnt_t num_blocks) { return ahci_rw(ata, buf, NULL, block, num_blocks); } -static int ahci_write(struct ata_port *ata, const void *buf, unsigned int block, - int num_blocks) +static int ahci_write(struct ata_port *ata, const void *buf, sector_t block, + blkcnt_t num_blocks) { return ahci_rw(ata, NULL, buf, block, num_blocks); } diff --git a/drivers/ata/disk_ata_drive.c b/drivers/ata/disk_ata_drive.c index 11f7151e51..3d9503fe7e 100644 --- a/drivers/ata/disk_ata_drive.c +++ b/drivers/ata/disk_ata_drive.c @@ -26,7 +26,7 @@ #include <disks.h> #include <dma.h> -static uint64_t ata_id_n_sectors(uint16_t *id) +static blkcnt_t ata_id_n_sectors(uint16_t *id) { if (ata_id_has_lba(id)) { if (ata_id_has_lba48(id)) @@ -75,7 +75,7 @@ static void __maybe_unused ata_dump_id(uint16_t *id) unsigned char serial[ATA_ID_SERNO_LEN + 1]; unsigned char firmware[ATA_ID_FW_REV_LEN + 1]; unsigned char product[ATA_ID_PROD_LEN + 1]; - uint64_t n_sectors; + sector_t n_sectors; /* Serial number */ ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial)); @@ -165,8 +165,8 @@ static void ata_fix_endianess(uint16_t *buf, unsigned wds) * @note Due to 'block' is of type 'int' only small disks can be handled! * @todo Optimize the read loop */ -static int ata_read(struct block_device *blk, void *buffer, int block, - int num_blocks) +static int ata_read(struct block_device *blk, void *buffer, sector_t block, + blkcnt_t num_blocks) { struct ata_port *port = container_of(blk, struct ata_port, blk); @@ -187,7 +187,7 @@ static int ata_read(struct block_device *blk, void *buffer, int block, * @todo Optimize the write loop */ static int __maybe_unused ata_write(struct block_device *blk, - const void *buffer, int block, int num_blocks) + const void *buffer, sector_t block, blkcnt_t num_blocks) { struct ata_port *port = container_of(blk, struct ata_port, blk); diff --git a/drivers/ata/disk_bios_drive.c b/drivers/ata/disk_bios_drive.c index 363af3c6dd..8f522eeba6 100644 --- a/drivers/ata/disk_bios_drive.c +++ b/drivers/ata/disk_bios_drive.c @@ -115,7 +115,7 @@ static struct DAPS bios_daps __attribute__((aligned(16))); * @param buffer Buffer to read from or write to (in the low memory area) * @return 0 on success, anything else on failure */ -static int biosdisk_bios_call(struct media_access *media, int cmd, uint64_t sector_start, unsigned sector_count, void *buffer) +static int biosdisk_bios_call(struct media_access *media, int cmd, sector_t sector_start, blkcnt_t sector_count, void *buffer) { int rc; @@ -150,12 +150,12 @@ static int biosdisk_bios_call(struct media_access *media, int cmd, uint64_t sect * * @note Due to 'block' is of type 'int' only small disks can be handled! */ -static int biosdisk_read(struct block_device *blk, void *buffer, int block, - int num_blocks) +static int biosdisk_read(struct block_device *blk, void *buffer, sector_t block, + blkcnt_t num_blocks) { int rc; - uint64_t sector_start = block; - unsigned sector_count = num_blocks; + sector_t sector_start = block; + blkcnt_t sector_count = num_blocks; struct media_access *media = to_media_access(blk); while (sector_count >= SECTORS_AT_ONCE) { @@ -191,11 +191,11 @@ static int biosdisk_read(struct block_device *blk, void *buffer, int block, * @note Due to 'block' is of type 'int' only small disks can be handled! */ static int __maybe_unused biosdisk_write(struct block_device *blk, - const void *buffer, int block, int num_blocks) + const void *buffer, sector_t block, blkcnt_t num_blocks) { int rc; - uint64_t sector_start = block; - unsigned sector_count = num_blocks; + sector_t sector_start = block; + blkcnt_t sector_count = num_blocks; struct media_access *media = to_media_access(blk); while (sector_count >= SECTORS_AT_ONCE) { diff --git a/drivers/ata/ide-sff.c b/drivers/ata/ide-sff.c index b7c8847266..a735c8c32c 100644 --- a/drivers/ata/ide-sff.c +++ b/drivers/ata/ide-sff.c @@ -138,7 +138,7 @@ static int ata_wait_ready(struct ide_port *ide, unsigned timeout) * @param num Sector number */ static int ata_set_lba_sector(struct ata_port *port, unsigned drive, - uint64_t num) + sector_t num) { struct ide_port *ide = to_ata_drive_access(port); @@ -324,11 +324,11 @@ static int ide_reset(struct ata_port *port) * @note Due to 'block' is of type 'int' only small disks can be handled! * @todo Optimize the read loop */ -static int ide_read(struct ata_port *port, void *buffer, unsigned int block, - int num_blocks) +static int ide_read(struct ata_port *port, void *buffer, sector_t block, + blkcnt_t num_blocks) { int rc; - uint64_t sector = block; + sector_t sector = block; struct ide_port *ide = to_ata_drive_access(port); while (num_blocks) { @@ -372,10 +372,10 @@ static int ide_read(struct ata_port *port, void *buffer, unsigned int block, * @todo Optimize the write loop */ static int __maybe_unused ide_write(struct ata_port *port, - const void *buffer, unsigned int block, int num_blocks) + const void *buffer, sector_t block, blkcnt_t num_blocks) { int rc; - uint64_t sector = block; + sector_t sector = block; struct ide_port *ide = to_ata_drive_access(port); while (num_blocks) { diff --git a/drivers/block/efi-block-io.c b/drivers/block/efi-block-io.c index 30db486876..4768c219ed 100644 --- a/drivers/block/efi-block-io.c +++ b/drivers/block/efi-block-io.c @@ -28,7 +28,7 @@ struct efi_block_io_media{ bool write_caching; u32 block_size; u32 io_align; - u64 last_block; + sector_t last_block; u64 lowest_aligned_lba; /* added in Revision 2 */ u32 logical_blocks_per_physical_block; /* added in Revision 2 */ u32 optimal_transfer_length_granularity; /* added in Revision 3 */ @@ -53,8 +53,8 @@ struct efi_bio_priv { u32 media_id; }; -static int efi_bio_read(struct block_device *blk, void *buffer, int block, - int num_blocks) +static int efi_bio_read(struct block_device *blk, void *buffer, sector_t block, + blkcnt_t num_blocks) { struct efi_bio_priv *priv = container_of(blk, struct efi_bio_priv, blk); efi_status_t efiret; @@ -69,7 +69,7 @@ static int efi_bio_read(struct block_device *blk, void *buffer, int block, } static int efi_bio_write(struct block_device *blk, - const void *buffer, int block, int num_blocks) + const void *buffer, sector_t block, blkcnt_t num_blocks) { struct efi_bio_priv *priv = container_of(blk, struct efi_bio_priv, blk); efi_status_t efiret; diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index cad902fd32..9c2e50e4a5 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -10,7 +10,7 @@ #include <linux/clk.h> #include <linux/err.h> #include <linux/log2.h> -#include <asm-generic/div64.h> +#include <linux/math64.h> static unsigned int _get_table_maxdiv(const struct clk_div_table *table) { diff --git a/drivers/clk/clk-qoric.c b/drivers/clk/clk-qoric.c index b3e0780bc8..5bf677d94e 100644 --- a/drivers/clk/clk-qoric.c +++ b/drivers/clk/clk-qoric.c @@ -13,7 +13,7 @@ #include <linux/kernel.h> #include <of_address.h> #include <of.h> -#include <asm-generic/div64.h> +#include <linux/math64.h> #define PLL_DIV1 0 #define PLL_DIV2 1 diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c index 6016c5bfd0..2380bd0c21 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c @@ -10,7 +10,7 @@ #include <io.h> #include <of.h> #include <of_address.h> -#include <asm-generic/div64.h> +#include <linux/math64.h> #include <dt-bindings/clock/stm32mp1-clks.h> diff --git a/drivers/clk/imx/clk-frac-pll.c b/drivers/clk/imx/clk-frac-pll.c index 2195762c8b..48866eadf0 100644 --- a/drivers/clk/imx/clk-frac-pll.c +++ b/drivers/clk/imx/clk-frac-pll.c @@ -8,7 +8,7 @@ #include <malloc.h> #include <linux/clk.h> #include <linux/err.h> -#include <asm-generic/div64.h> +#include <linux/math64.h> #include "clk.h" diff --git a/drivers/clk/imx/clk-pfd.c b/drivers/clk/imx/clk-pfd.c index eb2b1700ae..a7ca664524 100644 --- a/drivers/clk/imx/clk-pfd.c +++ b/drivers/clk/imx/clk-pfd.c @@ -12,7 +12,7 @@ #include <linux/clkdev.h> #include <linux/err.h> #include <malloc.h> -#include <asm-generic/div64.h> +#include <linux/math64.h> #include "clk.h" diff --git a/drivers/clk/imx/clk-pll14xx.c b/drivers/clk/imx/clk-pll14xx.c index 6ba519516b..3fd5a49ee7 100644 --- a/drivers/clk/imx/clk-pll14xx.c +++ b/drivers/clk/imx/clk-pll14xx.c @@ -14,7 +14,7 @@ #include <malloc.h> #include <clock.h> #include <soc/imx8m/clk-early.h> -#include <asm-generic/div64.h> +#include <linux/math64.h> #include "clk.h" diff --git a/drivers/clk/imx/clk-pllv1.c b/drivers/clk/imx/clk-pllv1.c index 9b5d28f22f..283ae843a7 100644 --- a/drivers/clk/imx/clk-pllv1.c +++ b/drivers/clk/imx/clk-pllv1.c @@ -8,7 +8,7 @@ #include <linux/clkdev.h> #include <linux/err.h> #include <malloc.h> -#include <asm-generic/div64.h> +#include <linux/math64.h> #include "clk.h" diff --git a/drivers/clk/imx/clk-pllv2.c b/drivers/clk/imx/clk-pllv2.c index 56005ca725..6af2d71352 100644 --- a/drivers/clk/imx/clk-pllv2.c +++ b/drivers/clk/imx/clk-pllv2.c @@ -8,7 +8,7 @@ #include <linux/clkdev.h> #include <linux/err.h> #include <malloc.h> -#include <asm-generic/div64.h> +#include <linux/math64.h> #include "clk.h" diff --git a/drivers/clk/imx/clk-pllv3.c b/drivers/clk/imx/clk-pllv3.c index e10b61b040..51e620a040 100644 --- a/drivers/clk/imx/clk-pllv3.c +++ b/drivers/clk/imx/clk-pllv3.c @@ -9,7 +9,7 @@ #include <linux/err.h> #include <malloc.h> #include <clock.h> -#include <asm-generic/div64.h> +#include <linux/math64.h> #include "clk.h" diff --git a/drivers/clk/imx/clk-sccg-pll.c b/drivers/clk/imx/clk-sccg-pll.c index aabab27a22..755ece0e12 100644 --- a/drivers/clk/imx/clk-sccg-pll.c +++ b/drivers/clk/imx/clk-sccg-pll.c @@ -12,7 +12,7 @@ #include <linux/err.h> #include <malloc.h> #include <clock.h> -#include <asm-generic/div64.h> +#include <linux/math64.h> #include "clk.h" diff --git a/drivers/clk/mxs/clk-frac.c b/drivers/clk/mxs/clk-frac.c index 21e572ff6f..a9d390121e 100644 --- a/drivers/clk/mxs/clk-frac.c +++ b/drivers/clk/mxs/clk-frac.c @@ -7,7 +7,7 @@ #include <linux/clk.h> #include <linux/err.h> #include <io.h> -#include <asm-generic/div64.h> +#include <linux/math64.h> #include "clk.h" diff --git a/drivers/clk/mxs/clk-ref.c b/drivers/clk/mxs/clk-ref.c index 16a2fc2991..69361f9ac3 100644 --- a/drivers/clk/mxs/clk-ref.c +++ b/drivers/clk/mxs/clk-ref.c @@ -7,7 +7,7 @@ #include <linux/clk.h> #include <linux/err.h> #include <io.h> -#include <asm-generic/div64.h> +#include <linux/math64.h> #include "clk.h" diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c index 8d3fd6cf1c..6bb8156f8c 100644 --- a/drivers/clk/rockchip/clk-pll.c +++ b/drivers/clk/rockchip/clk-pll.c @@ -4,7 +4,7 @@ * Author: Heiko Stuebner <heiko@sntech.de> */ -#include <asm-generic/div64.h> +#include <linux/math64.h> #include <common.h> #include <io.h> #include <linux/list.h> diff --git a/drivers/clk/socfpga/clk-pll-a10.c b/drivers/clk/socfpga/clk-pll-a10.c index 12d6ef6fc3..fcf31e9ea1 100644 --- a/drivers/clk/socfpga/clk-pll-a10.c +++ b/drivers/clk/socfpga/clk-pll-a10.c @@ -7,7 +7,7 @@ #include <malloc.h> #include <linux/clk.h> #include <linux/clkdev.h> -#include <asm-generic/div64.h> +#include <linux/math64.h> #include "clk.h" diff --git a/drivers/clk/tegra/clk-divider.c b/drivers/clk/tegra/clk-divider.c index 28a1342bbf..cc8b85520c 100644 --- a/drivers/clk/tegra/clk-divider.c +++ b/drivers/clk/tegra/clk-divider.c @@ -8,7 +8,7 @@ #include <common.h> #include <io.h> #include <malloc.h> -#include <asm-generic/div64.h> +#include <linux/math64.h> #include <linux/clk.h> #include <linux/err.h> diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index 3ac49cae47..832b3c5ea1 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c @@ -9,7 +9,7 @@ #include <clock.h> #include <io.h> #include <malloc.h> -#include <asm-generic/div64.h> +#include <linux/math64.h> #include <linux/clk.h> #include <linux/err.h> diff --git a/drivers/crypto/caam/caamrng.c b/drivers/crypto/caam/caamrng.c index 39a90568df..5d8cfb8bff 100644 --- a/drivers/crypto/caam/caamrng.c +++ b/drivers/crypto/caam/caamrng.c @@ -91,10 +91,8 @@ static void rng_done(struct device_d *jrdev, u32 *desc, u32 err, void *context) /* Buffer refilled, invalidate cache */ dma_sync_single_for_cpu(bd->addr, RN_BUF_SIZE, DMA_FROM_DEVICE); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "rng refreshed buf@: ", - DUMP_PREFIX_OFFSET, 16, 4, bd->buf, RN_BUF_SIZE, 1); -#endif + print_hex_dump_debug("rng refreshed buf@: ", DUMP_PREFIX_OFFSET, + 16, 4, bd->buf, RN_BUF_SIZE, 1); } static inline int submit_job(struct caam_rng_ctx *ctx, int to_current) @@ -186,10 +184,9 @@ static inline int rng_create_sh_desc(struct caam_rng_ctx *ctx) dma_sync_single_for_device((unsigned long)desc, desc_bytes(desc), DMA_TO_DEVICE); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "rng shdesc@: ", DUMP_PREFIX_OFFSET, 16, 4, + + print_hex_dump_debug("rng shdesc@: ", DUMP_PREFIX_OFFSET, 16, 4, desc, desc_bytes(desc), 1); -#endif return 0; } @@ -203,10 +200,9 @@ static inline int rng_create_job_desc(struct caam_rng_ctx *ctx, int buf_id) HDR_REVERSE); append_seq_out_ptr_intlen(desc, bd->addr, RN_BUF_SIZE, 0); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "rng job desc@: ", DUMP_PREFIX_OFFSET, 16, 4, + + print_hex_dump_debug("rng job desc@: ", DUMP_PREFIX_OFFSET, 16, 4, desc, desc_bytes(desc), 1); -#endif return 0; } diff --git a/drivers/ddr/fsl/util.c b/drivers/ddr/fsl/util.c index 977d22dcaa..1775b08be3 100644 --- a/drivers/ddr/fsl/util.c +++ b/drivers/ddr/fsl/util.c @@ -8,7 +8,7 @@ #include <soc/fsl/fsl_immap.h> #include <io.h> #include <soc/fsl/immap_lsch2.h> -#include <asm-generic/div64.h> +#include <linux/math64.h> #include "fsl_ddr.h" /* To avoid 64-bit full-divides, we factor this here */ diff --git a/drivers/gpio/gpio-orion.c b/drivers/gpio/gpio-orion.c index 63ef966edf..ba2729d1f0 100644 --- a/drivers/gpio/gpio-orion.c +++ b/drivers/gpio/gpio-orion.c @@ -91,10 +91,7 @@ static int orion_gpio_probe(struct device_d *dev) { struct resource *iores; struct orion_gpio_chip *gpio; - - dev->id = of_alias_get_id(dev->device_node, "gpio"); - if (dev->id < 0) - return dev->id; + int id; gpio = xzalloc(sizeof(*gpio)); iores = dev_request_mem_resource(dev, 0); @@ -105,7 +102,12 @@ static int orion_gpio_probe(struct device_d *dev) gpio->regs = IOMEM(iores->start); gpio->chip.dev = dev; gpio->chip.ops = &orion_gpio_ops; - gpio->chip.base = dev->id * 32; + + id = of_alias_get_id(dev->device_node, "gpio"); + if (id < 0) + return id; + + gpio->chip.base = id * 32; gpio->chip.ngpio = 32; of_property_read_u32(dev->device_node, "ngpios", &gpio->chip.ngpio); diff --git a/drivers/led/led-pwm.c b/drivers/led/led-pwm.c index d8866bf757..90c2ca929a 100644 --- a/drivers/led/led-pwm.c +++ b/drivers/led/led-pwm.c @@ -20,7 +20,7 @@ #include <led.h> #include <pwm.h> #include <of.h> -#include <asm-generic/div64.h> +#include <linux/math64.h> struct pwmled { bool active_low; diff --git a/drivers/mci/dw_mmc.c b/drivers/mci/dw_mmc.c index 8249403eb7..7979568841 100644 --- a/drivers/mci/dw_mmc.c +++ b/drivers/mci/dw_mmc.c @@ -19,7 +19,7 @@ #include <linux/bitops.h> #include <linux/clk.h> #include <linux/err.h> -#include <asm-generic/errno.h> +#include <errno.h> #include "dw_mmc.h" diff --git a/drivers/mci/imx-esdhc-pbl.c b/drivers/mci/imx-esdhc-pbl.c index 0cb32b46f1..c3a8b377e2 100644 --- a/drivers/mci/imx-esdhc-pbl.c +++ b/drivers/mci/imx-esdhc-pbl.c @@ -6,7 +6,7 @@ #include <io.h> #include <mci.h> #include <linux/sizes.h> -#include <asm-generic/sections.h> +#include <asm/sections.h> #include <asm/cache.h> #include <mach/xload.h> #ifdef CONFIG_ARCH_IMX diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c index f9066e3a1e..017f25d35f 100644 --- a/drivers/mci/mci-core.c +++ b/drivers/mci/mci-core.c @@ -14,7 +14,7 @@ #include <mci.h> #include <malloc.h> #include <errno.h> -#include <asm-generic/div64.h> +#include <linux/math64.h> #include <asm/byteorder.h> #include <block.h> #include <disks.h> @@ -398,16 +398,16 @@ int mci_switch(struct mci *mci, unsigned index, unsigned value) return mci_send_cmd(mci, &cmd, NULL); } -static int mci_calc_blk_cnt(uint64_t cap, unsigned shift) +static blkcnt_t mci_calc_blk_cnt(blkcnt_t cap, unsigned shift) { - unsigned ret = cap >> shift; + blkcnt_t ret = cap >> shift; if (ret > 0x7fffffff) { pr_warn("Limiting card size due to 31 bit contraints\n"); return 0x7fffffff; } - return (int)ret; + return ret; } static void mci_part_add(struct mci *mci, uint64_t size, @@ -1342,14 +1342,14 @@ static int mci_blk_part_switch(struct mci_part *part) * This routine expects the buffer has the correct size to read all data! */ static int __maybe_unused mci_sd_write(struct block_device *blk, - const void *buffer, int block, int num_blocks) + const void *buffer, sector_t block, blkcnt_t num_blocks) { struct mci_part *part = container_of(blk, struct mci_part, blk); struct mci *mci = part->mci; struct mci_host *host = mci->host; int rc; - unsigned max_req_block = num_blocks; - int write_block; + blkcnt_t max_req_block = num_blocks; + blkcnt_t write_block; if (mci->host->max_req_size) max_req_block = mci->host->max_req_size / mci->write_bl_len; @@ -1361,7 +1361,7 @@ static int __maybe_unused mci_sd_write(struct block_device *blk, return -EPERM; } - dev_dbg(&mci->dev, "%s: Write %d block(s), starting at %d\n", + dev_dbg(&mci->dev, "%s: Write %llu block(s), starting at %llu\n", __func__, num_blocks, block); if (mci->write_bl_len != SECTOR_SIZE) { @@ -1372,15 +1372,15 @@ static int __maybe_unused mci_sd_write(struct block_device *blk, /* size of the block number field in the MMC/SD command is 32 bit only */ if (block > MAX_BUFFER_NUMBER) { - dev_dbg(&mci->dev, "Cannot handle block number %d. Too large!\n", block); + dev_dbg(&mci->dev, "Cannot handle block number %llu. Too large!\n", block); return -EINVAL; } while (num_blocks) { - write_block = min_t(int, num_blocks, max_req_block); + write_block = min(num_blocks, max_req_block); rc = mci_block_write(mci, buffer, block, write_block); if (rc != 0) { - dev_dbg(&mci->dev, "Writing block %d failed with %d\n", block, rc); + dev_dbg(&mci->dev, "Writing block %llu failed with %d\n", block, rc); return rc; } num_blocks -= write_block; @@ -1401,13 +1401,13 @@ static int __maybe_unused mci_sd_write(struct block_device *blk, * * This routine expects the buffer has the correct size to store all data! */ -static int mci_sd_read(struct block_device *blk, void *buffer, int block, - int num_blocks) +static int mci_sd_read(struct block_device *blk, void *buffer, sector_t block, + blkcnt_t num_blocks) { struct mci_part *part = container_of(blk, struct mci_part, blk); struct mci *mci = part->mci; - unsigned max_req_block = num_blocks; - int read_block; + blkcnt_t max_req_block = num_blocks; + blkcnt_t read_block; int rc; if (mci->host->max_req_size) @@ -1415,7 +1415,7 @@ static int mci_sd_read(struct block_device *blk, void *buffer, int block, mci_blk_part_switch(part); - dev_dbg(&mci->dev, "%s: Read %d block(s), starting at %d\n", + dev_dbg(&mci->dev, "%s: Read %llu block(s), starting at %llu\n", __func__, num_blocks, block); if (mci->read_bl_len != SECTOR_SIZE) { @@ -1425,15 +1425,15 @@ static int mci_sd_read(struct block_device *blk, void *buffer, int block, } if (block > MAX_BUFFER_NUMBER) { - dev_err(&mci->dev, "Cannot handle block number %d. Too large!\n", block); + dev_err(&mci->dev, "Cannot handle block number %llu. Too large!\n", block); return -EINVAL; } while (num_blocks) { - read_block = min_t(int, num_blocks, max_req_block); + read_block = min(num_blocks, max_req_block); rc = mci_read_block(mci, buffer, block, read_block); if (rc != 0) { - dev_dbg(&mci->dev, "Reading block %d failed with %d\n", block, rc); + dev_dbg(&mci->dev, "Reading block %llu failed with %d\n", block, rc); return rc; } num_blocks -= read_block; diff --git a/drivers/mfd/rave-sp.c b/drivers/mfd/rave-sp.c index 8fc46b66bb..ef569dd513 100644 --- a/drivers/mfd/rave-sp.c +++ b/drivers/mfd/rave-sp.c @@ -269,9 +269,8 @@ static int rave_sp_write(struct rave_sp *sp, const u8 *data, u8 data_size) length = dest - frame; - if (IS_ENABLED(DEBUG)) - print_hex_dump(0, "rave-sp tx: ", DUMP_PREFIX_NONE, - 16, 1, frame, length, false); + print_hex_dump_debug("rave-sp tx: ", DUMP_PREFIX_NONE, 16, 1, + frame, length, false); return serdev_device_write(sp->serdev, frame, length, SECOND); } @@ -406,9 +405,8 @@ static void rave_sp_receive_frame(struct rave_sp *sp, struct device_d *dev = sp->serdev->dev; u8 crc_calculated[checksum_length]; - if (IS_ENABLED(DEBUG)) - print_hex_dump(0, "rave-sp rx: ", DUMP_PREFIX_NONE, - 16, 1, data, length, false); + print_hex_dump_debug("rave-sp rx: ", DUMP_PREFIX_NONE, 16, 1, + data, length, false); if (unlikely(length <= checksum_length)) { dev_warn(dev, "Dropping short frame\n"); diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index 3032c5a16d..8cd82327ba 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -27,7 +27,7 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/concat.h> -#include <asm-generic/div64.h> +#include <linux/math64.h> /* * Our storage structure: diff --git a/drivers/mtd/nand/bbt.c b/drivers/mtd/nand/bbt.c index 172ab5ffbc..8a78f9046f 100644 --- a/drivers/mtd/nand/bbt.c +++ b/drivers/mtd/nand/bbt.c @@ -113,18 +113,20 @@ int nanddev_bbt_set_block_status(struct nand_device *nand, unsigned int entry, ((entry * bits_per_block) / BITS_PER_LONG); unsigned int offs = (entry * bits_per_block) % BITS_PER_LONG; unsigned long val = status & GENMASK(bits_per_block - 1, 0); + unsigned long shift = ((bits_per_block + offs <= BITS_PER_LONG) ? + (offs + bits_per_block - 1) : (BITS_PER_LONG - 1)); if (entry >= nanddev_neraseblocks(nand)) return -ERANGE; - pos[0] &= ~GENMASK(offs + bits_per_block - 1, offs); + pos[0] &= ~GENMASK(shift, offs); pos[0] |= val << offs; if (bits_per_block + offs > BITS_PER_LONG) { unsigned int rbits = bits_per_block + offs - BITS_PER_LONG; pos[1] &= ~GENMASK(rbits - 1, 0); - pos[1] |= val >> rbits; + pos[1] |= (val >> (BITS_PER_LONG - offs)); } return 0; diff --git a/drivers/mtd/nand/nand_s3c24xx.c b/drivers/mtd/nand/nand_s3c24xx.c index 59bd6c9fed..f1d1441f50 100644 --- a/drivers/mtd/nand/nand_s3c24xx.c +++ b/drivers/mtd/nand/nand_s3c24xx.c @@ -32,7 +32,7 @@ #include <mach/s3c-iomap.h> #include <mach/s3c24xx-nand.h> #include <io.h> -#include <asm-generic/errno.h> +#include <errno.h> #include <asm/sections.h> #ifdef CONFIG_S3C_NAND_BOOT diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c index 6ae797c2bf..75d6b69f09 100644 --- a/drivers/mtd/ubi/debug.c +++ b/drivers/mtd/ubi/debug.c @@ -42,7 +42,7 @@ void ubi_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len) ubi_msg(ubi, "dumping %d bytes of data from PEB %d, offset %d", len, pnum, offset); - print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1); + print_hex_dump_debug("", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1); out: vfree(buf); return; @@ -63,8 +63,8 @@ void ubi_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr) pr_err("\timage_seq %d\n", be32_to_cpu(ec_hdr->image_seq)); pr_err("\thdr_crc %#08x\n", be32_to_cpu(ec_hdr->hdr_crc)); pr_err("erase counter header hexdump:\n"); - print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, - ec_hdr, UBI_EC_HDR_SIZE, 1); + print_hex_dump_debug("", DUMP_PREFIX_OFFSET, 32, 1, + ec_hdr, UBI_EC_HDR_SIZE, 1); } /** @@ -88,8 +88,8 @@ void ubi_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr) (unsigned long long)be64_to_cpu(vid_hdr->sqnum)); pr_err("\thdr_crc %08x\n", be32_to_cpu(vid_hdr->hdr_crc)); pr_err("Volume identifier header hexdump:\n"); - print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, - vid_hdr, UBI_VID_HDR_SIZE, 1); + print_hex_dump_debug("", DUMP_PREFIX_OFFSET, 32, 1, + vid_hdr, UBI_VID_HDR_SIZE, 1); } /** diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c index e1cab763eb..e1781f3f20 100644 --- a/drivers/mtd/ubi/kapi.c +++ b/drivers/mtd/ubi/kapi.c @@ -17,7 +17,7 @@ /* This file mostly implements UBI kernel API functions */ #include <linux/err.h> -#include <asm-generic/div64.h> +#include <linux/math64.h> #include "ubi.h" /** diff --git a/drivers/mtd/ubi/ubi-barebox.h b/drivers/mtd/ubi/ubi-barebox.h index 7ee87ffd3e..5b2d4a72c8 100644 --- a/drivers/mtd/ubi/ubi-barebox.h +++ b/drivers/mtd/ubi/ubi-barebox.h @@ -17,7 +17,7 @@ #include <common.h> #include <malloc.h> #include <crc.h> -#include <asm-generic/div64.h> +#include <linux/math64.h> #include <errno.h> #include <linux/err.h> #include <linux/types.h> diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index ea7cea5f1b..1edc16ce44 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -541,7 +541,7 @@ static int smc911x_probe(struct device_d *dev) * forbidden while this bit isn't set. Try for 100ms */ ret = wait_on_timeout(100 * MSECOND, smc911x_reg_read(priv, PMT_CTRL) & PMT_CTRL_READY); - if (!ret) { + if (ret) { dev_err(dev, "Device not READY in 100ms aborting\n"); return -ENODEV; } diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 257679fae8..a27a409cf5 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -222,7 +222,7 @@ static void __nvme_revalidate_disk(struct block_device *blk, } static void nvme_setup_rw(struct nvme_ns *ns, struct nvme_command *cmnd, - int block, int num_block) + sector_t block, blkcnt_t num_block) { cmnd->rw.nsid = cpu_to_le32(ns->head->ns_id); cmnd->rw.slba = cpu_to_le64(nvme_block_nr(ns, block)); @@ -239,7 +239,7 @@ static void nvme_setup_flush(struct nvme_ns *ns, struct nvme_command *cmnd) } static int nvme_submit_sync_rw(struct nvme_ns *ns, struct nvme_command *cmnd, - void *buffer, int block, int num_blocks) + void *buffer, sector_t block, blkcnt_t num_blocks) { /* * ns->ctrl->max_hw_sectors is in units of 512 bytes, so we @@ -251,7 +251,7 @@ static int nvme_submit_sync_rw(struct nvme_ns *ns, struct nvme_command *cmnd, if (num_blocks > max_hw_sectors) { while (num_blocks) { - const int chunk = min_t(int, num_blocks, + const u32 chunk = min_t(blkcnt_t, num_blocks, max_hw_sectors); ret = nvme_submit_sync_rw(ns, cmnd, buffer, block, @@ -275,7 +275,7 @@ static int nvme_submit_sync_rw(struct nvme_ns *ns, struct nvme_command *cmnd, if (ret) { dev_err(ns->ctrl->dev, - "I/O failed: block: %d, num blocks: %d, status code type: %xh, status code %02xh\n", + "I/O failed: block: %llu, num blocks: %llu, status code type: %xh, status code %02xh\n", block, num_blocks, (ret >> 8) & 0xf, ret & 0xff); return -EIO; @@ -286,7 +286,7 @@ static int nvme_submit_sync_rw(struct nvme_ns *ns, struct nvme_command *cmnd, static int nvme_block_device_read(struct block_device *blk, void *buffer, - int block, int num_blocks) + sector_t block, blkcnt_t num_blocks) { struct nvme_ns *ns = to_nvme_ns(blk); struct nvme_command cmnd = { }; @@ -298,7 +298,7 @@ static int nvme_block_device_read(struct block_device *blk, void *buffer, static int __maybe_unused nvme_block_device_write(struct block_device *blk, const void *buffer, - int block, int num_blocks) + sector_t block, blkcnt_t num_blocks) { struct nvme_ns *ns = to_nvme_ns(blk); struct nvme_command cmnd = { }; diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 06e1414769..2a1c4b6941 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -48,12 +48,6 @@ struct nvmem_cell { static LIST_HEAD(nvmem_cells); static LIST_HEAD(nvmem_devs); -int nvmem_device_read(struct nvmem_device *nvmem, unsigned int offset, - size_t bytes, void *buf); -int nvmem_device_write(struct nvmem_device *nvmem, unsigned int offset, - size_t bytes, const void *buf); - - static ssize_t nvmem_cdev_read(struct cdev *cdev, void *buf, size_t count, loff_t offset, unsigned long flags) { @@ -129,7 +123,7 @@ static struct nvmem_device *of_nvmem_find(struct device_node *nvmem_np) return NULL; list_for_each_entry(dev, &nvmem_devs, node) - if (dev->dev.device_node->name && !strcmp(dev->dev.device_node->name, nvmem_np->name)) + if (dev->dev.device_node == nvmem_np) return dev; return NULL; @@ -290,13 +284,14 @@ struct nvmem_device *of_nvmem_device_get(struct device_node *np, const char *id) { struct device_node *nvmem_np; - int index; + int index = 0; - index = of_property_match_string(np, "nvmem-names", id); + if (id) + index = of_property_match_string(np, "nvmem-names", id); nvmem_np = of_parse_phandle(np, "nvmem", index); if (!nvmem_np) - return ERR_PTR(-EINVAL); + return ERR_PTR(-ENOENT); return __nvmem_device_get(nvmem_np, NULL, NULL); } diff --git a/drivers/of/base.c b/drivers/of/base.c index edb0a8e71a..8759099d74 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -1704,8 +1704,8 @@ void barebox_register_of(struct device_node *root) if (root_node) return; - of_fix_tree(root); of_set_root_node(root); + of_fix_tree(root); if (IS_ENABLED(CONFIG_OFDEVICE)) of_probe(); diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c index 8bf632c1e7..8f4ee3f0a2 100644 --- a/drivers/of/overlay.c +++ b/drivers/of/overlay.c @@ -109,7 +109,7 @@ static char *of_overlay_fix_path(struct device_node *root, } static void of_overlay_apply_symbols(struct device_node *root, - struct device_node *overlay) + struct device_node *overlay) { const char *old_path; char *new_path; @@ -120,8 +120,13 @@ static void of_overlay_apply_symbols(struct device_node *root, root_symbols = of_get_child_by_name(root, "__symbols__"); overlay_symbols = of_get_child_by_name(overlay, "__symbols__"); - if (!overlay_symbols || !root_symbols) { - pr_info("overlay/root doesn't have a __symbols__ node\n"); + if (!overlay_symbols) { + pr_debug("overlay doesn't have a __symbols__ node\n"); + return; + } + + if (!root_symbols) { + pr_info("root doesn't have a __symbols__ node\n"); return; } diff --git a/drivers/of/partition.c b/drivers/of/partition.c index 65c24c5426..b71716218b 100644 --- a/drivers/of/partition.c +++ b/drivers/of/partition.c @@ -235,6 +235,9 @@ static int of_partition_fixup(struct device_node *root, void *ctx) struct device_node *np; char *name; + if (!cdev->device_node) + return -EINVAL; + name = of_get_reproducible_name(cdev->device_node); np = of_find_node_by_reproducible_name(root, name); free(name); diff --git a/drivers/phy/phy-stm32-usbphyc.c b/drivers/phy/phy-stm32-usbphyc.c index d9eaa8a754..d1e064440e 100644 --- a/drivers/phy/phy-stm32-usbphyc.c +++ b/drivers/phy/phy-stm32-usbphyc.c @@ -12,7 +12,7 @@ #include <io.h> #include <linux/phy/phy.h> #include <linux/reset.h> -#include <asm-generic/div64.h> +#include <linux/math64.h> #include <usb/phy.h> #define STM32_USBPHYC_PLL 0x0 diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index 8407b2f5e1..6dd6e3eb95 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -15,7 +15,7 @@ #include <pwm.h> #include <linux/clk.h> #include <linux/err.h> -#include <asm-generic/div64.h> +#include <linux/math64.h> /* i.MX1 and i.MX21 share the same PWM function block: */ diff --git a/drivers/pwm/pwm-mxs.c b/drivers/pwm/pwm-mxs.c index 08819b43bc..8f77ca07a6 100644 --- a/drivers/pwm/pwm-mxs.c +++ b/drivers/pwm/pwm-mxs.c @@ -9,7 +9,7 @@ #include <stmp-device.h> #include <linux/clk.h> #include <linux/err.h> -#include <asm-generic/div64.h> +#include <linux/math64.h> #define SET 0x4 #define CLR 0x8 diff --git a/drivers/pwm/pxa_pwm.c b/drivers/pwm/pxa_pwm.c index dc8e41464b..61c4b8da43 100644 --- a/drivers/pwm/pxa_pwm.c +++ b/drivers/pwm/pxa_pwm.c @@ -17,7 +17,7 @@ #include <mach/clock.h> #include <mach/pxa-regs.h> #include <mach/regs-pwm.h> -#include <asm-generic/div64.h> +#include <linux/math64.h> #include <linux/compiler.h> /* PWM registers and bits definitions */ diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 1ce057180a..9be81832f2 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -28,6 +28,15 @@ config REGULATOR_STM32_PWR This driver supports internal regulators (1V1, 1V8, 3V3) in the STMicroelectronics STM32 chips. +config REGULATOR_STM32_VREFBUF + tristate "STMicroelectronics STM32 VREFBUF" + depends on ARCH_STM32MP || COMPILE_TEST + help + This driver supports STMicroelectronics STM32 VREFBUF (voltage + reference buffer) which can be used as voltage reference for + internal ADCs, DACs and also for external components through + dedicated Vref+ pin. + config REGULATOR_STPMIC1 tristate "STMicroelectronics STPMIC1 PMIC Regulators" depends on MFD_STPMIC1 diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 4d0bba6c52..67859bb79e 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_REGULATOR_PFUZE) += pfuze.o obj-$(CONFIG_REGULATOR_STPMIC1) += stpmic1_regulator.o obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o obj-$(CONFIG_REGULATOR_STM32_PWR) += stm32-pwr.o +obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 6ea21a4609..ac3a9b048e 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -176,6 +176,12 @@ int of_regulator_register(struct regulator_dev *rd, struct device_node *node) ri->node = node; + if (rd->desc->off_on_delay) + ri->enable_time_us = rd->desc->off_on_delay; + + if (rd->desc->fixed_uV && rd->desc->n_voltages == 1) + ri->min_uv = ri->max_uv = rd->desc->fixed_uV; + of_property_read_u32(node, "regulator-enable-ramp-delay", &ri->enable_time_us); of_property_read_u32(node, "regulator-min-microvolt", @@ -539,6 +545,30 @@ void regulator_bulk_free(int num_consumers, } EXPORT_SYMBOL_GPL(regulator_bulk_free); +int regulator_get_voltage(struct regulator *regulator) +{ + struct regulator_dev *rdev = regulator->ri->rdev; + int sel, ret; + + if (rdev->desc->ops->get_voltage_sel) { + sel = rdev->desc->ops->get_voltage_sel(rdev); + if (sel < 0) + return sel; + ret = rdev->desc->ops->list_voltage(rdev, sel); + } else if (rdev->desc->ops->get_voltage) { + ret = rdev->desc->ops->get_voltage(rdev); + } else if (rdev->desc->ops->list_voltage) { + ret = rdev->desc->ops->list_voltage(rdev, 0); + } else if (rdev->desc->fixed_uV && (rdev->desc->n_voltages == 1)) { + ret = rdev->desc->fixed_uV; + } else { + return -EINVAL; + } + + return ret; +} +EXPORT_SYMBOL_GPL(regulator_get_voltage_rdev); + static void regulator_print_one(struct regulator_internal *ri) { struct regulator *r; diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c index c4877cecf7..e741944ce7 100644 --- a/drivers/regulator/helpers.c +++ b/drivers/regulator/helpers.c @@ -369,4 +369,29 @@ int regulator_map_voltage_iterate(struct regulator_dev *rdev, } EXPORT_SYMBOL_GPL(regulator_map_voltage_iterate); +/** + * regulator_list_voltage_table - List voltages with table based mapping + * + * @rdev: Regulator device + * @selector: Selector to convert into a voltage + * + * Regulators with table based mapping between voltages and + * selectors can set volt_table in the regulator descriptor + * and then use this function as their list_voltage() operation. + */ +int regulator_list_voltage_table(struct regulator_dev *rdev, + unsigned int selector) +{ + if (!rdev->desc->volt_table) { + BUG_ON(!rdev->desc->volt_table); + return -EINVAL; + } + if (selector >= rdev->desc->n_voltages) + return -EINVAL; + if (selector < rdev->desc->linear_min_sel) + return 0; + + return rdev->desc->volt_table[selector]; +} +EXPORT_SYMBOL_GPL(regulator_list_voltage_table); diff --git a/drivers/regulator/stm32-vrefbuf.c b/drivers/regulator/stm32-vrefbuf.c new file mode 100644 index 0000000000..3956b1f64f --- /dev/null +++ b/drivers/regulator/stm32-vrefbuf.c @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) STMicroelectronics 2017 + * + * Author: Fabrice Gasnier <fabrice.gasnier@st.com> + */ + +#include <common.h> +#include <linux/bitfield.h> +#include <linux/clk.h> +#include <linux/iopoll.h> +#include <of.h> +#include <regulator.h> + +/* STM32 VREFBUF registers */ +#define STM32_VREFBUF_CSR 0x00 + +/* STM32 VREFBUF CSR bitfields */ +#define STM32_VRS GENMASK(6, 4) +#define STM32_VRR BIT(3) +#define STM32_HIZ BIT(1) +#define STM32_ENVR BIT(0) + +#define STM32_VREFBUF_AUTO_SUSPEND_DELAY_MS 10 + +#define readl_relaxed readl +#define writel_relaxed writel + +struct stm32_vrefbuf { + void __iomem *base; + struct clk *clk; + struct device_d *dev; + struct regulator_dev rdev; +}; + +struct stm32_vrefbuf_desc { + struct regulator_desc desc; + const char *supply_name; +}; + +static inline struct stm32_vrefbuf *to_stm32_vrefbuf(struct regulator_dev *rdev) +{ + return container_of(rdev, struct stm32_vrefbuf, rdev); +} + +static const unsigned int stm32_vrefbuf_voltages[] = { + /* Matches resp. VRS = 000b, 001b, 010b, 011b */ + 2500000, 2048000, 1800000, 1500000, +}; + +static int stm32_vrefbuf_enable(struct regulator_dev *rdev) +{ + struct stm32_vrefbuf *priv = to_stm32_vrefbuf(rdev); + u32 val; + int ret; + + val = readl_relaxed(priv->base + STM32_VREFBUF_CSR); + val = (val & ~STM32_HIZ) | STM32_ENVR; + writel_relaxed(val, priv->base + STM32_VREFBUF_CSR); + + /* + * Vrefbuf startup time depends on external capacitor: wait here for + * VRR to be set. That means output has reached expected value. + * ~650us sleep should be enough for caps up to 1.5uF. Use 10ms as + * arbitrary timeout. + */ + ret = readl_poll_timeout(priv->base + STM32_VREFBUF_CSR, val, + val & STM32_VRR, 10000); + if (ret) { + dev_err(priv->dev, "stm32 vrefbuf timed out!\n"); + val = readl_relaxed(priv->base + STM32_VREFBUF_CSR); + val = (val & ~STM32_ENVR) | STM32_HIZ; + writel_relaxed(val, priv->base + STM32_VREFBUF_CSR); + } + + return ret; +} + +static int stm32_vrefbuf_disable(struct regulator_dev *rdev) +{ + struct stm32_vrefbuf *priv = to_stm32_vrefbuf(rdev); + u32 val; + + val = readl_relaxed(priv->base + STM32_VREFBUF_CSR); + val &= ~STM32_ENVR; + writel_relaxed(val, priv->base + STM32_VREFBUF_CSR); + + return 0; +} + +static int stm32_vrefbuf_is_enabled(struct regulator_dev *rdev) +{ + struct stm32_vrefbuf *priv = to_stm32_vrefbuf(rdev); + int ret; + + ret = readl_relaxed(priv->base + STM32_VREFBUF_CSR) & STM32_ENVR; + + return ret; +} + +static int stm32_vrefbuf_set_voltage_sel(struct regulator_dev *rdev, + unsigned sel) +{ + struct stm32_vrefbuf *priv = to_stm32_vrefbuf(rdev); + u32 val; + + val = readl_relaxed(priv->base + STM32_VREFBUF_CSR); + val = (val & ~STM32_VRS) | FIELD_PREP(STM32_VRS, sel); + writel_relaxed(val, priv->base + STM32_VREFBUF_CSR); + + return 0; +} + +static int stm32_vrefbuf_get_voltage_sel(struct regulator_dev *rdev) +{ + struct stm32_vrefbuf *priv = to_stm32_vrefbuf(rdev); + u32 val; + int ret; + + val = readl_relaxed(priv->base + STM32_VREFBUF_CSR); + ret = FIELD_GET(STM32_VRS, val); + + return ret; +} + +static const struct regulator_ops stm32_vrefbuf_volt_ops = { + .enable = stm32_vrefbuf_enable, + .disable = stm32_vrefbuf_disable, + .is_enabled = stm32_vrefbuf_is_enabled, + .get_voltage_sel = stm32_vrefbuf_get_voltage_sel, + .set_voltage_sel = stm32_vrefbuf_set_voltage_sel, + .list_voltage = regulator_list_voltage_table, +}; + +static const struct stm32_vrefbuf_desc stm32_vrefbuf_regu = { + .desc = { + .volt_table = stm32_vrefbuf_voltages, + .n_voltages = ARRAY_SIZE(stm32_vrefbuf_voltages), + .ops = &stm32_vrefbuf_volt_ops, + .off_on_delay = 1000, + }, + .supply_name = "vdda", +}; + +static int stm32_vrefbuf_probe(struct device_d *dev) +{ + struct stm32_vrefbuf *priv; + struct regulator_dev *rdev; + struct regulator *supply; + int ret; + + supply = regulator_get(dev, stm32_vrefbuf_regu.supply_name); + if (IS_ERR(supply)) + return PTR_ERR(supply); + + priv = xzalloc(sizeof(*priv)); + priv->dev = dev; + + priv->base = dev_request_mem_region(dev, 0); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + priv->clk = clk_get(dev, NULL); + if (IS_ERR(priv->clk)) + return PTR_ERR(priv->clk); + + ret = clk_enable(priv->clk); + if (ret) { + dev_err(dev, "clk enable failed with error %d\n", ret); + return ret; + } + + rdev = &priv->rdev; + + rdev->dev = dev; + rdev->desc = &stm32_vrefbuf_regu.desc; + + ret = of_regulator_register(rdev, dev->device_node); + if (ret) { + ret = PTR_ERR(rdev); + dev_err(dev, "register failed with error %d\n", ret); + goto err_clk_dis; + } + + regulator_enable(supply); + + dev->priv = priv; + + return 0; + +err_clk_dis: + clk_disable(priv->clk); + + return ret; +} + +static void stm32_vrefbuf_remove(struct device_d *dev) +{ + struct stm32_vrefbuf *priv = dev->priv; + + clk_disable(priv->clk); +}; + +static const struct of_device_id __maybe_unused stm32_vrefbuf_of_match[] = { + { .compatible = "st,stm32-vrefbuf", }, + {}, +}; + +static struct driver_d stm32_vrefbuf_driver = { + .probe = stm32_vrefbuf_probe, + .name = "stm32-vrefbuf", + .remove = stm32_vrefbuf_remove, + .of_compatible = stm32_vrefbuf_of_match, +}; +device_platform_driver(stm32_vrefbuf_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>"); +MODULE_DESCRIPTION("STMicroelectronics STM32 VREFBUF driver"); +MODULE_ALIAS("platform:stm32-vrefbuf"); diff --git a/drivers/serial/serial_ar933x.c b/drivers/serial/serial_ar933x.c index 2fe1b4f923..32ad1ba463 100644 --- a/drivers/serial/serial_ar933x.c +++ b/drivers/serial/serial_ar933x.c @@ -18,7 +18,7 @@ #include <init.h> #include <malloc.h> #include <io.h> -#include <asm-generic/div64.h> +#include <linux/math64.h> #include <linux/clk.h> #include <linux/err.h> diff --git a/drivers/sound/Kconfig b/drivers/sound/Kconfig new file mode 100644 index 0000000000..bf6f715200 --- /dev/null +++ b/drivers/sound/Kconfig @@ -0,0 +1,38 @@ +# SPDX-License-Identifier: GPL-2.0-only +menuconfig SOUND + bool "Sound drivers" + select POLLER + help + Say Y here for sound support. At the moment that's just beep tones. + Tones are played asynchronously in a poller. Check the beep command + for how to exercise the API. + +if SOUND + +config SOUND_SDL + bool "SDL sound driver for sandbox" + depends on SANDBOX && OFDEVICE + select SDL + +config PWM_BEEPER + bool "PWM beeper support" + depends on PWM && OFDEVICE + help + Say Y here to get support for PWM based beeper devices. + +config GPIO_BEEPER + bool "GPIO beeper support" + depends on GPIOLIB && OFDEVICE + help + Say Y here to get support for GPIO based beeper devices. + +config SYNTH_SQUARES + bool "Synthesize square waves only" + help + For beeping on PCM sound cards, barebox needs to synthesize samples, + which can take too much poller time for crisp playback and/or quick + booting. If your playback stutters, say Y here. This will have all + synthesizers output a gain-adjusted square wave instead, which is + less time-consuming to compute. + +endif diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile new file mode 100644 index 0000000000..57d9cbd332 --- /dev/null +++ b/drivers/sound/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-y += core.o synth.o +obj-$(CONFIG_SOUND_SDL) += sdl.o +obj-$(CONFIG_PWM_BEEPER) += pwm-beeper.o +obj-$(CONFIG_GPIO_BEEPER) += gpio-beeper.o diff --git a/drivers/sound/core.c b/drivers/sound/core.c new file mode 100644 index 0000000000..801b1fade5 --- /dev/null +++ b/drivers/sound/core.c @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: © 2021 Ahmad Fatoum + +#include <common.h> +#include <linux/list.h> +#include <sound.h> +#include <poller.h> +#include <linux/iopoll.h> + +static LIST_HEAD(card_list); + +struct beep { + int freq; + unsigned int us; + struct list_head list; +}; + +static int sound_card_do_beep(struct sound_card *card, + int freq, unsigned int us) +{ + if (freq == -1) + freq = card->bell_frequency; + + return card->beep(card, freq, us); +} + +static void sound_card_poller_cb(void *_card) +{ + struct sound_card *card = _card; + struct beep *beep; + + beep = list_first_entry_or_null(&card->tune, struct beep, list); + if (!beep) { + sound_card_do_beep(card, 0, 0); + return; + } + + list_del(&beep->list); + + poller_call_async(&card->poller, beep->us * 1000ULL, + sound_card_poller_cb, card); + sound_card_do_beep(card, beep->freq, beep->us); + + free(beep); +} + +int sound_card_register(struct sound_card *card) +{ + if (!card->name) + return -EINVAL; + + if (card->bell_frequency <= 0) + card->bell_frequency = 1000; + + poller_async_register(&card->poller, card->name); + INIT_LIST_HEAD(&card->tune); + + list_add_tail(&card->list, &card_list); + return 0; +} + +struct sound_card *sound_card_get_default(void) +{ + return list_first_entry_or_null(&card_list, struct sound_card, list); +} + +int sound_card_beep(struct sound_card *card, int freq, unsigned int us) +{ + struct beep *beep; + int ret; + + if (!card) + return -ENODEV; + + if (!poller_async_active(&card->poller)) { + ret = sound_card_do_beep(card, freq, us); + if (!ret) + poller_call_async(&card->poller, us * 1000ULL, + sound_card_poller_cb, card); + + return ret; + } + + beep = malloc(sizeof(*beep)); + if (!beep) + return -ENOMEM; + + beep->freq = freq; + beep->us = us; + + list_add_tail(&beep->list, &card->tune); + + return 0; +} + +int sound_card_beep_wait(struct sound_card *card, unsigned timeout) +{ + bool active; + return read_poll_timeout(poller_async_active, active, + !active, timeout, &card->poller); +} + +int sound_card_beep_cancel(struct sound_card *card) +{ + struct beep *beep, *tmp; + int ret; + + if (!card) + return -ENODEV; + + poller_async_cancel(&card->poller); + + ret = card->beep(card, 0, 0); + + list_for_each_entry_safe(beep, tmp, &card->tune, list) { + list_del(&beep->list); + free(beep); + } + + return ret; +} diff --git a/drivers/sound/gpio-beeper.c b/drivers/sound/gpio-beeper.c new file mode 100644 index 0000000000..86fd4a4ee6 --- /dev/null +++ b/drivers/sound/gpio-beeper.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2021, Ahmad Fatoum + */ + +#include <common.h> +#include <regulator.h> +#include <sound.h> +#include <of.h> +#include <gpio.h> +#include <of_gpio.h> + +struct gpio_beeper { + int gpio; + struct sound_card card; +}; + +static int gpio_beeper_beep(struct sound_card *card, unsigned freq, unsigned duration) +{ + struct gpio_beeper *beeper = container_of(card, struct gpio_beeper, card); + + gpio_set_active(beeper->gpio, freq); + return 0; +} + +static int gpio_beeper_probe(struct device_d *dev) +{ + struct device_node *np = dev->device_node; + struct gpio_beeper *beeper; + struct sound_card *card; + enum of_gpio_flags of_flags; + unsigned long gpio_flags = GPIOF_OUT_INIT_ACTIVE; + int ret, gpio; + + gpio = of_get_named_gpio_flags(np, "gpios", 0, &of_flags); + if (!gpio_is_valid(gpio)) + return gpio; + + if (of_flags & OF_GPIO_ACTIVE_LOW) + gpio_flags |= GPIOF_ACTIVE_LOW; + + ret = gpio_request_one(gpio, gpio_flags, "gpio-beeper"); + if (ret) { + dev_err(dev, "failed to request gpio %d: %d\n", gpio, ret); + return ret; + } + + beeper = xzalloc(sizeof(*beeper)); + beeper->gpio = gpio; + dev->priv = beeper; + + card = &beeper->card; + card->name = np->full_name; + card->beep = gpio_beeper_beep; + + return sound_card_register(card); +} + +static void gpio_beeper_suspend(struct device_d *dev) +{ + struct gpio_beeper *beeper = dev->priv; + + gpio_beeper_beep(&beeper->card, 0, 0); +} + +static const struct of_device_id gpio_beeper_match[] = { + { .compatible = "gpio-beeper", }, + { }, +}; + +static struct driver_d gpio_beeper_driver = { + .name = "gpio-beeper", + .probe = gpio_beeper_probe, + .remove = gpio_beeper_suspend, + .of_compatible = gpio_beeper_match, +}; +device_platform_driver(gpio_beeper_driver); diff --git a/drivers/sound/pwm-beeper.c b/drivers/sound/pwm-beeper.c new file mode 100644 index 0000000000..ef053f97cf --- /dev/null +++ b/drivers/sound/pwm-beeper.c @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de> + * Copyright (C) 2021, Ahmad Fatoum + */ + +#include <common.h> +#include <regulator.h> +#include <sound.h> +#include <of.h> +#include <pwm.h> + +struct pwm_beeper { + struct pwm_device *pwm; + struct regulator *amplifier; + struct sound_card card; +}; + +#define HZ_TO_NANOSECONDS(x) (1000000000UL/(x)) + +static int pwm_beeper_beep(struct sound_card *card, unsigned freq, unsigned duration) +{ + struct pwm_beeper *beeper = container_of(card, struct pwm_beeper, card); + struct pwm_state state; + int error = 0; + + if (!freq) { + regulator_disable(beeper->amplifier); + goto pwm_disable; + } + + pwm_get_state(beeper->pwm, &state); + + state.p_enable = true; + state.period_ns = HZ_TO_NANOSECONDS(freq); + pwm_set_relative_duty_cycle(&state, 50, 100); + + error = pwm_apply_state(beeper->pwm, &state); + if (error) + return error; + + error = regulator_enable(beeper->amplifier); + if (error) + goto pwm_disable; + + return 0; +pwm_disable: + pwm_disable(beeper->pwm); + return error; +} + +static int pwm_beeper_probe(struct device_d *dev) +{ + struct pwm_beeper *beeper; + struct sound_card *card; + struct pwm_state state; + u32 bell_frequency; + int error; + + beeper = xzalloc(sizeof(*beeper)); + dev->priv = beeper; + + beeper->pwm = of_pwm_request(dev->device_node, NULL); + if (IS_ERR(beeper->pwm)) { + error = PTR_ERR(beeper->pwm); + if (error != -EPROBE_DEFER) + dev_err(dev, "Failed to request PWM device: %d\n", + error); + return error; + } + + /* Sync up PWM state and ensure it is off. */ + pwm_init_state(beeper->pwm, &state); + state.p_enable = false; + error = pwm_apply_state(beeper->pwm, &state); + if (error) { + dev_err(dev, "failed to apply initial PWM state: %d\n", + error); + return error; + } + + beeper->amplifier = regulator_get(dev, "amp"); + if (IS_ERR(beeper->amplifier)) { + error = PTR_ERR(beeper->amplifier); + if (error != -EPROBE_DEFER) + dev_err(dev, "Failed to get 'amp' regulator: %d\n", + error); + return error; + } + + error = of_property_read_u32(dev->device_node, "beeper-hz", &bell_frequency); + if (error) { + bell_frequency = 1000; + dev_dbg(dev, "failed to parse 'beeper-hz' property, using default: %uHz\n", + bell_frequency); + } + + card = &beeper->card; + card->name = dev->device_node->full_name; + card->bell_frequency = bell_frequency; + card->beep = pwm_beeper_beep; + + return sound_card_register(card); +} + +static void pwm_beeper_suspend(struct device_d *dev) +{ + struct pwm_beeper *beeper = dev->priv; + + pwm_beeper_beep(&beeper->card, 0, 0); +} + +static const struct of_device_id pwm_beeper_match[] = { + { .compatible = "pwm-beeper", }, + { }, +}; + +static struct driver_d pwm_beeper_driver = { + .name = "pwm-beeper", + .probe = pwm_beeper_probe, + .remove = pwm_beeper_suspend, + .of_compatible = pwm_beeper_match, +}; +device_platform_driver(pwm_beeper_driver); diff --git a/drivers/sound/sdl.c b/drivers/sound/sdl.c new file mode 100644 index 0000000000..118d774295 --- /dev/null +++ b/drivers/sound/sdl.c @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <common.h> +#include <errno.h> +#include <driver.h> +#include <mach/linux.h> +#include <linux/time.h> +#include <linux/math64.h> +#include <of.h> +#include <sound.h> + +#define AMPLITUDE 28000 +#define SAMPLERATE 44000ULL + +struct sandbox_sound { + struct sound_card card; +}; + +static int sandbox_sound_beep(struct sound_card *card, unsigned freq, unsigned duration) +{ + size_t nsamples = div_s64(SAMPLERATE * duration, USEC_PER_SEC); + int16_t *data; + int ret; + + if (!freq) { + sdl_sound_stop(); + return 0; + } + + data = malloc(nsamples * sizeof(*data)); + if (!data) + return -ENOMEM; + + synth_sin(freq, AMPLITUDE, data, SAMPLERATE, nsamples); + ret = sdl_sound_play(data, nsamples); + if (ret) + ret = -EIO; + free(data); + + return ret; +} + +static int sandbox_sound_probe(struct device_d *dev) +{ + struct sandbox_sound *priv; + struct sound_card *card; + int ret; + + priv = xzalloc(sizeof(*priv)); + + card = &priv->card; + card->name = "SDL-Audio"; + card->beep = sandbox_sound_beep; + + ret = sdl_sound_init(SAMPLERATE); + if (ret) { + ret = -ENODEV; + goto free_priv; + } + + ret = sound_card_register(card); + if (ret) + goto sdl_sound_close; + + dev_info(dev, "probed\n"); + return 0; + +sdl_sound_close: + sdl_sound_close(); +free_priv: + free(priv); + + return ret; +} + + +static __maybe_unused struct of_device_id sandbox_sound_dt_ids[] = { + { .compatible = "barebox,sandbox-sound" }, + { /* sentinel */ } +}; + +static struct driver_d sandbox_sound_drv = { + .name = "sandbox-sound", + .of_compatible = sandbox_sound_dt_ids, + .probe = sandbox_sound_probe, +}; +device_platform_driver(sandbox_sound_drv); diff --git a/drivers/sound/synth.c b/drivers/sound/synth.c new file mode 100644 index 0000000000..c9de62b516 --- /dev/null +++ b/drivers/sound/synth.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2012 Samsung Electronics, R. Chandrasekar <rcsekar@samsung.com> + * Copyright (C) 2021 Ahmad Fatoum + */ + +#include <common.h> +#include <linux/fixp-arith.h> +#include <linux/math64.h> +#include <sound.h> + +void __synth_sin(unsigned freq, s16 amplitude, s16 *stream, + unsigned sample_rate, unsigned nsamples) +{ + int64_t v = 0; + int i = 0; + + for (i = 0; i < nsamples; i++) { + /* Assume RHS sign extension, true for GCC */ + stream[i] = (fixp_sin32(div_s64(v * 360, sample_rate)) * (int64_t)amplitude) >> 31; + v += freq; + } +} + +void __synth_square(unsigned freq, s16 amplitude, s16 *stream, + unsigned sample_rate, unsigned nsamples) +{ + unsigned period = freq ? sample_rate / freq : 0; + int half = period / 2; + + while (nsamples) { + int i; + + for (i = 0; nsamples && i < half; i++) { + nsamples--; + *stream++ = amplitude; + } + for (i = 0; nsamples && i < period - half; i++) { + nsamples--; + *stream++ = -amplitude; + } + } +} diff --git a/drivers/usb/gadget/dfu.c b/drivers/usb/gadget/dfu.c index 7e23fa3157..bb0b34aa94 100644 --- a/drivers/usb/gadget/dfu.c +++ b/drivers/usb/gadget/dfu.c @@ -32,6 +32,7 @@ * checking? * - make 'dnstate' attached to 'struct usb_device_instance' */ +#define pr_fmt(fmt) "dfu: " fmt #include <dma.h> #include <asm/byteorder.h> @@ -54,6 +55,7 @@ #include <fs.h> #include <ioctl.h> #include <linux/mtd/mtd-abi.h> +#include <work.h> #define USB_DT_DFU 0x21 @@ -153,6 +155,7 @@ struct f_dfu { u8 dfu_state; u8 dfu_status; struct usb_request *dnreq; + struct work_queue wq; }; static inline struct f_dfu *func_to_dfu(struct usb_function *f) @@ -173,6 +176,191 @@ static struct usb_gadget_strings *dfu_strings[] = { }; static void dn_complete(struct usb_ep *ep, struct usb_request *req); +static void up_complete(struct usb_ep *ep, struct usb_request *req); +static void dfu_cleanup(struct f_dfu *dfu); + +struct dfu_work { + struct work_struct work; + struct f_dfu *dfu; + void (*task)(struct dfu_work *dw); + size_t len; + uint8_t *rbuf; + uint8_t wbuf[CONFIG_USBD_DFU_XFER_SIZE]; +}; + +static void dfu_do_work(struct work_struct *w) +{ + struct dfu_work *dw = container_of(w, struct dfu_work, work); + struct f_dfu *dfu = dw->dfu; + + if (dfu->dfu_state != DFU_STATE_dfuERROR && dfu->dfu_status == DFU_STATUS_OK) + dw->task(dw); + else + pr_debug("skip work\n"); + + free(dw); +} + +static void dfu_work_cancel(struct work_struct *w) +{ + struct dfu_work *dw = container_of(w, struct dfu_work, work); + + free(dw); +} + +static void dfu_do_write(struct dfu_work *dw) +{ + struct f_dfu *dfu = dw->dfu; + ssize_t size, wlen = dw->len; + ssize_t ret; + + pr_debug("do write\n"); + + if (prog_erase && (dfu_written + wlen) > dfu_erased) { + size = roundup(wlen, dfu_mtdinfo.erasesize); + ret = erase(dfufd, size, dfu_erased); + dfu_erased += size; + if (ret && ret != -ENOSYS) { + perror("erase"); + dfu->dfu_state = DFU_STATE_dfuERROR; + dfu->dfu_status = DFU_STATUS_errERASE; + return; + } + } + + dfu_written += wlen; + ret = write(dfufd, dw->wbuf, wlen); + if (ret < wlen) { + perror("write"); + dfu->dfu_state = DFU_STATE_dfuERROR; + dfu->dfu_status = DFU_STATUS_errWRITE; + } +} + +static void dfu_do_read(struct dfu_work *dw) +{ + struct f_dfu *dfu = dw->dfu; + struct usb_composite_dev *cdev = dfu->func.config->cdev; + ssize_t size, rlen = dw->len; + + pr_debug("do read\n"); + + size = read(dfufd, dfu->dnreq->buf, rlen); + dfu->dnreq->length = size; + if (size < 0) { + perror("read"); + dfu->dnreq->length = 0; + dfu->dfu_state = DFU_STATE_dfuERROR; + dfu->dfu_status = DFU_STATUS_errFILE; + } else if (size < rlen) { + /* this is the last chunk, go to IDLE and close file */ + dfu_cleanup(dfu); + } + + dfu->dnreq->complete = up_complete; + usb_ep_queue(cdev->gadget->ep0, dfu->dnreq); +} + +static void dfu_do_open_dnload(struct dfu_work *dw) +{ + struct f_dfu *dfu = dw->dfu; + int ret; + + pr_debug("do open dnload\n"); + + if (dfu_file_entry->flags & FILE_LIST_FLAG_SAFE) { + dfufd = open(DFU_TEMPFILE, O_WRONLY | O_CREAT); + } else { + unsigned flags = O_WRONLY; + + if (dfu_file_entry->flags & FILE_LIST_FLAG_CREATE) + flags |= O_CREAT | O_TRUNC; + + dfufd = open(dfu_file_entry->filename, flags); + } + + if (dfufd < 0) { + perror("open"); + dfu->dfu_state = DFU_STATE_dfuERROR; + dfu->dfu_status = DFU_STATUS_errFILE; + return; + } + + if (!(dfu_file_entry->flags & FILE_LIST_FLAG_SAFE)) { + ret = ioctl(dfufd, MEMGETINFO, &dfu_mtdinfo); + if (!ret) /* file is on a mtd device */ + prog_erase = 1; + } +} + +static void dfu_do_open_upload(struct dfu_work *dw) +{ + struct f_dfu *dfu = dw->dfu; + + pr_debug("do open upload\n"); + + dfufd = open(dfu_file_entry->filename, O_RDONLY); + if (dfufd < 0) { + perror("open"); + dfu->dfu_state = DFU_STATE_dfuERROR; + dfu->dfu_status = DFU_STATUS_errFILE; + } +} + +static void dfu_do_close(struct dfu_work *dw) +{ + struct stat s; + + pr_debug("do close\n"); + + if (dfufd > 0) { + close(dfufd); + dfufd = -EINVAL; + } + + if (!stat(DFU_TEMPFILE, &s)) + unlink(DFU_TEMPFILE); +} + +static void dfu_do_copy(struct dfu_work *dw) +{ + struct f_dfu *dfu = dw->dfu; + unsigned flags = O_WRONLY; + int ret, fd; + + pr_debug("do copy\n"); + + if (dfu_file_entry->flags & FILE_LIST_FLAG_CREATE) + flags |= O_CREAT | O_TRUNC; + + fd = open(dfu_file_entry->filename, flags); + if (fd < 0) { + perror("open"); + dfu->dfu_state = DFU_STATE_dfuERROR; + dfu->dfu_status = DFU_STATUS_errERASE; + return; + } + + ret = erase(fd, ERASE_SIZE_ALL, 0); + close(fd); + if (ret && ret != -ENOSYS) { + perror("erase"); + dfu->dfu_state = DFU_STATE_dfuERROR; + dfu->dfu_status = DFU_STATUS_errERASE; + return; + } + + ret = copy_file(DFU_TEMPFILE, dfu_file_entry->filename, 0); + if (ret) { + pr_err("copy file failed\n"); + dfu->dfu_state = DFU_STATE_dfuERROR; + dfu->dfu_status = DFU_STATUS_errWRITE; + return; + } + + dfu->dfu_state = DFU_STATE_dfuIDLE; + dfu_do_close(dw); +} static int dfu_bind(struct usb_configuration *c, struct usb_function *f) @@ -181,7 +369,7 @@ dfu_bind(struct usb_configuration *c, struct usb_function *f) struct usb_descriptor_header **header; struct usb_interface_descriptor *desc; struct file_list_entry *fentry; - struct f_dfu *dfu = container_of(f, struct f_dfu, func); + struct f_dfu *dfu = func_to_dfu(f); int i; int status; struct usb_string *us; @@ -209,7 +397,7 @@ dfu_bind(struct usb_configuration *c, struct usb_function *f) dfu->dnreq = usb_ep_alloc_request(c->cdev->gadget->ep0); if (!dfu->dnreq) { - printf("usb_ep_alloc_request failed\n"); + pr_err("usb_ep_alloc_request failed\n"); status = -ENOMEM; goto out; } @@ -223,6 +411,10 @@ dfu_bind(struct usb_configuration *c, struct usb_function *f) goto out; } + dfu->wq.fn = dfu_do_work; + dfu->wq.cancel = dfu_work_cancel; + wq_register(&dfu->wq); + /* allocate instance-specific interface IDs, and patch descriptors */ status = usb_interface_id(c, f); if (status < 0) @@ -254,7 +446,7 @@ dfu_bind(struct usb_configuration *c, struct usb_function *f) i = 0; file_list_for_each_entry(dfu_files, fentry) { - printf("dfu: register alt%d(%s) with device %s\n", + pr_err("register alt%d(%s) with device %s\n", i, fentry->name, fentry->filename); i++; } @@ -278,6 +470,8 @@ dfu_unbind(struct usb_configuration *c, struct usb_function *f) dfu_file_entry = NULL; dfudetach = 0; + wq_unregister(&dfu->wq); + usb_free_all_descriptors(f); dma_free(dfu->dnreq->buf); @@ -320,47 +514,50 @@ static int dfu_status(struct usb_function *f, const struct usb_ctrlrequest *ctrl static void dfu_cleanup(struct f_dfu *dfu) { - struct stat s; + struct dfu_work *dw; + + pr_debug("dfu cleanup\n"); memset(&dfu_mtdinfo, 0, sizeof(dfu_mtdinfo)); dfu_written = 0; dfu_erased = 0; prog_erase = 0; - if (dfufd > 0) { - close(dfufd); - dfufd = -EINVAL; - } + dfu->dfu_state = DFU_STATE_dfuIDLE; + dfu->dfu_status = DFU_STATUS_OK; - if (!stat(DFU_TEMPFILE, &s)) - unlink(DFU_TEMPFILE); + dw = xzalloc(sizeof(*dw)); + dw->dfu = dfu; + dw->task = dfu_do_close; + wq_queue_work(&dfu->wq, &dw->work); } static void dn_complete(struct usb_ep *ep, struct usb_request *req) { struct f_dfu *dfu = req->context; - loff_t size; - int ret; + struct dfu_work *dw; + + dw = xzalloc(sizeof(*dw)); + dw->dfu = dfu; + dw->task = dfu_do_write; + dw->len = min_t(unsigned int, req->length, CONFIG_USBD_DFU_XFER_SIZE); + memcpy(dw->wbuf, req->buf, dw->len); + wq_queue_work(&dfu->wq, &dw->work); +} - if (prog_erase && (dfu_written + req->length) > dfu_erased) { - size = roundup(req->length, dfu_mtdinfo.erasesize); - ret = erase(dfufd, size, dfu_erased); - dfu_erased += size; - if (ret && ret != -ENOSYS) { - perror("erase"); - dfu->dfu_status = DFU_STATUS_errERASE; - dfu_cleanup(dfu); - return; - } - } +static int handle_manifest(struct usb_function *f, const struct usb_ctrlrequest *ctrl) +{ + struct f_dfu *dfu = func_to_dfu(f); + struct dfu_work *dw; - dfu_written += req->length; - ret = write(dfufd, req->buf, req->length); - if (ret < (int)req->length) { - perror("write"); - dfu->dfu_status = DFU_STATUS_errWRITE; - dfu_cleanup(dfu); + if (dfu_file_entry->flags & FILE_LIST_FLAG_SAFE) { + dw = xzalloc(sizeof(*dw)); + dw->dfu = dfu; + dw->task = dfu_do_copy; + wq_queue_work(&dfu->wq, &dw->work); } + + return 0; } static int handle_dnload(struct usb_function *f, const struct usb_ctrlrequest *ctrl) @@ -370,12 +567,8 @@ static int handle_dnload(struct usb_function *f, const struct usb_ctrlrequest *c u16 w_length = le16_to_cpu(ctrl->wLength); if (w_length == 0) { - if (dfu_file_entry->flags & FILE_LIST_FLAG_SAFE) { - dfu->dfu_state = DFU_STATE_dfuMANIFEST; - } else { - dfu->dfu_state = DFU_STATE_dfuIDLE; - dfu_cleanup(dfu); - } + handle_manifest(f, ctrl); + dfu->dfu_state = DFU_STATE_dfuMANIFEST; return 0; } @@ -386,53 +579,6 @@ static int handle_dnload(struct usb_function *f, const struct usb_ctrlrequest *c return 0; } -static int handle_manifest(struct usb_function *f, const struct usb_ctrlrequest *ctrl) -{ - struct f_dfu *dfu = func_to_dfu(f); - int ret; - - dfu->dfu_state = DFU_STATE_dfuIDLE; - - if (dfu_file_entry->flags & FILE_LIST_FLAG_SAFE) { - int fd; - unsigned flags = O_WRONLY; - - if (dfu_file_entry->flags & FILE_LIST_FLAG_CREATE) - flags |= O_CREAT | O_TRUNC; - - fd = open(dfu_file_entry->filename, flags); - if (fd < 0) { - perror("open"); - dfu->dfu_status = DFU_STATUS_errERASE; - ret = -EINVAL; - goto out; - } - - ret = erase(fd, ERASE_SIZE_ALL, 0); - close(fd); - if (ret && ret != -ENOSYS) { - dfu->dfu_status = DFU_STATUS_errERASE; - perror("erase"); - goto out; - } - - ret = copy_file(DFU_TEMPFILE, dfu_file_entry->filename, 0); - if (ret) { - printf("copy file failed\n"); - ret = -EINVAL; - goto out; - } - } - - return 0; - -out: - dfu->dfu_status = DFU_STATUS_errWRITE; - dfu->dfu_state = DFU_STATE_dfuERROR; - dfu_cleanup(dfu); - return ret; -} - static void up_complete(struct usb_ep *ep, struct usb_request *req) { } @@ -440,28 +586,22 @@ static void up_complete(struct usb_ep *ep, struct usb_request *req) static int handle_upload(struct usb_function *f, const struct usb_ctrlrequest *ctrl) { struct f_dfu *dfu = func_to_dfu(f); - struct usb_composite_dev *cdev = f->config->cdev; + struct dfu_work *dw; u16 w_length = le16_to_cpu(ctrl->wLength); - int len; - - len = read(dfufd, dfu->dnreq->buf, w_length); - dfu->dnreq->length = len; - if (len < w_length) { - dfu_cleanup(dfu); - dfu->dfu_state = DFU_STATE_dfuIDLE; - } - - dfu->dnreq->complete = up_complete; - usb_ep_queue(cdev->gadget->ep0, dfu->dnreq); + dw = xzalloc(sizeof(*dw)); + dw->dfu = dfu; + dw->task = dfu_do_read; + dw->len = w_length; + dw->rbuf = dfu->dnreq->buf; + wq_queue_work(&dfu->wq, &dw->work); return 0; } static void dfu_abort(struct f_dfu *dfu) { - dfu->dfu_state = DFU_STATE_dfuIDLE; - dfu->dfu_status = DFU_STATUS_OK; + wq_cancel_work(&dfu->wq); dfu_cleanup(dfu); } @@ -474,7 +614,7 @@ static int dfu_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) int value = -EOPNOTSUPP; int w_length = le16_to_cpu(ctrl->wLength); int w_value = le16_to_cpu(ctrl->wValue); - int ret; + struct dfu_work *dw; if (ctrl->bRequestType == USB_DIR_IN && ctrl->bRequest == USB_REQ_GET_DESCRIPTOR && (w_value >> 8) == 0x21) { @@ -500,46 +640,28 @@ static int dfu_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) value = -EINVAL; goto out; } - debug("dfu: starting download to %s\n", dfu_file_entry->filename); - if (dfu_file_entry->flags & FILE_LIST_FLAG_SAFE) { - dfufd = open(DFU_TEMPFILE, O_WRONLY | O_CREAT); - } else { - unsigned flags = O_WRONLY; - - if (dfu_file_entry->flags & FILE_LIST_FLAG_CREATE) - flags |= O_CREAT | O_TRUNC; - - dfufd = open(dfu_file_entry->filename, flags); - } - - if (dfufd < 0) { - dfu->dfu_state = DFU_STATE_dfuERROR; - perror("open"); - goto out; - } - - if (!(dfu_file_entry->flags & FILE_LIST_FLAG_SAFE)) { - ret = ioctl(dfufd, MEMGETINFO, &dfu_mtdinfo); - if (!ret) /* file is on a mtd device */ - prog_erase = 1; - } + pr_debug("starting download to %s\n", dfu_file_entry->filename); + dw = xzalloc(sizeof(*dw)); + dw->dfu = dfu; + dw->task = dfu_do_open_dnload; + wq_queue_work(&dfu->wq, &dw->work); value = handle_dnload(f, ctrl); dfu->dfu_state = DFU_STATE_dfuDNLOAD_IDLE; return 0; case USB_REQ_DFU_UPLOAD: dfu->dfu_state = DFU_STATE_dfuUPLOAD_IDLE; - debug("dfu: starting upload from %s\n", dfu_file_entry->filename); + pr_debug("starting upload from %s\n", dfu_file_entry->filename); if (!(dfu_file_entry->flags & FILE_LIST_FLAG_READBACK)) { dfu->dfu_state = DFU_STATE_dfuERROR; goto out; } - dfufd = open(dfu_file_entry->filename, O_RDONLY); - if (dfufd < 0) { - dfu->dfu_state = DFU_STATE_dfuERROR; - perror("open"); - goto out; - } + + dw = xzalloc(sizeof(*dw)); + dw->dfu = dfu; + dw->task = dfu_do_open_upload; + wq_queue_work(&dfu->wq, &dw->work); + handle_upload(f, ctrl); return 0; case USB_REQ_DFU_ABORT: @@ -606,6 +728,7 @@ static int dfu_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) } break; case DFU_STATE_dfuERROR: + wq_cancel_work(&dfu->wq); switch (ctrl->bRequest) { case USB_REQ_DFU_GETSTATUS: value = dfu_status(f, ctrl); @@ -647,10 +770,7 @@ static int dfu_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) } break; case DFU_STATE_dfuMANIFEST: - value = handle_manifest(f, ctrl); - if (dfu->dfu_state != DFU_STATE_dfuIDLE) { - return 0; - } + dfu->dfu_state = DFU_STATE_dfuMANIFEST_SYNC; switch (ctrl->bRequest) { case USB_REQ_DFU_GETSTATUS: value = dfu_status(f, ctrl); @@ -692,9 +812,7 @@ static void dfu_disable(struct usb_function *f) { struct f_dfu *dfu = func_to_dfu(f); - dfu->dfu_state = DFU_STATE_dfuIDLE; - - dfu_cleanup(dfu); + dfu_abort(dfu); } #define STRING_MANUFACTURER_IDX 0 @@ -863,7 +981,7 @@ out: static void dfu_free_func(struct usb_function *f) { - struct f_dfu *dfu = container_of(f, struct f_dfu, func); + struct f_dfu *dfu = func_to_dfu(f); free(dfu); } diff --git a/drivers/usb/otg/otgdev.c b/drivers/usb/otg/otgdev.c index 52f43b75d2..c233315d91 100644 --- a/drivers/usb/otg/otgdev.c +++ b/drivers/usb/otg/otgdev.c @@ -4,28 +4,33 @@ #include <driver.h> #include <usb/usb.h> -static int (*set_mode_callback)(void *ctx, enum usb_dr_mode mode); -static unsigned int otg_mode; +struct otg_mode { + struct device_d dev; + unsigned int var_mode; + unsigned int cur_mode; + int (*set_mode_callback)(void *ctx, enum usb_dr_mode mode); + void *ctx; +}; static int otg_set_mode(struct param_d *param, void *ctx) { - static int cur_mode = USB_DR_MODE_OTG; + struct otg_mode *otg = ctx; int ret; - if (otg_mode == USB_DR_MODE_UNKNOWN) + if (otg->var_mode == USB_DR_MODE_UNKNOWN) return -EINVAL; - if (otg_mode == cur_mode) + if (otg->var_mode == otg->cur_mode) return 0; - if (cur_mode != USB_DR_MODE_OTG) + if (otg->cur_mode != USB_DR_MODE_OTG) return -EBUSY; - ret = set_mode_callback(ctx, otg_mode); + ret = otg->set_mode_callback(otg->ctx, otg->var_mode); if (ret) return ret; - cur_mode = otg_mode; + otg->cur_mode = otg->var_mode; return 0; } @@ -47,20 +52,38 @@ int usb_register_otg_device(struct device_d *parent, { int ret; struct param_d *param_mode; - - if (otg_device.parent) - return -EBUSY; - - otg_device.parent = parent; - set_mode_callback = set_mode; - otg_mode = USB_DR_MODE_OTG; - - ret = register_device(&otg_device); + struct otg_mode *otg; + + otg = xzalloc(sizeof(*otg)); + otg->dev.priv = otg; + otg->dev.parent = parent; + otg->dev.id = DEVICE_ID_DYNAMIC; + dev_set_name(&otg->dev, "otg"); + + otg->var_mode = USB_DR_MODE_OTG; + otg->cur_mode = USB_DR_MODE_OTG; + otg->set_mode_callback = set_mode; + otg->ctx = ctx; + + /* register otg.mode as an alias of otg0.mode */ + if (otg_device.parent == NULL) { + otg_device.parent = parent; + ret = register_device(&otg_device); + if (ret) + return ret; + + param_mode = dev_add_param_enum(&otg_device, "mode", + otg_set_mode, NULL, &otg->var_mode, + otg_mode_names, ARRAY_SIZE(otg_mode_names), otg); + } + + ret = register_device(&otg->dev); if (ret) return ret; - param_mode = dev_add_param_enum(&otg_device, "mode", - otg_set_mode, NULL, &otg_mode, - otg_mode_names, ARRAY_SIZE(otg_mode_names), ctx); + param_mode = dev_add_param_enum(&otg->dev, "mode", + otg_set_mode, NULL, &otg->var_mode, + otg_mode_names, ARRAY_SIZE(otg_mode_names), otg); + return PTR_ERR_OR_ZERO(param_mode); } diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index e0ef4f5ef3..c264dd4b71 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -185,7 +185,7 @@ exit: } static int usb_stor_io_10(struct us_blk_dev *usb_blkdev, u8 opcode, - u32 start, u8 *data, u16 blocks) + sector_t start, u8 *data, u16 blocks) { u8 cmd[10]; @@ -206,7 +206,7 @@ static int usb_stor_io_10(struct us_blk_dev *usb_blkdev, u8 opcode, /* Read / write a chunk of sectors on media */ static int usb_stor_blk_io(struct block_device *disk_dev, - int sector_start, int sector_count, void *buffer, + sector_t sector_start, blkcnt_t sector_count, void *buffer, bool read) { struct us_blk_dev *pblk_dev = container_of(disk_dev, @@ -223,18 +223,18 @@ static int usb_stor_blk_io(struct block_device *disk_dev, } /* read / write the requested data */ - dev_dbg(dev, "%s %u block(s), starting from %d\n", + dev_dbg(dev, "%s %llu block(s), starting from %llu\n", read ? "Read" : "Write", sector_count, sector_start); while (sector_count > 0) { - unsigned n = min(sector_count, US_MAX_IO_BLK); + u16 n = min_t(blkcnt_t, sector_count, US_MAX_IO_BLK); if (usb_stor_io_10(pblk_dev, read ? SCSI_READ10 : SCSI_WRITE10, sector_start, buffer, n)) { - dev_dbg(dev, "I/O error at sector %d\n", sector_start); + dev_dbg(dev, "I/O error at sector %llu\n", sector_start); break; } sector_start += n; @@ -247,14 +247,14 @@ static int usb_stor_blk_io(struct block_device *disk_dev, /* Write a chunk of sectors to media */ static int __maybe_unused usb_stor_blk_write(struct block_device *blk, - const void *buffer, int block, int num_blocks) + const void *buffer, sector_t block, blkcnt_t num_blocks) { return usb_stor_blk_io(blk, block, num_blocks, (void *)buffer, false); } /* Read a chunk of sectors from media */ -static int usb_stor_blk_read(struct block_device *blk, void *buffer, int block, - int num_blocks) +static int usb_stor_blk_read(struct block_device *blk, void *buffer, sector_t block, + blkcnt_t num_blocks) { return usb_stor_blk_io(blk, block, num_blocks, buffer, true); } @@ -305,17 +305,18 @@ static int usb_stor_init_blkdev(struct us_blk_dev *pblk_dev) return result; } - if (last_lba > INT_MAX - 1) { - last_lba = INT_MAX - 1; + if (last_lba == U32_MAX) { + last_lba = U32_MAX - 1; dev_warn(dev, - "Limiting device size due to 31 bit contraints\n"); + "Limiting device size due to 32 bit constraints\n"); + /* To support LBA >= U32_MAX, a READ CAPACITY (16) should be issued here */ } pblk_dev->blk.num_blocks = last_lba + 1; if (block_length != SECTOR_SIZE) pr_warn("Support only %d bytes sectors\n", SECTOR_SIZE); pblk_dev->blk.blockbits = SECTOR_SHIFT; - dev_dbg(dev, "Capacity = 0x%x, blockshift = 0x%x\n", + dev_dbg(dev, "Capacity = 0x%llx, blockshift = 0x%x\n", pblk_dev->blk.num_blocks, pblk_dev->blk.blockbits); return 0; diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 9ec6ea4248..b6d468c63c 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -82,6 +82,7 @@ endif config DRIVER_VIDEO_SDL bool "SDL framebuffer driver" depends on SANDBOX + select SDL config DRIVER_VIDEO_PXA bool "PXA27x framebuffer driver" diff --git a/drivers/video/backlight-pwm.c b/drivers/video/backlight-pwm.c index cae016be8f..4410c7d047 100644 --- a/drivers/video/backlight-pwm.c +++ b/drivers/video/backlight-pwm.c @@ -24,7 +24,7 @@ #include <regulator.h> #include <gpio.h> #include <of_gpio.h> -#include <asm-generic/div64.h> +#include <linux/math64.h> struct pwm_backlight { struct backlight_device backlight; diff --git a/drivers/video/imx-ipu-fb.c b/drivers/video/imx-ipu-fb.c index 18171bdd81..a3f195373b 100644 --- a/drivers/video/imx-ipu-fb.c +++ b/drivers/video/imx-ipu-fb.c @@ -23,7 +23,7 @@ #include <mach/imxfb.h> #include <malloc.h> #include <errno.h> -#include <asm-generic/div64.h> +#include <linux/math64.h> #include <mmu.h> #include <mach/imx-ipu-fb.h> #include <linux/clk.h> diff --git a/drivers/video/imx-ipu-v3/imx-hdmi.c b/drivers/video/imx-ipu-v3/imx-hdmi.c index 1e55c97d24..589ef5e32d 100644 --- a/drivers/video/imx-ipu-v3/imx-hdmi.c +++ b/drivers/video/imx-ipu-v3/imx-hdmi.c @@ -19,7 +19,7 @@ #include <init.h> #include <linux/clk.h> #include <linux/err.h> -#include <asm-generic/div64.h> +#include <linux/math64.h> #include <linux/clk.h> #include <i2c/i2c.h> #include <video/media-bus-format.h> diff --git a/drivers/video/imx-ipu-v3/imx-ldb.c b/drivers/video/imx-ipu-v3/imx-ldb.c index d7793bdc0e..1316237161 100644 --- a/drivers/video/imx-ipu-v3/imx-ldb.c +++ b/drivers/video/imx-ipu-v3/imx-ldb.c @@ -31,7 +31,7 @@ #include <mfd/imx6q-iomuxc-gpr.h> #include <linux/clk.h> #include <linux/err.h> -#include <asm-generic/div64.h> +#include <linux/math64.h> #include <linux/clk.h> #include <mach/imx6-regs.h> #include <mach/imx53-regs.h> diff --git a/drivers/video/imx-ipu-v3/ipu-di.c b/drivers/video/imx-ipu-v3/ipu-di.c index b4302412e0..97613207c9 100644 --- a/drivers/video/imx-ipu-v3/ipu-di.c +++ b/drivers/video/imx-ipu-v3/ipu-di.c @@ -15,7 +15,7 @@ #include <common.h> #include <linux/err.h> #include <linux/clk.h> -#include <asm-generic/div64.h> +#include <linux/math64.h> #include <malloc.h> #include "imx-ipu-v3.h" diff --git a/drivers/video/imx-ipu-v3/ipufb.c b/drivers/video/imx-ipu-v3/ipufb.c index dd54d9df31..0b53916434 100644 --- a/drivers/video/imx-ipu-v3/ipufb.c +++ b/drivers/video/imx-ipu-v3/ipufb.c @@ -22,7 +22,7 @@ #include <of_graph.h> #include <linux/clk.h> #include <linux/err.h> -#include <asm-generic/div64.h> +#include <linux/math64.h> #include <video/media-bus-format.h> #include "imx-ipu-v3.h" diff --git a/drivers/video/imx.c b/drivers/video/imx.c index d15c2d88fb..e93859775a 100644 --- a/drivers/video/imx.c +++ b/drivers/video/imx.c @@ -25,7 +25,7 @@ #include <linux/clk.h> #include <linux/err.h> #include <linux/sizes.h> -#include <asm-generic/div64.h> +#include <linux/math64.h> #define LCDC_SSA 0x00 diff --git a/drivers/video/pxa.c b/drivers/video/pxa.c index d444e0981f..a2ff4bce2a 100644 --- a/drivers/video/pxa.c +++ b/drivers/video/pxa.c @@ -38,7 +38,7 @@ #include <mach/pxafb.h> #include <asm/io.h> -#include <asm-generic/div64.h> +#include <linux/math64.h> /* PXA LCD DMA descriptor */ struct pxafb_dma_descriptor { diff --git a/drivers/video/sdl.c b/drivers/video/sdl.c index 9811b2cf12..e9debc51b1 100644 --- a/drivers/video/sdl.c +++ b/drivers/video/sdl.c @@ -13,23 +13,25 @@ #include <errno.h> #include <gui/graphic_utils.h> +#define to_mask(color) GENMASK(color.length - 1, color.offset) + static void sdlfb_enable(struct fb_info *info) { - int ret; - - ret = sdl_open(info->xres, info->yres, info->bits_per_pixel, - info->screen_base); - if (ret) - return; - sdl_get_bitfield_rgba(&info->red, &info->green, &info->blue, &info->transp); - - sdl_start_timer(); + struct sdl_fb_info sdl_info = { + .screen_base = info->screen_base, + .xres = info->xres, .yres = info->yres, .bpp = info->bits_per_pixel, + .rmask = to_mask(info->red), + .gmask = to_mask(info->green), + .bmask = to_mask(info->blue), + .amask = to_mask(info->transp), + }; + + sdl_video_open(&sdl_info); } static void sdlfb_disable(struct fb_info *info) { - sdl_stop_timer(); - sdl_close(); + sdl_video_close(); } static struct fb_ops sdlfb_ops = { @@ -48,10 +50,19 @@ static int sdlfb_probe(struct device_d *dev) fb = xzalloc(sizeof(*fb)); fb->modes.modes = fb->mode = dev->platform_data; fb->modes.num_modes = 1; - fb->bits_per_pixel = 4 << 3; fb->xres = fb->mode->xres; fb->yres = fb->mode->yres; + fb->bits_per_pixel = 32; + fb->transp.length = 8; + fb->red.length = 8; + fb->green.length = 8; + fb->blue.length = 8; + fb->transp.offset = 24; + fb->red.offset = 16; + fb->green.offset = 8; + fb->blue.offset = 0; + fb->priv = fb; fb->fbops = &sdlfb_ops; @@ -68,7 +79,6 @@ static int sdlfb_probe(struct device_d *dev) kfree(fb->screen_base); kfree(fb); - sdl_close(); return ret; } @@ -78,7 +88,6 @@ static void sdlfb_remove(struct device_d *dev) kfree(fb->screen_base); kfree(fb); - sdl_close(); } static struct driver_d sdlfb_driver = { diff --git a/drivers/video/tc358767.c b/drivers/video/tc358767.c index e64dde1ddf..2a0fa8b368 100644 --- a/drivers/video/tc358767.c +++ b/drivers/video/tc358767.c @@ -31,7 +31,7 @@ #include <of_gpio.h> #include <video/media-bus-format.h> #include <video/vpl.h> -#include <asm-generic/div64.h> +#include <linux/math64.h> #define DP_LINK_BW_SET 0x100 #define DP_ENHANCED_FRAME_EN (1 << 7) @@ -1191,8 +1191,7 @@ static int tc_read_edid(struct tc_data *tc) #ifdef DEBUG printk(KERN_DEBUG "eDP display EDID:\n"); - print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 16, 1, tc->edid, - EDID_LENGTH, true); + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, tc->edid, EDID_LENGTH); #endif return 0; diff --git a/drivers/watchdog/stpmic1_wdt.c b/drivers/watchdog/stpmic1_wdt.c index 12280f1447..105ba39fb7 100644 --- a/drivers/watchdog/stpmic1_wdt.c +++ b/drivers/watchdog/stpmic1_wdt.c @@ -174,10 +174,6 @@ static int stpmic1_wdt_probe(struct device_d *dev) wdd->set_timeout = stpmic1_wdt_set_timeout; wdd->timeout_max = PMIC_WDT_MAX_TIMEOUT; - /* have the watchdog reset, not power-off the system */ - regmap_write_bits(wdt->regmap, SWOFF_PWRCTRL_CR, - RESTART_REQUEST_ENABLED, RESTART_REQUEST_ENABLED); - ret = watchdog_register(wdd); if (ret) { dev_err(dev, "Failed to register watchdog device\n"); diff --git a/drivers/watchdog/wd_core.c b/drivers/watchdog/wd_core.c index 643c53268f..4b0ee31d5b 100644 --- a/drivers/watchdog/wd_core.c +++ b/drivers/watchdog/wd_core.c @@ -54,6 +54,9 @@ int watchdog_set_timeout(struct watchdog *wd, unsigned timeout) if (ret) return ret; + wd->last_ping = get_time_ns(); + wd->timeout_cur = timeout; + wd->running = timeout ? WDOG_HW_RUNNING : WDOG_HW_NOT_RUNNING; return 0; @@ -155,6 +158,25 @@ static unsigned int dev_get_watchdog_priority(struct device_d *dev) return priority; } +static int seconds_to_expire_get(struct param_d *p, void *priv) +{ + struct watchdog *wd = priv; + uint64_t diff; + + if (!wd->timeout_cur) { + wd->seconds_to_expire = -1; + return 0; + } + + diff = get_time_ns() - wd->last_ping; + + do_div(diff, 1000000000); + + wd->seconds_to_expire = wd->timeout_cur - diff; + + return 0; +} + int watchdog_register(struct watchdog *wd) { struct param_d *p; @@ -218,6 +240,13 @@ int watchdog_register(struct watchdog *wd) goto error_unregister; } + p = dev_add_param_uint32(&wd->dev, "seconds_to_expire", param_set_readonly, + seconds_to_expire_get, &wd->seconds_to_expire, "%d", wd); + if (IS_ERR(p)) { + ret = PTR_ERR(p); + goto error_unregister; + } + list_add_tail(&wd->list, &watchdog_list); pr_debug("registering watchdog %s with priority %d\n", watchdog_name(wd), |