On register r/w macros/procedures of drivers/media/pci
I am starting a work on driver for techwell tw5864 media grabberencoder. I am basing on tw68 driver (mentorship, advising and testing by board owners are appreciated). And here (and in some other drivers/media/pci/ drivers) I see what confuses me: tw68-core.c: dev-lmmio = ioremap(pci_resource_start(pci_dev, 0), pci_resource_len(pci_dev, 0)); dev-bmmio = (__u8 __iomem *)dev-lmmio; tw68.h: #define tw_readl(reg) readl(dev-lmmio + ((reg) 2)) #define tw_readb(reg) readb(dev-bmmio + (reg)) #define tw_writel(reg, value) writel((value), dev-lmmio + ((reg) 2)) #define tw_writeb(reg, value) writeb((value), dev-bmmio + (reg)) I am mostly userland developer and I wouldn't expect bmmio pointer to contain value numerically different from lmmio after such simple casting. But still, if this is correct, then how should I implement tw_{read,write}w to operate on 2 bytes (a word)? Similarly, it would look like this: #define tw_readl(reg) readl(dev-lmmio + ((reg) 1)) That looks odd. In contrary, in drivers/media/pci/dm1105, we see no explicit shifting of register address. It uses {in,out}{b,w,l} macros, which seem to turn out the same {read,write}{b,w,l} (with some reservations): http://lxr.free-electrons.com/source/include/asm-generic/io.h#L354 dm1105.c:#define dm_io_mem(reg) ((unsigned long)(dev-io_mem[reg])) dm1105.c:#define dm_readb(reg) inb(dm_io_mem(reg)) dm1105.c:#define dm_writeb(reg, value) outb((value), (dm_io_mem(reg))) dm1105.c:#define dm_readw(reg) inw(dm_io_mem(reg)) dm1105.c:#define dm_writew(reg, value) outw((value), (dm_io_mem(reg))) dm1105.c:#define dm_readl(reg) inl(dm_io_mem(reg)) dm1105.c:#define dm_writel(reg, value) outl((value), (dm_io_mem(reg))) This looks like contradiction to me (shifting register address vs. no shifting), so that one practice may be even just wrong and broken (which is hard to believe due to active maintenance of all drivers). I highly appreciate your help me in determining the best practice to follow in this new driver. Thanks. -- Bluecherry developer. -- To unsubscribe from this list: send the line unsubscribe linux-media in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/2] clk: change clk_ops' -round_rate() prototype
Hi Boris, Am Freitag, 17. April 2015, 09:29:28 schrieb Boris Brezillon: Clock rates are stored in an unsigned long field, but -round_rate() (which returns a rounded rate from a requested one) returns a long value (errors are reported using negative error codes), which can lead to long overflow if the clock rate exceed 2Ghz. Change -round_rate() prototype to return 0 or an error code, and pass the requested rate as a pointer so that it can be adjusted depending on hardware capabilities. Signed-off-by: Boris Brezillon boris.brezil...@free-electrons.com --- On a rk3288-veyron-pinky with the fix described below: Tested-by: Heiko Stuebner he...@sntech.de diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index fa5a00e..1462ddc 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -1640,8 +1643,10 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *clk, parent_hw); parent = parent_hw ? parent_hw-core : NULL; } else if (clk-ops-round_rate) { - new_rate = clk-ops-round_rate(clk-hw, rate, - best_parent_rate); + if (clk-ops-round_rate(clk-hw, new_rate, + best_parent_rate)) + return NULL; + if (new_rate min_rate || new_rate max_rate) return NULL; } else if (!parent || !(clk-flags CLK_SET_RATE_PARENT)) { This is using new_rate uninitialized when calling into the round_rate callback. Which in turn pushed my PLLs up to 2.2GHz :-) I guess you'll need something like the following: diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index db4e4b2..afc7733 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -1605,6 +1605,7 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *clk, parent_hw); parent = parent_hw ? parent_hw-core : NULL; } else if (clk-ops-round_rate) { + new_rate = rate; if (clk-ops-round_rate(clk-hw, new_rate, best_parent_rate)) return NULL; diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c index f8d3baf..bd408ef 100644 --- a/drivers/clk/rockchip/clk-pll.c +++ b/drivers/clk/rockchip/clk-pll.c @@ -63,8 +63,8 @@ static const struct rockchip_pll_rate_table *rockchip_get_pll_settings( return NULL; } -static long rockchip_pll_round_rate(struct clk_hw *hw, - unsigned long drate, unsigned long *prate) +static int rockchip_pll_round_rate(struct clk_hw *hw, + unsigned long *drate, unsigned long *prate) { struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); const struct rockchip_pll_rate_table *rate_table = pll-rate_table; @@ -72,12 +72,15 @@ static long rockchip_pll_round_rate(struct clk_hw *hw, /* Assumming rate_table is in descending order */ for (i = 0; i pll-rate_count; i++) { - if (drate = rate_table[i].rate) - return rate_table[i].rate; + if (*drate = rate_table[i].rate) { + *drate = rate_table[i].rate; + return 0; + } } /* return minimum supported value */ - return rate_table[i - 1].rate; + *drate = rate_table[i - 1].rate; + return 0; } /* The rockchip-part: Reviewed-by: Heiko Stuebner he...@sntech.de And as I've stumbled onto this recently too, the clock-maintainership has expanded to Stephen Boyd and linux-...@vger.kernel.org . Heiko -- To unsubscribe from this list: send the line unsubscribe linux-media in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: On register r/w macros/procedures of drivers/media/pci
On 04/19/2015 09:36 AM, Andrey Utkin wrote: I am starting a work on driver for techwell tw5864 media grabberencoder. I am basing on tw68 driver (mentorship, advising and testing by board owners are appreciated). And here (and in some other drivers/media/pci/ drivers) I see what confuses me: tw68-core.c: dev-lmmio = ioremap(pci_resource_start(pci_dev, 0), pci_resource_len(pci_dev, 0)); dev-bmmio = (__u8 __iomem *)dev-lmmio; tw68.h: #define tw_readl(reg) readl(dev-lmmio + ((reg) 2)) #define tw_readb(reg) readb(dev-bmmio + (reg)) #define tw_writel(reg, value) writel((value), dev-lmmio + ((reg) 2)) #define tw_writeb(reg, value) writeb((value), dev-bmmio + (reg)) I am mostly userland developer and I wouldn't expect bmmio pointer to contain value numerically different from lmmio after such simple casting. Check the types of llmio and bbmio: u32 __iomem *lmmio; u8 __iomem *bmmio; So the values of the pointers are the same, but the types are not. So 'lmmio + 1' == 'bmmio + sizeof(u32)' == 'bbmio + 4'. Since all the registers are defined as byte offsets relative to the start of the memory map you cannot just do 'lmmio + reg' since that would be a factor 4 off. Instead you have to divide by 4 to get it back in line. Frankly, I don't think lmmio is necessary at all since readl/writel don't need a u32 pointer at all since they use void pointers. I never noticed that when I cleaned up the tw68 driver. Using 'void __iomem *mmio' instead of lmmio/bmmio and dropping the shifts in the tw_ macros would work just as well. But still, if this is correct, then how should I implement tw_{read,write}w to operate on 2 bytes (a word)? Similarly, it would look like this: #define tw_readl(reg) readl(dev-lmmio + ((reg) 1)) As suggested above, just use a single void __iomem *mmio pointer. That looks odd. In contrary, in drivers/media/pci/dm1105, we see no explicit shifting of register address. It uses {in,out}{b,w,l} macros, which seem to turn out the same {read,write}{b,w,l} (with some reservations): http://lxr.free-electrons.com/source/include/asm-generic/io.h#L354 dm1105.c:#define dm_io_mem(reg) ((unsigned long)(dev-io_mem[reg])) dm1105.c:#define dm_readb(reg) inb(dm_io_mem(reg)) dm1105.c:#define dm_writeb(reg, value) outb((value), (dm_io_mem(reg))) dm1105.c:#define dm_readw(reg) inw(dm_io_mem(reg)) dm1105.c:#define dm_writew(reg, value) outw((value), (dm_io_mem(reg))) dm1105.c:#define dm_readl(reg) inl(dm_io_mem(reg)) dm1105.c:#define dm_writel(reg, value) outl((value), (dm_io_mem(reg))) This looks like contradiction to me (shifting register address vs. no shifting), so that one practice may be even just wrong and broken (which is hard to believe due to active maintenance of all drivers). I highly appreciate your help me in determining the best practice to follow in this new driver. Thanks. Hope this helps, Hans -- To unsubscribe from this list: send the line unsubscribe linux-media in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: On register r/w macros/procedures of drivers/media/pci
On Sun, Apr 19, 2015 at 11:28 AM, Hans Verkuil hverk...@xs4all.nl wrote: Check the types of llmio and bbmio: u32 __iomem *lmmio; u8 __iomem *bmmio; So the values of the pointers are the same, but the types are not. So 'lmmio + 1' == 'bmmio + sizeof(u32)' == 'bbmio + 4'. Since all the registers are defined as byte offsets relative to the start of the memory map you cannot just do 'lmmio + reg' since that would be a factor 4 off. Instead you have to divide by 4 to get it back in line. Frankly, I don't think lmmio is necessary at all since readl/writel don't need a u32 pointer at all since they use void pointers. I never noticed that when I cleaned up the tw68 driver. Using 'void __iomem *mmio' instead of lmmio/bmmio and dropping the shifts in the tw_ macros would work just as well. Hope this helps, Oh, indeed, I have forgot this basic thing of pointer arithmetics. Thanks a lot for elaboration and the proposed solution. -- Bluecherry developer. -- To unsubscribe from this list: send the line unsubscribe linux-media in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v5 04/10] DT: Add documentation for the Skyworks AAT1290
On Wed, Apr 15, 2015 at 08:48:34AM +0200, Jacek Anaszewski wrote: This patch adds device tree binding documentation for 1.5A Step-Up Current Regulator for Flash LEDs. Signed-off-by: Jacek Anaszewski j.anaszew...@samsung.com Acked-by: Kyungmin Park kyungmin.p...@samsung.com Cc: Bryan Wu coolo...@gmail.com Cc: Richard Purdie rpur...@rpsys.net Cc: devicet...@vger.kernel.org Acked-by: Sakari Ailus sakari.ai...@linux.intel.com -- Sakari Ailus e-mail: sakari.ai...@iki.fi XMPP: sai...@retiisi.org.uk -- To unsubscribe from this list: send the line unsubscribe linux-media in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/2] gspca: sn9c2028: Add gain and autogain controls Genius Videocam Live v2
On Sun, 19 Apr 2015, Vasily Khoruzhick wrote: Autogain algorithm is very simple, if average luminance is low - increase gain, if it's high - decrease gain. Gain granularity is low enough for this algo to stabilize quickly. Signed-off-by: Vasily Khoruzhick anars...@gmail.com --- drivers/media/usb/gspca/sn9c2028.c | 121 + drivers/media/usb/gspca/sn9c2028.h | 20 +- 2 files changed, 138 insertions(+), 3 deletions(-) diff --git a/drivers/media/usb/gspca/sn9c2028.c b/drivers/media/usb/gspca/sn9c2028.c index 317b02c..0ff390f 100644 --- a/drivers/media/usb/gspca/sn9c2028.c +++ b/drivers/media/usb/gspca/sn9c2028.c @@ -34,6 +34,16 @@ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ u8 sof_read; u16 model; + +#define MIN_AVG_LUM 8500 +#define MAX_AVG_LUM 1 + int avg_lum; + u8 avg_lum_l; + + struct { /* autogain and gain control cluster */ + struct v4l2_ctrl *autogain; + struct v4l2_ctrl *gain; + }; }; struct init_command { @@ -252,6 +262,77 @@ static int run_start_commands(struct gspca_dev *gspca_dev, return 0; } +static void set_gain(struct gspca_dev *gspca_dev, s32 g) +{ + struct sd *sd = (struct sd *) gspca_dev; + + struct init_command genius_vcam_live_gain_cmds[] = { + {{0x1d, 0x25, 0x10, 0x20, 0xab, 0x00}, 0}, + }; + if (!gspca_dev-streaming) + return; + + switch (sd-model) { + case 0x7003: + genius_vcam_live_gain_cmds[0].instruction[2] = g; + run_start_commands(gspca_dev, genius_vcam_live_gain_cmds, + ARRAY_SIZE(genius_vcam_live_gain_cmds)); + break; + default: + break; + } +} + +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct gspca_dev *gspca_dev = + container_of(ctrl-handler, struct gspca_dev, ctrl_handler); + struct sd *sd = (struct sd *)gspca_dev; + + gspca_dev-usb_err = 0; + + if (!gspca_dev-streaming) + return 0; + + switch (ctrl-id) { + /* standalone gain control */ + case V4L2_CID_GAIN: + set_gain(gspca_dev, ctrl-val); + break; + /* autogain */ + case V4L2_CID_AUTOGAIN: + set_gain(gspca_dev, sd-gain-val); + break; + } + return gspca_dev-usb_err; +} + +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, +}; + + +static int sd_init_controls(struct gspca_dev *gspca_dev) +{ + struct v4l2_ctrl_handler *hdl = gspca_dev-ctrl_handler; + struct sd *sd = (struct sd *)gspca_dev; + + gspca_dev-vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 2); + + switch (sd-model) { + case 0x7003: + sd-gain = v4l2_ctrl_new_std(hdl, sd_ctrl_ops, + V4L2_CID_GAIN, 0, 20, 1, 0); + sd-autogain = v4l2_ctrl_new_std(hdl, sd_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, 1); + break; + default: + break; + } + + return 0; +} static int start_spy_cam(struct gspca_dev *gspca_dev) { struct init_command spy_start_commands[] = { @@ -641,6 +722,9 @@ static int start_genius_videocam_live(struct gspca_dev *gspca_dev) if (r 0) return r; + if (sd-gain) + set_gain(gspca_dev, v4l2_ctrl_g_ctrl(sd-gain)); + return r; } @@ -757,6 +841,8 @@ static int sd_start(struct gspca_dev *gspca_dev) return -ENXIO; } + sd-avg_lum = -1; + return err_code; } @@ -776,6 +862,39 @@ static void sd_stopN(struct gspca_dev *gspca_dev) PERR(Camera Stop command failed); } +static void do_autogain(struct gspca_dev *gspca_dev, int avg_lum) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 cur_gain = v4l2_ctrl_g_ctrl(sd-gain); + + if (avg_lum == -1) + return; + + if (avg_lum MIN_AVG_LUM) { + if (cur_gain == sd-gain-maximum) + return; + cur_gain++; + v4l2_ctrl_s_ctrl(sd-gain, cur_gain); + } + if (avg_lum MAX_AVG_LUM) { + if (cur_gain == sd-gain-minimum) + return; + cur_gain--; + v4l2_ctrl_s_ctrl(sd-gain, cur_gain); + } + +} + +static void sd_dqcallback(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd-autogain == NULL || !v4l2_ctrl_g_ctrl(sd-autogain)) + return; + + do_autogain(gspca_dev, sd-avg_lum); +} + /* Include sn9c2028 sof detection functions */ #include sn9c2028.h @@ -810,8 +929,10 @@ static const struct sd_desc sd_desc = { .name = MODULE_NAME, .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls,
Re: [PATCH] Add support for TechniSat Skystar S2
Hi, On Fri, 17 Apr 2015 11:06:30 +0200 Patrick Boettcher patrick.boettc...@posteo.de wrote: http://git.linuxtv.org/cgit.cgi/pb/media_tree.git/ cx24120-v2 Jannis pointed out, that my repository on linuxtv.org was not fetchable... I put one onto github, this should work: https://github.com/pboettch/linux.git cx24120-v2 It is the same commits as I was pushing to the linuxtv.org . regards, -- Patrick. -- To unsubscribe from this list: send the line unsubscribe linux-media in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/2] gspca: sn9c2028: Add support for Genius Videocam Live v2
Signed-off-by: Vasily Khoruzhick anars...@gmail.com --- drivers/media/usb/gspca/sn9c2028.c | 120 - 1 file changed, 119 insertions(+), 1 deletion(-) diff --git a/drivers/media/usb/gspca/sn9c2028.c b/drivers/media/usb/gspca/sn9c2028.c index 39b6b2e..317b02c 100644 --- a/drivers/media/usb/gspca/sn9c2028.c +++ b/drivers/media/usb/gspca/sn9c2028.c @@ -2,6 +2,7 @@ * SN9C2028 library * * Copyright (C) 2009 Theodore Kilgore kilg...@auburn.edu + * Copyright (C) 2015 Vasily Khoruzhick anars...@gmail.com * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -128,7 +129,7 @@ static int sn9c2028_long_command(struct gspca_dev *gspca_dev, u8 *command) status = -1; for (i = 0; i 256 status 2; i++) status = sn9c2028_read1(gspca_dev); - if (status != 2) { + if (status 0) { pr_err(long command status read error %d\n, status); return (status 0) ? status : -EIO; } @@ -178,6 +179,9 @@ static int sd_config(struct gspca_dev *gspca_dev, case 0x7005: PDEBUG(D_PROBE, Genius Smart 300 camera); break; + case 0x7003: + PDEBUG(D_PROBE, Genius Videocam Live v2); + break; case 0x8000: PDEBUG(D_PROBE, DC31VC); break; @@ -530,6 +534,116 @@ static int start_genius_cam(struct gspca_dev *gspca_dev) ARRAY_SIZE(genius_start_commands)); } +static int start_genius_videocam_live(struct gspca_dev *gspca_dev) +{ + int r; + struct sd *sd = (struct sd *) gspca_dev; + struct init_command genius_vcam_live_start_commands[] = { + {{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 0}, + {{0x16, 0x01, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x10, 0x00, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4}, + {{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4}, + + {{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4}, + {{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4}, + {{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4}, + {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, + {{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4}, + {{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4}, + {{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4}, + {{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x21, 0x2d, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x23, 0x03, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x11, 0x64, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x13, 0x91, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x15, 0x20, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x16, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x17, 0x60, 0x00, 0x00, 0x00}, 4}, + {{0x1c, 0x20, 0x00, 0x2d, 0x00, 0x00}, 4}, + {{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x22, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x23, 0x01, 0x01, 0x00, 0x00}, 4}, + {{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4}, + {{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4}, + {{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4}, + {{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4}, + {{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4}, + {{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, + {{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4}, + {{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4}, + {{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4}, + {{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4}, + {{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x01, 0x04, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x02, 0x92, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x11, 0x64, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x13, 0x91, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x15, 0x20, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x16, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x17, 0x60, 0x00, 0x00, 0x00}, 4}, +
[PATCH 2/2] gspca: sn9c2028: Add gain and autogain controls Genius Videocam Live v2
Autogain algorithm is very simple, if average luminance is low - increase gain, if it's high - decrease gain. Gain granularity is low enough for this algo to stabilize quickly. Signed-off-by: Vasily Khoruzhick anars...@gmail.com --- drivers/media/usb/gspca/sn9c2028.c | 121 + drivers/media/usb/gspca/sn9c2028.h | 20 +- 2 files changed, 138 insertions(+), 3 deletions(-) diff --git a/drivers/media/usb/gspca/sn9c2028.c b/drivers/media/usb/gspca/sn9c2028.c index 317b02c..0ff390f 100644 --- a/drivers/media/usb/gspca/sn9c2028.c +++ b/drivers/media/usb/gspca/sn9c2028.c @@ -34,6 +34,16 @@ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ u8 sof_read; u16 model; + +#define MIN_AVG_LUM 8500 +#define MAX_AVG_LUM 1 + int avg_lum; + u8 avg_lum_l; + + struct { /* autogain and gain control cluster */ + struct v4l2_ctrl *autogain; + struct v4l2_ctrl *gain; + }; }; struct init_command { @@ -252,6 +262,77 @@ static int run_start_commands(struct gspca_dev *gspca_dev, return 0; } +static void set_gain(struct gspca_dev *gspca_dev, s32 g) +{ + struct sd *sd = (struct sd *) gspca_dev; + + struct init_command genius_vcam_live_gain_cmds[] = { + {{0x1d, 0x25, 0x10, 0x20, 0xab, 0x00}, 0}, + }; + if (!gspca_dev-streaming) + return; + + switch (sd-model) { + case 0x7003: + genius_vcam_live_gain_cmds[0].instruction[2] = g; + run_start_commands(gspca_dev, genius_vcam_live_gain_cmds, + ARRAY_SIZE(genius_vcam_live_gain_cmds)); + break; + default: + break; + } +} + +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct gspca_dev *gspca_dev = + container_of(ctrl-handler, struct gspca_dev, ctrl_handler); + struct sd *sd = (struct sd *)gspca_dev; + + gspca_dev-usb_err = 0; + + if (!gspca_dev-streaming) + return 0; + + switch (ctrl-id) { + /* standalone gain control */ + case V4L2_CID_GAIN: + set_gain(gspca_dev, ctrl-val); + break; + /* autogain */ + case V4L2_CID_AUTOGAIN: + set_gain(gspca_dev, sd-gain-val); + break; + } + return gspca_dev-usb_err; +} + +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, +}; + + +static int sd_init_controls(struct gspca_dev *gspca_dev) +{ + struct v4l2_ctrl_handler *hdl = gspca_dev-ctrl_handler; + struct sd *sd = (struct sd *)gspca_dev; + + gspca_dev-vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 2); + + switch (sd-model) { + case 0x7003: + sd-gain = v4l2_ctrl_new_std(hdl, sd_ctrl_ops, + V4L2_CID_GAIN, 0, 20, 1, 0); + sd-autogain = v4l2_ctrl_new_std(hdl, sd_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, 1); + break; + default: + break; + } + + return 0; +} static int start_spy_cam(struct gspca_dev *gspca_dev) { struct init_command spy_start_commands[] = { @@ -641,6 +722,9 @@ static int start_genius_videocam_live(struct gspca_dev *gspca_dev) if (r 0) return r; + if (sd-gain) + set_gain(gspca_dev, v4l2_ctrl_g_ctrl(sd-gain)); + return r; } @@ -757,6 +841,8 @@ static int sd_start(struct gspca_dev *gspca_dev) return -ENXIO; } + sd-avg_lum = -1; + return err_code; } @@ -776,6 +862,39 @@ static void sd_stopN(struct gspca_dev *gspca_dev) PERR(Camera Stop command failed); } +static void do_autogain(struct gspca_dev *gspca_dev, int avg_lum) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 cur_gain = v4l2_ctrl_g_ctrl(sd-gain); + + if (avg_lum == -1) + return; + + if (avg_lum MIN_AVG_LUM) { + if (cur_gain == sd-gain-maximum) + return; + cur_gain++; + v4l2_ctrl_s_ctrl(sd-gain, cur_gain); + } + if (avg_lum MAX_AVG_LUM) { + if (cur_gain == sd-gain-minimum) + return; + cur_gain--; + v4l2_ctrl_s_ctrl(sd-gain, cur_gain); + } + +} + +static void sd_dqcallback(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd-autogain == NULL || !v4l2_ctrl_g_ctrl(sd-autogain)) + return; + + do_autogain(gspca_dev, sd-avg_lum); +} + /* Include sn9c2028 sof detection functions */ #include sn9c2028.h @@ -810,8 +929,10 @@ static const struct sd_desc sd_desc = { .name = MODULE_NAME, .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .start = sd_start,
cron job: media_tree daily build: ERRORS
This message is generated daily by a cron job that builds media_tree for the kernels and architectures in the list below. Results of the daily build of media_tree: date: Mon Apr 20 04:00:15 CEST 2015 git branch: test git hash: e183201b9e917daf2530b637b2f34f1d5afb934d gcc version:i686-linux-gcc (GCC) 4.9.1 sparse version: v0.5.0-44-g40791b9 smatch version: 0.4.1-3153-g7d56ab3 host hardware: x86_64 host os:3.19.0-1.slh.1-amd64 linux-git-arm-at91: OK linux-git-arm-davinci: OK linux-git-arm-exynos: OK linux-git-arm-mx: OK linux-git-arm-omap: OK linux-git-arm-omap1: OK linux-git-arm-pxa: OK linux-git-blackfin: OK linux-git-i686: WARNINGS linux-git-m32r: OK linux-git-mips: WARNINGS linux-git-powerpc64: OK linux-git-sh: OK linux-git-x86_64: OK linux-2.6.32.27-i686: ERRORS linux-2.6.33.7-i686: ERRORS linux-2.6.34.7-i686: ERRORS linux-2.6.35.9-i686: ERRORS linux-2.6.36.4-i686: ERRORS linux-2.6.37.6-i686: ERRORS linux-2.6.38.8-i686: WARNINGS linux-2.6.39.4-i686: WARNINGS linux-3.0.60-i686: OK linux-3.1.10-i686: OK linux-3.2.37-i686: OK linux-3.3.8-i686: OK linux-3.4.27-i686: OK linux-3.5.7-i686: OK linux-3.6.11-i686: OK linux-3.7.4-i686: OK linux-3.8-i686: OK linux-3.9.2-i686: OK linux-3.10.1-i686: OK linux-3.11.1-i686: OK linux-3.12.23-i686: OK linux-3.13.11-i686: ERRORS linux-3.14.9-i686: ERRORS linux-3.15.2-i686: ERRORS linux-3.16.7-i686: ERRORS linux-3.17.8-i686: WARNINGS linux-3.18.7-i686: WARNINGS linux-3.19-i686: WARNINGS linux-4.0-rc1-i686: WARNINGS linux-2.6.32.27-x86_64: ERRORS linux-2.6.33.7-x86_64: ERRORS linux-2.6.34.7-x86_64: ERRORS linux-2.6.35.9-x86_64: ERRORS linux-2.6.36.4-x86_64: ERRORS linux-2.6.37.6-x86_64: ERRORS linux-2.6.38.8-x86_64: WARNINGS linux-2.6.39.4-x86_64: WARNINGS linux-3.0.60-x86_64: OK linux-3.1.10-x86_64: OK linux-3.2.37-x86_64: OK linux-3.3.8-x86_64: OK linux-3.4.27-x86_64: OK linux-3.5.7-x86_64: OK linux-3.6.11-x86_64: OK linux-3.7.4-x86_64: OK linux-3.8-x86_64: OK linux-3.9.2-x86_64: OK linux-3.10.1-x86_64: OK linux-3.11.1-x86_64: OK linux-3.12.23-x86_64: OK linux-3.13.11-x86_64: ERRORS linux-3.14.9-x86_64: ERRORS linux-3.15.2-x86_64: ERRORS linux-3.16.7-x86_64: ERRORS linux-3.17.8-x86_64: OK linux-3.18.7-x86_64: OK linux-3.19-x86_64: OK linux-4.0-rc1-x86_64: OK apps: OK spec-git: OK sparse: WARNINGS smatch: ERRORS Detailed results are available here: http://www.xs4all.nl/~hverkuil/logs/Monday.log Full logs are available here: http://www.xs4all.nl/~hverkuil/logs/Monday.tar.bz2 The Media Infrastructure API from this daily build is here: http://www.xs4all.nl/~hverkuil/spec/media.html -- To unsubscribe from this list: send the line unsubscribe linux-media in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/2] clk: change clk_ops' -round_rate() prototype
Hi Heiko, On Sun, 19 Apr 2015 14:13:04 +0200 Heiko Stübner he...@sntech.de wrote: Hi Boris, Am Freitag, 17. April 2015, 09:29:28 schrieb Boris Brezillon: Clock rates are stored in an unsigned long field, but -round_rate() (which returns a rounded rate from a requested one) returns a long value (errors are reported using negative error codes), which can lead to long overflow if the clock rate exceed 2Ghz. Change -round_rate() prototype to return 0 or an error code, and pass the requested rate as a pointer so that it can be adjusted depending on hardware capabilities. Signed-off-by: Boris Brezillon boris.brezil...@free-electrons.com --- On a rk3288-veyron-pinky with the fix described below: Tested-by: Heiko Stuebner he...@sntech.de diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index fa5a00e..1462ddc 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -1640,8 +1643,10 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *clk, parent_hw); parent = parent_hw ? parent_hw-core : NULL; } else if (clk-ops-round_rate) { - new_rate = clk-ops-round_rate(clk-hw, rate, - best_parent_rate); + if (clk-ops-round_rate(clk-hw, new_rate, +best_parent_rate)) + return NULL; + if (new_rate min_rate || new_rate max_rate) return NULL; } else if (!parent || !(clk-flags CLK_SET_RATE_PARENT)) { This is using new_rate uninitialized when calling into the round_rate callback. Which in turn pushed my PLLs up to 2.2GHz :-) Indeed, thanks for the fix. [...] And as I've stumbled onto this recently too, the clock-maintainership has expanded to Stephen Boyd and linux-...@vger.kernel.org . Noted. I'll add Stephen and the new linux-clk ML in the recipient list next time. Best Regards, Boris -- Boris Brezillon, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com -- To unsubscribe from this list: send the line unsubscribe linux-media in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html