From e305bff3a706f58eb65e91cc8fde9bb67ba9688f Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 25 Jul 2019 18:02:09 -0400 Subject: video/fbdev: Drop JZ4740 driver The JZ4740 fbdev driver has been replaced with the ingenic-drm driver. Signed-off-by: Paul Cercueil Tested-by: Artur Rojek Acked-by: Sam Ravnborg Signed-off-by: Paul Burton --- drivers/video/fbdev/Kconfig | 9 - drivers/video/fbdev/Makefile | 1 - drivers/video/fbdev/jz4740_fb.c | 690 ---------------------------------------- 3 files changed, 700 deletions(-) delete mode 100644 drivers/video/fbdev/jz4740_fb.c (limited to 'drivers') diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index 6b2de93bd302..6fce711f42c5 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -2211,15 +2211,6 @@ config FB_BROADSHEET and could also have been called by other names when coupled with a bridge adapter. -config FB_JZ4740 - tristate "JZ4740 LCD framebuffer support" - depends on FB && MACH_JZ4740 - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - help - Framebuffer support for the JZ4740 SoC. - config FB_PUV3_UNIGFX tristate "PKUnity v3 Unigfx framebuffer support" depends on FB && UNICORE32 && ARCH_PUV3 diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile index 7dc4861a93e6..49502d6256cb 100644 --- a/drivers/video/fbdev/Makefile +++ b/drivers/video/fbdev/Makefile @@ -117,7 +117,6 @@ obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o obj-$(CONFIG_FB_CARMINE) += carminefb.o obj-$(CONFIG_FB_MB862XX) += mb862xx/ obj-$(CONFIG_FB_NUC900) += nuc900fb.o -obj-$(CONFIG_FB_JZ4740) += jz4740_fb.o obj-$(CONFIG_FB_PUV3_UNIGFX) += fb-puv3.o obj-$(CONFIG_FB_HYPERV) += hyperv_fb.o obj-$(CONFIG_FB_OPENCORES) += ocfb.o diff --git a/drivers/video/fbdev/jz4740_fb.c b/drivers/video/fbdev/jz4740_fb.c deleted file mode 100644 index 0b6fa25f6924..000000000000 --- a/drivers/video/fbdev/jz4740_fb.c +++ /dev/null @@ -1,690 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2009-2010, Lars-Peter Clausen - * JZ4740 SoC LCD framebuffer driver - */ - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include - -#include - -#define JZ_REG_LCD_CFG 0x00 -#define JZ_REG_LCD_VSYNC 0x04 -#define JZ_REG_LCD_HSYNC 0x08 -#define JZ_REG_LCD_VAT 0x0C -#define JZ_REG_LCD_DAH 0x10 -#define JZ_REG_LCD_DAV 0x14 -#define JZ_REG_LCD_PS 0x18 -#define JZ_REG_LCD_CLS 0x1C -#define JZ_REG_LCD_SPL 0x20 -#define JZ_REG_LCD_REV 0x24 -#define JZ_REG_LCD_CTRL 0x30 -#define JZ_REG_LCD_STATE 0x34 -#define JZ_REG_LCD_IID 0x38 -#define JZ_REG_LCD_DA0 0x40 -#define JZ_REG_LCD_SA0 0x44 -#define JZ_REG_LCD_FID0 0x48 -#define JZ_REG_LCD_CMD0 0x4C -#define JZ_REG_LCD_DA1 0x50 -#define JZ_REG_LCD_SA1 0x54 -#define JZ_REG_LCD_FID1 0x58 -#define JZ_REG_LCD_CMD1 0x5C - -#define JZ_LCD_CFG_SLCD BIT(31) -#define JZ_LCD_CFG_PS_DISABLE BIT(23) -#define JZ_LCD_CFG_CLS_DISABLE BIT(22) -#define JZ_LCD_CFG_SPL_DISABLE BIT(21) -#define JZ_LCD_CFG_REV_DISABLE BIT(20) -#define JZ_LCD_CFG_HSYNCM BIT(19) -#define JZ_LCD_CFG_PCLKM BIT(18) -#define JZ_LCD_CFG_INV BIT(17) -#define JZ_LCD_CFG_SYNC_DIR BIT(16) -#define JZ_LCD_CFG_PS_POLARITY BIT(15) -#define JZ_LCD_CFG_CLS_POLARITY BIT(14) -#define JZ_LCD_CFG_SPL_POLARITY BIT(13) -#define JZ_LCD_CFG_REV_POLARITY BIT(12) -#define JZ_LCD_CFG_HSYNC_ACTIVE_LOW BIT(11) -#define JZ_LCD_CFG_PCLK_FALLING_EDGE BIT(10) -#define JZ_LCD_CFG_DE_ACTIVE_LOW BIT(9) -#define JZ_LCD_CFG_VSYNC_ACTIVE_LOW BIT(8) -#define JZ_LCD_CFG_18_BIT BIT(7) -#define JZ_LCD_CFG_PDW (BIT(5) | BIT(4)) -#define JZ_LCD_CFG_MODE_MASK 0xf - -#define JZ_LCD_CTRL_BURST_4 (0x0 << 28) -#define JZ_LCD_CTRL_BURST_8 (0x1 << 28) -#define JZ_LCD_CTRL_BURST_16 (0x2 << 28) -#define JZ_LCD_CTRL_RGB555 BIT(27) -#define JZ_LCD_CTRL_OFUP BIT(26) -#define JZ_LCD_CTRL_FRC_GRAYSCALE_16 (0x0 << 24) -#define JZ_LCD_CTRL_FRC_GRAYSCALE_4 (0x1 << 24) -#define JZ_LCD_CTRL_FRC_GRAYSCALE_2 (0x2 << 24) -#define JZ_LCD_CTRL_PDD_MASK (0xff << 16) -#define JZ_LCD_CTRL_EOF_IRQ BIT(13) -#define JZ_LCD_CTRL_SOF_IRQ BIT(12) -#define JZ_LCD_CTRL_OFU_IRQ BIT(11) -#define JZ_LCD_CTRL_IFU0_IRQ BIT(10) -#define JZ_LCD_CTRL_IFU1_IRQ BIT(9) -#define JZ_LCD_CTRL_DD_IRQ BIT(8) -#define JZ_LCD_CTRL_QDD_IRQ BIT(7) -#define JZ_LCD_CTRL_REVERSE_ENDIAN BIT(6) -#define JZ_LCD_CTRL_LSB_FISRT BIT(5) -#define JZ_LCD_CTRL_DISABLE BIT(4) -#define JZ_LCD_CTRL_ENABLE BIT(3) -#define JZ_LCD_CTRL_BPP_1 0x0 -#define JZ_LCD_CTRL_BPP_2 0x1 -#define JZ_LCD_CTRL_BPP_4 0x2 -#define JZ_LCD_CTRL_BPP_8 0x3 -#define JZ_LCD_CTRL_BPP_15_16 0x4 -#define JZ_LCD_CTRL_BPP_18_24 0x5 - -#define JZ_LCD_CMD_SOF_IRQ BIT(31) -#define JZ_LCD_CMD_EOF_IRQ BIT(30) -#define JZ_LCD_CMD_ENABLE_PAL BIT(28) - -#define JZ_LCD_SYNC_MASK 0x3ff - -#define JZ_LCD_STATE_DISABLED BIT(0) - -struct jzfb_framedesc { - uint32_t next; - uint32_t addr; - uint32_t id; - uint32_t cmd; -} __packed; - -struct jzfb { - struct fb_info *fb; - struct platform_device *pdev; - void __iomem *base; - struct resource *mem; - struct jz4740_fb_platform_data *pdata; - - size_t vidmem_size; - void *vidmem; - dma_addr_t vidmem_phys; - struct jzfb_framedesc *framedesc; - dma_addr_t framedesc_phys; - - struct clk *ldclk; - struct clk *lpclk; - - unsigned is_enabled:1; - struct mutex lock; - - uint32_t pseudo_palette[16]; -}; - -static const struct fb_fix_screeninfo jzfb_fix = { - .id = "JZ4740 FB", - .type = FB_TYPE_PACKED_PIXELS, - .visual = FB_VISUAL_TRUECOLOR, - .xpanstep = 0, - .ypanstep = 0, - .ywrapstep = 0, - .accel = FB_ACCEL_NONE, -}; - -/* Based on CNVT_TOHW macro from skeletonfb.c */ -static inline uint32_t jzfb_convert_color_to_hw(unsigned val, - struct fb_bitfield *bf) -{ - return (((val << bf->length) + 0x7FFF - val) >> 16) << bf->offset; -} - -static int jzfb_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, struct fb_info *fb) -{ - uint32_t color; - - if (regno >= 16) - return -EINVAL; - - color = jzfb_convert_color_to_hw(red, &fb->var.red); - color |= jzfb_convert_color_to_hw(green, &fb->var.green); - color |= jzfb_convert_color_to_hw(blue, &fb->var.blue); - color |= jzfb_convert_color_to_hw(transp, &fb->var.transp); - - ((uint32_t *)(fb->pseudo_palette))[regno] = color; - - return 0; -} - -static int jzfb_get_controller_bpp(struct jzfb *jzfb) -{ - switch (jzfb->pdata->bpp) { - case 18: - case 24: - return 32; - case 15: - return 16; - default: - return jzfb->pdata->bpp; - } -} - -static struct fb_videomode *jzfb_get_mode(struct jzfb *jzfb, - struct fb_var_screeninfo *var) -{ - size_t i; - struct fb_videomode *mode = jzfb->pdata->modes; - - for (i = 0; i < jzfb->pdata->num_modes; ++i, ++mode) { - if (mode->xres == var->xres && mode->yres == var->yres) - return mode; - } - - return NULL; -} - -static int jzfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fb) -{ - struct jzfb *jzfb = fb->par; - struct fb_videomode *mode; - - if (var->bits_per_pixel != jzfb_get_controller_bpp(jzfb) && - var->bits_per_pixel != jzfb->pdata->bpp) - return -EINVAL; - - mode = jzfb_get_mode(jzfb, var); - if (mode == NULL) - return -EINVAL; - - fb_videomode_to_var(var, mode); - - switch (jzfb->pdata->bpp) { - case 8: - break; - case 15: - var->red.offset = 10; - var->red.length = 5; - var->green.offset = 6; - var->green.length = 5; - var->blue.offset = 0; - var->blue.length = 5; - break; - case 16: - var->red.offset = 11; - var->red.length = 5; - var->green.offset = 5; - var->green.length = 6; - var->blue.offset = 0; - var->blue.length = 5; - break; - case 18: - var->red.offset = 16; - var->red.length = 6; - var->green.offset = 8; - var->green.length = 6; - var->blue.offset = 0; - var->blue.length = 6; - var->bits_per_pixel = 32; - break; - case 32: - case 24: - var->transp.offset = 24; - var->transp.length = 8; - var->red.offset = 16; - var->red.length = 8; - var->green.offset = 8; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - var->bits_per_pixel = 32; - break; - default: - break; - } - - return 0; -} - -static int jzfb_set_par(struct fb_info *info) -{ - struct jzfb *jzfb = info->par; - struct jz4740_fb_platform_data *pdata = jzfb->pdata; - struct fb_var_screeninfo *var = &info->var; - struct fb_videomode *mode; - uint16_t hds, vds; - uint16_t hde, vde; - uint16_t ht, vt; - uint32_t ctrl; - uint32_t cfg; - unsigned long rate; - - mode = jzfb_get_mode(jzfb, var); - if (mode == NULL) - return -EINVAL; - - if (mode == info->mode) - return 0; - - info->mode = mode; - - hds = mode->hsync_len + mode->left_margin; - hde = hds + mode->xres; - ht = hde + mode->right_margin; - - vds = mode->vsync_len + mode->upper_margin; - vde = vds + mode->yres; - vt = vde + mode->lower_margin; - - ctrl = JZ_LCD_CTRL_OFUP | JZ_LCD_CTRL_BURST_16; - - switch (pdata->bpp) { - case 1: - ctrl |= JZ_LCD_CTRL_BPP_1; - break; - case 2: - ctrl |= JZ_LCD_CTRL_BPP_2; - break; - case 4: - ctrl |= JZ_LCD_CTRL_BPP_4; - break; - case 8: - ctrl |= JZ_LCD_CTRL_BPP_8; - break; - case 15: - ctrl |= JZ_LCD_CTRL_RGB555; /* Falltrough */ - case 16: - ctrl |= JZ_LCD_CTRL_BPP_15_16; - break; - case 18: - case 24: - case 32: - ctrl |= JZ_LCD_CTRL_BPP_18_24; - break; - default: - break; - } - - cfg = pdata->lcd_type & 0xf; - - if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT)) - cfg |= JZ_LCD_CFG_HSYNC_ACTIVE_LOW; - - if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT)) - cfg |= JZ_LCD_CFG_VSYNC_ACTIVE_LOW; - - if (pdata->pixclk_falling_edge) - cfg |= JZ_LCD_CFG_PCLK_FALLING_EDGE; - - if (pdata->date_enable_active_low) - cfg |= JZ_LCD_CFG_DE_ACTIVE_LOW; - - if (pdata->lcd_type == JZ_LCD_TYPE_GENERIC_18_BIT) - cfg |= JZ_LCD_CFG_18_BIT; - - if (mode->pixclock) { - rate = PICOS2KHZ(mode->pixclock) * 1000; - mode->refresh = rate / vt / ht; - } else { - if (pdata->lcd_type == JZ_LCD_TYPE_8BIT_SERIAL) - rate = mode->refresh * (vt + 2 * mode->xres) * ht; - else - rate = mode->refresh * vt * ht; - - mode->pixclock = KHZ2PICOS(rate / 1000); - } - - mutex_lock(&jzfb->lock); - if (!jzfb->is_enabled) - clk_enable(jzfb->ldclk); - else - ctrl |= JZ_LCD_CTRL_ENABLE; - - switch (pdata->lcd_type) { - case JZ_LCD_TYPE_SPECIAL_TFT_1: - case JZ_LCD_TYPE_SPECIAL_TFT_2: - case JZ_LCD_TYPE_SPECIAL_TFT_3: - writel(pdata->special_tft_config.spl, jzfb->base + JZ_REG_LCD_SPL); - writel(pdata->special_tft_config.cls, jzfb->base + JZ_REG_LCD_CLS); - writel(pdata->special_tft_config.ps, jzfb->base + JZ_REG_LCD_PS); - writel(pdata->special_tft_config.ps, jzfb->base + JZ_REG_LCD_REV); - break; - default: - cfg |= JZ_LCD_CFG_PS_DISABLE; - cfg |= JZ_LCD_CFG_CLS_DISABLE; - cfg |= JZ_LCD_CFG_SPL_DISABLE; - cfg |= JZ_LCD_CFG_REV_DISABLE; - break; - } - - writel(mode->hsync_len, jzfb->base + JZ_REG_LCD_HSYNC); - writel(mode->vsync_len, jzfb->base + JZ_REG_LCD_VSYNC); - - writel((ht << 16) | vt, jzfb->base + JZ_REG_LCD_VAT); - - writel((hds << 16) | hde, jzfb->base + JZ_REG_LCD_DAH); - writel((vds << 16) | vde, jzfb->base + JZ_REG_LCD_DAV); - - writel(cfg, jzfb->base + JZ_REG_LCD_CFG); - - writel(ctrl, jzfb->base + JZ_REG_LCD_CTRL); - - if (!jzfb->is_enabled) - clk_disable_unprepare(jzfb->ldclk); - - mutex_unlock(&jzfb->lock); - - clk_set_rate(jzfb->lpclk, rate); - clk_set_rate(jzfb->ldclk, rate * 3); - - return 0; -} - -static void jzfb_enable(struct jzfb *jzfb) -{ - uint32_t ctrl; - - clk_prepare_enable(jzfb->ldclk); - - pinctrl_pm_select_default_state(&jzfb->pdev->dev); - - writel(0, jzfb->base + JZ_REG_LCD_STATE); - - writel(jzfb->framedesc->next, jzfb->base + JZ_REG_LCD_DA0); - - ctrl = readl(jzfb->base + JZ_REG_LCD_CTRL); - ctrl |= JZ_LCD_CTRL_ENABLE; - ctrl &= ~JZ_LCD_CTRL_DISABLE; - writel(ctrl, jzfb->base + JZ_REG_LCD_CTRL); -} - -static void jzfb_disable(struct jzfb *jzfb) -{ - uint32_t ctrl; - - ctrl = readl(jzfb->base + JZ_REG_LCD_CTRL); - ctrl |= JZ_LCD_CTRL_DISABLE; - writel(ctrl, jzfb->base + JZ_REG_LCD_CTRL); - do { - ctrl = readl(jzfb->base + JZ_REG_LCD_STATE); - } while (!(ctrl & JZ_LCD_STATE_DISABLED)); - - pinctrl_pm_select_sleep_state(&jzfb->pdev->dev); - - clk_disable_unprepare(jzfb->ldclk); -} - -static int jzfb_blank(int blank_mode, struct fb_info *info) -{ - struct jzfb *jzfb = info->par; - - switch (blank_mode) { - case FB_BLANK_UNBLANK: - mutex_lock(&jzfb->lock); - if (jzfb->is_enabled) { - mutex_unlock(&jzfb->lock); - return 0; - } - - jzfb_enable(jzfb); - jzfb->is_enabled = 1; - - mutex_unlock(&jzfb->lock); - break; - default: - mutex_lock(&jzfb->lock); - if (!jzfb->is_enabled) { - mutex_unlock(&jzfb->lock); - return 0; - } - - jzfb_disable(jzfb); - jzfb->is_enabled = 0; - - mutex_unlock(&jzfb->lock); - break; - } - - return 0; -} - -static int jzfb_alloc_devmem(struct jzfb *jzfb) -{ - int max_videosize = 0; - struct fb_videomode *mode = jzfb->pdata->modes; - int i; - - for (i = 0; i < jzfb->pdata->num_modes; ++mode, ++i) { - if (max_videosize < mode->xres * mode->yres) - max_videosize = mode->xres * mode->yres; - } - - max_videosize *= jzfb_get_controller_bpp(jzfb) >> 3; - - jzfb->framedesc = dma_alloc_coherent(&jzfb->pdev->dev, - sizeof(*jzfb->framedesc), - &jzfb->framedesc_phys, GFP_KERNEL); - - if (!jzfb->framedesc) - return -ENOMEM; - - jzfb->vidmem_size = PAGE_ALIGN(max_videosize); - jzfb->vidmem = dma_alloc_coherent(&jzfb->pdev->dev, - jzfb->vidmem_size, - &jzfb->vidmem_phys, GFP_KERNEL); - - if (!jzfb->vidmem) - goto err_free_framedesc; - - jzfb->framedesc->next = jzfb->framedesc_phys; - jzfb->framedesc->addr = jzfb->vidmem_phys; - jzfb->framedesc->id = 0xdeafbead; - jzfb->framedesc->cmd = 0; - jzfb->framedesc->cmd |= max_videosize / 4; - - return 0; - -err_free_framedesc: - dma_free_coherent(&jzfb->pdev->dev, sizeof(*jzfb->framedesc), - jzfb->framedesc, jzfb->framedesc_phys); - return -ENOMEM; -} - -static void jzfb_free_devmem(struct jzfb *jzfb) -{ - dma_free_coherent(&jzfb->pdev->dev, jzfb->vidmem_size, - jzfb->vidmem, jzfb->vidmem_phys); - dma_free_coherent(&jzfb->pdev->dev, sizeof(*jzfb->framedesc), - jzfb->framedesc, jzfb->framedesc_phys); -} - -static struct fb_ops jzfb_ops = { - .owner = THIS_MODULE, - .fb_check_var = jzfb_check_var, - .fb_set_par = jzfb_set_par, - .fb_blank = jzfb_blank, - .fb_fillrect = sys_fillrect, - .fb_copyarea = sys_copyarea, - .fb_imageblit = sys_imageblit, - .fb_setcolreg = jzfb_setcolreg, -}; - -static int jzfb_probe(struct platform_device *pdev) -{ - int ret; - struct jzfb *jzfb; - struct fb_info *fb; - struct jz4740_fb_platform_data *pdata = pdev->dev.platform_data; - struct resource *mem; - - if (!pdata) { - dev_err(&pdev->dev, "Missing platform data\n"); - return -ENXIO; - } - - fb = framebuffer_alloc(sizeof(struct jzfb), &pdev->dev); - if (!fb) - return -ENOMEM; - - fb->fbops = &jzfb_ops; - fb->flags = FBINFO_DEFAULT; - - jzfb = fb->par; - jzfb->pdev = pdev; - jzfb->pdata = pdata; - - jzfb->ldclk = devm_clk_get(&pdev->dev, "lcd"); - if (IS_ERR(jzfb->ldclk)) { - ret = PTR_ERR(jzfb->ldclk); - dev_err(&pdev->dev, "Failed to get lcd clock: %d\n", ret); - goto err_framebuffer_release; - } - - jzfb->lpclk = devm_clk_get(&pdev->dev, "lcd_pclk"); - if (IS_ERR(jzfb->lpclk)) { - ret = PTR_ERR(jzfb->lpclk); - dev_err(&pdev->dev, "Failed to get lcd pixel clock: %d\n", ret); - goto err_framebuffer_release; - } - - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - jzfb->base = devm_ioremap_resource(&pdev->dev, mem); - if (IS_ERR(jzfb->base)) { - ret = PTR_ERR(jzfb->base); - goto err_framebuffer_release; - } - - platform_set_drvdata(pdev, jzfb); - - mutex_init(&jzfb->lock); - - fb_videomode_to_modelist(pdata->modes, pdata->num_modes, - &fb->modelist); - fb_videomode_to_var(&fb->var, pdata->modes); - fb->var.bits_per_pixel = pdata->bpp; - jzfb_check_var(&fb->var, fb); - - ret = jzfb_alloc_devmem(jzfb); - if (ret) { - dev_err(&pdev->dev, "Failed to allocate video memory\n"); - goto err_framebuffer_release; - } - - fb->fix = jzfb_fix; - fb->fix.line_length = fb->var.bits_per_pixel * fb->var.xres / 8; - fb->fix.mmio_start = mem->start; - fb->fix.mmio_len = resource_size(mem); - fb->fix.smem_start = jzfb->vidmem_phys; - fb->fix.smem_len = fb->fix.line_length * fb->var.yres; - fb->screen_base = jzfb->vidmem; - fb->pseudo_palette = jzfb->pseudo_palette; - - fb_alloc_cmap(&fb->cmap, 256, 0); - - clk_prepare_enable(jzfb->ldclk); - jzfb->is_enabled = 1; - - writel(jzfb->framedesc->next, jzfb->base + JZ_REG_LCD_DA0); - - fb->mode = NULL; - jzfb_set_par(fb); - - ret = register_framebuffer(fb); - if (ret) { - dev_err(&pdev->dev, "Failed to register framebuffer: %d\n", ret); - goto err_free_devmem; - } - - jzfb->fb = fb; - - return 0; - -err_free_devmem: - fb_dealloc_cmap(&fb->cmap); - jzfb_free_devmem(jzfb); -err_framebuffer_release: - framebuffer_release(fb); - return ret; -} - -static int jzfb_remove(struct platform_device *pdev) -{ - struct jzfb *jzfb = platform_get_drvdata(pdev); - - jzfb_blank(FB_BLANK_POWERDOWN, jzfb->fb); - - fb_dealloc_cmap(&jzfb->fb->cmap); - jzfb_free_devmem(jzfb); - - framebuffer_release(jzfb->fb); - - return 0; -} - -#ifdef CONFIG_PM - -static int jzfb_suspend(struct device *dev) -{ - struct jzfb *jzfb = dev_get_drvdata(dev); - - console_lock(); - fb_set_suspend(jzfb->fb, 1); - console_unlock(); - - mutex_lock(&jzfb->lock); - if (jzfb->is_enabled) - jzfb_disable(jzfb); - mutex_unlock(&jzfb->lock); - - return 0; -} - -static int jzfb_resume(struct device *dev) -{ - struct jzfb *jzfb = dev_get_drvdata(dev); - clk_prepare_enable(jzfb->ldclk); - - mutex_lock(&jzfb->lock); - if (jzfb->is_enabled) - jzfb_enable(jzfb); - mutex_unlock(&jzfb->lock); - - console_lock(); - fb_set_suspend(jzfb->fb, 0); - console_unlock(); - - return 0; -} - -static const struct dev_pm_ops jzfb_pm_ops = { - .suspend = jzfb_suspend, - .resume = jzfb_resume, - .poweroff = jzfb_suspend, - .restore = jzfb_resume, -}; - -#define JZFB_PM_OPS (&jzfb_pm_ops) - -#else -#define JZFB_PM_OPS NULL -#endif - -static struct platform_driver jzfb_driver = { - .probe = jzfb_probe, - .remove = jzfb_remove, - .driver = { - .name = "jz4740-fb", - .pm = JZFB_PM_OPS, - }, -}; -module_platform_driver(jzfb_driver); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Lars-Peter Clausen "); -MODULE_DESCRIPTION("JZ4740 SoC LCD framebuffer driver"); -MODULE_ALIAS("platform:jz4740-fb"); -- cgit v1.2.3 From 091c6104ade5527ce29035673ff262a24c4f036c Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 25 Jul 2019 18:02:10 -0400 Subject: dma: Drop JZ4740 driver The newer and better JZ4780 driver is now used to provide DMA functionality on the JZ4740. Signed-off-by: Paul Cercueil Tested-by: Artur Rojek Acked-by: Vinod Koul Signed-off-by: Paul Burton --- drivers/dma/Kconfig | 6 - drivers/dma/Makefile | 1 - drivers/dma/dma-jz4740.c | 623 ----------------------------------------------- 3 files changed, 630 deletions(-) delete mode 100644 drivers/dma/dma-jz4740.c (limited to 'drivers') diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 03fa0c58cef3..7dd9831b4e6e 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -137,12 +137,6 @@ config DMA_BCM2835 select DMA_ENGINE select DMA_VIRTUAL_CHANNELS -config DMA_JZ4740 - tristate "JZ4740 DMA support" - depends on MACH_JZ4740 || COMPILE_TEST - select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - config DMA_JZ4780 tristate "JZ4780 DMA support" depends on MIPS || COMPILE_TEST diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index 5bddf6f8790f..f5ce8665e944 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -22,7 +22,6 @@ obj-$(CONFIG_AXI_DMAC) += dma-axi-dmac.o obj-$(CONFIG_BCM_SBA_RAID) += bcm-sba-raid.o obj-$(CONFIG_COH901318) += coh901318.o coh901318_lli.o obj-$(CONFIG_DMA_BCM2835) += bcm2835-dma.o -obj-$(CONFIG_DMA_JZ4740) += dma-jz4740.o obj-$(CONFIG_DMA_JZ4780) += dma-jz4780.o obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o obj-$(CONFIG_DMA_SUN4I) += sun4i-dma.o diff --git a/drivers/dma/dma-jz4740.c b/drivers/dma/dma-jz4740.c deleted file mode 100644 index 39c676c47082..000000000000 --- a/drivers/dma/dma-jz4740.c +++ /dev/null @@ -1,623 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2013, Lars-Peter Clausen - * JZ4740 DMAC support - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "virt-dma.h" - -#define JZ_DMA_NR_CHANS 6 - -#define JZ_REG_DMA_SRC_ADDR(x) (0x00 + (x) * 0x20) -#define JZ_REG_DMA_DST_ADDR(x) (0x04 + (x) * 0x20) -#define JZ_REG_DMA_TRANSFER_COUNT(x) (0x08 + (x) * 0x20) -#define JZ_REG_DMA_REQ_TYPE(x) (0x0C + (x) * 0x20) -#define JZ_REG_DMA_STATUS_CTRL(x) (0x10 + (x) * 0x20) -#define JZ_REG_DMA_CMD(x) (0x14 + (x) * 0x20) -#define JZ_REG_DMA_DESC_ADDR(x) (0x18 + (x) * 0x20) - -#define JZ_REG_DMA_CTRL 0x300 -#define JZ_REG_DMA_IRQ 0x304 -#define JZ_REG_DMA_DOORBELL 0x308 -#define JZ_REG_DMA_DOORBELL_SET 0x30C - -#define JZ_DMA_STATUS_CTRL_NO_DESC BIT(31) -#define JZ_DMA_STATUS_CTRL_DESC_INV BIT(6) -#define JZ_DMA_STATUS_CTRL_ADDR_ERR BIT(4) -#define JZ_DMA_STATUS_CTRL_TRANSFER_DONE BIT(3) -#define JZ_DMA_STATUS_CTRL_HALT BIT(2) -#define JZ_DMA_STATUS_CTRL_COUNT_TERMINATE BIT(1) -#define JZ_DMA_STATUS_CTRL_ENABLE BIT(0) - -#define JZ_DMA_CMD_SRC_INC BIT(23) -#define JZ_DMA_CMD_DST_INC BIT(22) -#define JZ_DMA_CMD_RDIL_MASK (0xf << 16) -#define JZ_DMA_CMD_SRC_WIDTH_MASK (0x3 << 14) -#define JZ_DMA_CMD_DST_WIDTH_MASK (0x3 << 12) -#define JZ_DMA_CMD_INTERVAL_LENGTH_MASK (0x7 << 8) -#define JZ_DMA_CMD_BLOCK_MODE BIT(7) -#define JZ_DMA_CMD_DESC_VALID BIT(4) -#define JZ_DMA_CMD_DESC_VALID_MODE BIT(3) -#define JZ_DMA_CMD_VALID_IRQ_ENABLE BIT(2) -#define JZ_DMA_CMD_TRANSFER_IRQ_ENABLE BIT(1) -#define JZ_DMA_CMD_LINK_ENABLE BIT(0) - -#define JZ_DMA_CMD_FLAGS_OFFSET 22 -#define JZ_DMA_CMD_RDIL_OFFSET 16 -#define JZ_DMA_CMD_SRC_WIDTH_OFFSET 14 -#define JZ_DMA_CMD_DST_WIDTH_OFFSET 12 -#define JZ_DMA_CMD_TRANSFER_SIZE_OFFSET 8 -#define JZ_DMA_CMD_MODE_OFFSET 7 - -#define JZ_DMA_CTRL_PRIORITY_MASK (0x3 << 8) -#define JZ_DMA_CTRL_HALT BIT(3) -#define JZ_DMA_CTRL_ADDRESS_ERROR BIT(2) -#define JZ_DMA_CTRL_ENABLE BIT(0) - -enum jz4740_dma_width { - JZ4740_DMA_WIDTH_32BIT = 0, - JZ4740_DMA_WIDTH_8BIT = 1, - JZ4740_DMA_WIDTH_16BIT = 2, -}; - -enum jz4740_dma_transfer_size { - JZ4740_DMA_TRANSFER_SIZE_4BYTE = 0, - JZ4740_DMA_TRANSFER_SIZE_1BYTE = 1, - JZ4740_DMA_TRANSFER_SIZE_2BYTE = 2, - JZ4740_DMA_TRANSFER_SIZE_16BYTE = 3, - JZ4740_DMA_TRANSFER_SIZE_32BYTE = 4, -}; - -enum jz4740_dma_flags { - JZ4740_DMA_SRC_AUTOINC = 0x2, - JZ4740_DMA_DST_AUTOINC = 0x1, -}; - -enum jz4740_dma_mode { - JZ4740_DMA_MODE_SINGLE = 0, - JZ4740_DMA_MODE_BLOCK = 1, -}; - -struct jz4740_dma_sg { - dma_addr_t addr; - unsigned int len; -}; - -struct jz4740_dma_desc { - struct virt_dma_desc vdesc; - - enum dma_transfer_direction direction; - bool cyclic; - - unsigned int num_sgs; - struct jz4740_dma_sg sg[]; -}; - -struct jz4740_dmaengine_chan { - struct virt_dma_chan vchan; - unsigned int id; - struct dma_slave_config config; - - dma_addr_t fifo_addr; - unsigned int transfer_shift; - - struct jz4740_dma_desc *desc; - unsigned int next_sg; -}; - -struct jz4740_dma_dev { - struct dma_device ddev; - void __iomem *base; - struct clk *clk; - - struct jz4740_dmaengine_chan chan[JZ_DMA_NR_CHANS]; -}; - -static struct jz4740_dma_dev *jz4740_dma_chan_get_dev( - struct jz4740_dmaengine_chan *chan) -{ - return container_of(chan->vchan.chan.device, struct jz4740_dma_dev, - ddev); -} - -static struct jz4740_dmaengine_chan *to_jz4740_dma_chan(struct dma_chan *c) -{ - return container_of(c, struct jz4740_dmaengine_chan, vchan.chan); -} - -static struct jz4740_dma_desc *to_jz4740_dma_desc(struct virt_dma_desc *vdesc) -{ - return container_of(vdesc, struct jz4740_dma_desc, vdesc); -} - -static inline uint32_t jz4740_dma_read(struct jz4740_dma_dev *dmadev, - unsigned int reg) -{ - return readl(dmadev->base + reg); -} - -static inline void jz4740_dma_write(struct jz4740_dma_dev *dmadev, - unsigned reg, uint32_t val) -{ - writel(val, dmadev->base + reg); -} - -static inline void jz4740_dma_write_mask(struct jz4740_dma_dev *dmadev, - unsigned int reg, uint32_t val, uint32_t mask) -{ - uint32_t tmp; - - tmp = jz4740_dma_read(dmadev, reg); - tmp &= ~mask; - tmp |= val; - jz4740_dma_write(dmadev, reg, tmp); -} - -static struct jz4740_dma_desc *jz4740_dma_alloc_desc(unsigned int num_sgs) -{ - return kzalloc(sizeof(struct jz4740_dma_desc) + - sizeof(struct jz4740_dma_sg) * num_sgs, GFP_ATOMIC); -} - -static enum jz4740_dma_width jz4740_dma_width(enum dma_slave_buswidth width) -{ - switch (width) { - case DMA_SLAVE_BUSWIDTH_1_BYTE: - return JZ4740_DMA_WIDTH_8BIT; - case DMA_SLAVE_BUSWIDTH_2_BYTES: - return JZ4740_DMA_WIDTH_16BIT; - case DMA_SLAVE_BUSWIDTH_4_BYTES: - return JZ4740_DMA_WIDTH_32BIT; - default: - return JZ4740_DMA_WIDTH_32BIT; - } -} - -static enum jz4740_dma_transfer_size jz4740_dma_maxburst(u32 maxburst) -{ - if (maxburst <= 1) - return JZ4740_DMA_TRANSFER_SIZE_1BYTE; - else if (maxburst <= 3) - return JZ4740_DMA_TRANSFER_SIZE_2BYTE; - else if (maxburst <= 15) - return JZ4740_DMA_TRANSFER_SIZE_4BYTE; - else if (maxburst <= 31) - return JZ4740_DMA_TRANSFER_SIZE_16BYTE; - - return JZ4740_DMA_TRANSFER_SIZE_32BYTE; -} - -static int jz4740_dma_slave_config_write(struct dma_chan *c, - struct dma_slave_config *config, - enum dma_transfer_direction direction) -{ - struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c); - struct jz4740_dma_dev *dmadev = jz4740_dma_chan_get_dev(chan); - enum jz4740_dma_width src_width; - enum jz4740_dma_width dst_width; - enum jz4740_dma_transfer_size transfer_size; - enum jz4740_dma_flags flags; - uint32_t cmd; - - switch (direction) { - case DMA_MEM_TO_DEV: - flags = JZ4740_DMA_SRC_AUTOINC; - transfer_size = jz4740_dma_maxburst(config->dst_maxburst); - chan->fifo_addr = config->dst_addr; - break; - case DMA_DEV_TO_MEM: - flags = JZ4740_DMA_DST_AUTOINC; - transfer_size = jz4740_dma_maxburst(config->src_maxburst); - chan->fifo_addr = config->src_addr; - break; - default: - return -EINVAL; - } - - src_width = jz4740_dma_width(config->src_addr_width); - dst_width = jz4740_dma_width(config->dst_addr_width); - - switch (transfer_size) { - case JZ4740_DMA_TRANSFER_SIZE_2BYTE: - chan->transfer_shift = 1; - break; - case JZ4740_DMA_TRANSFER_SIZE_4BYTE: - chan->transfer_shift = 2; - break; - case JZ4740_DMA_TRANSFER_SIZE_16BYTE: - chan->transfer_shift = 4; - break; - case JZ4740_DMA_TRANSFER_SIZE_32BYTE: - chan->transfer_shift = 5; - break; - default: - chan->transfer_shift = 0; - break; - } - - cmd = flags << JZ_DMA_CMD_FLAGS_OFFSET; - cmd |= src_width << JZ_DMA_CMD_SRC_WIDTH_OFFSET; - cmd |= dst_width << JZ_DMA_CMD_DST_WIDTH_OFFSET; - cmd |= transfer_size << JZ_DMA_CMD_TRANSFER_SIZE_OFFSET; - cmd |= JZ4740_DMA_MODE_SINGLE << JZ_DMA_CMD_MODE_OFFSET; - cmd |= JZ_DMA_CMD_TRANSFER_IRQ_ENABLE; - - jz4740_dma_write(dmadev, JZ_REG_DMA_CMD(chan->id), cmd); - jz4740_dma_write(dmadev, JZ_REG_DMA_STATUS_CTRL(chan->id), 0); - jz4740_dma_write(dmadev, JZ_REG_DMA_REQ_TYPE(chan->id), - config->slave_id); - - return 0; -} - -static int jz4740_dma_slave_config(struct dma_chan *c, - struct dma_slave_config *config) -{ - struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c); - - memcpy(&chan->config, config, sizeof(*config)); - return 0; -} - -static int jz4740_dma_terminate_all(struct dma_chan *c) -{ - struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c); - struct jz4740_dma_dev *dmadev = jz4740_dma_chan_get_dev(chan); - unsigned long flags; - LIST_HEAD(head); - - spin_lock_irqsave(&chan->vchan.lock, flags); - jz4740_dma_write_mask(dmadev, JZ_REG_DMA_STATUS_CTRL(chan->id), 0, - JZ_DMA_STATUS_CTRL_ENABLE); - chan->desc = NULL; - vchan_get_all_descriptors(&chan->vchan, &head); - spin_unlock_irqrestore(&chan->vchan.lock, flags); - - vchan_dma_desc_free_list(&chan->vchan, &head); - - return 0; -} - -static int jz4740_dma_start_transfer(struct jz4740_dmaengine_chan *chan) -{ - struct jz4740_dma_dev *dmadev = jz4740_dma_chan_get_dev(chan); - dma_addr_t src_addr, dst_addr; - struct virt_dma_desc *vdesc; - struct jz4740_dma_sg *sg; - - jz4740_dma_write_mask(dmadev, JZ_REG_DMA_STATUS_CTRL(chan->id), 0, - JZ_DMA_STATUS_CTRL_ENABLE); - - if (!chan->desc) { - vdesc = vchan_next_desc(&chan->vchan); - if (!vdesc) - return 0; - chan->desc = to_jz4740_dma_desc(vdesc); - chan->next_sg = 0; - } - - if (chan->next_sg == chan->desc->num_sgs) - chan->next_sg = 0; - - sg = &chan->desc->sg[chan->next_sg]; - - if (chan->desc->direction == DMA_MEM_TO_DEV) { - src_addr = sg->addr; - dst_addr = chan->fifo_addr; - } else { - src_addr = chan->fifo_addr; - dst_addr = sg->addr; - } - jz4740_dma_write(dmadev, JZ_REG_DMA_SRC_ADDR(chan->id), src_addr); - jz4740_dma_write(dmadev, JZ_REG_DMA_DST_ADDR(chan->id), dst_addr); - jz4740_dma_write(dmadev, JZ_REG_DMA_TRANSFER_COUNT(chan->id), - sg->len >> chan->transfer_shift); - - chan->next_sg++; - - jz4740_dma_write_mask(dmadev, JZ_REG_DMA_STATUS_CTRL(chan->id), - JZ_DMA_STATUS_CTRL_NO_DESC | JZ_DMA_STATUS_CTRL_ENABLE, - JZ_DMA_STATUS_CTRL_HALT | JZ_DMA_STATUS_CTRL_NO_DESC | - JZ_DMA_STATUS_CTRL_ENABLE); - - jz4740_dma_write_mask(dmadev, JZ_REG_DMA_CTRL, - JZ_DMA_CTRL_ENABLE, - JZ_DMA_CTRL_HALT | JZ_DMA_CTRL_ENABLE); - - return 0; -} - -static void jz4740_dma_chan_irq(struct jz4740_dmaengine_chan *chan) -{ - spin_lock(&chan->vchan.lock); - if (chan->desc) { - if (chan->desc->cyclic) { - vchan_cyclic_callback(&chan->desc->vdesc); - } else { - if (chan->next_sg == chan->desc->num_sgs) { - list_del(&chan->desc->vdesc.node); - vchan_cookie_complete(&chan->desc->vdesc); - chan->desc = NULL; - } - } - } - jz4740_dma_start_transfer(chan); - spin_unlock(&chan->vchan.lock); -} - -static irqreturn_t jz4740_dma_irq(int irq, void *devid) -{ - struct jz4740_dma_dev *dmadev = devid; - uint32_t irq_status; - unsigned int i; - - irq_status = readl(dmadev->base + JZ_REG_DMA_IRQ); - - for (i = 0; i < 6; ++i) { - if (irq_status & (1 << i)) { - jz4740_dma_write_mask(dmadev, - JZ_REG_DMA_STATUS_CTRL(i), 0, - JZ_DMA_STATUS_CTRL_ENABLE | - JZ_DMA_STATUS_CTRL_TRANSFER_DONE); - - jz4740_dma_chan_irq(&dmadev->chan[i]); - } - } - - return IRQ_HANDLED; -} - -static void jz4740_dma_issue_pending(struct dma_chan *c) -{ - struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c); - unsigned long flags; - - spin_lock_irqsave(&chan->vchan.lock, flags); - if (vchan_issue_pending(&chan->vchan) && !chan->desc) - jz4740_dma_start_transfer(chan); - spin_unlock_irqrestore(&chan->vchan.lock, flags); -} - -static struct dma_async_tx_descriptor *jz4740_dma_prep_slave_sg( - struct dma_chan *c, struct scatterlist *sgl, - unsigned int sg_len, enum dma_transfer_direction direction, - unsigned long flags, void *context) -{ - struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c); - struct jz4740_dma_desc *desc; - struct scatterlist *sg; - unsigned int i; - - desc = jz4740_dma_alloc_desc(sg_len); - if (!desc) - return NULL; - - for_each_sg(sgl, sg, sg_len, i) { - desc->sg[i].addr = sg_dma_address(sg); - desc->sg[i].len = sg_dma_len(sg); - } - - desc->num_sgs = sg_len; - desc->direction = direction; - desc->cyclic = false; - - jz4740_dma_slave_config_write(c, &chan->config, direction); - - return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); -} - -static struct dma_async_tx_descriptor *jz4740_dma_prep_dma_cyclic( - struct dma_chan *c, dma_addr_t buf_addr, size_t buf_len, - size_t period_len, enum dma_transfer_direction direction, - unsigned long flags) -{ - struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c); - struct jz4740_dma_desc *desc; - unsigned int num_periods, i; - - if (buf_len % period_len) - return NULL; - - num_periods = buf_len / period_len; - - desc = jz4740_dma_alloc_desc(num_periods); - if (!desc) - return NULL; - - for (i = 0; i < num_periods; i++) { - desc->sg[i].addr = buf_addr; - desc->sg[i].len = period_len; - buf_addr += period_len; - } - - desc->num_sgs = num_periods; - desc->direction = direction; - desc->cyclic = true; - - jz4740_dma_slave_config_write(c, &chan->config, direction); - - return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); -} - -static size_t jz4740_dma_desc_residue(struct jz4740_dmaengine_chan *chan, - struct jz4740_dma_desc *desc, unsigned int next_sg) -{ - struct jz4740_dma_dev *dmadev = jz4740_dma_chan_get_dev(chan); - unsigned int residue, count; - unsigned int i; - - residue = 0; - - for (i = next_sg; i < desc->num_sgs; i++) - residue += desc->sg[i].len; - - if (next_sg != 0) { - count = jz4740_dma_read(dmadev, - JZ_REG_DMA_TRANSFER_COUNT(chan->id)); - residue += count << chan->transfer_shift; - } - - return residue; -} - -static enum dma_status jz4740_dma_tx_status(struct dma_chan *c, - dma_cookie_t cookie, struct dma_tx_state *state) -{ - struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c); - struct virt_dma_desc *vdesc; - enum dma_status status; - unsigned long flags; - - status = dma_cookie_status(c, cookie, state); - if (status == DMA_COMPLETE || !state) - return status; - - spin_lock_irqsave(&chan->vchan.lock, flags); - vdesc = vchan_find_desc(&chan->vchan, cookie); - if (cookie == chan->desc->vdesc.tx.cookie) { - state->residue = jz4740_dma_desc_residue(chan, chan->desc, - chan->next_sg); - } else if (vdesc) { - state->residue = jz4740_dma_desc_residue(chan, - to_jz4740_dma_desc(vdesc), 0); - } else { - state->residue = 0; - } - spin_unlock_irqrestore(&chan->vchan.lock, flags); - - return status; -} - -static void jz4740_dma_free_chan_resources(struct dma_chan *c) -{ - vchan_free_chan_resources(to_virt_chan(c)); -} - -static void jz4740_dma_desc_free(struct virt_dma_desc *vdesc) -{ - kfree(container_of(vdesc, struct jz4740_dma_desc, vdesc)); -} - -#define JZ4740_DMA_BUSWIDTHS (BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \ - BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | BIT(DMA_SLAVE_BUSWIDTH_4_BYTES)) - -static int jz4740_dma_probe(struct platform_device *pdev) -{ - struct jz4740_dmaengine_chan *chan; - struct jz4740_dma_dev *dmadev; - struct dma_device *dd; - unsigned int i; - struct resource *res; - int ret; - int irq; - - dmadev = devm_kzalloc(&pdev->dev, sizeof(*dmadev), GFP_KERNEL); - if (!dmadev) - return -EINVAL; - - dd = &dmadev->ddev; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dmadev->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(dmadev->base)) - return PTR_ERR(dmadev->base); - - dmadev->clk = clk_get(&pdev->dev, "dma"); - if (IS_ERR(dmadev->clk)) - return PTR_ERR(dmadev->clk); - - clk_prepare_enable(dmadev->clk); - - dma_cap_set(DMA_SLAVE, dd->cap_mask); - dma_cap_set(DMA_CYCLIC, dd->cap_mask); - dd->device_free_chan_resources = jz4740_dma_free_chan_resources; - dd->device_tx_status = jz4740_dma_tx_status; - dd->device_issue_pending = jz4740_dma_issue_pending; - dd->device_prep_slave_sg = jz4740_dma_prep_slave_sg; - dd->device_prep_dma_cyclic = jz4740_dma_prep_dma_cyclic; - dd->device_config = jz4740_dma_slave_config; - dd->device_terminate_all = jz4740_dma_terminate_all; - dd->src_addr_widths = JZ4740_DMA_BUSWIDTHS; - dd->dst_addr_widths = JZ4740_DMA_BUSWIDTHS; - dd->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); - dd->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; - dd->dev = &pdev->dev; - INIT_LIST_HEAD(&dd->channels); - - for (i = 0; i < JZ_DMA_NR_CHANS; i++) { - chan = &dmadev->chan[i]; - chan->id = i; - chan->vchan.desc_free = jz4740_dma_desc_free; - vchan_init(&chan->vchan, dd); - } - - ret = dma_async_device_register(dd); - if (ret) - goto err_clk; - - irq = platform_get_irq(pdev, 0); - ret = request_irq(irq, jz4740_dma_irq, 0, dev_name(&pdev->dev), dmadev); - if (ret) - goto err_unregister; - - platform_set_drvdata(pdev, dmadev); - - return 0; - -err_unregister: - dma_async_device_unregister(dd); -err_clk: - clk_disable_unprepare(dmadev->clk); - return ret; -} - -static void jz4740_cleanup_vchan(struct dma_device *dmadev) -{ - struct jz4740_dmaengine_chan *chan, *_chan; - - list_for_each_entry_safe(chan, _chan, - &dmadev->channels, vchan.chan.device_node) { - list_del(&chan->vchan.chan.device_node); - tasklet_kill(&chan->vchan.task); - } -} - - -static int jz4740_dma_remove(struct platform_device *pdev) -{ - struct jz4740_dma_dev *dmadev = platform_get_drvdata(pdev); - int irq = platform_get_irq(pdev, 0); - - free_irq(irq, dmadev); - - jz4740_cleanup_vchan(&dmadev->ddev); - dma_async_device_unregister(&dmadev->ddev); - clk_disable_unprepare(dmadev->clk); - - return 0; -} - -static struct platform_driver jz4740_dma_driver = { - .probe = jz4740_dma_probe, - .remove = jz4740_dma_remove, - .driver = { - .name = "jz4740-dma", - }, -}; -module_platform_driver(jz4740_dma_driver); - -MODULE_AUTHOR("Lars-Peter Clausen "); -MODULE_DESCRIPTION("JZ4740 DMA driver"); -MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From b58451e00f2b803961c3ec8b46f5fcfd8cf78bef Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 25 Jul 2019 18:02:11 -0400 Subject: mtd: rawnand: Drop obsolete JZ4740 NAND driver It has been replaced with the newer Ingenic NAND driver. Signed-off-by: Paul Cercueil Tested-by: Artur Rojek Acked-by: Miquel Raynal Signed-off-by: Paul Burton --- drivers/mtd/nand/raw/ingenic/Kconfig | 7 - drivers/mtd/nand/raw/ingenic/Makefile | 1 - drivers/mtd/nand/raw/ingenic/jz4740_nand.c | 536 ----------------------------- 3 files changed, 544 deletions(-) delete mode 100644 drivers/mtd/nand/raw/ingenic/jz4740_nand.c (limited to 'drivers') diff --git a/drivers/mtd/nand/raw/ingenic/Kconfig b/drivers/mtd/nand/raw/ingenic/Kconfig index 66b7cffdb0c2..e30feb56b650 100644 --- a/drivers/mtd/nand/raw/ingenic/Kconfig +++ b/drivers/mtd/nand/raw/ingenic/Kconfig @@ -1,11 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only -config MTD_NAND_JZ4740 - tristate "JZ4740 NAND controller" - depends on MACH_JZ4740 || COMPILE_TEST - depends on HAS_IOMEM - help - Enables support for NAND Flash on JZ4740 SoC based boards. - config MTD_NAND_JZ4780 tristate "JZ4780 NAND controller" depends on JZ4780_NEMC diff --git a/drivers/mtd/nand/raw/ingenic/Makefile b/drivers/mtd/nand/raw/ingenic/Makefile index b63d36889263..4c53f5e759c3 100644 --- a/drivers/mtd/nand/raw/ingenic/Makefile +++ b/drivers/mtd/nand/raw/ingenic/Makefile @@ -1,5 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o obj-$(CONFIG_MTD_NAND_JZ4780) += ingenic_nand.o ingenic_nand-y += ingenic_nand_drv.o diff --git a/drivers/mtd/nand/raw/ingenic/jz4740_nand.c b/drivers/mtd/nand/raw/ingenic/jz4740_nand.c deleted file mode 100644 index acdf674fcc87..000000000000 --- a/drivers/mtd/nand/raw/ingenic/jz4740_nand.c +++ /dev/null @@ -1,536 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2009-2010, Lars-Peter Clausen - * JZ4740 SoC NAND controller driver - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include - -#define JZ_REG_NAND_CTRL 0x50 -#define JZ_REG_NAND_ECC_CTRL 0x100 -#define JZ_REG_NAND_DATA 0x104 -#define JZ_REG_NAND_PAR0 0x108 -#define JZ_REG_NAND_PAR1 0x10C -#define JZ_REG_NAND_PAR2 0x110 -#define JZ_REG_NAND_IRQ_STAT 0x114 -#define JZ_REG_NAND_IRQ_CTRL 0x118 -#define JZ_REG_NAND_ERR(x) (0x11C + ((x) << 2)) - -#define JZ_NAND_ECC_CTRL_PAR_READY BIT(4) -#define JZ_NAND_ECC_CTRL_ENCODING BIT(3) -#define JZ_NAND_ECC_CTRL_RS BIT(2) -#define JZ_NAND_ECC_CTRL_RESET BIT(1) -#define JZ_NAND_ECC_CTRL_ENABLE BIT(0) - -#define JZ_NAND_STATUS_ERR_COUNT (BIT(31) | BIT(30) | BIT(29)) -#define JZ_NAND_STATUS_PAD_FINISH BIT(4) -#define JZ_NAND_STATUS_DEC_FINISH BIT(3) -#define JZ_NAND_STATUS_ENC_FINISH BIT(2) -#define JZ_NAND_STATUS_UNCOR_ERROR BIT(1) -#define JZ_NAND_STATUS_ERROR BIT(0) - -#define JZ_NAND_CTRL_ENABLE_CHIP(x) BIT((x) << 1) -#define JZ_NAND_CTRL_ASSERT_CHIP(x) BIT(((x) << 1) + 1) -#define JZ_NAND_CTRL_ASSERT_CHIP_MASK 0xaa - -#define JZ_NAND_MEM_CMD_OFFSET 0x08000 -#define JZ_NAND_MEM_ADDR_OFFSET 0x10000 - -struct jz_nand { - struct nand_chip chip; - void __iomem *base; - struct resource *mem; - - unsigned char banks[JZ_NAND_NUM_BANKS]; - void __iomem *bank_base[JZ_NAND_NUM_BANKS]; - struct resource *bank_mem[JZ_NAND_NUM_BANKS]; - - int selected_bank; - - struct gpio_desc *busy_gpio; - bool is_reading; -}; - -static inline struct jz_nand *mtd_to_jz_nand(struct mtd_info *mtd) -{ - return container_of(mtd_to_nand(mtd), struct jz_nand, chip); -} - -static void jz_nand_select_chip(struct nand_chip *chip, int chipnr) -{ - struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip)); - uint32_t ctrl; - int banknr; - - ctrl = readl(nand->base + JZ_REG_NAND_CTRL); - ctrl &= ~JZ_NAND_CTRL_ASSERT_CHIP_MASK; - - if (chipnr == -1) { - banknr = -1; - } else { - banknr = nand->banks[chipnr] - 1; - chip->legacy.IO_ADDR_R = nand->bank_base[banknr]; - chip->legacy.IO_ADDR_W = nand->bank_base[banknr]; - } - writel(ctrl, nand->base + JZ_REG_NAND_CTRL); - - nand->selected_bank = banknr; -} - -static void jz_nand_cmd_ctrl(struct nand_chip *chip, int dat, - unsigned int ctrl) -{ - struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip)); - uint32_t reg; - void __iomem *bank_base = nand->bank_base[nand->selected_bank]; - - BUG_ON(nand->selected_bank < 0); - - if (ctrl & NAND_CTRL_CHANGE) { - BUG_ON((ctrl & NAND_ALE) && (ctrl & NAND_CLE)); - if (ctrl & NAND_ALE) - bank_base += JZ_NAND_MEM_ADDR_OFFSET; - else if (ctrl & NAND_CLE) - bank_base += JZ_NAND_MEM_CMD_OFFSET; - chip->legacy.IO_ADDR_W = bank_base; - - reg = readl(nand->base + JZ_REG_NAND_CTRL); - if (ctrl & NAND_NCE) - reg |= JZ_NAND_CTRL_ASSERT_CHIP(nand->selected_bank); - else - reg &= ~JZ_NAND_CTRL_ASSERT_CHIP(nand->selected_bank); - writel(reg, nand->base + JZ_REG_NAND_CTRL); - } - if (dat != NAND_CMD_NONE) - writeb(dat, chip->legacy.IO_ADDR_W); -} - -static int jz_nand_dev_ready(struct nand_chip *chip) -{ - struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip)); - return gpiod_get_value_cansleep(nand->busy_gpio); -} - -static void jz_nand_hwctl(struct nand_chip *chip, int mode) -{ - struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip)); - uint32_t reg; - - writel(0, nand->base + JZ_REG_NAND_IRQ_STAT); - reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL); - - reg |= JZ_NAND_ECC_CTRL_RESET; - reg |= JZ_NAND_ECC_CTRL_ENABLE; - reg |= JZ_NAND_ECC_CTRL_RS; - - switch (mode) { - case NAND_ECC_READ: - reg &= ~JZ_NAND_ECC_CTRL_ENCODING; - nand->is_reading = true; - break; - case NAND_ECC_WRITE: - reg |= JZ_NAND_ECC_CTRL_ENCODING; - nand->is_reading = false; - break; - default: - break; - } - - writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL); -} - -static int jz_nand_calculate_ecc_rs(struct nand_chip *chip, const uint8_t *dat, - uint8_t *ecc_code) -{ - struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip)); - uint32_t reg, status; - int i; - unsigned int timeout = 1000; - static uint8_t empty_block_ecc[] = {0xcd, 0x9d, 0x90, 0x58, 0xf4, - 0x8b, 0xff, 0xb7, 0x6f}; - - if (nand->is_reading) - return 0; - - do { - status = readl(nand->base + JZ_REG_NAND_IRQ_STAT); - } while (!(status & JZ_NAND_STATUS_ENC_FINISH) && --timeout); - - if (timeout == 0) - return -1; - - reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL); - reg &= ~JZ_NAND_ECC_CTRL_ENABLE; - writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL); - - for (i = 0; i < 9; ++i) - ecc_code[i] = readb(nand->base + JZ_REG_NAND_PAR0 + i); - - /* If the written data is completly 0xff, we also want to write 0xff as - * ecc, otherwise we will get in trouble when doing subpage writes. */ - if (memcmp(ecc_code, empty_block_ecc, 9) == 0) - memset(ecc_code, 0xff, 9); - - return 0; -} - -static void jz_nand_correct_data(uint8_t *dat, int index, int mask) -{ - int offset = index & 0x7; - uint16_t data; - - index += (index >> 3); - - data = dat[index]; - data |= dat[index+1] << 8; - - mask ^= (data >> offset) & 0x1ff; - data &= ~(0x1ff << offset); - data |= (mask << offset); - - dat[index] = data & 0xff; - dat[index+1] = (data >> 8) & 0xff; -} - -static int jz_nand_correct_ecc_rs(struct nand_chip *chip, uint8_t *dat, - uint8_t *read_ecc, uint8_t *calc_ecc) -{ - struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip)); - int i, error_count, index; - uint32_t reg, status, error; - unsigned int timeout = 1000; - - for (i = 0; i < 9; ++i) - writeb(read_ecc[i], nand->base + JZ_REG_NAND_PAR0 + i); - - reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL); - reg |= JZ_NAND_ECC_CTRL_PAR_READY; - writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL); - - do { - status = readl(nand->base + JZ_REG_NAND_IRQ_STAT); - } while (!(status & JZ_NAND_STATUS_DEC_FINISH) && --timeout); - - if (timeout == 0) - return -ETIMEDOUT; - - reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL); - reg &= ~JZ_NAND_ECC_CTRL_ENABLE; - writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL); - - if (status & JZ_NAND_STATUS_ERROR) { - if (status & JZ_NAND_STATUS_UNCOR_ERROR) - return -EBADMSG; - - error_count = (status & JZ_NAND_STATUS_ERR_COUNT) >> 29; - - for (i = 0; i < error_count; ++i) { - error = readl(nand->base + JZ_REG_NAND_ERR(i)); - index = ((error >> 16) & 0x1ff) - 1; - if (index >= 0 && index < 512) - jz_nand_correct_data(dat, index, error & 0x1ff); - } - - return error_count; - } - - return 0; -} - -static int jz_nand_ioremap_resource(struct platform_device *pdev, - const char *name, struct resource **res, void __iomem **base) -{ - int ret; - - *res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); - if (!*res) { - dev_err(&pdev->dev, "Failed to get platform %s memory\n", name); - ret = -ENXIO; - goto err; - } - - *res = request_mem_region((*res)->start, resource_size(*res), - pdev->name); - if (!*res) { - dev_err(&pdev->dev, "Failed to request %s memory region\n", name); - ret = -EBUSY; - goto err; - } - - *base = ioremap((*res)->start, resource_size(*res)); - if (!*base) { - dev_err(&pdev->dev, "Failed to ioremap %s memory region\n", name); - ret = -EBUSY; - goto err_release_mem; - } - - return 0; - -err_release_mem: - release_mem_region((*res)->start, resource_size(*res)); -err: - *res = NULL; - *base = NULL; - return ret; -} - -static inline void jz_nand_iounmap_resource(struct resource *res, - void __iomem *base) -{ - iounmap(base); - release_mem_region(res->start, resource_size(res)); -} - -static int jz_nand_detect_bank(struct platform_device *pdev, - struct jz_nand *nand, unsigned char bank, - size_t chipnr, uint8_t *nand_maf_id, - uint8_t *nand_dev_id) -{ - int ret; - char res_name[6]; - uint32_t ctrl; - struct nand_chip *chip = &nand->chip; - struct mtd_info *mtd = nand_to_mtd(chip); - struct nand_memory_organization *memorg; - u8 id[2]; - - memorg = nanddev_get_memorg(&chip->base); - - /* Request I/O resource. */ - sprintf(res_name, "bank%d", bank); - ret = jz_nand_ioremap_resource(pdev, res_name, - &nand->bank_mem[bank - 1], - &nand->bank_base[bank - 1]); - if (ret) - return ret; - - /* Enable chip in bank. */ - ctrl = readl(nand->base + JZ_REG_NAND_CTRL); - ctrl |= JZ_NAND_CTRL_ENABLE_CHIP(bank - 1); - writel(ctrl, nand->base + JZ_REG_NAND_CTRL); - - if (chipnr == 0) { - /* Detect first chip. */ - ret = nand_scan(chip, 1); - if (ret) - goto notfound_id; - - /* Retrieve the IDs from the first chip. */ - nand_select_target(chip, 0); - nand_reset_op(chip); - nand_readid_op(chip, 0, id, sizeof(id)); - *nand_maf_id = id[0]; - *nand_dev_id = id[1]; - } else { - /* Detect additional chip. */ - nand_select_target(chip, chipnr); - nand_reset_op(chip); - nand_readid_op(chip, 0, id, sizeof(id)); - if (*nand_maf_id != id[0] || *nand_dev_id != id[1]) { - ret = -ENODEV; - goto notfound_id; - } - - /* Update size of the MTD. */ - memorg->ntargets++; - mtd->size += nanddev_target_size(&chip->base); - } - - dev_info(&pdev->dev, "Found chip %zu on bank %i\n", chipnr, bank); - return 0; - -notfound_id: - dev_info(&pdev->dev, "No chip found on bank %i\n", bank); - ctrl &= ~(JZ_NAND_CTRL_ENABLE_CHIP(bank - 1)); - writel(ctrl, nand->base + JZ_REG_NAND_CTRL); - jz_nand_iounmap_resource(nand->bank_mem[bank - 1], - nand->bank_base[bank - 1]); - return ret; -} - -static int jz_nand_attach_chip(struct nand_chip *chip) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - struct device *dev = mtd->dev.parent; - struct jz_nand_platform_data *pdata = dev_get_platdata(dev); - struct platform_device *pdev = to_platform_device(dev); - - if (pdata && pdata->ident_callback) - pdata->ident_callback(pdev, mtd, &pdata->partitions, - &pdata->num_partitions); - - return 0; -} - -static const struct nand_controller_ops jz_nand_controller_ops = { - .attach_chip = jz_nand_attach_chip, -}; - -static int jz_nand_probe(struct platform_device *pdev) -{ - int ret; - struct jz_nand *nand; - struct nand_chip *chip; - struct mtd_info *mtd; - struct jz_nand_platform_data *pdata = dev_get_platdata(&pdev->dev); - size_t chipnr, bank_idx; - uint8_t nand_maf_id = 0, nand_dev_id = 0; - - nand = kzalloc(sizeof(*nand), GFP_KERNEL); - if (!nand) - return -ENOMEM; - - ret = jz_nand_ioremap_resource(pdev, "mmio", &nand->mem, &nand->base); - if (ret) - goto err_free; - - nand->busy_gpio = devm_gpiod_get_optional(&pdev->dev, "busy", GPIOD_IN); - if (IS_ERR(nand->busy_gpio)) { - ret = PTR_ERR(nand->busy_gpio); - dev_err(&pdev->dev, "Failed to request busy gpio %d\n", - ret); - goto err_iounmap_mmio; - } - - chip = &nand->chip; - mtd = nand_to_mtd(chip); - mtd->dev.parent = &pdev->dev; - mtd->name = "jz4740-nand"; - - chip->ecc.hwctl = jz_nand_hwctl; - chip->ecc.calculate = jz_nand_calculate_ecc_rs; - chip->ecc.correct = jz_nand_correct_ecc_rs; - chip->ecc.mode = NAND_ECC_HW_OOB_FIRST; - chip->ecc.size = 512; - chip->ecc.bytes = 9; - chip->ecc.strength = 4; - chip->ecc.options = NAND_ECC_GENERIC_ERASED_CHECK; - - chip->legacy.chip_delay = 50; - chip->legacy.cmd_ctrl = jz_nand_cmd_ctrl; - chip->legacy.select_chip = jz_nand_select_chip; - chip->legacy.dummy_controller.ops = &jz_nand_controller_ops; - - if (nand->busy_gpio) - chip->legacy.dev_ready = jz_nand_dev_ready; - - platform_set_drvdata(pdev, nand); - - /* We are going to autodetect NAND chips in the banks specified in the - * platform data. Although nand_scan_ident() can detect multiple chips, - * it requires those chips to be numbered consecuitively, which is not - * always the case for external memory banks. And a fixed chip-to-bank - * mapping is not practical either, since for example Dingoo units - * produced at different times have NAND chips in different banks. - */ - chipnr = 0; - for (bank_idx = 0; bank_idx < JZ_NAND_NUM_BANKS; bank_idx++) { - unsigned char bank; - - /* If there is no platform data, look for NAND in bank 1, - * which is the most likely bank since it is the only one - * that can be booted from. - */ - bank = pdata ? pdata->banks[bank_idx] : bank_idx ^ 1; - if (bank == 0) - break; - if (bank > JZ_NAND_NUM_BANKS) { - dev_warn(&pdev->dev, - "Skipping non-existing bank: %d\n", bank); - continue; - } - /* The detection routine will directly or indirectly call - * jz_nand_select_chip(), so nand->banks has to contain the - * bank we're checking. - */ - nand->banks[chipnr] = bank; - if (jz_nand_detect_bank(pdev, nand, bank, chipnr, - &nand_maf_id, &nand_dev_id) == 0) - chipnr++; - else - nand->banks[chipnr] = 0; - } - if (chipnr == 0) { - dev_err(&pdev->dev, "No NAND chips found\n"); - goto err_iounmap_mmio; - } - - ret = mtd_device_register(mtd, pdata ? pdata->partitions : NULL, - pdata ? pdata->num_partitions : 0); - - if (ret) { - dev_err(&pdev->dev, "Failed to add mtd device\n"); - goto err_cleanup_nand; - } - - dev_info(&pdev->dev, "Successfully registered JZ4740 NAND driver\n"); - - return 0; - -err_cleanup_nand: - nand_cleanup(chip); - while (chipnr--) { - unsigned char bank = nand->banks[chipnr]; - jz_nand_iounmap_resource(nand->bank_mem[bank - 1], - nand->bank_base[bank - 1]); - } - writel(0, nand->base + JZ_REG_NAND_CTRL); -err_iounmap_mmio: - jz_nand_iounmap_resource(nand->mem, nand->base); -err_free: - kfree(nand); - return ret; -} - -static int jz_nand_remove(struct platform_device *pdev) -{ - struct jz_nand *nand = platform_get_drvdata(pdev); - size_t i; - - nand_release(&nand->chip); - - /* Deassert and disable all chips */ - writel(0, nand->base + JZ_REG_NAND_CTRL); - - for (i = 0; i < JZ_NAND_NUM_BANKS; ++i) { - unsigned char bank = nand->banks[i]; - if (bank != 0) { - jz_nand_iounmap_resource(nand->bank_mem[bank - 1], - nand->bank_base[bank - 1]); - } - } - - jz_nand_iounmap_resource(nand->mem, nand->base); - - kfree(nand); - - return 0; -} - -static struct platform_driver jz_nand_driver = { - .probe = jz_nand_probe, - .remove = jz_nand_remove, - .driver = { - .name = "jz4740-nand", - }, -}; - -module_platform_driver(jz_nand_driver); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Lars-Peter Clausen "); -MODULE_DESCRIPTION("NAND controller driver for JZ4740 SoC"); -MODULE_ALIAS("platform:jz4740-nand"); -- cgit v1.2.3 From aea12071d6fcf143b8140bcdde80cdc419101299 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 25 Jul 2019 18:02:12 -0400 Subject: power/supply: Drop obsolete JZ4740 driver It has been replaced with the more mature ingenic-battery driver. Signed-off-by: Paul Cercueil Tested-by: Artur Rojek Acked-by: Sebastian Reichel Signed-off-by: Paul Burton --- drivers/power/supply/Kconfig | 11 - drivers/power/supply/Makefile | 1 - drivers/power/supply/jz4740-battery.c | 421 ---------------------------------- 3 files changed, 433 deletions(-) delete mode 100644 drivers/power/supply/jz4740-battery.c (limited to 'drivers') diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index 5d91b5160b41..6ba602ed7979 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -417,17 +417,6 @@ config CHARGER_PCF50633 help Say Y to include support for NXP PCF50633 Main Battery Charger. -config BATTERY_JZ4740 - tristate "Ingenic JZ4740 battery" - depends on MACH_JZ4740 - depends on MFD_JZ4740_ADC - help - Say Y to enable support for the battery on Ingenic JZ4740 based - boards. - - This driver can be build as a module. If so, the module will be - called jz4740-battery. - config BATTERY_RX51 tristate "Nokia RX-51 (N900) battery driver" depends on TWL4030_MADC diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile index 96c2b74b36bf..6c7da920ea83 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile @@ -58,7 +58,6 @@ obj-$(CONFIG_BATTERY_S3C_ADC) += s3c_adc_battery.o obj-$(CONFIG_BATTERY_TWL4030_MADC) += twl4030_madc_battery.o obj-$(CONFIG_CHARGER_88PM860X) += 88pm860x_charger.o obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o -obj-$(CONFIG_BATTERY_JZ4740) += jz4740-battery.o obj-$(CONFIG_BATTERY_RX51) += rx51_battery.o obj-$(CONFIG_AB8500_BM) += ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o abx500_chargalg.o pm2301_charger.o obj-$(CONFIG_CHARGER_CPCAP) += cpcap-charger.o diff --git a/drivers/power/supply/jz4740-battery.c b/drivers/power/supply/jz4740-battery.c deleted file mode 100644 index 6366bd61ea9f..000000000000 --- a/drivers/power/supply/jz4740-battery.c +++ /dev/null @@ -1,421 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Battery measurement code for Ingenic JZ SOC. - * - * Copyright (C) 2009 Jiejing Zhang - * Copyright (C) 2010, Lars-Peter Clausen - * - * based on tosa_battery.c - * - * Copyright (C) 2008 Marek Vasut - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -struct jz_battery { - struct jz_battery_platform_data *pdata; - struct platform_device *pdev; - - void __iomem *base; - - int irq; - int charge_irq; - - const struct mfd_cell *cell; - - int status; - long voltage; - - struct completion read_completion; - - struct power_supply *battery; - struct power_supply_desc battery_desc; - struct delayed_work work; - - struct mutex lock; -}; - -static inline struct jz_battery *psy_to_jz_battery(struct power_supply *psy) -{ - return power_supply_get_drvdata(psy); -} - -static irqreturn_t jz_battery_irq_handler(int irq, void *devid) -{ - struct jz_battery *battery = devid; - - complete(&battery->read_completion); - return IRQ_HANDLED; -} - -static long jz_battery_read_voltage(struct jz_battery *battery) -{ - long t; - unsigned long val; - long voltage; - - mutex_lock(&battery->lock); - - reinit_completion(&battery->read_completion); - - enable_irq(battery->irq); - battery->cell->enable(battery->pdev); - - t = wait_for_completion_interruptible_timeout(&battery->read_completion, - HZ); - - if (t > 0) { - val = readw(battery->base) & 0xfff; - - if (battery->pdata->info.voltage_max_design <= 2500000) - val = (val * 78125UL) >> 7UL; - else - val = ((val * 924375UL) >> 9UL) + 33000; - voltage = (long)val; - } else { - voltage = t ? t : -ETIMEDOUT; - } - - battery->cell->disable(battery->pdev); - disable_irq(battery->irq); - - mutex_unlock(&battery->lock); - - return voltage; -} - -static int jz_battery_get_capacity(struct power_supply *psy) -{ - struct jz_battery *jz_battery = psy_to_jz_battery(psy); - struct power_supply_info *info = &jz_battery->pdata->info; - long voltage; - int ret; - int voltage_span; - - voltage = jz_battery_read_voltage(jz_battery); - - if (voltage < 0) - return voltage; - - voltage_span = info->voltage_max_design - info->voltage_min_design; - ret = ((voltage - info->voltage_min_design) * 100) / voltage_span; - - if (ret > 100) - ret = 100; - else if (ret < 0) - ret = 0; - - return ret; -} - -static int jz_battery_get_property(struct power_supply *psy, - enum power_supply_property psp, union power_supply_propval *val) -{ - struct jz_battery *jz_battery = psy_to_jz_battery(psy); - struct power_supply_info *info = &jz_battery->pdata->info; - long voltage; - - switch (psp) { - case POWER_SUPPLY_PROP_STATUS: - val->intval = jz_battery->status; - break; - case POWER_SUPPLY_PROP_TECHNOLOGY: - val->intval = jz_battery->pdata->info.technology; - break; - case POWER_SUPPLY_PROP_HEALTH: - voltage = jz_battery_read_voltage(jz_battery); - if (voltage < info->voltage_min_design) - val->intval = POWER_SUPPLY_HEALTH_DEAD; - else - val->intval = POWER_SUPPLY_HEALTH_GOOD; - break; - case POWER_SUPPLY_PROP_CAPACITY: - val->intval = jz_battery_get_capacity(psy); - break; - case POWER_SUPPLY_PROP_VOLTAGE_NOW: - val->intval = jz_battery_read_voltage(jz_battery); - if (val->intval < 0) - return val->intval; - break; - case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: - val->intval = info->voltage_max_design; - break; - case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: - val->intval = info->voltage_min_design; - break; - case POWER_SUPPLY_PROP_PRESENT: - val->intval = 1; - break; - default: - return -EINVAL; - } - return 0; -} - -static void jz_battery_external_power_changed(struct power_supply *psy) -{ - struct jz_battery *jz_battery = psy_to_jz_battery(psy); - - mod_delayed_work(system_wq, &jz_battery->work, 0); -} - -static irqreturn_t jz_battery_charge_irq(int irq, void *data) -{ - struct jz_battery *jz_battery = data; - - mod_delayed_work(system_wq, &jz_battery->work, 0); - - return IRQ_HANDLED; -} - -static void jz_battery_update(struct jz_battery *jz_battery) -{ - int status; - long voltage; - bool has_changed = false; - int is_charging; - - if (gpio_is_valid(jz_battery->pdata->gpio_charge)) { - is_charging = gpio_get_value(jz_battery->pdata->gpio_charge); - is_charging ^= jz_battery->pdata->gpio_charge_active_low; - if (is_charging) - status = POWER_SUPPLY_STATUS_CHARGING; - else - status = POWER_SUPPLY_STATUS_NOT_CHARGING; - - if (status != jz_battery->status) { - jz_battery->status = status; - has_changed = true; - } - } - - voltage = jz_battery_read_voltage(jz_battery); - if (voltage >= 0 && abs(voltage - jz_battery->voltage) > 50000) { - jz_battery->voltage = voltage; - has_changed = true; - } - - if (has_changed) - power_supply_changed(jz_battery->battery); -} - -static enum power_supply_property jz_battery_properties[] = { - POWER_SUPPLY_PROP_STATUS, - POWER_SUPPLY_PROP_TECHNOLOGY, - POWER_SUPPLY_PROP_HEALTH, - POWER_SUPPLY_PROP_CAPACITY, - POWER_SUPPLY_PROP_VOLTAGE_NOW, - POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, - POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, - POWER_SUPPLY_PROP_PRESENT, -}; - -static void jz_battery_work(struct work_struct *work) -{ - /* Too small interval will increase system workload */ - const int interval = HZ * 30; - struct jz_battery *jz_battery = container_of(work, struct jz_battery, - work.work); - - jz_battery_update(jz_battery); - schedule_delayed_work(&jz_battery->work, interval); -} - -static int jz_battery_probe(struct platform_device *pdev) -{ - int ret = 0; - struct jz_battery_platform_data *pdata = pdev->dev.parent->platform_data; - struct power_supply_config psy_cfg = {}; - struct jz_battery *jz_battery; - struct power_supply_desc *battery_desc; - struct resource *mem; - - if (!pdata) { - dev_err(&pdev->dev, "No platform_data supplied\n"); - return -ENXIO; - } - - jz_battery = devm_kzalloc(&pdev->dev, sizeof(*jz_battery), GFP_KERNEL); - if (!jz_battery) { - dev_err(&pdev->dev, "Failed to allocate driver structure\n"); - return -ENOMEM; - } - - jz_battery->cell = mfd_get_cell(pdev); - - jz_battery->irq = platform_get_irq(pdev, 0); - if (jz_battery->irq < 0) { - dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret); - return jz_battery->irq; - } - - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - jz_battery->base = devm_ioremap_resource(&pdev->dev, mem); - if (IS_ERR(jz_battery->base)) - return PTR_ERR(jz_battery->base); - - battery_desc = &jz_battery->battery_desc; - battery_desc->name = pdata->info.name; - battery_desc->type = POWER_SUPPLY_TYPE_BATTERY; - battery_desc->properties = jz_battery_properties; - battery_desc->num_properties = ARRAY_SIZE(jz_battery_properties); - battery_desc->get_property = jz_battery_get_property; - battery_desc->external_power_changed = - jz_battery_external_power_changed; - battery_desc->use_for_apm = 1; - - psy_cfg.drv_data = jz_battery; - - jz_battery->pdata = pdata; - jz_battery->pdev = pdev; - - init_completion(&jz_battery->read_completion); - mutex_init(&jz_battery->lock); - - INIT_DELAYED_WORK(&jz_battery->work, jz_battery_work); - - ret = request_irq(jz_battery->irq, jz_battery_irq_handler, 0, pdev->name, - jz_battery); - if (ret) { - dev_err(&pdev->dev, "Failed to request irq %d\n", ret); - return ret; - } - disable_irq(jz_battery->irq); - - if (gpio_is_valid(pdata->gpio_charge)) { - ret = gpio_request(pdata->gpio_charge, dev_name(&pdev->dev)); - if (ret) { - dev_err(&pdev->dev, "charger state gpio request failed.\n"); - goto err_free_irq; - } - ret = gpio_direction_input(pdata->gpio_charge); - if (ret) { - dev_err(&pdev->dev, "charger state gpio set direction failed.\n"); - goto err_free_gpio; - } - - jz_battery->charge_irq = gpio_to_irq(pdata->gpio_charge); - - if (jz_battery->charge_irq >= 0) { - ret = request_irq(jz_battery->charge_irq, - jz_battery_charge_irq, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - dev_name(&pdev->dev), jz_battery); - if (ret) { - dev_err(&pdev->dev, "Failed to request charge irq: %d\n", ret); - goto err_free_gpio; - } - } - } else { - jz_battery->charge_irq = -1; - } - - if (jz_battery->pdata->info.voltage_max_design <= 2500000) - jz4740_adc_set_config(pdev->dev.parent, JZ_ADC_CONFIG_BAT_MB, - JZ_ADC_CONFIG_BAT_MB); - else - jz4740_adc_set_config(pdev->dev.parent, JZ_ADC_CONFIG_BAT_MB, 0); - - jz_battery->battery = power_supply_register(&pdev->dev, battery_desc, - &psy_cfg); - if (IS_ERR(jz_battery->battery)) { - dev_err(&pdev->dev, "power supply battery register failed.\n"); - ret = PTR_ERR(jz_battery->battery); - goto err_free_charge_irq; - } - - platform_set_drvdata(pdev, jz_battery); - schedule_delayed_work(&jz_battery->work, 0); - - return 0; - -err_free_charge_irq: - if (jz_battery->charge_irq >= 0) - free_irq(jz_battery->charge_irq, jz_battery); -err_free_gpio: - if (gpio_is_valid(pdata->gpio_charge)) - gpio_free(jz_battery->pdata->gpio_charge); -err_free_irq: - free_irq(jz_battery->irq, jz_battery); - return ret; -} - -static int jz_battery_remove(struct platform_device *pdev) -{ - struct jz_battery *jz_battery = platform_get_drvdata(pdev); - - cancel_delayed_work_sync(&jz_battery->work); - - if (gpio_is_valid(jz_battery->pdata->gpio_charge)) { - if (jz_battery->charge_irq >= 0) - free_irq(jz_battery->charge_irq, jz_battery); - gpio_free(jz_battery->pdata->gpio_charge); - } - - power_supply_unregister(jz_battery->battery); - - free_irq(jz_battery->irq, jz_battery); - - return 0; -} - -#ifdef CONFIG_PM -static int jz_battery_suspend(struct device *dev) -{ - struct jz_battery *jz_battery = dev_get_drvdata(dev); - - cancel_delayed_work_sync(&jz_battery->work); - jz_battery->status = POWER_SUPPLY_STATUS_UNKNOWN; - - return 0; -} - -static int jz_battery_resume(struct device *dev) -{ - struct jz_battery *jz_battery = dev_get_drvdata(dev); - - schedule_delayed_work(&jz_battery->work, 0); - - return 0; -} - -static const struct dev_pm_ops jz_battery_pm_ops = { - .suspend = jz_battery_suspend, - .resume = jz_battery_resume, -}; - -#define JZ_BATTERY_PM_OPS (&jz_battery_pm_ops) -#else -#define JZ_BATTERY_PM_OPS NULL -#endif - -static struct platform_driver jz_battery_driver = { - .probe = jz_battery_probe, - .remove = jz_battery_remove, - .driver = { - .name = "jz4740-battery", - .pm = JZ_BATTERY_PM_OPS, - }, -}; - -module_platform_driver(jz_battery_driver); - -MODULE_ALIAS("platform:jz4740-battery"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Lars-Peter Clausen "); -MODULE_DESCRIPTION("JZ4740 SoC battery driver"); -- cgit v1.2.3 From d202742058b2ee5666d9820d539b67dc14f64712 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 25 Jul 2019 18:02:13 -0400 Subject: hwmon: Drop obsolete JZ4740 driver The JZ4740 boards now use the iio-hwmon driver. Signed-off-by: Paul Cercueil Tested-by: Artur Rojek Acked-by: Guenter Roeck Signed-off-by: Paul Burton --- drivers/hwmon/Kconfig | 10 ---- drivers/hwmon/Makefile | 1 - drivers/hwmon/jz4740-hwmon.c | 135 ------------------------------------------- 3 files changed, 146 deletions(-) delete mode 100644 drivers/hwmon/jz4740-hwmon.c (limited to 'drivers') diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 650dd71f9724..2199ac1d0ba7 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -660,16 +660,6 @@ config SENSORS_IT87 This driver can also be built as a module. If so, the module will be called it87. -config SENSORS_JZ4740 - tristate "Ingenic JZ4740 SoC ADC driver" - depends on MACH_JZ4740 && MFD_JZ4740_ADC - help - If you say yes here you get support for reading adc values from the ADCIN - pin on Ingenic JZ4740 SoC based boards. - - This driver can also be built as a module. If so, the module will be - called jz4740-hwmon. - config SENSORS_JC42 tristate "JEDEC JC42.4 compliant memory module temperature sensors" depends on I2C diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 8db472ea04f0..1e82e912a5c4 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -85,7 +85,6 @@ obj-$(CONFIG_SENSORS_INA2XX) += ina2xx.o obj-$(CONFIG_SENSORS_INA3221) += ina3221.o obj-$(CONFIG_SENSORS_IT87) += it87.o obj-$(CONFIG_SENSORS_JC42) += jc42.o -obj-$(CONFIG_SENSORS_JZ4740) += jz4740-hwmon.o obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o obj-$(CONFIG_SENSORS_K10TEMP) += k10temp.o obj-$(CONFIG_SENSORS_LINEAGE) += lineage-pem.o diff --git a/drivers/hwmon/jz4740-hwmon.c b/drivers/hwmon/jz4740-hwmon.c deleted file mode 100644 index bec5befd1d8b..000000000000 --- a/drivers/hwmon/jz4740-hwmon.c +++ /dev/null @@ -1,135 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2009-2010, Lars-Peter Clausen - * JZ4740 SoC HWMON driver - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -struct jz4740_hwmon { - void __iomem *base; - int irq; - const struct mfd_cell *cell; - struct platform_device *pdev; - struct completion read_completion; - struct mutex lock; -}; - -static irqreturn_t jz4740_hwmon_irq(int irq, void *data) -{ - struct jz4740_hwmon *hwmon = data; - - complete(&hwmon->read_completion); - return IRQ_HANDLED; -} - -static ssize_t in0_input_show(struct device *dev, - struct device_attribute *dev_attr, char *buf) -{ - struct jz4740_hwmon *hwmon = dev_get_drvdata(dev); - struct platform_device *pdev = hwmon->pdev; - struct completion *completion = &hwmon->read_completion; - long t; - unsigned long val; - int ret; - - mutex_lock(&hwmon->lock); - - reinit_completion(completion); - - enable_irq(hwmon->irq); - hwmon->cell->enable(pdev); - - t = wait_for_completion_interruptible_timeout(completion, HZ); - - if (t > 0) { - val = readw(hwmon->base) & 0xfff; - val = (val * 3300) >> 12; - ret = sprintf(buf, "%lu\n", val); - } else { - ret = t ? t : -ETIMEDOUT; - } - - hwmon->cell->disable(pdev); - disable_irq(hwmon->irq); - - mutex_unlock(&hwmon->lock); - - return ret; -} - -static DEVICE_ATTR_RO(in0_input); - -static struct attribute *jz4740_attrs[] = { - &dev_attr_in0_input.attr, - NULL -}; - -ATTRIBUTE_GROUPS(jz4740); - -static int jz4740_hwmon_probe(struct platform_device *pdev) -{ - int ret; - struct device *dev = &pdev->dev; - struct jz4740_hwmon *hwmon; - struct device *hwmon_dev; - - hwmon = devm_kzalloc(dev, sizeof(*hwmon), GFP_KERNEL); - if (!hwmon) - return -ENOMEM; - - hwmon->cell = mfd_get_cell(pdev); - - hwmon->irq = platform_get_irq(pdev, 0); - if (hwmon->irq < 0) { - dev_err(&pdev->dev, "Failed to get platform irq: %d\n", - hwmon->irq); - return hwmon->irq; - } - - hwmon->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(hwmon->base)) - return PTR_ERR(hwmon->base); - - hwmon->pdev = pdev; - init_completion(&hwmon->read_completion); - mutex_init(&hwmon->lock); - - ret = devm_request_irq(dev, hwmon->irq, jz4740_hwmon_irq, 0, - pdev->name, hwmon); - if (ret) { - dev_err(&pdev->dev, "Failed to request irq: %d\n", ret); - return ret; - } - disable_irq(hwmon->irq); - - hwmon_dev = devm_hwmon_device_register_with_groups(dev, "jz4740", hwmon, - jz4740_groups); - return PTR_ERR_OR_ZERO(hwmon_dev); -} - -static struct platform_driver jz4740_hwmon_driver = { - .probe = jz4740_hwmon_probe, - .driver = { - .name = "jz4740-hwmon", - }, -}; - -module_platform_driver(jz4740_hwmon_driver); - -MODULE_DESCRIPTION("JZ4740 SoC HWMON driver"); -MODULE_AUTHOR("Lars-Peter Clausen "); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:jz4740-hwmon"); -- cgit v1.2.3 From 39233b7c611248c0d05209b4854bc63e26485655 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 24 Jul 2019 13:16:06 -0400 Subject: mfd/syscon: Add device_node_to_regmap() device_node_to_regmap() is exactly like syscon_node_to_regmap(), but it does not check that the node is compatible with "syscon", and won't attach the first clock it finds to the regmap. The rationale behind this, is that one device node with a standard compatible string "foo,bar" can be covered by multiple drivers sharing a regmap, or by a single driver doing all the job without a regmap, but these are implementation details which shouldn't reflect on the devicetree. Signed-off-by: Paul Cercueil Acked-by: Arnd Bergmann Signed-off-by: Paul Burton Cc: Ralf Baechle Cc: James Hogan Cc: Jonathan Corbet Cc: Lee Jones Cc: Daniel Lezcano Cc: Thomas Gleixner Cc: Michael Turquette Cc: Stephen Boyd Cc: Jason Cooper Cc: Marc Zyngier Cc: Rob Herring Cc: Mark Rutland Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: linux-doc@vger.kernel.org Cc: linux-mips@vger.kernel.org Cc: linux-clk@vger.kernel.org Cc: od@zcrc.me Cc: Mathieu Malaterre --- drivers/mfd/syscon.c | 46 ++++++++++++++++++++++++++++++---------------- include/linux/mfd/syscon.h | 6 ++++++ 2 files changed, 36 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c index b65e585fc8c6..660723276481 100644 --- a/drivers/mfd/syscon.c +++ b/drivers/mfd/syscon.c @@ -40,7 +40,7 @@ static const struct regmap_config syscon_regmap_config = { .reg_stride = 4, }; -static struct syscon *of_syscon_register(struct device_node *np) +static struct syscon *of_syscon_register(struct device_node *np, bool check_clk) { struct clk *clk; struct syscon *syscon; @@ -51,9 +51,6 @@ static struct syscon *of_syscon_register(struct device_node *np) struct regmap_config syscon_config = syscon_regmap_config; struct resource res; - if (!of_device_is_compatible(np, "syscon")) - return ERR_PTR(-EINVAL); - syscon = kzalloc(sizeof(*syscon), GFP_KERNEL); if (!syscon) return ERR_PTR(-ENOMEM); @@ -117,16 +114,18 @@ static struct syscon *of_syscon_register(struct device_node *np) goto err_regmap; } - clk = of_clk_get(np, 0); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - /* clock is optional */ - if (ret != -ENOENT) - goto err_clk; - } else { - ret = regmap_mmio_attach_clk(regmap, clk); - if (ret) - goto err_attach; + if (check_clk) { + clk = of_clk_get(np, 0); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + /* clock is optional */ + if (ret != -ENOENT) + goto err_clk; + } else { + ret = regmap_mmio_attach_clk(regmap, clk); + if (ret) + goto err_attach; + } } syscon->regmap = regmap; @@ -150,7 +149,8 @@ err_map: return ERR_PTR(ret); } -struct regmap *syscon_node_to_regmap(struct device_node *np) +static struct regmap *device_node_get_regmap(struct device_node *np, + bool check_clk) { struct syscon *entry, *syscon = NULL; @@ -165,13 +165,27 @@ struct regmap *syscon_node_to_regmap(struct device_node *np) spin_unlock(&syscon_list_slock); if (!syscon) - syscon = of_syscon_register(np); + syscon = of_syscon_register(np, check_clk); if (IS_ERR(syscon)) return ERR_CAST(syscon); return syscon->regmap; } + +struct regmap *device_node_to_regmap(struct device_node *np) +{ + return device_node_get_regmap(np, false); +} +EXPORT_SYMBOL_GPL(device_node_to_regmap); + +struct regmap *syscon_node_to_regmap(struct device_node *np) +{ + if (!of_device_is_compatible(np, "syscon")) + return ERR_PTR(-EINVAL); + + return device_node_get_regmap(np, true); +} EXPORT_SYMBOL_GPL(syscon_node_to_regmap); struct regmap *syscon_regmap_lookup_by_compatible(const char *s) diff --git a/include/linux/mfd/syscon.h b/include/linux/mfd/syscon.h index 8cfda0554381..112dc66262cc 100644 --- a/include/linux/mfd/syscon.h +++ b/include/linux/mfd/syscon.h @@ -17,12 +17,18 @@ struct device_node; #ifdef CONFIG_MFD_SYSCON +extern struct regmap *device_node_to_regmap(struct device_node *np); extern struct regmap *syscon_node_to_regmap(struct device_node *np); extern struct regmap *syscon_regmap_lookup_by_compatible(const char *s); extern struct regmap *syscon_regmap_lookup_by_phandle( struct device_node *np, const char *property); #else +static inline struct regmap *device_node_to_regmap(struct device_node *np) +{ + return ERR_PTR(-ENOTSUPP); +} + static inline struct regmap *syscon_node_to_regmap(struct device_node *np) { return ERR_PTR(-ENOTSUPP); -- cgit v1.2.3 From 4f89e4b8f1215c113d87081efc99f28b3fcb6292 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 24 Jul 2019 13:16:07 -0400 Subject: clk: ingenic: Add driver for the TCU clocks Add driver to support the clocks provided by the Timer/Counter Unit (TCU) of the JZ47xx SoCs from Ingenic. Signed-off-by: Paul Cercueil Tested-by: Mathieu Malaterre Tested-by: Artur Rojek Acked-by: Stephen Boyd Signed-off-by: Paul Burton Cc: Ralf Baechle Cc: James Hogan Cc: Jonathan Corbet Cc: Lee Jones Cc: Arnd Bergmann Cc: Daniel Lezcano Cc: Thomas Gleixner Cc: Michael Turquette Cc: Jason Cooper Cc: Marc Zyngier Cc: Rob Herring Cc: Mark Rutland Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: linux-doc@vger.kernel.org Cc: linux-mips@vger.kernel.org Cc: linux-clk@vger.kernel.org Cc: od@zcrc.me --- drivers/clk/ingenic/Kconfig | 10 +- drivers/clk/ingenic/Makefile | 1 + drivers/clk/ingenic/tcu.c | 474 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 484 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/ingenic/tcu.c (limited to 'drivers') diff --git a/drivers/clk/ingenic/Kconfig b/drivers/clk/ingenic/Kconfig index fe8db93cf21a..1cb489959a99 100644 --- a/drivers/clk/ingenic/Kconfig +++ b/drivers/clk/ingenic/Kconfig @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -menu "Ingenic JZ47xx CGU drivers" +menu "Ingenic SoCs drivers" depends on MIPS config INGENIC_CGU_COMMON @@ -45,4 +45,12 @@ config INGENIC_CGU_JZ4780 If building for a JZ4780 SoC, you want to say Y here. +config INGENIC_TCU_CLK + bool "Ingenic JZ47xx TCU clocks driver" + default MACH_INGENIC + select MFD_SYSCON + help + Support the clocks of the Timer/Counter Unit (TCU) of the Ingenic + JZ47xx SoCs. + endmenu diff --git a/drivers/clk/ingenic/Makefile b/drivers/clk/ingenic/Makefile index 250570a809d3..097220b05131 100644 --- a/drivers/clk/ingenic/Makefile +++ b/drivers/clk/ingenic/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_INGENIC_CGU_JZ4740) += jz4740-cgu.o obj-$(CONFIG_INGENIC_CGU_JZ4725B) += jz4725b-cgu.o obj-$(CONFIG_INGENIC_CGU_JZ4770) += jz4770-cgu.o obj-$(CONFIG_INGENIC_CGU_JZ4780) += jz4780-cgu.o +obj-$(CONFIG_INGENIC_TCU_CLK) += tcu.o diff --git a/drivers/clk/ingenic/tcu.c b/drivers/clk/ingenic/tcu.c new file mode 100644 index 000000000000..a1a5f9cb439e --- /dev/null +++ b/drivers/clk/ingenic/tcu.c @@ -0,0 +1,474 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * JZ47xx SoCs TCU clocks driver + * Copyright (C) 2019 Paul Cercueil + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* 8 channels max + watchdog + OST */ +#define TCU_CLK_COUNT 10 + +#undef pr_fmt +#define pr_fmt(fmt) "ingenic-tcu-clk: " fmt + +enum tcu_clk_parent { + TCU_PARENT_PCLK, + TCU_PARENT_RTC, + TCU_PARENT_EXT, +}; + +struct ingenic_soc_info { + unsigned int num_channels; + bool has_ost; + bool has_tcu_clk; +}; + +struct ingenic_tcu_clk_info { + struct clk_init_data init_data; + u8 gate_bit; + u8 tcsr_reg; +}; + +struct ingenic_tcu_clk { + struct clk_hw hw; + unsigned int idx; + struct ingenic_tcu *tcu; + const struct ingenic_tcu_clk_info *info; +}; + +struct ingenic_tcu { + const struct ingenic_soc_info *soc_info; + struct regmap *map; + struct clk *clk; + + struct clk_hw_onecell_data *clocks; +}; + +static struct ingenic_tcu *ingenic_tcu; + +static inline struct ingenic_tcu_clk *to_tcu_clk(struct clk_hw *hw) +{ + return container_of(hw, struct ingenic_tcu_clk, hw); +} + +static int ingenic_tcu_enable(struct clk_hw *hw) +{ + struct ingenic_tcu_clk *tcu_clk = to_tcu_clk(hw); + const struct ingenic_tcu_clk_info *info = tcu_clk->info; + struct ingenic_tcu *tcu = tcu_clk->tcu; + + regmap_write(tcu->map, TCU_REG_TSCR, BIT(info->gate_bit)); + + return 0; +} + +static void ingenic_tcu_disable(struct clk_hw *hw) +{ + struct ingenic_tcu_clk *tcu_clk = to_tcu_clk(hw); + const struct ingenic_tcu_clk_info *info = tcu_clk->info; + struct ingenic_tcu *tcu = tcu_clk->tcu; + + regmap_write(tcu->map, TCU_REG_TSSR, BIT(info->gate_bit)); +} + +static int ingenic_tcu_is_enabled(struct clk_hw *hw) +{ + struct ingenic_tcu_clk *tcu_clk = to_tcu_clk(hw); + const struct ingenic_tcu_clk_info *info = tcu_clk->info; + unsigned int value; + + regmap_read(tcu_clk->tcu->map, TCU_REG_TSR, &value); + + return !(value & BIT(info->gate_bit)); +} + +static bool ingenic_tcu_enable_regs(struct clk_hw *hw) +{ + struct ingenic_tcu_clk *tcu_clk = to_tcu_clk(hw); + const struct ingenic_tcu_clk_info *info = tcu_clk->info; + struct ingenic_tcu *tcu = tcu_clk->tcu; + bool enabled = false; + + /* + * If the SoC has no global TCU clock, we must ungate the channel's + * clock to be able to access its registers. + * If we have a TCU clock, it will be enabled automatically as it has + * been attached to the regmap. + */ + if (!tcu->clk) { + enabled = !!ingenic_tcu_is_enabled(hw); + regmap_write(tcu->map, TCU_REG_TSCR, BIT(info->gate_bit)); + } + + return enabled; +} + +static void ingenic_tcu_disable_regs(struct clk_hw *hw) +{ + struct ingenic_tcu_clk *tcu_clk = to_tcu_clk(hw); + const struct ingenic_tcu_clk_info *info = tcu_clk->info; + struct ingenic_tcu *tcu = tcu_clk->tcu; + + if (!tcu->clk) + regmap_write(tcu->map, TCU_REG_TSSR, BIT(info->gate_bit)); +} + +static u8 ingenic_tcu_get_parent(struct clk_hw *hw) +{ + struct ingenic_tcu_clk *tcu_clk = to_tcu_clk(hw); + const struct ingenic_tcu_clk_info *info = tcu_clk->info; + unsigned int val = 0; + int ret; + + ret = regmap_read(tcu_clk->tcu->map, info->tcsr_reg, &val); + WARN_ONCE(ret < 0, "Unable to read TCSR %d", tcu_clk->idx); + + return ffs(val & TCU_TCSR_PARENT_CLOCK_MASK) - 1; +} + +static int ingenic_tcu_set_parent(struct clk_hw *hw, u8 idx) +{ + struct ingenic_tcu_clk *tcu_clk = to_tcu_clk(hw); + const struct ingenic_tcu_clk_info *info = tcu_clk->info; + bool was_enabled; + int ret; + + was_enabled = ingenic_tcu_enable_regs(hw); + + ret = regmap_update_bits(tcu_clk->tcu->map, info->tcsr_reg, + TCU_TCSR_PARENT_CLOCK_MASK, BIT(idx)); + WARN_ONCE(ret < 0, "Unable to update TCSR %d", tcu_clk->idx); + + if (!was_enabled) + ingenic_tcu_disable_regs(hw); + + return 0; +} + +static unsigned long ingenic_tcu_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct ingenic_tcu_clk *tcu_clk = to_tcu_clk(hw); + const struct ingenic_tcu_clk_info *info = tcu_clk->info; + unsigned int prescale; + int ret; + + ret = regmap_read(tcu_clk->tcu->map, info->tcsr_reg, &prescale); + WARN_ONCE(ret < 0, "Unable to read TCSR %d", tcu_clk->idx); + + prescale = (prescale & TCU_TCSR_PRESCALE_MASK) >> TCU_TCSR_PRESCALE_LSB; + + return parent_rate >> (prescale * 2); +} + +static u8 ingenic_tcu_get_prescale(unsigned long rate, unsigned long req_rate) +{ + u8 prescale; + + for (prescale = 0; prescale < 5; prescale++) + if ((rate >> (prescale * 2)) <= req_rate) + return prescale; + + return 5; /* /1024 divider */ +} + +static long ingenic_tcu_round_rate(struct clk_hw *hw, unsigned long req_rate, + unsigned long *parent_rate) +{ + unsigned long rate = *parent_rate; + u8 prescale; + + if (req_rate > rate) + return -EINVAL; + + prescale = ingenic_tcu_get_prescale(rate, req_rate); + + return rate >> (prescale * 2); +} + +static int ingenic_tcu_set_rate(struct clk_hw *hw, unsigned long req_rate, + unsigned long parent_rate) +{ + struct ingenic_tcu_clk *tcu_clk = to_tcu_clk(hw); + const struct ingenic_tcu_clk_info *info = tcu_clk->info; + u8 prescale = ingenic_tcu_get_prescale(parent_rate, req_rate); + bool was_enabled; + int ret; + + was_enabled = ingenic_tcu_enable_regs(hw); + + ret = regmap_update_bits(tcu_clk->tcu->map, info->tcsr_reg, + TCU_TCSR_PRESCALE_MASK, + prescale << TCU_TCSR_PRESCALE_LSB); + WARN_ONCE(ret < 0, "Unable to update TCSR %d", tcu_clk->idx); + + if (!was_enabled) + ingenic_tcu_disable_regs(hw); + + return 0; +} + +static const struct clk_ops ingenic_tcu_clk_ops = { + .get_parent = ingenic_tcu_get_parent, + .set_parent = ingenic_tcu_set_parent, + + .recalc_rate = ingenic_tcu_recalc_rate, + .round_rate = ingenic_tcu_round_rate, + .set_rate = ingenic_tcu_set_rate, + + .enable = ingenic_tcu_enable, + .disable = ingenic_tcu_disable, + .is_enabled = ingenic_tcu_is_enabled, +}; + +static const char * const ingenic_tcu_timer_parents[] = { + [TCU_PARENT_PCLK] = "pclk", + [TCU_PARENT_RTC] = "rtc", + [TCU_PARENT_EXT] = "ext", +}; + +#define DEF_TIMER(_name, _gate_bit, _tcsr) \ + { \ + .init_data = { \ + .name = _name, \ + .parent_names = ingenic_tcu_timer_parents, \ + .num_parents = ARRAY_SIZE(ingenic_tcu_timer_parents),\ + .ops = &ingenic_tcu_clk_ops, \ + .flags = CLK_SET_RATE_UNGATE, \ + }, \ + .gate_bit = _gate_bit, \ + .tcsr_reg = _tcsr, \ + } +static const struct ingenic_tcu_clk_info ingenic_tcu_clk_info[] = { + [TCU_CLK_TIMER0] = DEF_TIMER("timer0", 0, TCU_REG_TCSRc(0)), + [TCU_CLK_TIMER1] = DEF_TIMER("timer1", 1, TCU_REG_TCSRc(1)), + [TCU_CLK_TIMER2] = DEF_TIMER("timer2", 2, TCU_REG_TCSRc(2)), + [TCU_CLK_TIMER3] = DEF_TIMER("timer3", 3, TCU_REG_TCSRc(3)), + [TCU_CLK_TIMER4] = DEF_TIMER("timer4", 4, TCU_REG_TCSRc(4)), + [TCU_CLK_TIMER5] = DEF_TIMER("timer5", 5, TCU_REG_TCSRc(5)), + [TCU_CLK_TIMER6] = DEF_TIMER("timer6", 6, TCU_REG_TCSRc(6)), + [TCU_CLK_TIMER7] = DEF_TIMER("timer7", 7, TCU_REG_TCSRc(7)), +}; + +static const struct ingenic_tcu_clk_info ingenic_tcu_watchdog_clk_info = + DEF_TIMER("wdt", 16, TCU_REG_WDT_TCSR); +static const struct ingenic_tcu_clk_info ingenic_tcu_ost_clk_info = + DEF_TIMER("ost", 15, TCU_REG_OST_TCSR); +#undef DEF_TIMER + +static int __init ingenic_tcu_register_clock(struct ingenic_tcu *tcu, + unsigned int idx, enum tcu_clk_parent parent, + const struct ingenic_tcu_clk_info *info, + struct clk_hw_onecell_data *clocks) +{ + struct ingenic_tcu_clk *tcu_clk; + int err; + + tcu_clk = kzalloc(sizeof(*tcu_clk), GFP_KERNEL); + if (!tcu_clk) + return -ENOMEM; + + tcu_clk->hw.init = &info->init_data; + tcu_clk->idx = idx; + tcu_clk->info = info; + tcu_clk->tcu = tcu; + + /* Reset channel and clock divider, set default parent */ + ingenic_tcu_enable_regs(&tcu_clk->hw); + regmap_update_bits(tcu->map, info->tcsr_reg, 0xffff, BIT(parent)); + ingenic_tcu_disable_regs(&tcu_clk->hw); + + err = clk_hw_register(NULL, &tcu_clk->hw); + if (err) { + kfree(tcu_clk); + return err; + } + + clocks->hws[idx] = &tcu_clk->hw; + + return 0; +} + +static const struct ingenic_soc_info jz4740_soc_info = { + .num_channels = 8, + .has_ost = false, + .has_tcu_clk = true, +}; + +static const struct ingenic_soc_info jz4725b_soc_info = { + .num_channels = 6, + .has_ost = true, + .has_tcu_clk = true, +}; + +static const struct ingenic_soc_info jz4770_soc_info = { + .num_channels = 8, + .has_ost = true, + .has_tcu_clk = false, +}; + +static const struct of_device_id ingenic_tcu_of_match[] __initconst = { + { .compatible = "ingenic,jz4740-tcu", .data = &jz4740_soc_info, }, + { .compatible = "ingenic,jz4725b-tcu", .data = &jz4725b_soc_info, }, + { .compatible = "ingenic,jz4770-tcu", .data = &jz4770_soc_info, }, + { /* sentinel */ } +}; + +static int __init ingenic_tcu_probe(struct device_node *np) +{ + const struct of_device_id *id = of_match_node(ingenic_tcu_of_match, np); + struct ingenic_tcu *tcu; + struct regmap *map; + unsigned int i; + int ret; + + map = device_node_to_regmap(np); + if (IS_ERR(map)) + return PTR_ERR(map); + + tcu = kzalloc(sizeof(*tcu), GFP_KERNEL); + if (!tcu) + return -ENOMEM; + + tcu->map = map; + tcu->soc_info = id->data; + + if (tcu->soc_info->has_tcu_clk) { + tcu->clk = of_clk_get_by_name(np, "tcu"); + if (IS_ERR(tcu->clk)) { + ret = PTR_ERR(tcu->clk); + pr_crit("Cannot get TCU clock\n"); + goto err_free_tcu; + } + + ret = clk_prepare_enable(tcu->clk); + if (ret) { + pr_crit("Unable to enable TCU clock\n"); + goto err_put_clk; + } + } + + tcu->clocks = kzalloc(sizeof(*tcu->clocks) + + sizeof(*tcu->clocks->hws) * TCU_CLK_COUNT, + GFP_KERNEL); + if (!tcu->clocks) { + ret = -ENOMEM; + goto err_clk_disable; + } + + tcu->clocks->num = TCU_CLK_COUNT; + + for (i = 0; i < tcu->soc_info->num_channels; i++) { + ret = ingenic_tcu_register_clock(tcu, i, TCU_PARENT_EXT, + &ingenic_tcu_clk_info[i], + tcu->clocks); + if (ret) { + pr_crit("cannot register clock %d\n", i); + goto err_unregister_timer_clocks; + } + } + + /* + * We set EXT as the default parent clock for all the TCU clocks + * except for the watchdog one, where we set the RTC clock as the + * parent. Since the EXT and PCLK are much faster than the RTC clock, + * the watchdog would kick after a maximum time of 5s, and we might + * want a slower kicking time. + */ + ret = ingenic_tcu_register_clock(tcu, TCU_CLK_WDT, TCU_PARENT_RTC, + &ingenic_tcu_watchdog_clk_info, + tcu->clocks); + if (ret) { + pr_crit("cannot register watchdog clock\n"); + goto err_unregister_timer_clocks; + } + + if (tcu->soc_info->has_ost) { + ret = ingenic_tcu_register_clock(tcu, TCU_CLK_OST, + TCU_PARENT_EXT, + &ingenic_tcu_ost_clk_info, + tcu->clocks); + if (ret) { + pr_crit("cannot register ost clock\n"); + goto err_unregister_watchdog_clock; + } + } + + ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, tcu->clocks); + if (ret) { + pr_crit("cannot add OF clock provider\n"); + goto err_unregister_ost_clock; + } + + ingenic_tcu = tcu; + + return 0; + +err_unregister_ost_clock: + if (tcu->soc_info->has_ost) + clk_hw_unregister(tcu->clocks->hws[i + 1]); +err_unregister_watchdog_clock: + clk_hw_unregister(tcu->clocks->hws[i]); +err_unregister_timer_clocks: + for (i = 0; i < tcu->clocks->num; i++) + if (tcu->clocks->hws[i]) + clk_hw_unregister(tcu->clocks->hws[i]); + kfree(tcu->clocks); +err_clk_disable: + if (tcu->soc_info->has_tcu_clk) + clk_disable_unprepare(tcu->clk); +err_put_clk: + if (tcu->soc_info->has_tcu_clk) + clk_put(tcu->clk); +err_free_tcu: + kfree(tcu); + return ret; +} + +static int __maybe_unused tcu_pm_suspend(void) +{ + struct ingenic_tcu *tcu = ingenic_tcu; + + if (tcu->clk) + clk_disable(tcu->clk); + + return 0; +} + +static void __maybe_unused tcu_pm_resume(void) +{ + struct ingenic_tcu *tcu = ingenic_tcu; + + if (tcu->clk) + clk_enable(tcu->clk); +} + +static struct syscore_ops __maybe_unused tcu_pm_ops = { + .suspend = tcu_pm_suspend, + .resume = tcu_pm_resume, +}; + +static void __init ingenic_tcu_init(struct device_node *np) +{ + int ret = ingenic_tcu_probe(np); + + if (ret) + pr_crit("Failed to initialize TCU clocks: %d\n", ret); + + if (IS_ENABLED(CONFIG_PM_SLEEP)) + register_syscore_ops(&tcu_pm_ops); +} + +CLK_OF_DECLARE_DRIVER(jz4740_cgu, "ingenic,jz4740-tcu", ingenic_tcu_init); +CLK_OF_DECLARE_DRIVER(jz4725b_cgu, "ingenic,jz4725b-tcu", ingenic_tcu_init); +CLK_OF_DECLARE_DRIVER(jz4770_cgu, "ingenic,jz4770-tcu", ingenic_tcu_init); -- cgit v1.2.3 From 9536eba03ec7f64fc65144b1323aef7c5e9aafcd Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 24 Jul 2019 13:16:08 -0400 Subject: irqchip: Add irq-ingenic-tcu driver This driver handles the interrupt controller built in the Timer/Counter Unit (TCU) of the JZ47xx SoCs from Ingenic. Signed-off-by: Paul Cercueil Tested-by: Mathieu Malaterre Tested-by: Artur Rojek Reviewed-by: Thomas Gleixner Acked-by: Marc Zyngier Signed-off-by: Paul Burton Cc: Ralf Baechle Cc: James Hogan Cc: Jonathan Corbet Cc: Lee Jones Cc: Arnd Bergmann Cc: Daniel Lezcano Cc: Michael Turquette Cc: Stephen Boyd Cc: Jason Cooper Cc: Marc Zyngier Cc: Rob Herring Cc: Mark Rutland Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: linux-doc@vger.kernel.org Cc: linux-mips@vger.kernel.org Cc: linux-clk@vger.kernel.org Cc: od@zcrc.me --- drivers/irqchip/Kconfig | 11 +++ drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-ingenic-tcu.c | 182 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 194 insertions(+) create mode 100644 drivers/irqchip/irq-ingenic-tcu.c (limited to 'drivers') diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 80e10f4e213a..3c8308e6b3a7 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -315,6 +315,17 @@ config INGENIC_IRQ depends on MACH_INGENIC default y +config INGENIC_TCU_IRQ + bool "Ingenic JZ47xx TCU interrupt controller" + default MACH_INGENIC + depends on MIPS || COMPILE_TEST + select MFD_SYSCON + help + Support for interrupts in the Timer/Counter Unit (TCU) of the Ingenic + JZ47xx SoCs. + + If unsure, say N. + config RENESAS_H8300H_INTC bool select IRQ_DOMAIN diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 8d0fcec6ab23..cc7c43932f16 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -75,6 +75,7 @@ obj-$(CONFIG_RENESAS_H8300H_INTC) += irq-renesas-h8300h.o obj-$(CONFIG_RENESAS_H8S_INTC) += irq-renesas-h8s.o obj-$(CONFIG_ARCH_SA1100) += irq-sa11x0.o obj-$(CONFIG_INGENIC_IRQ) += irq-ingenic.o +obj-$(CONFIG_INGENIC_TCU_IRQ) += irq-ingenic-tcu.o obj-$(CONFIG_IMX_GPCV2) += irq-imx-gpcv2.o obj-$(CONFIG_PIC32_EVIC) += irq-pic32-evic.o obj-$(CONFIG_MSCC_OCELOT_IRQ) += irq-mscc-ocelot.o diff --git a/drivers/irqchip/irq-ingenic-tcu.c b/drivers/irqchip/irq-ingenic-tcu.c new file mode 100644 index 000000000000..6d05cefe9d79 --- /dev/null +++ b/drivers/irqchip/irq-ingenic-tcu.c @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * JZ47xx SoCs TCU IRQ driver + * Copyright (C) 2019 Paul Cercueil + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct ingenic_tcu { + struct regmap *map; + struct clk *clk; + struct irq_domain *domain; + unsigned int nb_parent_irqs; + u32 parent_irqs[3]; +}; + +static void ingenic_tcu_intc_cascade(struct irq_desc *desc) +{ + struct irq_chip *irq_chip = irq_data_get_irq_chip(&desc->irq_data); + struct irq_domain *domain = irq_desc_get_handler_data(desc); + struct irq_chip_generic *gc = irq_get_domain_generic_chip(domain, 0); + struct regmap *map = gc->private; + uint32_t irq_reg, irq_mask; + unsigned int i; + + regmap_read(map, TCU_REG_TFR, &irq_reg); + regmap_read(map, TCU_REG_TMR, &irq_mask); + + chained_irq_enter(irq_chip, desc); + + irq_reg &= ~irq_mask; + + for_each_set_bit(i, (unsigned long *)&irq_reg, 32) + generic_handle_irq(irq_linear_revmap(domain, i)); + + chained_irq_exit(irq_chip, desc); +} + +static void ingenic_tcu_gc_unmask_enable_reg(struct irq_data *d) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct irq_chip_type *ct = irq_data_get_chip_type(d); + struct regmap *map = gc->private; + u32 mask = d->mask; + + irq_gc_lock(gc); + regmap_write(map, ct->regs.ack, mask); + regmap_write(map, ct->regs.enable, mask); + *ct->mask_cache |= mask; + irq_gc_unlock(gc); +} + +static void ingenic_tcu_gc_mask_disable_reg(struct irq_data *d) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct irq_chip_type *ct = irq_data_get_chip_type(d); + struct regmap *map = gc->private; + u32 mask = d->mask; + + irq_gc_lock(gc); + regmap_write(map, ct->regs.disable, mask); + *ct->mask_cache &= ~mask; + irq_gc_unlock(gc); +} + +static void ingenic_tcu_gc_mask_disable_reg_and_ack(struct irq_data *d) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct irq_chip_type *ct = irq_data_get_chip_type(d); + struct regmap *map = gc->private; + u32 mask = d->mask; + + irq_gc_lock(gc); + regmap_write(map, ct->regs.ack, mask); + regmap_write(map, ct->regs.disable, mask); + irq_gc_unlock(gc); +} + +static int __init ingenic_tcu_irq_init(struct device_node *np, + struct device_node *parent) +{ + struct irq_chip_generic *gc; + struct irq_chip_type *ct; + struct ingenic_tcu *tcu; + struct regmap *map; + unsigned int i; + int ret, irqs; + + map = device_node_to_regmap(np); + if (IS_ERR(map)) + return PTR_ERR(map); + + tcu = kzalloc(sizeof(*tcu), GFP_KERNEL); + if (!tcu) + return -ENOMEM; + + tcu->map = map; + + irqs = of_property_count_elems_of_size(np, "interrupts", sizeof(u32)); + if (irqs < 0 || irqs > ARRAY_SIZE(tcu->parent_irqs)) { + pr_crit("%s: Invalid 'interrupts' property\n", __func__); + ret = -EINVAL; + goto err_free_tcu; + } + + tcu->nb_parent_irqs = irqs; + + tcu->domain = irq_domain_add_linear(np, 32, &irq_generic_chip_ops, + NULL); + if (!tcu->domain) { + ret = -ENOMEM; + goto err_free_tcu; + } + + ret = irq_alloc_domain_generic_chips(tcu->domain, 32, 1, "TCU", + handle_level_irq, 0, + IRQ_NOPROBE | IRQ_LEVEL, 0); + if (ret) { + pr_crit("%s: Invalid 'interrupts' property\n", __func__); + goto out_domain_remove; + } + + gc = irq_get_domain_generic_chip(tcu->domain, 0); + ct = gc->chip_types; + + gc->wake_enabled = IRQ_MSK(32); + gc->private = tcu->map; + + ct->regs.disable = TCU_REG_TMSR; + ct->regs.enable = TCU_REG_TMCR; + ct->regs.ack = TCU_REG_TFCR; + ct->chip.irq_unmask = ingenic_tcu_gc_unmask_enable_reg; + ct->chip.irq_mask = ingenic_tcu_gc_mask_disable_reg; + ct->chip.irq_mask_ack = ingenic_tcu_gc_mask_disable_reg_and_ack; + ct->chip.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE; + + /* Mask all IRQs by default */ + regmap_write(tcu->map, TCU_REG_TMSR, IRQ_MSK(32)); + + /* + * On JZ4740, timer 0 and timer 1 have their own interrupt line; + * timers 2-7 share one interrupt. + * On SoCs >= JZ4770, timer 5 has its own interrupt line; + * timers 0-4 and 6-7 share one single interrupt. + * + * To keep things simple, we just register the same handler to + * all parent interrupts. The handler will properly detect which + * channel fired the interrupt. + */ + for (i = 0; i < irqs; i++) { + tcu->parent_irqs[i] = irq_of_parse_and_map(np, i); + if (!tcu->parent_irqs[i]) { + ret = -EINVAL; + goto out_unmap_irqs; + } + + irq_set_chained_handler_and_data(tcu->parent_irqs[i], + ingenic_tcu_intc_cascade, + tcu->domain); + } + + return 0; + +out_unmap_irqs: + for (; i > 0; i--) + irq_dispose_mapping(tcu->parent_irqs[i - 1]); +out_domain_remove: + irq_domain_remove(tcu->domain); +err_free_tcu: + kfree(tcu); + return ret; +} +IRQCHIP_DECLARE(jz4740_tcu_irq, "ingenic,jz4740-tcu", ingenic_tcu_irq_init); +IRQCHIP_DECLARE(jz4725b_tcu_irq, "ingenic,jz4725b-tcu", ingenic_tcu_irq_init); +IRQCHIP_DECLARE(jz4770_tcu_irq, "ingenic,jz4770-tcu", ingenic_tcu_irq_init); -- cgit v1.2.3 From 34e9368301d534a9c5cded879f277791194fdb31 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 24 Jul 2019 13:16:09 -0400 Subject: clocksource: Add a new timer-ingenic driver This driver handles the TCU (Timer Counter Unit) present on the Ingenic JZ47xx SoCs, and provides the kernel with a system timer, a clocksource and a sched_clock. Signed-off-by: Paul Cercueil Tested-by: Mathieu Malaterre Tested-by: Artur Rojek Reviewed-by: Thomas Gleixner Signed-off-by: Paul Burton Cc: Ralf Baechle Cc: James Hogan Cc: Jonathan Corbet Cc: Lee Jones Cc: Arnd Bergmann Cc: Daniel Lezcano Cc: Michael Turquette Cc: Stephen Boyd Cc: Jason Cooper Cc: Marc Zyngier Cc: Rob Herring Cc: Mark Rutland Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: linux-doc@vger.kernel.org Cc: linux-mips@vger.kernel.org Cc: linux-clk@vger.kernel.org Cc: od@zcrc.me --- drivers/clocksource/Kconfig | 11 ++ drivers/clocksource/Makefile | 1 + drivers/clocksource/ingenic-timer.c | 356 ++++++++++++++++++++++++++++++++++++ 3 files changed, 368 insertions(+) create mode 100644 drivers/clocksource/ingenic-timer.c (limited to 'drivers') diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 5e9317dc3d39..a9cdc2c4f8bd 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -685,4 +685,15 @@ config MILBEAUT_TIMER help Enables the support for Milbeaut timer driver. +config INGENIC_TIMER + bool "Clocksource/timer using the TCU in Ingenic JZ SoCs" + default MACH_INGENIC + depends on MIPS || COMPILE_TEST + depends on COMMON_CLK + select MFD_SYSCON + select TIMER_OF + select IRQ_DOMAIN + help + Support for the timer/counter unit of the Ingenic JZ SoCs. + endmenu diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 2e7936e7833f..4dfe4225ece7 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -80,6 +80,7 @@ obj-$(CONFIG_ASM9260_TIMER) += asm9260_timer.o obj-$(CONFIG_H8300_TMR8) += h8300_timer8.o obj-$(CONFIG_H8300_TMR16) += h8300_timer16.o obj-$(CONFIG_H8300_TPU) += h8300_tpu.o +obj-$(CONFIG_INGENIC_TIMER) += ingenic-timer.o obj-$(CONFIG_CLKSRC_ST_LPC) += clksrc_st_lpc.o obj-$(CONFIG_X86_NUMACHIP) += numachip.o obj-$(CONFIG_ATCPIT100_TIMER) += timer-atcpit100.o diff --git a/drivers/clocksource/ingenic-timer.c b/drivers/clocksource/ingenic-timer.c new file mode 100644 index 000000000000..4bbdb3d3d0c6 --- /dev/null +++ b/drivers/clocksource/ingenic-timer.c @@ -0,0 +1,356 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * JZ47xx SoCs TCU IRQ driver + * Copyright (C) 2019 Paul Cercueil + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +struct ingenic_soc_info { + unsigned int num_channels; +}; + +struct ingenic_tcu { + struct regmap *map; + struct clk *timer_clk, *cs_clk; + unsigned int timer_channel, cs_channel; + struct clock_event_device cevt; + struct clocksource cs; + char name[4]; + unsigned long pwm_channels_mask; +}; + +static struct ingenic_tcu *ingenic_tcu; + +static u64 notrace ingenic_tcu_timer_read(void) +{ + struct ingenic_tcu *tcu = ingenic_tcu; + unsigned int count; + + regmap_read(tcu->map, TCU_REG_TCNTc(tcu->cs_channel), &count); + + return count; +} + +static u64 notrace ingenic_tcu_timer_cs_read(struct clocksource *cs) +{ + return ingenic_tcu_timer_read(); +} + +static inline struct ingenic_tcu *to_ingenic_tcu(struct clock_event_device *evt) +{ + return container_of(evt, struct ingenic_tcu, cevt); +} + +static int ingenic_tcu_cevt_set_state_shutdown(struct clock_event_device *evt) +{ + struct ingenic_tcu *tcu = to_ingenic_tcu(evt); + + regmap_write(tcu->map, TCU_REG_TECR, BIT(tcu->timer_channel)); + + return 0; +} + +static int ingenic_tcu_cevt_set_next(unsigned long next, + struct clock_event_device *evt) +{ + struct ingenic_tcu *tcu = to_ingenic_tcu(evt); + + if (next > 0xffff) + return -EINVAL; + + regmap_write(tcu->map, TCU_REG_TDFRc(tcu->timer_channel), next); + regmap_write(tcu->map, TCU_REG_TCNTc(tcu->timer_channel), 0); + regmap_write(tcu->map, TCU_REG_TESR, BIT(tcu->timer_channel)); + + return 0; +} + +static irqreturn_t ingenic_tcu_cevt_cb(int irq, void *dev_id) +{ + struct clock_event_device *evt = dev_id; + struct ingenic_tcu *tcu = to_ingenic_tcu(evt); + + regmap_write(tcu->map, TCU_REG_TECR, BIT(tcu->timer_channel)); + + if (evt->event_handler) + evt->event_handler(evt); + + return IRQ_HANDLED; +} + +static struct clk * __init ingenic_tcu_get_clock(struct device_node *np, int id) +{ + struct of_phandle_args args; + + args.np = np; + args.args_count = 1; + args.args[0] = id; + + return of_clk_get_from_provider(&args); +} + +static int __init ingenic_tcu_timer_init(struct device_node *np, + struct ingenic_tcu *tcu) +{ + unsigned int timer_virq, channel = tcu->timer_channel; + struct irq_domain *domain; + unsigned long rate; + int err; + + tcu->timer_clk = ingenic_tcu_get_clock(np, channel); + if (IS_ERR(tcu->timer_clk)) + return PTR_ERR(tcu->timer_clk); + + err = clk_prepare_enable(tcu->timer_clk); + if (err) + goto err_clk_put; + + rate = clk_get_rate(tcu->timer_clk); + if (!rate) { + err = -EINVAL; + goto err_clk_disable; + } + + domain = irq_find_host(np); + if (!domain) { + err = -ENODEV; + goto err_clk_disable; + } + + timer_virq = irq_create_mapping(domain, channel); + if (!timer_virq) { + err = -EINVAL; + goto err_clk_disable; + } + + snprintf(tcu->name, sizeof(tcu->name), "TCU"); + + err = request_irq(timer_virq, ingenic_tcu_cevt_cb, IRQF_TIMER, + tcu->name, &tcu->cevt); + if (err) + goto err_irq_dispose_mapping; + + tcu->cevt.cpumask = cpumask_of(smp_processor_id()); + tcu->cevt.features = CLOCK_EVT_FEAT_ONESHOT; + tcu->cevt.name = tcu->name; + tcu->cevt.rating = 200; + tcu->cevt.set_state_shutdown = ingenic_tcu_cevt_set_state_shutdown; + tcu->cevt.set_next_event = ingenic_tcu_cevt_set_next; + + clockevents_config_and_register(&tcu->cevt, rate, 10, 0xffff); + + return 0; + +err_irq_dispose_mapping: + irq_dispose_mapping(timer_virq); +err_clk_disable: + clk_disable_unprepare(tcu->timer_clk); +err_clk_put: + clk_put(tcu->timer_clk); + return err; +} + +static int __init ingenic_tcu_clocksource_init(struct device_node *np, + struct ingenic_tcu *tcu) +{ + unsigned int channel = tcu->cs_channel; + struct clocksource *cs = &tcu->cs; + unsigned long rate; + int err; + + tcu->cs_clk = ingenic_tcu_get_clock(np, channel); + if (IS_ERR(tcu->cs_clk)) + return PTR_ERR(tcu->cs_clk); + + err = clk_prepare_enable(tcu->cs_clk); + if (err) + goto err_clk_put; + + rate = clk_get_rate(tcu->cs_clk); + if (!rate) { + err = -EINVAL; + goto err_clk_disable; + } + + /* Reset channel */ + regmap_update_bits(tcu->map, TCU_REG_TCSRc(channel), + 0xffff & ~TCU_TCSR_RESERVED_BITS, 0); + + /* Reset counter */ + regmap_write(tcu->map, TCU_REG_TDFRc(channel), 0xffff); + regmap_write(tcu->map, TCU_REG_TCNTc(channel), 0); + + /* Enable channel */ + regmap_write(tcu->map, TCU_REG_TESR, BIT(channel)); + + cs->name = "ingenic-timer"; + cs->rating = 200; + cs->flags = CLOCK_SOURCE_IS_CONTINUOUS; + cs->mask = CLOCKSOURCE_MASK(16); + cs->read = ingenic_tcu_timer_cs_read; + + err = clocksource_register_hz(cs, rate); + if (err) + goto err_clk_disable; + + return 0; + +err_clk_disable: + clk_disable_unprepare(tcu->cs_clk); +err_clk_put: + clk_put(tcu->cs_clk); + return err; +} + +static const struct ingenic_soc_info jz4740_soc_info = { + .num_channels = 8, +}; + +static const struct ingenic_soc_info jz4725b_soc_info = { + .num_channels = 6, +}; + +static const struct of_device_id ingenic_tcu_of_match[] = { + { .compatible = "ingenic,jz4740-tcu", .data = &jz4740_soc_info, }, + { .compatible = "ingenic,jz4725b-tcu", .data = &jz4725b_soc_info, }, + { .compatible = "ingenic,jz4770-tcu", .data = &jz4740_soc_info, }, + { /* sentinel */ } +}; + +static int __init ingenic_tcu_init(struct device_node *np) +{ + const struct of_device_id *id = of_match_node(ingenic_tcu_of_match, np); + const struct ingenic_soc_info *soc_info = id->data; + struct ingenic_tcu *tcu; + struct regmap *map; + long rate; + int ret; + + of_node_clear_flag(np, OF_POPULATED); + + map = device_node_to_regmap(np); + if (IS_ERR(map)) + return PTR_ERR(map); + + tcu = kzalloc(sizeof(*tcu), GFP_KERNEL); + if (!tcu) + return -ENOMEM; + + /* Enable all TCU channels for PWM use by default except channels 0/1 */ + tcu->pwm_channels_mask = GENMASK(soc_info->num_channels - 1, 2); + of_property_read_u32(np, "ingenic,pwm-channels-mask", + (u32 *)&tcu->pwm_channels_mask); + + /* Verify that we have at least two free channels */ + if (hweight8(tcu->pwm_channels_mask) > soc_info->num_channels - 2) { + pr_crit("%s: Invalid PWM channel mask: 0x%02lx\n", __func__, + tcu->pwm_channels_mask); + ret = -EINVAL; + goto err_free_ingenic_tcu; + } + + tcu->map = map; + ingenic_tcu = tcu; + + tcu->timer_channel = find_first_zero_bit(&tcu->pwm_channels_mask, + soc_info->num_channels); + tcu->cs_channel = find_next_zero_bit(&tcu->pwm_channels_mask, + soc_info->num_channels, + tcu->timer_channel + 1); + + ret = ingenic_tcu_clocksource_init(np, tcu); + if (ret) { + pr_crit("%s: Unable to init clocksource: %d\n", __func__, ret); + goto err_free_ingenic_tcu; + } + + ret = ingenic_tcu_timer_init(np, tcu); + if (ret) + goto err_tcu_clocksource_cleanup; + + /* Register the sched_clock at the end as there's no way to undo it */ + rate = clk_get_rate(tcu->cs_clk); + sched_clock_register(ingenic_tcu_timer_read, 16, rate); + + return 0; + +err_tcu_clocksource_cleanup: + clocksource_unregister(&tcu->cs); + clk_disable_unprepare(tcu->cs_clk); + clk_put(tcu->cs_clk); +err_free_ingenic_tcu: + kfree(tcu); + return ret; +} + +TIMER_OF_DECLARE(jz4740_tcu_intc, "ingenic,jz4740-tcu", ingenic_tcu_init); +TIMER_OF_DECLARE(jz4725b_tcu_intc, "ingenic,jz4725b-tcu", ingenic_tcu_init); +TIMER_OF_DECLARE(jz4770_tcu_intc, "ingenic,jz4770-tcu", ingenic_tcu_init); + + +static int __init ingenic_tcu_probe(struct platform_device *pdev) +{ + platform_set_drvdata(pdev, ingenic_tcu); + + return 0; +} + +static int __maybe_unused ingenic_tcu_suspend(struct device *dev) +{ + struct ingenic_tcu *tcu = dev_get_drvdata(dev); + + clk_disable(tcu->cs_clk); + clk_disable(tcu->timer_clk); + return 0; +} + +static int __maybe_unused ingenic_tcu_resume(struct device *dev) +{ + struct ingenic_tcu *tcu = dev_get_drvdata(dev); + int ret; + + ret = clk_enable(tcu->timer_clk); + if (ret) + return ret; + + ret = clk_enable(tcu->cs_clk); + if (ret) { + clk_disable(tcu->timer_clk); + return ret; + } + + return 0; +} + +static const struct dev_pm_ops __maybe_unused ingenic_tcu_pm_ops = { + /* _noirq: We want the TCU clocks to be gated last / ungated first */ + .suspend_noirq = ingenic_tcu_suspend, + .resume_noirq = ingenic_tcu_resume, +}; + +static struct platform_driver ingenic_tcu_driver = { + .driver = { + .name = "ingenic-tcu-timer", +#ifdef CONFIG_PM_SLEEP + .pm = &ingenic_tcu_pm_ops, +#endif + .of_match_table = ingenic_tcu_of_match, + }, +}; +builtin_platform_driver_probe(ingenic_tcu_driver, ingenic_tcu_probe); -- cgit v1.2.3 From 73dd11dc1a883d4c994d729dc9984f4890001157 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 24 Jul 2019 13:16:10 -0400 Subject: clk: jz4740: Add TCU clock Add the missing TCU clock to the list of clocks supplied by the CGU for the JZ4740 SoC. Signed-off-by: Paul Cercueil Tested-by: Mathieu Malaterre Tested-by: Artur Rojek Acked-by: Stephen Boyd Acked-by: Rob Herring Signed-off-by: Paul Burton Cc: Ralf Baechle Cc: James Hogan Cc: Jonathan Corbet Cc: Lee Jones Cc: Arnd Bergmann Cc: Daniel Lezcano Cc: Thomas Gleixner Cc: Michael Turquette Cc: Jason Cooper Cc: Marc Zyngier Cc: Rob Herring Cc: Mark Rutland Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: linux-doc@vger.kernel.org Cc: linux-mips@vger.kernel.org Cc: linux-clk@vger.kernel.org Cc: od@zcrc.me --- drivers/clk/ingenic/jz4740-cgu.c | 6 ++++++ include/dt-bindings/clock/jz4740-cgu.h | 1 + 2 files changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/ingenic/jz4740-cgu.c b/drivers/clk/ingenic/jz4740-cgu.c index 4c0a20949c2c..67f8a0e14284 100644 --- a/drivers/clk/ingenic/jz4740-cgu.c +++ b/drivers/clk/ingenic/jz4740-cgu.c @@ -222,6 +222,12 @@ static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = { .parents = { JZ4740_CLK_EXT, -1, -1, -1 }, .gate = { CGU_REG_CLKGR, 5 }, }, + + [JZ4740_CLK_TCU] = { + "tcu", CGU_CLK_GATE, + .parents = { JZ4740_CLK_EXT, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR, 1 }, + }, }; static void __init jz4740_cgu_init(struct device_node *np) diff --git a/include/dt-bindings/clock/jz4740-cgu.h b/include/dt-bindings/clock/jz4740-cgu.h index 6ed83f926ae7..e82d77028581 100644 --- a/include/dt-bindings/clock/jz4740-cgu.h +++ b/include/dt-bindings/clock/jz4740-cgu.h @@ -34,5 +34,6 @@ #define JZ4740_CLK_ADC 19 #define JZ4740_CLK_I2C 20 #define JZ4740_CLK_AIC 21 +#define JZ4740_CLK_TCU 22 #endif /* __DT_BINDINGS_CLOCK_JZ4740_CGU_H__ */ -- cgit v1.2.3 From 8084499bd7d44b2c96658d788e329f3c232eb050 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 13 Aug 2019 09:56:02 +0800 Subject: irqchip/irq-ingenic-tcu: Fix COMPILE_TEST building While do COMPILE_TEST building, if GENERIC_IRQ_CHIP is not selected, it fails: drivers/irqchip/irq-ingenic-tcu.o: In function `ingenic_tcu_intc_cascade': irq-ingenic-tcu.c:(.text+0x13f): undefined reference to `irq_get_domain_generic_chip' drivers/irqchip/irq-ingenic-tcu.o: In function `ingenic_tcu_irq_init': irq-ingenic-tcu.c:(.init.text+0x97): undefined reference to `irq_generic_chip_ops' irq-ingenic-tcu.c:(.init.text+0xdd): undefined reference to `__irq_alloc_domain_generic_chips' irq-ingenic-tcu.c:(.init.text+0x10b): undefined reference to `irq_get_domain_generic_chip' select GENERIC_IRQ_CHIP to fix this. Reported-by: Hulk Robot Fixes: 9536eba03ec7 ("irqchip: Add irq-ingenic-tcu driver") Signed-off-by: YueHaibing Acked-by: Thomas Gleixner Signed-off-by: Paul Burton Cc: Cc: Cc: Cc: Cc: Cc: Cc: --- drivers/irqchip/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 3c8308e6b3a7..ccbb8973a324 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -320,6 +320,7 @@ config INGENIC_TCU_IRQ default MACH_INGENIC depends on MIPS || COMPILE_TEST select MFD_SYSCON + select GENERIC_IRQ_CHIP help Support for interrupts in the Timer/Counter Unit (TCU) of the Ingenic JZ47xx SoCs. -- cgit v1.2.3 From feb4eb060c3aecc3c5076bebe699cd09f1133c41 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 14 May 2019 10:38:14 -0700 Subject: firmware: bcm47xx_nvram: Correct size_t printf format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When building on a 64-bit host, we will get warnings like those: drivers/firmware/broadcom/bcm47xx_nvram.c:103:3: note: in expansion of macro 'pr_err' pr_err("nvram on flash (%i bytes) is bigger than the reserved space in memory, will just copy the first %i bytes\n", ^~~~~~ drivers/firmware/broadcom/bcm47xx_nvram.c:103:28: note: format string is defined here pr_err("nvram on flash (%i bytes) is bigger than the reserved space in memory, will just copy the first %i bytes\n", ~^ %li Use %zu instead for that purpose. Signed-off-by: Florian Fainelli Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: joe@perches.com Cc: Rafał Miłecki Cc: linux-mips@vger.kernel.org Cc: linux-kernel@vger.kernel.org --- drivers/firmware/broadcom/bcm47xx_nvram.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/firmware/broadcom/bcm47xx_nvram.c b/drivers/firmware/broadcom/bcm47xx_nvram.c index 77eb74666ecb..6d2820f6aca1 100644 --- a/drivers/firmware/broadcom/bcm47xx_nvram.c +++ b/drivers/firmware/broadcom/bcm47xx_nvram.c @@ -96,7 +96,7 @@ found: nvram_len = size; } if (nvram_len >= NVRAM_SPACE) { - pr_err("nvram on flash (%i bytes) is bigger than the reserved space in memory, will just copy the first %i bytes\n", + pr_err("nvram on flash (%zu bytes) is bigger than the reserved space in memory, will just copy the first %i bytes\n", nvram_len, NVRAM_SPACE - 1); nvram_len = NVRAM_SPACE - 1; } @@ -148,7 +148,7 @@ static int nvram_init(void) header.len > sizeof(header)) { nvram_len = header.len; if (nvram_len >= NVRAM_SPACE) { - pr_err("nvram on flash (%i bytes) is bigger than the reserved space in memory, will just copy the first %i bytes\n", + pr_err("nvram on flash (%zu bytes) is bigger than the reserved space in memory, will just copy the first %i bytes\n", header.len, NVRAM_SPACE); nvram_len = NVRAM_SPACE - 1; } -- cgit v1.2.3 From 5699ad0aaf1091824f22492a708478912c38c7d2 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 14 May 2019 10:38:15 -0700 Subject: firmware: bcm47xx_nvram: Allow COMPILE_TEST MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow building building the BCM47xx NVRAM and SPROM drivers using COMPILE_TEST. Signed-off-by: Florian Fainelli Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: joe@perches.com Cc: Rafał Miłecki Cc: linux-mips@vger.kernel.org Cc: linux-kernel@vger.kernel.org --- drivers/firmware/broadcom/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/firmware/broadcom/Kconfig b/drivers/firmware/broadcom/Kconfig index 64680824f984..d03ed8e43ad7 100644 --- a/drivers/firmware/broadcom/Kconfig +++ b/drivers/firmware/broadcom/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config BCM47XX_NVRAM bool "Broadcom NVRAM driver" - depends on BCM47XX || ARCH_BCM_5301X + depends on BCM47XX || ARCH_BCM_5301X || COMPILE_TEST help Broadcom home routers contain flash partition called "nvram" with all important hardware configuration as well as some minor user setup. -- cgit v1.2.3