lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Tue, 29 Jul 2014 17:35:39 +0800
From:	caesar <caesar.wang@...k-chips.com>
To:	Olof Johansson <olof@...om.net>
CC:	Doug Anderson <dianders@...omium.org>,
	Thierry Reding <thierry.reding@...il.com>,
	linux-pwm@...r.kernel.org,
	"devicetree@...r.kernel.org" <devicetree@...r.kernel.org>,
	"linux-doc@...r.kernel.org" <linux-doc@...r.kernel.org>,
	"linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org>
Subject: Re: [PATCH v2 2/2] pwm: add this patch to support the new pwm of
 Rockchip SoCs

Hi Olof,

Sorry, I didn't understand all of what you mean.
Please allow me to paste the following code [1].

在 2014年07月29日 00:58, Olof Johansson 写道:
> On Mon, Jul 28, 2014 at 4:19 AM, caesar <caesar.wang@...k-chips.com> wrote:
>> Doug,
>> 在 2014年07月28日 12:01, Doug Anderson 写道:
>>
>>> Caesar,
>>>
>>> On Sun, Jul 27, 2014 at 7:00 AM, caesar <caesar.wang@...k-chips.com>
>>> wrote:
>>>> /*I think will be show the faill log:->
>>>>
>>>> * rockchip-pwm ff9301a0.pwm: can't request region for resource [mem
>>>> 0xff9301a0-0xff93019f]
>>>> */
>>>>
>>>> pc->base = devm_ioremap_resource(dev, regs);
>>> Did you actually code this up and try it and get this error?
>> Yeah.
>>
>>> I hadn't
>>> tried it but I researched other dts files and it looked as if there
>>> was one example that was doing this.  ...but perhaps it wasn't
>>> actually doing the ioremap_resource on both ranges.
>>>
>>> I'd imagine that this is _probably_ equivalent to what Thierry was
>>> suggesting, so if it didn't work then maybe Thierry's won't work
>>> either?
>>>
>>> I don't have any other great suggestions other than doing two memory
>>> ranges for lcdc:
>>>
>>>            lcdc@...30000 {
>>>                    compatible = "rockchip,rk3288-lcdc";
>>>                    reg = <0xff930000 0x1a0>, <0xff9301b0 0xfe50>;
>>>                    ...
>>>            };
>>>            pwm@...301a0 {
>>>                    compatible = "rockchip,vop-pwm";
>>>                    reg = <0xff9301a0 0x10>;
>>>                    ...
>>>            };
>>>
>>> ...but I am certainly nowhere near an expert on this stuff...
>>>
>>> -Doug
>>>
>>>
>>>
>> I has solve in lcdc driver,but I always feel awkward. I think a good way to
>> solve in pwm driver.
>> Unfortunately that  so far ,I have not a good idle in pwm driver.
>>
>> Maybe,I  let do it that way in lcdc driver.
> I think there's an easier way to do this, by not focusing _too_ much
> on the device tree:
>
> * Define a platform_data structure for the PWM driver, which contains
> readl/writel accessors as well as the device type (i.e. what you use
> the compatible field and the lookup table for today).
Maybe, as the following  code: "pwm_data_vop" has been implement it. right?
> * Populate the platform_device in the clcd driver, and register that
Yeah,the lcdc driver can register it.
> * Make the PWM driver probe as a regular platform device if pdata is passed
> * Make a readl/writel wrapper that either falls back to native
> readl/writel when there aren't any passed in, or make the DT code fill
> in the pdata with the native versions in that case.
Sorry,This step I don't understand it. Perhaps, could you give a simple 
case for it ?:-P

> Going full MFD on this seems overkill, unless there is also a shared
> interrupt that needs to be handled.
>
> -Olof
>
>
>
>

[1]:The driver/pwm/pwm-rockchip.c

#include <linux/clk.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pwm.h>
#include <linux/time.h>

#define PWM_CNTR        0x00        /* Counter register */
#define PWM_HRC            0x04        /* High reference register */
#define PWM_LRC            0x08        /* Low reference register */
#define PWM_CTRL        0x0c        /* Control register */
#define PWM_CTRL_TIMER_EN    (1 << 0)
#define PWM_CTRL_OUTPUT_EN    (1 << 3)

#define PRESCALER        2

#define PWM_ENABLE        (1 << 0)
#define PWM_CONTINUOUS        (1 << 1)
#define PWM_DUTY_POSITIVE    (1 << 3)
#define PWM_INACTIVE_NEGATIVE    (0 << 4)
#define PWM_OUTPUT_LEFT        (0 << 5)
#define PWM_LP_DISABLE        (0 << 8)

struct rockchip_pwm_chip {
     struct pwm_chip chip;
     struct clk *clk;
     const struct rockchip_pwm_data *data;
     void __iomem *base;
};

struct rockchip_pwm_regs {
     unsigned long duty;
     unsigned long period;
     unsigned long cntr;
     unsigned long ctrl;
};

struct rockchip_pwm_data {
     struct rockchip_pwm_regs regs;
     unsigned int prescaler;

     void (*set_enable)(struct pwm_chip *chip, bool enable);
};

static inline struct rockchip_pwm_chip *to_rockchip_pwm_chip(struct 
pwm_chip *c)
{
     return container_of(c, struct rockchip_pwm_chip, chip);
}

static void rockchip_pwm_set_enable_v1(struct pwm_chip *chip, bool enable)
{
     struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
     u32 val = 0;
     u32 enable_conf = PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN;

     val = readl_relaxed(pc->base + pc->data->regs.ctrl);

     if (enable)
         val |= enable_conf;
     else
         val &= ~enable_conf;

     writel_relaxed(val, pc->base + pc->data->regs.ctrl);
}

