diff options
-rw-r--r-- | Documentation/devicetree/bindings/pwm/pxa-pwm.txt | 30 | ||||
-rw-r--r-- | drivers/pwm/pwm-pxa.c | 53 |
2 files changed, 83 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/pwm/pxa-pwm.txt b/Documentation/devicetree/bindings/pwm/pxa-pwm.txt new file mode 100644 index 000000000000..5ae9f1e3c338 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/pxa-pwm.txt | |||
@@ -0,0 +1,30 @@ | |||
1 | Marvell PWM controller | ||
2 | |||
3 | Required properties: | ||
4 | - compatible: should be one or more of: | ||
5 | - "marvell,pxa250-pwm" | ||
6 | - "marvell,pxa270-pwm" | ||
7 | - "marvell,pxa168-pwm" | ||
8 | - "marvell,pxa910-pwm" | ||
9 | - reg: Physical base address and length of the registers used by the PWM channel | ||
10 | Note that one device instance must be created for each PWM that is used, so the | ||
11 | length covers only the register window for one PWM output, not that of the | ||
12 | entire PWM controller. Currently length is 0x10 for all supported devices. | ||
13 | - #pwm-cells: Should be 1. This cell is used to specify the period in | ||
14 | nanoseconds. | ||
15 | |||
16 | Example PWM device node: | ||
17 | |||
18 | pwm0: pwm@40b00000 { | ||
19 | compatible = "marvell,pxa250-pwm"; | ||
20 | reg = <0x40b00000 0x10>; | ||
21 | #pwm-cells = <1>; | ||
22 | }; | ||
23 | |||
24 | Example PWM client node: | ||
25 | |||
26 | backlight { | ||
27 | compatible = "pwm-backlight"; | ||
28 | pwms = <&pwm0 5000000>; | ||
29 | ... | ||
30 | } | ||
diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c index a4d2164aaf55..3dc7c10bb7a0 100644 --- a/drivers/pwm/pwm-pxa.c +++ b/drivers/pwm/pwm-pxa.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/clk.h> | 19 | #include <linux/clk.h> |
20 | #include <linux/io.h> | 20 | #include <linux/io.h> |
21 | #include <linux/pwm.h> | 21 | #include <linux/pwm.h> |
22 | #include <linux/of_device.h> | ||
22 | 23 | ||
23 | #include <asm/div64.h> | 24 | #include <asm/div64.h> |
24 | 25 | ||
@@ -124,6 +125,46 @@ static struct pwm_ops pxa_pwm_ops = { | |||
124 | .owner = THIS_MODULE, | 125 | .owner = THIS_MODULE, |
125 | }; | 126 | }; |
126 | 127 | ||
128 | #ifdef CONFIG_OF | ||
129 | /* | ||
130 | * Device tree users must create one device instance for each pwm channel. | ||
131 | * Hence we dispense with the HAS_SECONDARY_PWM and "tell" the original driver | ||
132 | * code that this is a single channel pxa25x-pwm. Currently all devices are | ||
133 | * supported identically. | ||
134 | */ | ||
135 | static struct of_device_id pwm_of_match[] = { | ||
136 | { .compatible = "marvell,pxa250-pwm", .data = &pwm_id_table[0]}, | ||
137 | { .compatible = "marvell,pxa270-pwm", .data = &pwm_id_table[0]}, | ||
138 | { .compatible = "marvell,pxa168-pwm", .data = &pwm_id_table[0]}, | ||
139 | { .compatible = "marvell,pxa910-pwm", .data = &pwm_id_table[0]}, | ||
140 | { } | ||
141 | }; | ||
142 | MODULE_DEVICE_TABLE(of, pwm_of_match); | ||
143 | #else | ||
144 | #define pwm_of_match NULL | ||
145 | #endif | ||
146 | |||
147 | static const struct platform_device_id *pxa_pwm_get_id_dt(struct device *dev) | ||
148 | { | ||
149 | const struct of_device_id *id = of_match_device(pwm_of_match, dev); | ||
150 | |||
151 | return id ? id->data : NULL; | ||
152 | } | ||
153 | |||
154 | static struct pwm_device * | ||
155 | pxa_pwm_of_xlate(struct pwm_chip *pc, const struct of_phandle_args *args) | ||
156 | { | ||
157 | struct pwm_device *pwm; | ||
158 | |||
159 | pwm = pwm_request_from_chip(pc, 0, NULL); | ||
160 | if (IS_ERR(pwm)) | ||
161 | return pwm; | ||
162 | |||
163 | pwm_set_period(pwm, args->args[0]); | ||
164 | |||
165 | return pwm; | ||
166 | } | ||
167 | |||
127 | static int pwm_probe(struct platform_device *pdev) | 168 | static int pwm_probe(struct platform_device *pdev) |
128 | { | 169 | { |
129 | const struct platform_device_id *id = platform_get_device_id(pdev); | 170 | const struct platform_device_id *id = platform_get_device_id(pdev); |
@@ -131,6 +172,12 @@ static int pwm_probe(struct platform_device *pdev) | |||
131 | struct resource *r; | 172 | struct resource *r; |
132 | int ret = 0; | 173 | int ret = 0; |
133 | 174 | ||
175 | if (IS_ENABLED(CONFIG_OF) && id == NULL) | ||
176 | id = pxa_pwm_get_id_dt(&pdev->dev); | ||
177 | |||
178 | if (id == NULL) | ||
179 | return -EINVAL; | ||
180 | |||
134 | pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); | 181 | pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); |
135 | if (pwm == NULL) { | 182 | if (pwm == NULL) { |
136 | dev_err(&pdev->dev, "failed to allocate memory\n"); | 183 | dev_err(&pdev->dev, "failed to allocate memory\n"); |
@@ -146,6 +193,11 @@ static int pwm_probe(struct platform_device *pdev) | |||
146 | pwm->chip.base = -1; | 193 | pwm->chip.base = -1; |
147 | pwm->chip.npwm = (id->driver_data & HAS_SECONDARY_PWM) ? 2 : 1; | 194 | pwm->chip.npwm = (id->driver_data & HAS_SECONDARY_PWM) ? 2 : 1; |
148 | 195 | ||
196 | if (IS_ENABLED(CONFIG_OF)) { | ||
197 | pwm->chip.of_xlate = pxa_pwm_of_xlate; | ||
198 | pwm->chip.of_pwm_n_cells = 1; | ||
199 | } | ||
200 | |||
149 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 201 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
150 | pwm->mmio_base = devm_ioremap_resource(&pdev->dev, r); | 202 | pwm->mmio_base = devm_ioremap_resource(&pdev->dev, r); |
151 | if (IS_ERR(pwm->mmio_base)) | 203 | if (IS_ERR(pwm->mmio_base)) |
@@ -176,6 +228,7 @@ static struct platform_driver pwm_driver = { | |||
176 | .driver = { | 228 | .driver = { |
177 | .name = "pxa25x-pwm", | 229 | .name = "pxa25x-pwm", |
178 | .owner = THIS_MODULE, | 230 | .owner = THIS_MODULE, |
231 | .of_match_table = pwm_of_match, | ||
179 | }, | 232 | }, |
180 | .probe = pwm_probe, | 233 | .probe = pwm_probe, |
181 | .remove = pwm_remove, | 234 | .remove = pwm_remove, |