diff options
Diffstat (limited to 'drivers/staging/most')
-rw-r--r-- | drivers/staging/most/cdev/cdev.c | 16 | ||||
-rw-r--r-- | drivers/staging/most/core.c | 68 | ||||
-rw-r--r-- | drivers/staging/most/core.h | 4 | ||||
-rw-r--r-- | drivers/staging/most/dim2/Kconfig | 2 | ||||
-rw-r--r-- | drivers/staging/most/dim2/dim2.c | 397 | ||||
-rw-r--r-- | drivers/staging/most/dim2/dim2.h | 21 | ||||
-rw-r--r-- | drivers/staging/most/dim2/hal.c | 9 | ||||
-rw-r--r-- | drivers/staging/most/dim2/reg.h | 84 | ||||
-rw-r--r-- | drivers/staging/most/i2c/i2c.c | 140 | ||||
-rw-r--r-- | drivers/staging/most/sound/sound.c | 123 | ||||
-rw-r--r-- | drivers/staging/most/usb/usb.c | 55 | ||||
-rw-r--r-- | drivers/staging/most/video/video.c | 32 |
12 files changed, 561 insertions, 390 deletions
diff --git a/drivers/staging/most/cdev/cdev.c b/drivers/staging/most/cdev/cdev.c index 4d7fce8731fe..4569838f27a0 100644 --- a/drivers/staging/most/cdev/cdev.c +++ b/drivers/staging/most/cdev/cdev.c @@ -18,6 +18,8 @@ #include <linux/idr.h> #include "most/core.h" +#define CHRDEV_REGION_SIZE 50 + static struct cdev_component { dev_t devno; struct ida minor_id; @@ -51,7 +53,7 @@ static inline bool ch_has_mbo(struct comp_channel *c) return channel_has_mbo(c->iface, c->channel_id, &comp.cc) > 0; } -static inline bool ch_get_mbo(struct comp_channel *c, struct mbo **mbo) +static inline struct mbo *ch_get_mbo(struct comp_channel *c, struct mbo **mbo) { if (!kfifo_peek(&c->fifo, mbo)) { *mbo = most_get_mbo(c->iface, c->channel_id, &comp.cc); @@ -242,7 +244,7 @@ static ssize_t comp_read(struct file *filp, char __user *buf, size_t count, loff_t *offset) { size_t to_copy, not_copied, copied; - struct mbo *mbo; + struct mbo *mbo = NULL; struct comp_channel *c = filp->private_data; mutex_lock(&c->io_mutex); @@ -290,13 +292,15 @@ static __poll_t comp_poll(struct file *filp, poll_table *wait) poll_wait(filp, &c->wq, wait); + mutex_lock(&c->io_mutex); if (c->cfg->direction == MOST_CH_RX) { - if (!kfifo_is_empty(&c->fifo)) + if (!c->dev || !kfifo_is_empty(&c->fifo)) mask |= EPOLLIN | EPOLLRDNORM; } else { - if (!kfifo_is_empty(&c->fifo) || ch_has_mbo(c)) + if (!c->dev || !kfifo_is_empty(&c->fifo) || ch_has_mbo(c)) mask |= EPOLLOUT | EPOLLWRNORM; } + mutex_unlock(&c->io_mutex); return mask; } @@ -513,7 +517,7 @@ static int __init mod_init(void) spin_lock_init(&ch_list_lock); ida_init(&comp.minor_id); - err = alloc_chrdev_region(&comp.devno, 0, 50, "cdev"); + err = alloc_chrdev_region(&comp.devno, 0, CHRDEV_REGION_SIZE, "cdev"); if (err < 0) goto dest_ida; comp.major = MAJOR(comp.devno); @@ -523,7 +527,7 @@ static int __init mod_init(void) return 0; free_cdev: - unregister_chrdev_region(comp.devno, 1); + unregister_chrdev_region(comp.devno, CHRDEV_REGION_SIZE); dest_ida: ida_destroy(&comp.minor_id); class_destroy(comp.class); diff --git a/drivers/staging/most/core.c b/drivers/staging/most/core.c index 8f2833526f7f..f4c464625a67 100644 --- a/drivers/staging/most/core.c +++ b/drivers/staging/most/core.c @@ -111,8 +111,10 @@ static void most_free_mbo_coherent(struct mbo *mbo) struct most_channel *c = mbo->context; u16 const coherent_buf_size = c->cfg.buffer_size + c->cfg.extra_len; - dma_free_coherent(NULL, coherent_buf_size, mbo->virt_address, - mbo->bus_address); + if (c->iface->dma_free) + c->iface->dma_free(mbo, coherent_buf_size); + else + kfree(mbo->virt_address); kfree(mbo); if (atomic_sub_and_test(1, &c->mbo_ref)) complete(&c->cleanup); @@ -420,6 +422,26 @@ static ssize_t set_packets_per_xact_store(struct device *dev, return count; } +static ssize_t set_dbr_size_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct most_channel *c = to_channel(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", c->cfg.dbr_size); +} + +static ssize_t set_dbr_size_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct most_channel *c = to_channel(dev); + int ret = kstrtou16(buf, 0, &c->cfg.dbr_size); + + if (ret) + return ret; + return count; +} + #define DEV_ATTR(_name) (&dev_attr_##_name.attr) static DEVICE_ATTR_RO(available_directions); @@ -435,6 +457,7 @@ static DEVICE_ATTR_RW(set_direction); static DEVICE_ATTR_RW(set_datatype); static DEVICE_ATTR_RW(set_subbuffer_size); static DEVICE_ATTR_RW(set_packets_per_xact); +static DEVICE_ATTR_RW(set_dbr_size); static struct attribute *channel_attrs[] = { DEV_ATTR(available_directions), @@ -450,6 +473,7 @@ static struct attribute *channel_attrs[] = { DEV_ATTR(set_datatype), DEV_ATTR(set_subbuffer_size), DEV_ATTR(set_packets_per_xact), + DEV_ATTR(set_dbr_size), NULL, }; @@ -952,45 +976,49 @@ static int arm_mbo_chain(struct most_channel *c, int dir, void (*compl)(struct mbo *)) { unsigned int i; - int retval; struct mbo *mbo; + unsigned long flags; u32 coherent_buf_size = c->cfg.buffer_size + c->cfg.extra_len; atomic_set(&c->mbo_nq_level, 0); for (i = 0; i < c->cfg.num_buffers; i++) { mbo = kzalloc(sizeof(*mbo), GFP_KERNEL); - if (!mbo) { - retval = i; - goto _exit; - } + if (!mbo) + goto flush_fifos; + mbo->context = c; mbo->ifp = c->iface; mbo->hdm_channel_id = c->channel_id; - mbo->virt_address = dma_alloc_coherent(NULL, - coherent_buf_size, - &mbo->bus_address, - GFP_KERNEL); - if (!mbo->virt_address) { - pr_info("WARN: No DMA coherent buffer.\n"); - retval = i; - goto _error1; + if (c->iface->dma_alloc) { + mbo->virt_address = + c->iface->dma_alloc(mbo, coherent_buf_size); + } else { + mbo->virt_address = + kzalloc(coherent_buf_size, GFP_KERNEL); } + if (!mbo->virt_address) + goto release_mbo; + mbo->complete = compl; mbo->num_buffers_ptr = &dummy_num_buffers; if (dir == MOST_CH_RX) { nq_hdm_mbo(mbo); atomic_inc(&c->mbo_nq_level); } else { - arm_mbo(mbo); + spin_lock_irqsave(&c->fifo_lock, flags); + list_add_tail(&mbo->list, &c->fifo); + spin_unlock_irqrestore(&c->fifo_lock, flags); } } - return i; + return c->cfg.num_buffers; -_error1: +release_mbo: kfree(mbo); -_exit: - return retval; + +flush_fifos: + flush_channel_fifos(c); + return 0; } /** diff --git a/drivers/staging/most/core.h b/drivers/staging/most/core.h index 884bd71fafce..64cc02f161e7 100644 --- a/drivers/staging/most/core.h +++ b/drivers/staging/most/core.h @@ -128,6 +128,7 @@ struct most_channel_config { u16 extra_len; u16 subbuffer_size; u16 packets_per_xact; + u16 dbr_size; }; /* @@ -229,11 +230,14 @@ struct mbo { */ struct most_interface { struct device dev; + struct device *driver_dev; struct module *mod; enum most_interface_type interface; const char *description; unsigned int num_channels; struct most_channel_capability *channel_vector; + void *(*dma_alloc)(struct mbo *mbo, u32 size); + void (*dma_free)(struct mbo *mbo, u32 size); int (*configure)(struct most_interface *iface, int channel_idx, struct most_channel_config *channel_config); int (*enqueue)(struct most_interface *iface, int channel_idx, diff --git a/drivers/staging/most/dim2/Kconfig b/drivers/staging/most/dim2/Kconfig index e39c4e525cac..5aeef22c3cba 100644 --- a/drivers/staging/most/dim2/Kconfig +++ b/drivers/staging/most/dim2/Kconfig @@ -4,7 +4,7 @@ config MOST_DIM2 tristate "DIM2" - depends on HAS_IOMEM + depends on HAS_IOMEM && OF ---help--- Say Y here if you want to connect via MediaLB to network transceiver. diff --git a/drivers/staging/most/dim2/dim2.c b/drivers/staging/most/dim2/dim2.c index f9bc7dea75b8..fe90a7cb56f7 100644 --- a/drivers/staging/most/dim2/dim2.c +++ b/drivers/staging/most/dim2/dim2.c @@ -8,6 +8,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/module.h> +#include <linux/of_platform.h> #include <linux/printk.h> #include <linux/kernel.h> #include <linux/init.h> @@ -15,13 +16,13 @@ #include <linux/interrupt.h> #include <linux/slab.h> #include <linux/io.h> +#include <linux/clk.h> #include <linux/dma-mapping.h> #include <linux/sched.h> #include <linux/kthread.h> #include "most/core.h" #include "hal.h" -#include "dim2.h" #include "errors.h" #include "sysfs.h" @@ -32,11 +33,6 @@ #define MAX_BUF_SIZE_PACKET 2048 #define MAX_BUF_SIZE_STREAMING (8 * 1024) -/* command line parameter to select clock speed */ -static char *clock_speed; -module_param(clock_speed, charp, 0000); -MODULE_PARM_DESC(clock_speed, "MediaLB Clock Speed"); - /* * The parameter representing the number of frames per sub-buffer for * synchronous channels. Valid values: [0 .. 6]. @@ -66,6 +62,7 @@ struct hdm_channel { char name[sizeof "caNNN"]; bool is_initialized; struct dim_channel ch; + u16 *reset_dbr_size; struct list_head pending_list; /* before dim_enqueue_buffer() */ struct list_head started_list; /* after dim_enqueue_buffer() */ enum most_channel_direction direction; @@ -78,7 +75,6 @@ struct hdm_channel { * @most_iface: most interface structure * @capabilities: an array of channel capability data * @io_base: I/O register base address - * @clk_speed: user selectable (through command line parameter) clock speed * @netinfo_task: thread to deliver network status * @netinfo_waitq: waitq for the thread to sleep * @deliver_netinfo: to identify whether network status received @@ -93,7 +89,9 @@ struct dim2_hdm { struct most_interface most_iface; char name[16 + sizeof "dim2-"]; void __iomem *io_base; - int clk_speed; + u8 clk_speed; + struct clk *clk; + struct clk *clk_pll; struct task_struct *netinfo_task; wait_queue_head_t netinfo_waitq; int deliver_netinfo; @@ -103,6 +101,12 @@ struct dim2_hdm { struct medialb_bus bus; void (*on_netinfo)(struct most_interface *most_iface, unsigned char link_state, unsigned char *addrs); + void (*disable_platform)(struct platform_device *); +}; + +struct dim2_platform_data { + int (*enable)(struct platform_device *); + void (*disable)(struct platform_device *); }; #define iface_to_hdm(iface) container_of(iface, struct dim2_hdm, most_iface) @@ -156,65 +160,6 @@ void dimcb_on_error(u8 error_id, const char *error_message) } /** - * startup_dim - initialize the dim2 interface - * @pdev: platform device - * - * Get the value of command line parameter "clock_speed" if given or use the - * default value, enable the clock and PLL, and initialize the dim2 interface. - */ -static int startup_dim(struct platform_device *pdev) -{ - struct dim2_hdm *dev = platform_get_drvdata(pdev); - struct dim2_platform_data *pdata = pdev->dev.platform_data; - u8 hal_ret; - - dev->clk_speed = -1; - - if (clock_speed) { - if (!strcmp(clock_speed, "256fs")) - dev->clk_speed = CLK_256FS; - else if (!strcmp(clock_speed, "512fs")) - dev->clk_speed = CLK_512FS; - else if (!strcmp(clock_speed, "1024fs")) - dev->clk_speed = CLK_1024FS; - else if (!strcmp(clock_speed, "2048fs")) - dev->clk_speed = CLK_2048FS; - else if (!strcmp(clock_speed, "3072fs")) - dev->clk_speed = CLK_3072FS; - else if (!strcmp(clock_speed, "4096fs")) - dev->clk_speed = CLK_4096FS; - else if (!strcmp(clock_speed, "6144fs")) - dev->clk_speed = CLK_6144FS; - else if (!strcmp(clock_speed, "8192fs")) - dev->clk_speed = CLK_8192FS; - } - - if (dev->clk_speed == -1) { - pr_info("Bad or missing clock speed parameter, using default value: 3072fs\n"); - dev->clk_speed = CLK_3072FS; - } else { - pr_info("Selected clock speed: %s\n", clock_speed); - } - if (pdata && pdata->init) { - int ret = pdata->init(pdata, dev->io_base, dev->clk_speed); - - if (ret) - return ret; - } - - pr_info("sync: num of frames per sub-buffer: %u\n", fcnt); - hal_ret = dim_startup(dev->io_base, dev->clk_speed, fcnt); - if (hal_ret != DIM_NO_ERROR) { - pr_err("dim_startup failed: %d\n", hal_ret); - if (pdata && pdata->destroy) - pdata->destroy(pdata); - return -ENODEV; - } - - return 0; -} - -/** * try_start_dim_transfer - try to transfer a buffer on a channel * @hdm_ch: channel specific data * @@ -528,6 +473,12 @@ static int configure_channel(struct most_interface *most_iface, int ch_idx, if (hdm_ch->is_initialized) return -EPERM; + /* do not reset if the property was set by user, see poison_channel */ + hdm_ch->reset_dbr_size = ccfg->dbr_size ? NULL : &ccfg->dbr_size; + + /* zero value is default dbr_size, see dim2 hal */ + hdm_ch->ch.dbr_size = ccfg->dbr_size; + switch (ccfg->data_type) { case MOST_CH_CONTROL: new_size = dim_norm_ctrl_async_buffer_size(buf_size); @@ -608,6 +559,7 @@ static int configure_channel(struct most_interface *most_iface, int ch_idx, dev->atx_idx = ch_idx; spin_unlock_irqrestore(&dim_lock, flags); + ccfg->dbr_size = hdm_ch->ch.dbr_size; return 0; } @@ -723,10 +675,64 @@ static int poison_channel(struct most_interface *most_iface, int ch_idx) complete_all_mbos(&hdm_ch->started_list); complete_all_mbos(&hdm_ch->pending_list); + if (hdm_ch->reset_dbr_size) + *hdm_ch->reset_dbr_size = 0; return ret; } +static void *dma_alloc(struct mbo *mbo, u32 size) +{ + struct device *dev = mbo->ifp->driver_dev; + + return dma_alloc_coherent(dev, size, &mbo->bus_address, GFP_KERNEL); +} + +static void dma_free(struct mbo *mbo, u32 size) +{ + struct device *dev = mbo->ifp->driver_dev; + + dma_free_coherent(dev, size, mbo->virt_address, mbo->bus_address); +} + +static const struct of_device_id dim2_of_match[]; + +static struct { + const char *clock_speed; + u8 clk_speed; +} clk_mt[] = { + { "256fs", CLK_256FS }, + { "512fs", CLK_512FS }, + { "1024fs", CLK_1024FS }, + { "2048fs", CLK_2048FS }, + { "3072fs", CLK_3072FS }, + { "4096fs", CLK_4096FS }, + { "6144fs", CLK_6144FS }, + { "8192fs", CLK_8192FS }, +}; + +/** + * get_dim2_clk_speed - converts string to DIM2 clock speed value + * + * @clock_speed: string in the format "{NUMBER}fs" + * @val: pointer to get one of the CLK_{NUMBER}FS values + * + * By success stores one of the CLK_{NUMBER}FS in the *val and returns 0, + * otherwise returns -EINVAL. + */ +static int get_dim2_clk_speed(const char *clock_speed, u8 *val) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(clk_mt); i++) { + if (!strcmp(clock_speed, clk_mt[i].clock_speed)) { + *val = clk_mt[i].clk_speed; + return 0; + } + } + return -EINVAL; +} + /* * dim2_probe - dim2 probe handler * @pdev: platform device structure @@ -736,11 +742,17 @@ static int poison_channel(struct most_interface *most_iface, int ch_idx) */ static int dim2_probe(struct platform_device *pdev) { + const struct dim2_platform_data *pdata; + const struct of_device_id *of_id; + const char *clock_speed; struct dim2_hdm *dev; struct resource *res; int ret, i; + u8 hal_ret; int irq; + enum { MLB_INT_IDX, AHB0_INT_IDX }; + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; @@ -748,43 +760,77 @@ static int dim2_probe(struct platform_device *pdev) dev->atx_idx = -1; platform_set_drvdata(pdev, dev); + + ret = of_property_read_string(pdev->dev.of_node, + "microchip,clock-speed", &clock_speed); + if (ret) { + dev_err(&pdev->dev, "missing dt property clock-speed\n"); + return ret; + } + + ret = get_dim2_clk_speed(clock_speed, &dev->clk_speed); + if (ret) { + dev_err(&pdev->dev, "bad dt property clock-speed\n"); + return ret; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); dev->io_base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(dev->io_base)) return PTR_ERR(dev->io_base); - irq = platform_get_irq(pdev, 0); + of_id = of_match_node(dim2_of_match, pdev->dev.of_node); + pdata = of_id->data; + ret = pdata && pdata->enable ? pdata->enable(pdev) : 0; + if (ret) + return ret; + + dev->disable_platform = pdata ? pdata->disable : 0; + + dev_info(&pdev->dev, "sync: num of frames per sub-buffer: %u\n", fcnt); + hal_ret = dim_startup(dev->io_base, dev->clk_speed, fcnt); + if (hal_ret != DIM_NO_ERROR) { + dev_err(&pdev->dev, "dim_startup failed: %d\n", hal_ret); + ret = -ENODEV; + goto err_disable_platform; + } + + irq = platform_get_irq(pdev, AHB0_INT_IDX); if (irq < 0) { dev_err(&pdev->dev, "failed to get ahb0_int irq: %d\n", irq); - return irq; + ret = irq; + goto err_shutdown_dim; } ret = devm_request_irq(&pdev->dev, irq, dim2_ahb_isr, 0, "dim2_ahb0_int", dev); if (ret) { dev_err(&pdev->dev, "failed to request ahb0_int irq %d\n", irq); - return ret; + goto err_shutdown_dim; } - irq = platform_get_irq(pdev, 1); + irq = platform_get_irq(pdev, MLB_INT_IDX); if (irq < 0) { dev_err(&pdev->dev, "failed to get mlb_int irq: %d\n", irq); - return irq; + ret = irq; + goto err_shutdown_dim; } ret = devm_request_irq(&pdev->dev, irq, dim2_mlb_isr, 0, "dim2_mlb_int", dev); if (ret) { dev_err(&pdev->dev, "failed to request mlb_int irq %d\n", irq); - return ret; + goto err_shutdown_dim; } init_waitqueue_head(&dev->netinfo_waitq); dev->deliver_netinfo = 0; - dev->netinfo_task = kthread_run(&deliver_netinfo_thread, (void *)dev, + dev->netinfo_task = kthread_run(&deliver_netinfo_thread, dev, "dim2_netinfo"); - if (IS_ERR(dev->netinfo_task)) - return PTR_ERR(dev->netinfo_task); + if (IS_ERR(dev->netinfo_task)) { + ret = PTR_ERR(dev->netinfo_task); + goto err_shutdown_dim; + } for (i = 0; i < DMA_CHANNELS; i++) { struct most_channel_capability *cap = dev->capabilities + i; @@ -824,8 +870,11 @@ static int dim2_probe(struct platform_device *pdev) dev->most_iface.channel_vector = dev->capabilities; dev->most_iface.configure = configure_channel; dev->most_iface.enqueue = enqueue; + dev->most_iface.dma_alloc = dma_alloc; + dev->most_iface.dma_free = dma_free; dev->most_iface.poison_channel = poison_channel; dev->most_iface.request_netinfo = request_netinfo; + dev->most_iface.driver_dev = &pdev->dev; dev->dev.init_name = "dim2_state"; dev->dev.parent = &dev->most_iface.dev; @@ -841,20 +890,17 @@ static int dim2_probe(struct platform_device *pdev) goto err_unreg_iface; } - ret = startup_dim(pdev); - if (ret) { - dev_err(&pdev->dev, "failed to initialize DIM2\n"); - goto err_destroy_bus; - } - return 0; -err_destroy_bus: - dim2_sysfs_destroy(&dev->dev); err_unreg_iface: most_deregister_interface(&dev->most_iface); err_stop_thread: kthread_stop(dev->netinfo_task); +err_shutdown_dim: + dim_shutdown(); +err_disable_platform: + if (dev->disable_platform) + dev->disable_platform(pdev); return ret; } @@ -868,48 +914,197 @@ err_stop_thread: static int dim2_remove(struct platform_device *pdev) { struct dim2_hdm *dev = platform_get_drvdata(pdev); - struct dim2_platform_data *pdata = pdev->dev.platform_data; unsigned long flags; + dim2_sysfs_destroy(&dev->dev); + most_deregister_interface(&dev->most_iface); + kthread_stop(dev->netinfo_task); + spin_lock_irqsave(&dim_lock, flags); dim_shutdown(); spin_unlock_irqrestore(&dim_lock, flags); - if (pdata && pdata->destroy) - pdata->destroy(pdata); + if (dev->disable_platform) + dev->disable_platform(pdev); - dim2_sysfs_destroy(&dev->dev); - most_deregister_interface(&dev->most_iface); - kthread_stop(dev->netinfo_task); + return 0; +} + +/* platform specific functions [[ */ + +static int fsl_mx6_enable(struct platform_device *pdev) +{ + struct dim2_hdm *dev = platform_get_drvdata(pdev); + int ret; + + dev->clk = devm_clk_get(&pdev->dev, "mlb"); + if (IS_ERR_OR_NULL(dev->clk)) { + dev_err(&pdev->dev, "unable to get mlb clock\n"); + return -EFAULT; + } + + ret = clk_prepare_enable(dev->clk); + if (ret) { + dev_err(&pdev->dev, "%s\n", "clk_prepare_enable failed"); + return ret; + } + + if (dev->clk_speed >= CLK_2048FS) { + /* enable pll */ + dev->clk_pll = devm_clk_get(&pdev->dev, "pll8_mlb"); + if (IS_ERR_OR_NULL(dev->clk_pll)) { + dev_err(&pdev->dev, "unable to get mlb pll clock\n"); + clk_disable_unprepare(dev->clk); + return -EFAULT; + } + + writel(0x888, dev->io_base + 0x38); + clk_prepare_enable(dev->clk_pll); + } + + return 0; +} + +static void fsl_mx6_disable(struct platform_device *pdev) +{ + struct dim2_hdm *dev = platform_get_drvdata(pdev); + + if (dev->clk_speed >= CLK_2048FS) + clk_disable_unprepare(dev->clk_pll); + + clk_disable_unprepare(dev->clk); +} + +static int rcar_h2_enable(struct platform_device *pdev) +{ + struct dim2_hdm *dev = platform_get_drvdata(pdev); + int ret; + + dev->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(dev->clk)) { + dev_err(&pdev->dev, "cannot get clock\n"); + return PTR_ERR(dev->clk); + } - /* - * break link to local platform_device_id struct - * to prevent crash by unload platform device module - */ - pdev->id_entry = NULL; + ret = clk_prepare_enable(dev->clk); + if (ret) { + dev_err(&pdev->dev, "%s\n", "clk_prepare_enable failed"); + return ret; + } + + if (dev->clk_speed >= CLK_2048FS) { + /* enable MLP pll and LVDS drivers */ + writel(0x03, dev->io_base + 0x600); + /* set bias */ + writel(0x888, dev->io_base + 0x38); + } else { + /* PLL */ + writel(0x04, dev->io_base + 0x600); + } + + + /* BBCR = 0b11 */ + writel(0x03, dev->io_base + 0x500); + writel(0x0002FF02, dev->io_base + 0x508); return 0; } -static const struct platform_device_id dim2_id[] = { - { "medialb_dim2" }, - { }, /* Terminating entry */ +static void rcar_h2_disable(struct platform_device *pdev) +{ + struct dim2_hdm *dev = platform_get_drvdata(pdev); + + clk_disable_unprepare(dev->clk); + + /* disable PLLs and LVDS drivers */ + writel(0x0, dev->io_base + 0x600); +} + +static int rcar_m3_enable(struct platform_device *pdev) +{ + struct dim2_hdm *dev = platform_get_drvdata(pdev); + u32 enable_512fs = dev->clk_speed == CLK_512FS; + int ret; + + dev->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(dev->clk)) { + dev_err(&pdev->dev, "cannot get clock\n"); + return PTR_ERR(dev->clk); + } + + ret = clk_prepare_enable(dev->clk); + if (ret) { + dev_err(&pdev->dev, "%s\n", "clk_prepare_enable failed"); + return ret; + } + + /* PLL */ + writel(0x04, dev->io_base + 0x600); + + writel(enable_512fs, dev->io_base + 0x604); + + /* BBCR = 0b11 */ + writel(0x03, dev->io_base + 0x500); + writel(0x0002FF02, dev->io_base + 0x508); + + return 0; +} + +static void rcar_m3_disable(struct platform_device *pdev) +{ + struct dim2_hdm *dev = platform_get_drvdata(pdev); + + clk_disable_unprepare(dev->clk); + + /* disable PLLs and LVDS drivers */ + writel(0x0, dev->io_base + 0x600); +} + +/* ]] platform specific functions */ + +enum dim2_platforms { FSL_MX6, RCAR_H2, RCAR_M3 }; + +static struct dim2_platform_data plat_data[] = { + [FSL_MX6] = { .enable = fsl_mx6_enable, .disable = fsl_mx6_disable }, + [RCAR_H2] = { .enable = rcar_h2_enable, .disable = rcar_h2_disable }, + [RCAR_M3] = { .enable = rcar_m3_enable, .disable = rcar_m3_disable }, +}; + +static const struct of_device_id dim2_of_match[] = { + { + .compatible = "fsl,imx6q-mlb150", + .data = plat_data + FSL_MX6 + }, + { + .compatible = "renesas,mlp", + .data = plat_data + RCAR_H2 + }, + { + .compatible = "rcar,medialb-dim2", + .data = plat_data + RCAR_M3 + }, + { + .compatible = "xlnx,axi4-os62420_3pin-1.00.a", + }, + { + .compatible = "xlnx,axi4-os62420_6pin-1.00.a", + }, + {}, }; -MODULE_DEVICE_TABLE(platform, dim2_id); +MODULE_DEVICE_TABLE(of, dim2_of_match); static struct platform_driver dim2_driver = { .probe = dim2_probe, .remove = dim2_remove, - .id_table = dim2_id, .driver = { .name = "hdm_dim2", + .of_match_table = dim2_of_match, }, }; module_platform_driver(dim2_driver); -MODULE_AUTHOR("Jain Roy Ambi <JainRoy.Ambi@microchip.com>"); MODULE_AUTHOR("Andrey Shvetsov <andrey.shvetsov@k2l.de>"); MODULE_DESCRIPTION("MediaLB DIM2 Hardware Dependent Module"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/most/dim2/dim2.h b/drivers/staging/most/dim2/dim2.h deleted file mode 100644 index 6a9fc51a2eb4..000000000000 --- a/drivers/staging/most/dim2/dim2.h +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * dim2.h - MediaLB DIM2 HDM Header - * - * Copyright (C) 2015, Microchip Technology Germany II GmbH & Co. KG - */ - -#ifndef DIM2_HDM_H -#define DIM2_HDM_H - -struct device; - -/* platform dependent data for dim2 interface */ -struct dim2_platform_data { - int (*init)(struct dim2_platform_data *pd, void __iomem *io_base, - int clk_speed); - void (*destroy)(struct dim2_platform_data *pd); - void *priv; -}; - -#endif /* DIM2_HDM_H */ diff --git a/drivers/staging/most/dim2/hal.c b/drivers/staging/most/dim2/hal.c index 17c04e1c5e62..699e02f83bd4 100644 --- a/drivers/staging/most/dim2/hal.c +++ b/drivers/staging/most/dim2/hal.c @@ -760,7 +760,8 @@ static u8 init_ctrl_async(struct dim_channel *ch, u8 type, u8 is_tx, if (!check_channel_address(ch_address)) return DIM_INIT_ERR_CHANNEL_ADDRESS; - ch->dbr_size = ROUND_UP_TO(hw_buffer_size, DBR_BLOCK_SIZE); + if (!ch->dbr_size) + ch->dbr_size = ROUND_UP_TO(hw_buffer_size, DBR_BLOCK_SIZE); ch->dbr_addr = alloc_dbr(ch->dbr_size); if (ch->dbr_addr >= DBR_SIZE) return DIM_INIT_ERR_OUT_OF_MEMORY; @@ -846,7 +847,8 @@ u8 dim_init_isoc(struct dim_channel *ch, u8 is_tx, u16 ch_address, if (!check_packet_length(packet_length)) return DIM_ERR_BAD_CONFIG; - ch->dbr_size = packet_length * ISOC_DBR_FACTOR; + if (!ch->dbr_size) + ch->dbr_size = packet_length * ISOC_DBR_FACTOR; ch->dbr_addr = alloc_dbr(ch->dbr_size); if (ch->dbr_addr >= DBR_SIZE) return DIM_INIT_ERR_OUT_OF_MEMORY; @@ -873,7 +875,8 @@ u8 dim_init_sync(struct dim_channel *ch, u8 is_tx, u16 ch_address, if (!check_bytes_per_frame(bytes_per_frame)) return DIM_ERR_BAD_CONFIG; - ch->dbr_size = bytes_per_frame << bd_factor; + if (!ch->dbr_size) + ch->dbr_size = bytes_per_frame << bd_factor; ch->dbr_addr = alloc_dbr(ch->dbr_size); if (ch->dbr_addr >= DBR_SIZE) return DIM_INIT_ERR_OUT_OF_MEMORY; diff --git a/drivers/staging/most/dim2/reg.h b/drivers/staging/most/dim2/reg.h index 69cbf78239f1..4343a483017e 100644 --- a/drivers/staging/most/dim2/reg.h +++ b/drivers/staging/most/dim2/reg.h @@ -12,48 +12,48 @@ #include <linux/types.h> struct dim2_regs { - /* 0x00 */ u32 MLBC0; - /* 0x01 */ u32 rsvd0[1]; - /* 0x02 */ u32 MLBPC0; - /* 0x03 */ u32 MS0; - /* 0x04 */ u32 rsvd1[1]; - /* 0x05 */ u32 MS1; - /* 0x06 */ u32 rsvd2[2]; - /* 0x08 */ u32 MSS; - /* 0x09 */ u32 MSD; - /* 0x0A */ u32 rsvd3[1]; - /* 0x0B */ u32 MIEN; - /* 0x0C */ u32 rsvd4[1]; - /* 0x0D */ u32 MLBPC2; - /* 0x0E */ u32 MLBPC1; - /* 0x0F */ u32 MLBC1; - /* 0x10 */ u32 rsvd5[0x10]; - /* 0x20 */ u32 HCTL; - /* 0x21 */ u32 rsvd6[1]; - /* 0x22 */ u32 HCMR0; - /* 0x23 */ u32 HCMR1; - /* 0x24 */ u32 HCER0; - /* 0x25 */ u32 HCER1; - /* 0x26 */ u32 HCBR0; - /* 0x27 */ u32 HCBR1; - /* 0x28 */ u32 rsvd7[8]; - /* 0x30 */ u32 MDAT0; - /* 0x31 */ u32 MDAT1; - /* 0x32 */ u32 MDAT2; - /* 0x33 */ u32 MDAT3; - /* 0x34 */ u32 MDWE0; - /* 0x35 */ u32 MDWE1; - /* 0x36 */ u32 MDWE2; - /* 0x37 */ u32 MDWE3; - /* 0x38 */ u32 MCTL; - /* 0x39 */ u32 MADR; - /* 0x3A */ u32 rsvd8[0xB6]; - /* 0xF0 */ u32 ACTL; - /* 0xF1 */ u32 rsvd9[3]; - /* 0xF4 */ u32 ACSR0; - /* 0xF5 */ u32 ACSR1; - /* 0xF6 */ u32 ACMR0; - /* 0xF7 */ u32 ACMR1; + u32 MLBC0; /* 0x00 */ + u32 rsvd0[1]; /* 0x01 */ + u32 MLBPC0; /* 0x02 */ + u32 MS0; /* 0x03 */ + u32 rsvd1[1]; /* 0x04 */ + u32 MS1; /* 0x05 */ + u32 rsvd2[2]; /* 0x06 */ + u32 MSS; /* 0x08 */ + u32 MSD; /* 0x09 */ + u32 rsvd3[1]; /* 0x0A */ + u32 MIEN; /* 0x0B */ + u32 rsvd4[1]; /* 0x0C */ + u32 MLBPC2; /* 0x0D */ + u32 MLBPC1; /* 0x0E */ + u32 MLBC1; /* 0x0F */ + u32 rsvd5[0x10]; /* 0x10 */ + u32 HCTL; /* 0x20 */ + u32 rsvd6[1]; /* 0x21 */ + u32 HCMR0; /* 0x22 */ + u32 HCMR1; /* 0x23 */ + u32 HCER0; /* 0x24 */ + u32 HCER1; /* 0x25 */ + u32 HCBR0; /* 0x26 */ + u32 HCBR1; /* 0x27 */ + u32 rsvd7[8]; /* 0x28 */ + u32 MDAT0; /* 0x30 */ + u32 MDAT1; /* 0x31 */ + u32 MDAT2; /* 0x32 */ + u32 MDAT3; /* 0x33 */ + u32 MDWE0; /* 0x34 */ + u32 MDWE1; /* 0x35 */ + u32 MDWE2; /* 0x36 */ + u32 MDWE3; /* 0x37 */ + u32 MCTL; /* 0x38 */ + u32 MADR; /* 0x39 */ + u32 rsvd8[0xb6]; /* 0x3A */ + u32 ACTL; /* 0xF0 */ + u32 rsvd9[3]; /* 0xF1 */ + u32 ACSR0; /* 0xF4 */ + u32 ACSR1; /* 0xF5 */ + u32 ACMR0; /* 0xF6 */ + u32 ACMR1; /* 0xF7 */ }; #define DIM2_MASK(n) (~((~(u32)0) << (n))) diff --git a/drivers/staging/most/i2c/i2c.c b/drivers/staging/most/i2c/i2c.c index 141239fc9f51..4a4fc1005932 100644 --- a/drivers/staging/most/i2c/i2c.c +++ b/drivers/staging/most/i2c/i2c.c @@ -11,7 +11,6 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/i2c.h> -#include <linux/sched.h> #include <linux/interrupt.h> #include <linux/err.h> @@ -29,33 +28,28 @@ enum { CH_RX, CH_TX, NUM_CHANNELS }; #define list_first_mbo(ptr) \ list_first_entry(ptr, struct mbo, list) -/* IRQ / Polling option */ -static bool polling_req; -module_param(polling_req, bool, 0444); -MODULE_PARM_DESC(polling_req, "Request Polling. Default = 0 (use irq)"); - -/* Polling Rate */ -static int scan_rate = 100; -module_param(scan_rate, int, 0644); -MODULE_PARM_DESC(scan_rate, "Polling rate in times/sec. Default = 100"); +static unsigned int polling_rate; +module_param(polling_rate, uint, 0644); +MODULE_PARM_DESC(polling_rate, "Polling rate [Hz]. Default = 0 (use IRQ)"); struct hdm_i2c { - bool is_open[NUM_CHANNELS]; - bool polling_mode; struct most_interface most_iface; struct most_channel_capability capabilities[NUM_CHANNELS]; struct i2c_client *client; struct rx { struct delayed_work dwork; - wait_queue_head_t waitq; struct list_head list; - struct mutex list_mutex; + bool int_disabled; + unsigned int delay; } rx; char name[64]; }; #define to_hdm(iface) container_of(iface, struct hdm_i2c, most_iface) +static irqreturn_t most_irq_handler(int, void *); +static void pending_rx_work(struct work_struct *); + /** * configure_channel - called from MOST core to configure a channel * @iface: interface the channel belongs to @@ -71,10 +65,11 @@ static int configure_channel(struct most_interface *most_iface, int ch_idx, struct most_channel_config *channel_config) { + int ret; struct hdm_i2c *dev = to_hdm(most_iface); + unsigned int delay, pr; BUG_ON(ch_idx < 0 || ch_idx >= NUM_CHANNELS); - BUG_ON(dev->is_open[ch_idx]); if (channel_config->data_type != MOST_CH_CONTROL) { pr_err("bad data type for channel %d\n", ch_idx); @@ -86,11 +81,27 @@ static int configure_channel(struct most_interface *most_iface, return -EPERM; } - if ((channel_config->direction == MOST_CH_RX) && (dev->polling_mode)) { - schedule_delayed_work(&dev->rx.dwork, - msecs_to_jiffies(MSEC_PER_SEC / 4)); + if (channel_config->direction == MOST_CH_RX) { + if (!polling_rate) { + if (dev->client->irq <= 0) { + pr_err("bad irq: %d\n", dev->client->irq); + return -ENOENT; + } + dev->rx.int_disabled = false; + ret = request_irq(dev->client->irq, most_irq_handler, 0, + dev->client->name, dev); + if (ret) { + pr_err("request_irq(%d) failed: %d\n", + dev->client->irq, ret); + return ret; + } + } else { + delay = msecs_to_jiffies(MSEC_PER_SEC / polling_rate); + dev->rx.delay = delay ? delay : 1; + pr = MSEC_PER_SEC / jiffies_to_msecs(dev->rx.delay); + pr_info("polling rate is %u Hz\n", pr); + } } - dev->is_open[ch_idx] = true; return 0; } @@ -113,14 +124,17 @@ static int enqueue(struct most_interface *most_iface, int ret; BUG_ON(ch_idx < 0 || ch_idx >= NUM_CHANNELS); - BUG_ON(!dev->is_open[ch_idx]); if (ch_idx == CH_RX) { /* RX */ - mutex_lock(&dev->rx.list_mutex); + if (!polling_rate) + disable_irq(dev->client->irq); + cancel_delayed_work_sync(&dev->rx.dwork); list_add_tail(&mbo->list, &dev->rx.list); - mutex_unlock(&dev->rx.list_mutex); - wake_up_interruptible(&dev->rx.waitq); + if (dev->rx.int_disabled || polling_rate) + pending_rx_work(&dev->rx.dwork.work); + if (!polling_rate) + enable_irq(dev->client->irq); } else { /* TX */ ret = i2c_master_send(dev->client, mbo->virt_address, @@ -155,25 +169,20 @@ static int poison_channel(struct most_interface *most_iface, struct mbo *mbo; BUG_ON(ch_idx < 0 || ch_idx >= NUM_CHANNELS); - BUG_ON(!dev->is_open[ch_idx]); - - dev->is_open[ch_idx] = false; if (ch_idx == CH_RX) { - mutex_lock(&dev->rx.list_mutex); + if (!polling_rate) + free_irq(dev->client->irq, dev); + cancel_delayed_work_sync(&dev->rx.dwork); + while (!list_empty(&dev->rx.list)) { mbo = list_first_mbo(&dev->rx.list); list_del(&mbo->list); - mutex_unlock(&dev->rx.list_mutex); mbo->processed_length = 0; mbo->status = MBO_E_CLOSE; mbo->complete(mbo); - - mutex_lock(&dev->rx.list_mutex); } - mutex_unlock(&dev->rx.list_mutex); - wake_up_interruptible(&dev->rx.waitq); } return 0; @@ -183,7 +192,7 @@ static void do_rx_work(struct hdm_i2c *dev) { struct mbo *mbo; unsigned char msg[MAX_BUF_SIZE_CONTROL]; - int ret, ch_idx = CH_RX; + int ret; u16 pml, data_size; /* Read PML (2 bytes) */ @@ -206,32 +215,8 @@ static void do_rx_work(struct hdm_i2c *dev) return; } - for (;;) { - /* Conditions to wait for: poisoned channel or free buffer - * available for reading - */ - if (wait_event_interruptible(dev->rx.waitq, - !dev->is_open[ch_idx] || - !list_empty(&dev->rx.list))) { - pr_err("wait_event_interruptible() failed\n"); - return; - } - - if (!dev->is_open[ch_idx]) - return; - - mutex_lock(&dev->rx.list_mutex); - - /* list may be empty if poison or remove is called */ - if (!list_empty(&dev->rx.list)) - break; - - mutex_unlock(&dev->rx.list_mutex); - } - mbo = list_first_mbo(&dev->rx.list); list_del(&mbo->list); - mutex_unlock(&dev->rx.list_mutex); mbo->processed_length = min(data_size, mbo->buffer_length); memcpy(mbo->virt_address, msg, mbo->processed_length); @@ -249,14 +234,15 @@ static void pending_rx_work(struct work_struct *work) { struct hdm_i2c *dev = container_of(work, struct hdm_i2c, rx.dwork.work); + if (list_empty(&dev->rx.list)) + return; + do_rx_work(dev); - if (dev->polling_mode) { - if (dev->is_open[CH_RX]) - schedule_delayed_work(&dev->rx.dwork, - msecs_to_jiffies(MSEC_PER_SEC - / scan_rate)); + if (polling_rate) { + schedule_delayed_work(&dev->rx.dwork, dev->rx.delay); } else { + dev->rx.int_disabled = false; enable_irq(dev->client->irq); } } @@ -284,7 +270,7 @@ static irqreturn_t most_irq_handler(int irq, void *_dev) struct hdm_i2c *dev = _dev; disable_irq_nosync(irq); - + dev->rx.int_disabled = true; schedule_delayed_work(&dev->rx.dwork, 0); return IRQ_HANDLED; @@ -313,7 +299,6 @@ static int i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) client->adapter->nr, client->addr); for (i = 0; i < NUM_CHANNELS; i++) { - dev->is_open[i] = false; dev->capabilities[i].data_type = MOST_CH_CONTROL; dev->capabilities[i].num_buffers_packet = MAX_BUFFERS_CONTROL; dev->capabilities[i].buffer_size_packet = MAX_BUF_SIZE_CONTROL; @@ -332,8 +317,6 @@ static int i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) dev->most_iface.poison_channel = poison_channel; INIT_LIST_HEAD(&dev->rx.list); - mutex_init(&dev->rx.list_mutex); - init_waitqueue_head(&dev->rx.waitq); INIT_DELAYED_WORK(&dev->rx.dwork, pending_rx_work); @@ -347,21 +330,6 @@ static int i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) return ret; } - dev->polling_mode = polling_req || client->irq <= 0; - if (!dev->polling_mode) { - pr_info("Requesting IRQ: %d\n", client->irq); - ret = request_irq(client->irq, most_irq_handler, 0, - client->name, dev); - if (ret) { - pr_info("IRQ request failed: %d, falling back to polling\n", - ret); - dev->polling_mode = true; - } - } - - if (dev->polling_mode) - pr_info("Using polling at rate: %d times/sec\n", scan_rate); - return 0; } @@ -376,17 +344,8 @@ static int i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) static int i2c_remove(struct i2c_client *client) { struct hdm_i2c *dev = i2c_get_clientdata(client); - int i; - - if (!dev->polling_mode) - free_irq(client->irq, dev); most_deregister_interface(&dev->most_iface); - - for (i = 0 ; i < NUM_CHANNELS; i++) - if (dev->is_open[i]) - poison_channel(&dev->most_iface, i); - cancel_delayed_work_sync(&dev->rx.dwork); kfree(dev); return 0; @@ -410,7 +369,6 @@ static struct i2c_driver i2c_driver = { module_i2c_driver(i2c_driver); -MODULE_AUTHOR("Jain Roy Ambi <JainRoy.Ambi@microchip.com>"); MODULE_AUTHOR("Andrey Shvetsov <andrey.shvetsov@k2l.de>"); MODULE_DESCRIPTION("I2C Hardware Dependent Module"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/most/sound/sound.c b/drivers/staging/most/sound/sound.c index 83cec21c85b8..04c18323c2ea 100644 --- a/drivers/staging/most/sound/sound.c +++ b/drivers/staging/most/sound/sound.c @@ -460,21 +460,68 @@ static const struct snd_pcm_ops pcm_ops = { .mmap = snd_pcm_lib_mmap_vmalloc, }; -static int split_arg_list(char *buf, char **card_name, char **pcm_format) +static int split_arg_list(char *buf, char **card_name, u16 *ch_num, + char **sample_res) { + char *num; + int ret; + *card_name = strsep(&buf, "."); - if (!*card_name) - return -EIO; - *pcm_format = strsep(&buf, ".\n"); - if (!*pcm_format) + if (!*card_name) { + pr_err("Missing sound card name\n"); return -EIO; + } + num = strsep(&buf, "x"); + if (!num) + goto err; + ret = kstrtou16(num, 0, ch_num); + if (ret) + goto err; + *sample_res = strsep(&buf, ".\n"); + if (!*sample_res) + goto err; return 0; + +err: + pr_err("Bad PCM format\n"); + return -EIO; } +static const struct sample_resolution_info { + const char *sample_res; + int bytes; + u64 formats; +} sinfo[] = { + { "8", 1, SNDRV_PCM_FMTBIT_S8 }, + { "16", 2, SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE }, + { "24", 3, SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE }, + { "32", 4, SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE }, +}; + static int audio_set_hw_params(struct snd_pcm_hardware *pcm_hw, - char *pcm_format, + u16 ch_num, char *sample_res, struct most_channel_config *cfg) { + int i; + + for (i = 0; i < ARRAY_SIZE(sinfo); i++) { + if (!strcmp(sample_res, sinfo[i].sample_res)) + goto found; + } + pr_err("Unsupported PCM format\n"); + return -EIO; + +found: + if (!ch_num) { + pr_err("Bad number of channels\n"); + return -EINVAL; + } + + if (cfg->subbuffer_size != ch_num * sinfo[i].bytes) { + pr_err("Audio resolution doesn't fit subbuffer size\n"); + return -EINVAL; + } + pcm_hw->info = MOST_PCM_INFO; pcm_hw->rates = SNDRV_PCM_RATE_48000; pcm_hw->rate_min = 48000; @@ -484,54 +531,10 @@ static int audio_set_hw_params(struct snd_pcm_hardware *pcm_hw, pcm_hw->period_bytes_max = cfg->buffer_size; pcm_hw->periods_min = 1; pcm_hw->periods_max = cfg->num_buffers; - - if (!strcmp(pcm_format, "1x8")) { - if (cfg->subbuffer_size != 1) - goto error; - pr_info("PCM format is 8-bit mono\n"); - pcm_hw->channels_min = 1; - pcm_hw->channels_max = 1; - pcm_hw->formats = SNDRV_PCM_FMTBIT_S8; - } else if (!strcmp(pcm_format, "2x16")) { - if (cfg->subbuffer_size != 4) - goto error; - pr_info("PCM format is 16-bit stereo\n"); - pcm_hw->channels_min = 2; - pcm_hw->channels_max = 2; - pcm_hw->formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S16_BE; - } else if (!strcmp(pcm_format, "2x24")) { - if (cfg->subbuffer_size != 6) - goto error; - pr_info("PCM format is 24-bit stereo\n"); - pcm_hw->channels_min = 2; - pcm_hw->channels_max = 2; - pcm_hw->formats = SNDRV_PCM_FMTBIT_S24_3LE | - SNDRV_PCM_FMTBIT_S24_3BE; - } else if (!strcmp(pcm_format, "2x32")) { - if (cfg->subbuffer_size != 8) - goto error; - pr_info("PCM format is 32-bit stereo\n"); - pcm_hw->channels_min = 2; - pcm_hw->channels_max = 2; - pcm_hw->formats = SNDRV_PCM_FMTBIT_S32_LE | - SNDRV_PCM_FMTBIT_S32_BE; - } else if (!strcmp(pcm_format, "6x16")) { - if (cfg->subbuffer_size != 12) - goto error; - pr_info("PCM format is 16-bit 5.1 multi channel\n"); - pcm_hw->channels_min = 6; - pcm_hw->channels_max = 6; - pcm_hw->formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S16_BE; - } else { - pr_err("PCM format %s not supported\n", pcm_format); - return -EIO; - } + pcm_hw->channels_min = ch_num; + pcm_hw->channels_max = ch_num; + pcm_hw->formats = sinfo[i].formats; return 0; -error: - pr_err("Audio resolution doesn't fit subbuffer size\n"); - return -EINVAL; } /** @@ -558,7 +561,8 @@ static int audio_probe_channel(struct most_interface *iface, int channel_id, int ret; int direction; char *card_name; - char *pcm_format; + u16 ch_num; + char *sample_res; if (!iface) return -EINVAL; @@ -582,13 +586,11 @@ static int audio_probe_channel(struct most_interface *iface, int channel_id, direction = SNDRV_PCM_STREAM_CAPTURE; } - ret = split_arg_list(arg_list, &card_name, &pcm_format); - if (ret < 0) { - pr_info("PCM format missing\n"); + ret = split_arg_list(arg_list, &card_name, &ch_num, &sample_res); + if (ret < 0) return ret; - } - ret = snd_card_new(NULL, -1, card_name, THIS_MODULE, + ret = snd_card_new(&iface->dev, -1, card_name, THIS_MODULE, sizeof(*channel), &card); if (ret < 0) return ret; @@ -600,7 +602,8 @@ static int audio_probe_channel(struct most_interface *iface, int channel_id, channel->id = channel_id; init_waitqueue_head(&channel->playback_waitq); - ret = audio_set_hw_params(&channel->pcm_hardware, pcm_format, cfg); + ret = audio_set_hw_params(&channel->pcm_hardware, ch_num, sample_res, + cfg); if (ret) goto err_free_card; diff --git a/drivers/staging/most/usb/usb.c b/drivers/staging/most/usb/usb.c index 31f184cfcd69..bc820f90bcb1 100644 --- a/drivers/staging/most/usb/usb.c +++ b/drivers/staging/most/usb/usb.c @@ -338,7 +338,6 @@ static void hdm_write_completion(struct urb *urb) struct mbo *mbo = urb->context; struct most_dev *mdev = to_mdev(mbo->ifp); unsigned int channel = mbo->hdm_channel_id; - struct device *dev = &mdev->usb_device->dev; spinlock_t *lock = mdev->channel_lock + channel; unsigned long flags; @@ -354,7 +353,9 @@ static void hdm_write_completion(struct urb *urb) mbo->status = MBO_SUCCESS; break; case -EPIPE: - dev_warn(dev, "Broken OUT pipe detected\n"); + dev_warn(&mdev->usb_device->dev, + "Broken pipe on ep%02x\n", + mdev->ep_address[channel]); mdev->is_channel_healthy[channel] = false; mdev->clear_work[channel].pipe = urb->pipe; schedule_work(&mdev->clear_work[channel].ws); @@ -507,7 +508,8 @@ static void hdm_read_completion(struct urb *urb) } break; case -EPIPE: - dev_warn(dev, "Broken IN pipe detected\n"); + dev_warn(dev, "Broken pipe on ep%02x\n", + mdev->ep_address[channel]); mdev->is_channel_healthy[channel] = false; mdev->clear_work[channel].pipe = urb->pipe; schedule_work(&mdev->clear_work[channel].ws); @@ -517,7 +519,8 @@ static void hdm_read_completion(struct urb *urb) mbo->status = MBO_E_CLOSE; break; case -EOVERFLOW: - dev_warn(dev, "Babble on IN pipe detected\n"); + dev_warn(dev, "Babble on ep%02x\n", + mdev->ep_address[channel]); break; } } @@ -549,7 +552,6 @@ static int hdm_enqueue(struct most_interface *iface, int channel, { struct most_dev *mdev; struct most_channel_config *conf; - struct device *dev; int retval = 0; struct urb *urb; unsigned long length; @@ -562,14 +564,18 @@ static int hdm_enqueue(struct most_interface *iface, int channel, mdev = to_mdev(iface); conf = &mdev->conf[channel]; - dev = &mdev->usb_device->dev; - if (!mdev->usb_device) - return -ENODEV; + mutex_lock(&mdev->io_mutex); + if (!mdev->usb_device) { + retval = -ENODEV; + goto _exit; + } urb = usb_alloc_urb(NO_ISOCHRONOUS_URB, GFP_ATOMIC); - if (!urb) - return -ENOMEM; + if (!urb) { + retval = -ENOMEM; + goto _exit; + } if ((conf->direction & MOST_CH_TX) && mdev->padding_active[channel] && hdm_add_padding(mdev, channel, mbo)) { @@ -589,7 +595,8 @@ static int hdm_enqueue(struct most_interface *iface, int channel, length, hdm_write_completion, mbo); - if (conf->data_type != MOST_CH_ISOC) + if (conf->data_type != MOST_CH_ISOC && + conf->data_type != MOST_CH_SYNC) urb->transfer_flags |= URB_ZERO_PACKET; } else { usb_fill_bulk_urb(urb, mdev->usb_device, @@ -606,18 +613,37 @@ static int hdm_enqueue(struct most_interface *iface, int channel, retval = usb_submit_urb(urb, GFP_KERNEL); if (retval) { - dev_err(dev, "URB submit failed with error %d.\n", retval); + dev_err(&mdev->usb_device->dev, + "URB submit failed with error %d.\n", retval); goto _error_1; } - return 0; + goto _exit; _error_1: usb_unanchor_urb(urb); _error: usb_free_urb(urb); +_exit: + mutex_unlock(&mdev->io_mutex); return retval; } +static void *hdm_dma_alloc(struct mbo *mbo, u32 size) +{ + struct most_dev *mdev = to_mdev(mbo->ifp); + + return usb_alloc_coherent(mdev->usb_device, size, GFP_KERNEL, + &mbo->bus_address); +} + +static void hdm_dma_free(struct mbo *mbo, u32 size) +{ + struct most_dev *mdev = to_mdev(mbo->ifp); + + usb_free_coherent(mdev->usb_device, size, mbo->virt_address, + mbo->bus_address); +} + /** * hdm_configure_channel - receive channel configuration from core * @iface: interface @@ -1027,11 +1053,14 @@ hdm_probe(struct usb_interface *interface, const struct usb_device_id *id) mdev->link_stat_timer.expires = jiffies + (2 * HZ); mdev->iface.mod = hdm_usb_fops.owner; + mdev->iface.driver_dev = &interface->dev; mdev->iface.interface = ITYPE_USB; mdev->iface.configure = hdm_configure_channel; mdev->iface.request_netinfo = hdm_request_netinfo; mdev->iface.enqueue = hdm_enqueue; mdev->iface.poison_channel = hdm_poison_channel; + mdev->iface.dma_alloc = hdm_dma_alloc; + mdev->iface.dma_free = hdm_dma_free; mdev->iface.description = mdev->description; mdev->iface.num_channels = num_endpoints; diff --git a/drivers/staging/most/video/video.c b/drivers/staging/most/video/video.c index 9d7e747519d9..cf342eb58e10 100644 --- a/drivers/staging/most/video/video.c +++ b/drivers/staging/most/video/video.c @@ -73,8 +73,6 @@ static int comp_vdev_open(struct file *filp) struct most_video_dev *mdev = video_drvdata(filp); struct comp_fh *fh; - v4l2_info(&mdev->v4l2_dev, "comp_vdev_open()\n"); - switch (vdev->vfl_type) { case VFL_TYPE_GRABBER: break; @@ -122,8 +120,6 @@ static int comp_vdev_close(struct file *filp) struct most_video_dev *mdev = fh->mdev; struct mbo *mbo, *tmp; - v4l2_info(&mdev->v4l2_dev, "comp_vdev_close()\n"); - /* * We need to put MBOs back before we call most_stop_channel() * to deallocate MBOs. @@ -250,8 +246,6 @@ static int vidioc_querycap(struct file *file, void *priv, struct comp_fh *fh = priv; struct most_video_dev *mdev = fh->mdev; - v4l2_info(&mdev->v4l2_dev, "vidioc_querycap()\n"); - strlcpy(cap->driver, "v4l2_component", sizeof(cap->driver)); strlcpy(cap->card, "MOST", sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), @@ -267,11 +261,6 @@ static int vidioc_querycap(struct file *file, void *priv, static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct comp_fh *fh = priv; - struct most_video_dev *mdev = fh->mdev; - - v4l2_info(&mdev->v4l2_dev, "vidioc_enum_fmt_vid_cap() %d\n", f->index); - if (f->index) return -EINVAL; @@ -286,11 +275,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct comp_fh *fh = priv; - struct most_video_dev *mdev = fh->mdev; - - v4l2_info(&mdev->v4l2_dev, "vidioc_g_fmt_vid_cap()\n"); - comp_set_format_struct(f); return 0; } @@ -315,11 +299,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm) { - struct comp_fh *fh = priv; - struct most_video_dev *mdev = fh->mdev; - - v4l2_info(&mdev->v4l2_dev, "vidioc_g_std()\n"); - *norm = V4L2_STD_UNKNOWN; return 0; } @@ -355,8 +334,6 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int index) struct comp_fh *fh = priv; struct most_video_dev *mdev = fh->mdev; - v4l2_info(&mdev->v4l2_dev, "vidioc_s_input(%d)\n", index); - if (index >= V4L2_CMP_MAX_INPUT) return -EINVAL; mdev->ctrl_input = index; @@ -435,8 +412,6 @@ static int comp_register_videodev(struct most_video_dev *mdev) { int ret; - v4l2_info(&mdev->v4l2_dev, "comp_register_videodev()\n"); - init_waitqueue_head(&mdev->wait_data); /* allocate and fill v4l2 video struct */ @@ -465,8 +440,6 @@ static int comp_register_videodev(struct most_video_dev *mdev) static void comp_unregister_videodev(struct most_video_dev *mdev) { - v4l2_info(&mdev->v4l2_dev, "comp_unregister_videodev()\n"); - video_unregister_device(mdev->vdev); } @@ -485,8 +458,6 @@ static int comp_probe_channel(struct most_interface *iface, int channel_idx, int ret; struct most_video_dev *mdev = get_comp_dev(iface, channel_idx); - pr_info("comp_probe_channel(%s)\n", name); - if (mdev) { pr_err("channel already linked\n"); return -EEXIST; @@ -531,7 +502,6 @@ static int comp_probe_channel(struct most_interface *iface, int channel_idx, spin_lock_irq(&list_lock); list_add(&mdev->list, &video_devices); spin_unlock_irq(&list_lock); - v4l2_info(&mdev->v4l2_dev, "comp_probe_channel() done\n"); return 0; err_unreg: @@ -550,8 +520,6 @@ static int comp_disconnect_channel(struct most_interface *iface, return -ENOENT; } - v4l2_info(&mdev->v4l2_dev, "comp_disconnect_channel()\n"); - spin_lock_irq(&list_lock); list_del(&mdev->list); spin_unlock_irq(&list_lock); |