static void rockchip_pwm_set_enable_v2(struct pwm_chip *chip, bool enable)
{
     struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
     u32 val = 0;
     u32 enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE |
         PWM_CONTINUOUS | PWM_DUTY_POSITIVE | PWM_INACTIVE_NEGATIVE;

     val = readl_relaxed(pc->base + pc->data->regs.ctrl);

     if (enable)
         val |= enable_conf;
     else
         val &= ~enable_conf;

     writel_relaxed(val, pc->base + pc->data->regs.ctrl);
}

static int rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device 
*pwm,
                    int duty_ns, int period_ns)
{
     struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
     unsigned long period, duty;
     u64 clk_rate, div;
     int ret;

     clk_rate = clk_get_rate(pc->clk);

     /*
      * Since period and duty cycle registers have a width of 32
      * bits, every possible input period can be obtained using the
      * default prescaler value for all practical clock rate values.
      */
     div = clk_rate * period_ns;
     do_div(div, pc->data->prescaler * NSEC_PER_SEC);
     period = div;

     div = clk_rate * duty_ns;
     do_div(div, pc->data->prescaler * NSEC_PER_SEC);
     duty = div;

     ret = clk_enable(pc->clk);
     if (ret)
         return ret;

     writel(period, pc->base + pc->data->regs.period);
     writel(duty, pc->base + pc->data->regs.duty);
     writel(0, pc->base + pc->data->regs.cntr);

     clk_disable(pc->clk);

     return 0;
}

static int rockchip_pwm_enable(struct pwm_chip *chip, struct pwm_device 
*pwm)
{
     struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
     int ret;

     ret = clk_enable(pc->clk);
     if (ret)
         return ret;

     pc->data->set_enable(chip, true);

     return 0;
}

static void rockchip_pwm_disable(struct pwm_chip *chip, struct 
pwm_device *pwm)
{
     struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);

     pc->data->set_enable(chip, false);

     clk_disable(pc->clk);
}

static const struct pwm_ops rockchip_pwm_ops = {
     .config = rockchip_pwm_config,
     .enable = rockchip_pwm_enable,
     .disable = rockchip_pwm_disable,
     .owner = THIS_MODULE,
};

static const struct rockchip_pwm_data pwm_data_v1 = {
     .regs.duty = PWM_HRC,
     .regs.period = PWM_LRC,
     .regs.cntr = PWM_CNTR,
     .regs.ctrl = PWM_CTRL,
     .prescaler = PRESCALER,
     .set_enable = rockchip_pwm_set_enable_v1,
};

static const struct rockchip_pwm_data pwm_data_v2 = {
     .regs.duty = PWM_LRC,
     .regs.period = PWM_HRC,
     .regs.cntr = PWM_CNTR,
     .regs.ctrl = PWM_CTRL,
     .prescaler = PRESCALER-1,
     .set_enable = rockchip_pwm_set_enable_v2,
};

static const struct rockchip_pwm_data pwm_data_vop = {
     .regs.duty = PWM_LRC,
     .regs.period = PWM_HRC,
     .regs.cntr = PWM_CTRL,
     .regs.ctrl = PWM_CNTR,
     .prescaler = PRESCALER-1,
     .set_enable = rockchip_pwm_set_enable_v2,
};

static const struct of_device_id rockchip_pwm_dt_ids[] = {
     { .compatible = "rockchip,rk2928-pwm", .data = &pwm_data_v1},
     { .compatible = "rockchip,rk3288-pwm", .data = &pwm_data_v2},
     { .compatible = "rockchip,vop-pwm", .data = &pwm_data_vop},
     { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, rockchip_pwm_dt_ids);

static int rockchip_pwm_probe(struct platform_device *pdev)
{
     const struct of_device_id *id;
     struct rockchip_pwm_chip *pc;
     struct resource *r;
     int ret;

     id = of_match_device(rockchip_pwm_dt_ids, &pdev->dev);
     if (!id)
         return -EINVAL;

     pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
     if (!pc)
         return -ENOMEM;

     r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
     pc->base = devm_ioremap_resource(&pdev->dev, r);
     if (IS_ERR(pc->base))
         return PTR_ERR(pc->base);

     pc->clk = devm_clk_get(&pdev->dev, NULL);
     if (IS_ERR(pc->clk))
         return PTR_ERR(pc->clk);

     ret = clk_prepare(pc->clk);
     if (ret)
         return ret;

     platform_set_drvdata(pdev, pc);

     pc->data = id->data;
     pc->chip.dev = &pdev->dev;
     pc->chip.ops = &rockchip_pwm_ops;
     pc->chip.base = -1;
     pc->chip.npwm = 1;

     ret = pwmchip_add(&pc->chip);
     if (ret < 0) {
         clk_unprepare(pc->clk);
         dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
     }

     return ret;
}

static int rockchip_pwm_remove(struct platform_device *pdev)
{
     struct rockchip_pwm_chip *pc = platform_get_drvdata(pdev);

     clk_unprepare(pc->clk);

     return pwmchip_remove(&pc->chip);
}

static struct platform_driver rockchip_pwm_driver = {
     .driver = {
         .name = "rockchip-pwm",
         .of_match_table = rockchip_pwm_dt_ids,
     },
     .probe = rockchip_pwm_probe,
     .remove = rockchip_pwm_remove,
};
module_platform_driver(rockchip_pwm_driver);

MODULE_AUTHOR("Beniamino Galvani <b.galvani@...il.com>");
MODULE_DESCRIPTION("Rockchip SoC PWM driver");
MODULE_LICENSE("GPL v2");

-Caesar

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