diff --git a/Documentation/boards/sandbox.rst b/Documentation/boards/sandbox.rst index 8b00093..8b24b6a 100644 --- a/Documentation/boards/sandbox.rst +++ b/Documentation/boards/sandbox.rst @@ -17,7 +17,7 @@ Running the sandbox ------------------- -Once you compile barebox for the sandbox, you can run it with:: +Once you compile barebox for the sandbox, you can run it with: .. code-block:: console diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile index 3b9f60a..ba46c1a 100644 --- a/arch/arm/mach-at91/Makefile +++ b/arch/arm/mach-at91/Makefile @@ -1,4 +1,4 @@ -obj-y += setup.o aic.o +obj-y += setup.o aic.o bootm-barebox.o lwl-y += at91_pmc_ll.o ddramc_ll.o matrix.o lwl-$(CONFIG_CLOCKSOURCE_ATMEL_PIT) += early_udelay.o diff --git a/arch/arm/mach-at91/bootm-barebox.c b/arch/arm/mach-at91/bootm-barebox.c new file mode 100644 index 0000000..1dccdb8 --- /dev/null +++ b/arch/arm/mach-at91/bootm-barebox.c @@ -0,0 +1,46 @@ +#define pr_fmt(fmt) "at91-bootm-barebox: " fmt + +#include +#include +#include +#include +#include +#include + +static int do_bootm_at91_barebox_image(struct image_data *data) +{ + resource_size_t start, end; + int ret; + + ret = memory_bank_first_find_space(&start, &end); + if (ret) + return ret; + + ret = bootm_load_os(data, start); + if (ret) + return ret; + + if (data->verbose) + printf("Loaded barebox image to 0x%08zx\n", start); + + shutdown_barebox(); + + sama5_boot_xload((void *)start, at91_bootsource); + + return -EIO; +} + +static struct image_handler image_handler_at91_barebox_image = { + .name = "AT91 barebox image", + .bootm = do_bootm_at91_barebox_image, + .filetype = filetype_arm_barebox, +}; + +static int at91_register_barebox_image_handler(void) +{ + if (!of_machine_is_compatible("atmel,sama5d2")) + return 0; + + return register_image_handler(&image_handler_at91_barebox_image); +} +late_initcall(at91_register_barebox_image_handler); diff --git a/arch/arm/mach-at91/include/mach/cpu.h b/arch/arm/mach-at91/include/mach/cpu.h index 6e0f25f..fa25a47 100644 --- a/arch/arm/mach-at91/include/mach/cpu.h +++ b/arch/arm/mach-at91/include/mach/cpu.h @@ -167,6 +167,7 @@ extern struct at91_socinfo at91_soc_initdata; const char *at91_get_soc_type(struct at91_socinfo *c); const char *at91_get_soc_subtype(struct at91_socinfo *c); +extern unsigned long at91_bootsource; static inline int at91_soc_is_detected(void) { diff --git a/arch/arm/mach-at91/include/mach/sama5_bootsource.h b/arch/arm/mach-at91/include/mach/sama5_bootsource.h index 0f90afe..8355c2e 100644 --- a/arch/arm/mach-at91/include/mach/sama5_bootsource.h +++ b/arch/arm/mach-at91/include/mach/sama5_bootsource.h @@ -46,4 +46,11 @@ #define __sama5d2_stashed_bootrom_r4 \ (*(volatile u32 *)(SAMA5D2_SRAM_BASE + SAMA5D2_SRAM_SIZE - 0x4)) +static inline void __noreturn sama5_boot_xload(void __noreturn (*bb)(void), u32 r4) +{ + asm volatile("mov r4, %0" : : "r"(r4) : ); + asm volatile("bx %0" : : "r"(bb) : ); + __builtin_unreachable(); +} + #endif diff --git a/arch/arm/mach-at91/include/mach/xload.h b/arch/arm/mach-at91/include/mach/xload.h index f110236..338577c 100644 --- a/arch/arm/mach-at91/include/mach/xload.h +++ b/arch/arm/mach-at91/include/mach/xload.h @@ -9,4 +9,3 @@ int at91_sdhci_bio_init(struct pbl_bio *bio, void __iomem *base); #endif /* __MACH_XLOAD_H */ - diff --git a/arch/arm/mach-at91/sama5d2.c b/arch/arm/mach-at91/sama5d2.c index 2ce6d7f..a4aa8a2 100644 --- a/arch/arm/mach-at91/sama5d2.c +++ b/arch/arm/mach-at91/sama5d2.c @@ -8,6 +8,7 @@ #include #include #include +#include #define SFR_CAN 0x48 #define SFR_L2CC_HRAMC 0x58 @@ -56,15 +57,13 @@ static int sama5d2_bootsource_init(void) { - u32 r4; - if (!of_machine_is_compatible("atmel,sama5d2")) return 0; - r4 = __sama5d2_stashed_bootrom_r4; + at91_bootsource = __sama5d2_stashed_bootrom_r4; - bootsource_set(sama5_bootsource(r4)); - bootsource_set_instance(sama5_bootsource_instance(r4)); + bootsource_set(sama5_bootsource(at91_bootsource)); + bootsource_set_instance(sama5_bootsource_instance(at91_bootsource)); return 0; } diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c index b7a66aa..47247dc 100644 --- a/arch/arm/mach-at91/setup.c +++ b/arch/arm/mach-at91/setup.c @@ -403,3 +403,6 @@ /* Restore NRST value */ writel(AT91_RSTC_KEY | (rstc) | AT91_RSTC_URSTEN, rstc_base + AT91_RSTC_MR); } + +unsigned long at91_bootsource; +EXPORT_SYMBOL(at91_bootsource); diff --git a/arch/arm/mach-at91/xload-mmc.c b/arch/arm/mach-at91/xload-mmc.c index 42341fa..e9edecc 100644 --- a/arch/arm/mach-at91/xload-mmc.c +++ b/arch/arm/mach-at91/xload-mmc.c @@ -8,12 +8,6 @@ #include #include -static void __naked __noreturn xload_bb(void __noreturn (*bb)(void), u32 r4) -{ - asm volatile("mov r4, %0" : : "r"(r4) : ); - asm volatile("bx %0" : : "r"(bb) : ); -} - static void at91_fat_start_image(struct pbl_bio *bio, void *buf, unsigned int len, u32 r4) @@ -31,7 +25,7 @@ sync_caches_for_execution(); - xload_bb(bb, r4); + sama5_boot_xload(bb, r4); } static const struct sdhci_instance { diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c index e4c4f39..2e0dad9 100644 --- a/drivers/gpio/gpio-generic.c +++ b/drivers/gpio/gpio-generic.c @@ -62,7 +62,7 @@ { struct bgpio_chip *bgc = to_bgpio_chip(gc); - return bgc->read_reg(bgc->reg_dat) & bgc->pin2mask(bgc, gpio); + return !!(bgc->read_reg(bgc->reg_dat) & bgc->pin2mask(bgc, gpio)); } static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index 76bb51b..70e87c1 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -48,6 +48,8 @@ #define AT91_TWI_IADR 0x000c /* Internal Address Register */ #define AT91_TWI_CWGR 0x0010 /* Clock Waveform Generator Reg */ +#define AT91_TWI_CWGR_HOLD_MAX 0x1f +#define AT91_TWI_CWGR_HOLD(x) (((x) & AT91_TWI_CWGR_HOLD_MAX) << 24) #define AT91_TWI_SR 0x0020 /* Status Register */ #define AT91_TWI_TXCOMP 0x0001 /* Transmission Complete */ @@ -64,14 +66,27 @@ #define AT91_TWI_RHR 0x0030 /* Receive Holding Register */ #define AT91_TWI_THR 0x0034 /* Transmit Holding Register */ +#define AT91_TWI_FILTR 0x0044 +#define AT91_TWI_FILTR_FILT BIT(0) +#define AT91_TWI_FILTR_PADFEN BIT(1) +#define AT91_TWI_FILTR_THRES(v) ((v) << 8) +#define AT91_TWI_FILTR_THRES_MAX 7 +#define AT91_TWI_FILTR_THRES_MASK GENMASK(10, 8) + struct at91_twi_pdata { unsigned clk_max_div; unsigned clk_offset; bool has_unre_flag; + bool has_alt_cmd; + bool has_hold_field; + bool has_dig_filtr; + bool has_adv_dig_filtr; + bool has_ana_filtr; + bool has_clear_cmd; }; struct at91_twi_dev { - struct device *dev; + struct device_d *dev; void __iomem *base; struct clk *clk; u8 *buf; @@ -82,6 +97,10 @@ struct i2c_adapter adapter; unsigned twi_cwgr_reg; struct at91_twi_pdata *pdata; + u32 filter_width; + + bool enable_dig_filt; + bool enable_ana_filt; }; #define to_at91_twi_dev(a) container_of(a, struct at91_twi_dev, adapter) @@ -104,11 +123,31 @@ static void at91_init_twi_bus(struct at91_twi_dev *dev) { + struct at91_twi_pdata *pdata = dev->pdata; + u32 filtr = 0; + at91_disable_twi_interrupts(dev); at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SWRST); at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_MSEN); at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SVDIS); at91_twi_write(dev, AT91_TWI_CWGR, dev->twi_cwgr_reg); + + /* enable digital filter */ + if (pdata->has_dig_filtr && dev->enable_dig_filt) + filtr |= AT91_TWI_FILTR_FILT; + + /* enable advanced digital filter */ + if (pdata->has_adv_dig_filtr && dev->enable_dig_filt) + filtr |= AT91_TWI_FILTR_FILT | + (AT91_TWI_FILTR_THRES(dev->filter_width) & + AT91_TWI_FILTR_THRES_MASK); + + /* enable analog filter */ + if (pdata->has_ana_filtr && dev->enable_ana_filt) + filtr |= AT91_TWI_FILTR_PADFEN; + + if (filtr) + at91_twi_write(dev, AT91_TWI_FILTR, filtr); } /* @@ -117,10 +156,13 @@ */ static void at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk) { - int ckdiv, cdiv, div; + int ckdiv, cdiv, div, hold = 0, filter_width = 0; struct at91_twi_pdata *pdata = dev->pdata; int offset = pdata->clk_offset; int max_ckdiv = pdata->clk_max_div; + struct i2c_timings timings, *t = &timings; + + i2c_parse_fw_timings(dev->dev, t, true); div = max(0, (int)DIV_ROUND_UP(clk_get_rate(dev->clk), 2 * twi_clk) - offset); @@ -128,14 +170,54 @@ cdiv = div >> ckdiv; if (ckdiv > max_ckdiv) { - dev_warn(&dev->adapter.dev, "%d exceeds ckdiv max value which is %d.\n", + dev_warn(dev->dev, "%d exceeds ckdiv max value which is %d.\n", ckdiv, max_ckdiv); ckdiv = max_ckdiv; cdiv = 255; } - dev->twi_cwgr_reg = (ckdiv << 16) | (cdiv << 8) | cdiv; - dev_dbg(&dev->adapter.dev, "cdiv %d ckdiv %d\n", cdiv, ckdiv); + if (pdata->has_hold_field) { + /* + * hold time = HOLD + 3 x T_peripheral_clock + * Use clk rate in kHz to prevent overflows when computing + * hold. + */ + hold = DIV_ROUND_UP(t->sda_hold_ns + * (clk_get_rate(dev->clk) / 1000), 1000000); + hold -= 3; + if (hold < 0) + hold = 0; + if (hold > AT91_TWI_CWGR_HOLD_MAX) { + dev_warn(dev->dev, + "HOLD field set to its maximum value (%d instead of %d)\n", + AT91_TWI_CWGR_HOLD_MAX, hold); + hold = AT91_TWI_CWGR_HOLD_MAX; + } + } + + if (pdata->has_adv_dig_filtr) { + /* + * filter width = 0 to AT91_TWI_FILTR_THRES_MAX + * peripheral clocks + */ + filter_width = DIV_ROUND_UP(t->digital_filter_width_ns + * (clk_get_rate(dev->clk) / 1000), 1000000); + if (filter_width > AT91_TWI_FILTR_THRES_MAX) { + dev_warn(dev->dev, + "Filter threshold set to its maximum value (%d instead of %d)\n", + AT91_TWI_FILTR_THRES_MAX, filter_width); + filter_width = AT91_TWI_FILTR_THRES_MAX; + } + } + + dev->twi_cwgr_reg = (ckdiv << 16) | (cdiv << 8) | cdiv + | AT91_TWI_CWGR_HOLD(hold); + + dev->filter_width = filter_width; + + dev_dbg(dev->dev, "cdiv %d ckdiv %d hold %d (%d ns), filter_width %d (%d ns)\n", + cdiv, ckdiv, hold, t->sda_hold_ns, filter_width, + t->digital_filter_width_ns); } static void at91_twi_write_next_byte(struct at91_twi_dev *dev) @@ -149,7 +231,7 @@ if (--dev->buf_len == 0) at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP); - dev_dbg(&dev->adapter.dev, "wrote 0x%x, to go %d\n", *dev->buf, dev->buf_len); + dev_dbg(dev->dev, "wrote 0x%x, to go %d\n", *dev->buf, dev->buf_len); ++dev->buf; } @@ -166,7 +248,7 @@ if (dev->buf_len == 1) at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP); - dev_dbg(&dev->adapter.dev, "read 0x%x, to go %d\n", *dev->buf, dev->buf_len); + dev_dbg(dev->dev, "read 0x%x, to go %d\n", *dev->buf, dev->buf_len); ++dev->buf; } @@ -183,7 +265,7 @@ if (!(status & irqstatus)) { if (is_timeout(start, AT91_I2C_TIMEOUT)) { - dev_warn(&dev->adapter.dev, "timeout waiting for bus ready\n"); + dev_warn(dev->dev, "timeout waiting for bus ready\n"); return -ETIMEDOUT; } else { continue; @@ -195,7 +277,7 @@ else if (irqstatus & AT91_TWI_TXRDY) at91_twi_write_next_byte(dev); else - dev_warn(&dev->adapter.dev, "neither rx and tx are ready\n"); + dev_warn(dev->dev, "neither rx and tx are ready\n"); dev->transfer_status |= status; @@ -211,7 +293,7 @@ int ret; bool has_unre_flag = dev->pdata->has_unre_flag; - dev_dbg(&dev->adapter.dev, "transfer: %s %d bytes.\n", + dev_dbg(dev->dev, "transfer: %s %d bytes.\n", (dev->msg->flags & I2C_M_RD) ? "read" : "write", dev->buf_len); dev->transfer_status = 0; @@ -223,7 +305,7 @@ unsigned start_flags = AT91_TWI_START; if (at91_twi_read(dev, AT91_TWI_SR) & AT91_TWI_RXRDY) { - dev_err(&dev->adapter.dev, "RXRDY still set!"); + dev_err(dev->dev, "RXRDY still set!"); at91_twi_read(dev, AT91_TWI_RHR); } @@ -243,27 +325,27 @@ ret = at91_twi_wait_completion(dev); if (ret < 0) { - dev_err(&dev->adapter.dev, "controller timed out\n"); + dev_err(dev->dev, "controller timed out\n"); at91_init_twi_bus(dev); ret = -ETIMEDOUT; goto error; } if (dev->transfer_status & AT91_TWI_NACK) { - dev_dbg(&dev->adapter.dev, "received nack\n"); + dev_dbg(dev->dev, "received nack\n"); ret = -EREMOTEIO; goto error; } if (dev->transfer_status & AT91_TWI_OVRE) { - dev_err(&dev->adapter.dev, "overrun while reading\n"); + dev_err(dev->dev, "overrun while reading\n"); ret = -EIO; goto error; } if (has_unre_flag && dev->transfer_status & AT91_TWI_UNRE) { - dev_err(&dev->adapter.dev, "underrun while writing\n"); + dev_err(dev->dev, "underrun while writing\n"); ret = -EIO; goto error; } - dev_dbg(&dev->adapter.dev, "transfer complete\n"); + dev_dbg(dev->dev, "transfer complete\n"); return 0; @@ -285,7 +367,7 @@ * repeated start via it's internal address feature. */ if (num > 2) { - dev_err(&dev->adapter.dev, + dev_err(dev->dev, "cannot handle more than two concatenated messages.\n"); return 0; } else if (num == 2) { @@ -293,11 +375,11 @@ int i; if (msg->flags & I2C_M_RD) { - dev_err(&dev->adapter.dev, "first transfer must be write.\n"); + dev_err(dev->dev, "first transfer must be write.\n"); return -EINVAL; } if (msg->len > 3) { - dev_err(&dev->adapter.dev, "first message size must be <= 3.\n"); + dev_err(dev->dev, "first message size must be <= 3.\n"); return -EINVAL; } @@ -360,6 +442,17 @@ .has_unre_flag = false, }; +static struct at91_twi_pdata sama5d2_config = { + .clk_max_div = 7, + .clk_offset = 3, + .has_unre_flag = true, + .has_alt_cmd = true, + .has_hold_field = true, + .has_dig_filtr = true, + .has_adv_dig_filtr = true, + .has_ana_filtr = true, +}; + static struct platform_device_id at91_twi_devtypes[] = { { .name = "at91rm9200-i2c", @@ -404,6 +497,9 @@ .compatible = "atmel,at91sam9x5-i2c", .data = &at91sam9x5_config, }, { + .compatible = "atmel,sama5d2-i2c", + .data = &sama5d2_config, + }, { /* sentinel */ } }; @@ -417,6 +513,7 @@ u32 bus_clk_rate; i2c_at91 = xzalloc(sizeof(struct at91_twi_dev)); + i2c_at91->dev = dev; rc = dev_get_drvdata(dev, (const void **)&i2c_data); if (rc < 0) { diff --git a/drivers/i2c/busses/i2c-stm32.c b/drivers/i2c/busses/i2c-stm32.c index 9f34760..971f2e6 100644 --- a/drivers/i2c/busses/i2c-stm32.c +++ b/drivers/i2c/busses/i2c-stm32.c @@ -847,6 +847,7 @@ static __maybe_unused struct of_device_id stm32_i2c_dt_ids[] = { { .compatible = "st,stm32f7-i2c", .data = &stm32f7_setup, }, + { .compatible = "st,stm32mp15-i2c", .data = &stm32f7_setup}, { /* sentinel */ } }; diff --git a/drivers/i2c/i2c.c b/drivers/i2c/i2c.c index 2fed624..57d8c70 100644 --- a/drivers/i2c/i2c.c +++ b/drivers/i2c/i2c.c @@ -569,6 +569,18 @@ return to_i2c_client(dev); } +static void i2c_parse_timing(struct device_d *dev, char *prop_name, u32 *cur_val_p, + u32 def_val, bool use_def) +{ + int ret; + + ret = of_property_read_u32(dev->device_node, prop_name, cur_val_p); + if (ret && use_def) + *cur_val_p = def_val; + + dev_dbg(dev, "%s: %u\n", prop_name, *cur_val_p); +} + /** * i2c_parse_fw_timings - get I2C related timing parameters from firmware * @dev: The device to scan for I2C timing properties @@ -587,45 +599,28 @@ void i2c_parse_fw_timings(struct device_d *dev, struct i2c_timings *t, bool use_defaults) { - int ret; + bool u = use_defaults; + u32 d; - memset(t, 0, sizeof(*t)); + i2c_parse_timing(dev, "clock-frequency", &t->bus_freq_hz, + I2C_MAX_STANDARD_MODE_FREQ, u); - ret = of_property_read_u32(dev->device_node, "clock-frequency", - &t->bus_freq_hz); - if (ret && use_defaults) - t->bus_freq_hz = 100000; + d = t->bus_freq_hz <= I2C_MAX_STANDARD_MODE_FREQ ? 1000 : + t->bus_freq_hz <= I2C_MAX_FAST_MODE_FREQ ? 300 : 120; + i2c_parse_timing(dev, "i2c-scl-rising-time-ns", &t->scl_rise_ns, d, u); - ret = of_property_read_u32(dev->device_node, "i2c-scl-rising-time-ns", - &t->scl_rise_ns); - if (ret && use_defaults) { - if (t->bus_freq_hz <= 100000) - t->scl_rise_ns = 1000; - else if (t->bus_freq_hz <= 400000) - t->scl_rise_ns = 300; - else - t->scl_rise_ns = 120; - } + d = t->bus_freq_hz <= I2C_MAX_FAST_MODE_FREQ ? 300 : 120; + i2c_parse_timing(dev, "i2c-scl-falling-time-ns", &t->scl_fall_ns, d, u); - ret = of_property_read_u32(dev->device_node, "i2c-scl-falling-time-ns", - &t->scl_fall_ns); - if (ret && use_defaults) { - if (t->bus_freq_hz <= 400000) - t->scl_fall_ns = 300; - else - t->scl_fall_ns = 120; - } - - of_property_read_u32(dev->device_node, "i2c-scl-internal-delay-ns", - &t->scl_int_delay_ns); - - ret = of_property_read_u32(dev->device_node, "i2c-sda-falling-time-ns", - &t->sda_fall_ns); - if (ret && use_defaults) - t->sda_fall_ns = t->scl_fall_ns; - - of_property_read_u32(dev->device_node, "i2c-sda-hold-time-ns", - &t->sda_hold_ns); + i2c_parse_timing(dev, "i2c-scl-internal-delay-ns", + &t->scl_int_delay_ns, 0, u); + i2c_parse_timing(dev, "i2c-sda-falling-time-ns", &t->sda_fall_ns, + t->scl_fall_ns, u); + i2c_parse_timing(dev, "i2c-sda-hold-time-ns", &t->sda_hold_ns, 0, u); + i2c_parse_timing(dev, "i2c-digital-filter-width-ns", + &t->digital_filter_width_ns, 0, u); + i2c_parse_timing(dev, "i2c-analog-filter-cutoff-frequency", + &t->analog_filter_cutoff_freq_hz, 0, u); } EXPORT_SYMBOL_GPL(i2c_parse_fw_timings); diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index d03d481..d7a8949 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -91,4 +91,14 @@ Select this to get regmap support for the timer blocks on STM32 MCUs and MPUs. +config MFD_ATMEL_FLEXCOM + tristate "Atmel Flexcom (Flexible Serial Communication Unit)" + depends on OFDEVICE + help + Select this to get support for Atmel Flexcom. This is a wrapper + which embeds a SPI controller, a I2C controller and a USART. Only + one function can be used at a time. The choice is done at boot time + by the probe function of this MFD driver according to a device tree + property. + endmenu diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index a3b296a..690e536 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_FINTEK_SUPERIO) += fintek-superio.o obj-$(CONFIG_SMSC_SUPERIO) += smsc-superio.o obj-$(CONFIG_MFD_STM32_TIMERS) += stm32-timers.o +obj-$(CONFIG_MFD_ATMEL_FLEXCOM) += atmel-flexcom.o diff --git a/drivers/mfd/atmel-flexcom.c b/drivers/mfd/atmel-flexcom.c new file mode 100644 index 0000000..996d485 --- /dev/null +++ b/drivers/mfd/atmel-flexcom.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: (C) 2015 Atmel Corporation +/* + * Driver for Atmel Flexcom + * Author: Cyrille Pitchen + */ + +#include +#include +#include +#include + +/* I/O register offsets */ +#define FLEX_MR 0x0 /* Mode Register */ +#define FLEX_VERSION 0xfc /* Version Register */ + +/* Mode Register bit fields */ +#define FLEX_MR_OPMODE_OFFSET (0) /* Operating Mode */ +#define FLEX_MR_OPMODE_MASK (0x3 << FLEX_MR_OPMODE_OFFSET) +#define FLEX_MR_OPMODE(opmode) (((opmode) << FLEX_MR_OPMODE_OFFSET) & \ + FLEX_MR_OPMODE_MASK) + +static int atmel_flexcom_probe(struct device_d *dev) +{ + struct resource *res; + struct clk *clk; + u32 opmode; + int err; + + err = of_property_read_u32(dev->device_node, + "atmel,flexcom-mode", &opmode); + if (err) + return err; + + if (opmode < ATMEL_FLEXCOM_MODE_USART || opmode > ATMEL_FLEXCOM_MODE_TWI) + return -EINVAL; + + res = dev_request_mem_resource(dev, 0); + if (IS_ERR(res)) + return PTR_ERR(res); + + clk = clk_get(dev, NULL); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + err = clk_enable(clk); + if (err) + return err; + + /* + * Set the Operating Mode in the Mode Register: only the selected device + * is clocked. Hence, registers of the other serial devices remain + * inaccessible and are read as zero. Also the external I/O lines of the + * Flexcom are muxed to reach the selected device. + */ + writel(FLEX_MR_OPMODE(opmode), IOMEM(res->start) + FLEX_MR); + + clk_disable(clk); + + return of_platform_populate(dev->device_node, NULL, dev); +} + +static const struct of_device_id atmel_flexcom_of_match[] = { + { .compatible = "atmel,sama5d2-flexcom" }, + { /* sentinel */ } +}; + +static struct driver_d atmel_flexcom_driver = { + .probe = atmel_flexcom_probe, + .name = "atmel_flexcom", + .of_compatible = atmel_flexcom_of_match, +}; +coredevice_platform_driver(atmel_flexcom_driver); diff --git a/include/i2c/i2c.h b/include/i2c/i2c.h index bfc1eab..af62876 100644 --- a/include/i2c/i2c.h +++ b/include/i2c/i2c.h @@ -31,6 +31,14 @@ int bitrate; }; +/* I2C Frequency Modes */ +#define I2C_MAX_STANDARD_MODE_FREQ 100000 +#define I2C_MAX_FAST_MODE_FREQ 400000 +#define I2C_MAX_FAST_MODE_PLUS_FREQ 1000000 +#define I2C_MAX_TURBO_MODE_FREQ 1400000 +#define I2C_MAX_HIGH_SPEED_MODE_FREQ 3400000 +#define I2C_MAX_ULTRA_FAST_MODE_FREQ 5000000 + #define I2C_NAME_SIZE 20 #define I2C_M_RD 0x0001 /* read data, from slave to master */ @@ -246,6 +254,10 @@ * @scl_int_delay_ns: time IP core additionally needs to setup SCL in ns * @sda_fall_ns: time SDA signal takes to fall in ns; t(f) in the I2C specification * @sda_hold_ns: time IP core additionally needs to hold SDA in ns + * @digital_filter_width_ns: width in ns of spikes on i2c lines that the IP core + * digital filter can filter out + * @analog_filter_cutoff_freq_hz: threshold frequency for the low pass IP core + * analog filter */ struct i2c_timings { u32 bus_freq_hz; @@ -254,6 +266,8 @@ u32 scl_int_delay_ns; u32 sda_fall_ns; u32 sda_hold_ns; + u32 digital_filter_width_ns; + u32 analog_filter_cutoff_freq_hz; }; /** diff --git a/scripts/rsatoc.c b/scripts/rsatoc.c index 6473802..8f2eb8f 100644 --- a/scripts/rsatoc.c +++ b/scripts/rsatoc.c @@ -471,10 +471,12 @@ path++; if (!strncmp(path, "__ENV__", 7)) { - path = getenv(path + 7); + const char *orig_path = path; + + path = getenv(orig_path + 7); if (!path) { fprintf(stderr, "%s doesn't contain a path\n", - path + 7); + orig_path + 7); exit(1); } }