diff options
author | Manjunathappa, Prakash <prakash.pm@ti.com> | 2013-05-21 10:08:00 -0400 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2013-06-16 05:56:52 -0400 |
commit | 4e7e8017a80e1810100c9b416b86e3baef900285 (patch) | |
tree | 98f812edd3f0c787a5ac04c6b0304dce5bffd00f | |
parent | ac844b62713045557c834c8d5fe2863b8bbaf124 (diff) |
pinctrl: pinctrl-single: enhance to configure multiple pins of different modules
Add support to configure multiple pins in each register, existing
implementation added by [1] does not support full fledge multiple pin
configuration in single register, reports a pin clash when different
modules configure different bits of same register. The issue reported
and discussed here
http://www.spinics.net/lists/arm-kernel/msg235213.html
With pinctrl-single,bits-per-mux property specified, use function-mask
property to find out number pins to configure. Allocate and register
pin control functions based sub mask.
Tested on da850/omap-l138 EVM.
does not support variable submask for pins.
does not support pinconf.
[1] "pinctrl: pinctrl-single: Add pinctrl-single,bits type of mux"
(9e605cb68a21d5704839a192a46ebcf387773704),
Signed-off-by: Manjunathappa, Prakash <prakash.pm@ti.com>
Reported-by: Lad, Prabhakar <prabhakar.csengg@gmail.com>
Tested-by: Lad, Prabhakar <prabhakar.csengg@gmail.com>
Acked-by: Haojian Zhuang <haojian.zhuang@gmail.com>
Acked-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
-rw-r--r-- | Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt | 3 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-single.c | 198 |
2 files changed, 167 insertions, 34 deletions
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt index 08f0c3d01575..5a02e30dd262 100644 --- a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt | |||
@@ -18,7 +18,8 @@ Optional properties: | |||
18 | pin functions is ignored | 18 | pin functions is ignored |
19 | 19 | ||
20 | - pinctrl-single,bit-per-mux : boolean to indicate that one register controls | 20 | - pinctrl-single,bit-per-mux : boolean to indicate that one register controls |
21 | more than one pin | 21 | more than one pin, for which "pinctrl-single,function-mask" property specifies |
22 | position mask of pin. | ||
22 | 23 | ||
23 | - pinctrl-single,drive-strength : array of value that are used to configure | 24 | - pinctrl-single,drive-strength : array of value that are used to configure |
24 | drive strength in the pinmux register. They're value of drive strength | 25 | drive strength in the pinmux register. They're value of drive strength |
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index b9fa04618601..9a1ea65014d7 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c | |||
@@ -163,6 +163,7 @@ struct pcs_name { | |||
163 | * @foff: value to turn mux off | 163 | * @foff: value to turn mux off |
164 | * @fmax: max number of functions in fmask | 164 | * @fmax: max number of functions in fmask |
165 | * @is_pinconf: whether supports pinconf | 165 | * @is_pinconf: whether supports pinconf |
166 | * @bits_per_pin:number of bits per pin | ||
166 | * @names: array of register names for pins | 167 | * @names: array of register names for pins |
167 | * @pins: physical pins on the SoC | 168 | * @pins: physical pins on the SoC |
168 | * @pgtree: pingroup index radix tree | 169 | * @pgtree: pingroup index radix tree |
@@ -190,6 +191,7 @@ struct pcs_device { | |||
190 | unsigned fmax; | 191 | unsigned fmax; |
191 | bool bits_per_mux; | 192 | bool bits_per_mux; |
192 | bool is_pinconf; | 193 | bool is_pinconf; |
194 | unsigned bits_per_pin; | ||
193 | struct pcs_name *names; | 195 | struct pcs_name *names; |
194 | struct pcs_data pins; | 196 | struct pcs_data pins; |
195 | struct radix_tree_root pgtree; | 197 | struct radix_tree_root pgtree; |
@@ -431,10 +433,11 @@ static int pcs_enable(struct pinctrl_dev *pctldev, unsigned fselector, | |||
431 | 433 | ||
432 | vals = &func->vals[i]; | 434 | vals = &func->vals[i]; |
433 | val = pcs->read(vals->reg); | 435 | val = pcs->read(vals->reg); |
434 | if (!vals->mask) | 436 | |
435 | mask = pcs->fmask; | 437 | if (pcs->bits_per_mux) |
438 | mask = vals->mask; | ||
436 | else | 439 | else |
437 | mask = pcs->fmask & vals->mask; | 440 | mask = pcs->fmask; |
438 | 441 | ||
439 | val &= ~mask; | 442 | val &= ~mask; |
440 | val |= (vals->val & mask); | 443 | val |= (vals->val & mask); |
@@ -779,7 +782,13 @@ static int pcs_allocate_pin_table(struct pcs_device *pcs) | |||
779 | int mux_bytes, nr_pins, i; | 782 | int mux_bytes, nr_pins, i; |
780 | 783 | ||
781 | mux_bytes = pcs->width / BITS_PER_BYTE; | 784 | mux_bytes = pcs->width / BITS_PER_BYTE; |
782 | nr_pins = pcs->size / mux_bytes; | 785 | |
786 | if (pcs->bits_per_mux) { | ||
787 | pcs->bits_per_pin = fls(pcs->fmask); | ||
788 | nr_pins = (pcs->size * BITS_PER_BYTE) / pcs->bits_per_pin; | ||
789 | } else { | ||
790 | nr_pins = pcs->size / mux_bytes; | ||
791 | } | ||
783 | 792 | ||
784 | dev_dbg(pcs->dev, "allocating %i pins\n", nr_pins); | 793 | dev_dbg(pcs->dev, "allocating %i pins\n", nr_pins); |
785 | pcs->pins.pa = devm_kzalloc(pcs->dev, | 794 | pcs->pins.pa = devm_kzalloc(pcs->dev, |
@@ -800,8 +809,14 @@ static int pcs_allocate_pin_table(struct pcs_device *pcs) | |||
800 | for (i = 0; i < pcs->desc.npins; i++) { | 809 | for (i = 0; i < pcs->desc.npins; i++) { |
801 | unsigned offset; | 810 | unsigned offset; |
802 | int res; | 811 | int res; |
812 | int byte_num; | ||
803 | 813 | ||
804 | offset = i * mux_bytes; | 814 | if (pcs->bits_per_mux) { |
815 | byte_num = (pcs->bits_per_pin * i) / BITS_PER_BYTE; | ||
816 | offset = (byte_num / mux_bytes) * mux_bytes; | ||
817 | } else { | ||
818 | offset = i * mux_bytes; | ||
819 | } | ||
805 | res = pcs_add_pin(pcs, offset); | 820 | res = pcs_add_pin(pcs, offset); |
806 | if (res < 0) { | 821 | if (res < 0) { |
807 | dev_err(pcs->dev, "error adding pins: %i\n", res); | 822 | dev_err(pcs->dev, "error adding pins: %i\n", res); |
@@ -919,7 +934,10 @@ static int pcs_get_pin_by_offset(struct pcs_device *pcs, unsigned offset) | |||
919 | return -EINVAL; | 934 | return -EINVAL; |
920 | } | 935 | } |
921 | 936 | ||
922 | index = offset / (pcs->width / BITS_PER_BYTE); | 937 | if (pcs->bits_per_mux) |
938 | index = (offset * BITS_PER_BYTE) / pcs->bits_per_pin; | ||
939 | else | ||
940 | index = offset / (pcs->width / BITS_PER_BYTE); | ||
923 | 941 | ||
924 | return index; | 942 | return index; |
925 | } | 943 | } |
@@ -1097,29 +1115,18 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs, | |||
1097 | { | 1115 | { |
1098 | struct pcs_func_vals *vals; | 1116 | struct pcs_func_vals *vals; |
1099 | const __be32 *mux; | 1117 | const __be32 *mux; |
1100 | int size, params, rows, *pins, index = 0, found = 0, res = -ENOMEM; | 1118 | int size, rows, *pins, index = 0, found = 0, res = -ENOMEM; |
1101 | struct pcs_function *function; | 1119 | struct pcs_function *function; |
1102 | 1120 | ||
1103 | if (pcs->bits_per_mux) { | 1121 | mux = of_get_property(np, PCS_MUX_PINS_NAME, &size); |
1104 | params = 3; | 1122 | if ((!mux) || (size < sizeof(*mux) * 2)) { |
1105 | mux = of_get_property(np, PCS_MUX_BITS_NAME, &size); | 1123 | dev_err(pcs->dev, "bad data for mux %s\n", |
1106 | } else { | 1124 | np->name); |
1107 | params = 2; | ||
1108 | mux = of_get_property(np, PCS_MUX_PINS_NAME, &size); | ||
1109 | } | ||
1110 | |||
1111 | if (!mux) { | ||
1112 | dev_err(pcs->dev, "no valid property for %s\n", np->name); | ||
1113 | return -EINVAL; | ||
1114 | } | ||
1115 | |||
1116 | if (size < (sizeof(*mux) * params)) { | ||
1117 | dev_err(pcs->dev, "bad data for %s\n", np->name); | ||
1118 | return -EINVAL; | 1125 | return -EINVAL; |
1119 | } | 1126 | } |
1120 | 1127 | ||
1121 | size /= sizeof(*mux); /* Number of elements in array */ | 1128 | size /= sizeof(*mux); /* Number of elements in array */ |
1122 | rows = size / params; | 1129 | rows = size / 2; |
1123 | 1130 | ||
1124 | vals = devm_kzalloc(pcs->dev, sizeof(*vals) * rows, GFP_KERNEL); | 1131 | vals = devm_kzalloc(pcs->dev, sizeof(*vals) * rows, GFP_KERNEL); |
1125 | if (!vals) | 1132 | if (!vals) |
@@ -1137,10 +1144,6 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs, | |||
1137 | val = be32_to_cpup(mux + index++); | 1144 | val = be32_to_cpup(mux + index++); |
1138 | vals[found].reg = pcs->base + offset; | 1145 | vals[found].reg = pcs->base + offset; |
1139 | vals[found].val = val; | 1146 | vals[found].val = val; |
1140 | if (params == 3) { | ||
1141 | val = be32_to_cpup(mux + index++); | ||
1142 | vals[found].mask = val; | ||
1143 | } | ||
1144 | 1147 | ||
1145 | pin = pcs_get_pin_by_offset(pcs, offset); | 1148 | pin = pcs_get_pin_by_offset(pcs, offset); |
1146 | if (pin < 0) { | 1149 | if (pin < 0) { |
@@ -1189,6 +1192,125 @@ free_vals: | |||
1189 | 1192 | ||
1190 | return res; | 1193 | return res; |
1191 | } | 1194 | } |
1195 | |||
1196 | #define PARAMS_FOR_BITS_PER_MUX 3 | ||
1197 | |||
1198 | static int pcs_parse_bits_in_pinctrl_entry(struct pcs_device *pcs, | ||
1199 | struct device_node *np, | ||
1200 | struct pinctrl_map **map, | ||
1201 | unsigned *num_maps, | ||
1202 | const char **pgnames) | ||
1203 | { | ||
1204 | struct pcs_func_vals *vals; | ||
1205 | const __be32 *mux; | ||
1206 | int size, rows, *pins, index = 0, found = 0, res = -ENOMEM; | ||
1207 | int npins_in_row; | ||
1208 | struct pcs_function *function; | ||
1209 | |||
1210 | mux = of_get_property(np, PCS_MUX_BITS_NAME, &size); | ||
1211 | |||
1212 | if (!mux) { | ||
1213 | dev_err(pcs->dev, "no valid property for %s\n", np->name); | ||
1214 | return -EINVAL; | ||
1215 | } | ||
1216 | |||
1217 | if (size < (sizeof(*mux) * PARAMS_FOR_BITS_PER_MUX)) { | ||
1218 | dev_err(pcs->dev, "bad data for %s\n", np->name); | ||
1219 | return -EINVAL; | ||
1220 | } | ||
1221 | |||
1222 | /* Number of elements in array */ | ||
1223 | size /= sizeof(*mux); | ||
1224 | |||
1225 | rows = size / PARAMS_FOR_BITS_PER_MUX; | ||
1226 | npins_in_row = pcs->width / pcs->bits_per_pin; | ||
1227 | |||
1228 | vals = devm_kzalloc(pcs->dev, sizeof(*vals) * rows * npins_in_row, | ||
1229 | GFP_KERNEL); | ||
1230 | if (!vals) | ||
1231 | return -ENOMEM; | ||
1232 | |||
1233 | pins = devm_kzalloc(pcs->dev, sizeof(*pins) * rows * npins_in_row, | ||
1234 | GFP_KERNEL); | ||
1235 | if (!pins) | ||
1236 | goto free_vals; | ||
1237 | |||
1238 | while (index < size) { | ||
1239 | unsigned offset, val; | ||
1240 | unsigned mask, bit_pos, val_pos, mask_pos, submask; | ||
1241 | unsigned pin_num_from_lsb; | ||
1242 | int pin; | ||
1243 | |||
1244 | offset = be32_to_cpup(mux + index++); | ||
1245 | val = be32_to_cpup(mux + index++); | ||
1246 | mask = be32_to_cpup(mux + index++); | ||
1247 | |||
1248 | /* Parse pins in each row from LSB */ | ||
1249 | while (mask) { | ||
1250 | bit_pos = ffs(mask); | ||
1251 | pin_num_from_lsb = bit_pos / pcs->bits_per_pin; | ||
1252 | mask_pos = ((pcs->fmask) << (bit_pos - 1)); | ||
1253 | val_pos = val & mask_pos; | ||
1254 | submask = mask & mask_pos; | ||
1255 | mask &= ~mask_pos; | ||
1256 | |||
1257 | if (submask != mask_pos) { | ||
1258 | dev_warn(pcs->dev, | ||
1259 | "Invalid submask 0x%x for %s at 0x%x\n", | ||
1260 | submask, np->name, offset); | ||
1261 | continue; | ||
1262 | } | ||
1263 | |||
1264 | vals[found].mask = submask; | ||
1265 | vals[found].reg = pcs->base + offset; | ||
1266 | vals[found].val = val_pos; | ||
1267 | |||
1268 | pin = pcs_get_pin_by_offset(pcs, offset); | ||
1269 | if (pin < 0) { | ||
1270 | dev_err(pcs->dev, | ||
1271 | "could not add functions for %s %ux\n", | ||
1272 | np->name, offset); | ||
1273 | break; | ||
1274 | } | ||
1275 | pins[found++] = pin + pin_num_from_lsb; | ||
1276 | } | ||
1277 | } | ||
1278 | |||
1279 | pgnames[0] = np->name; | ||
1280 | function = pcs_add_function(pcs, np, np->name, vals, found, pgnames, 1); | ||
1281 | if (!function) | ||
1282 | goto free_pins; | ||
1283 | |||
1284 | res = pcs_add_pingroup(pcs, np, np->name, pins, found); | ||
1285 | if (res < 0) | ||
1286 | goto free_function; | ||
1287 | |||
1288 | (*map)->type = PIN_MAP_TYPE_MUX_GROUP; | ||
1289 | (*map)->data.mux.group = np->name; | ||
1290 | (*map)->data.mux.function = np->name; | ||
1291 | |||
1292 | if (pcs->is_pinconf) { | ||
1293 | dev_err(pcs->dev, "pinconf not supported\n"); | ||
1294 | goto free_pingroups; | ||
1295 | } | ||
1296 | |||
1297 | *num_maps = 1; | ||
1298 | return 0; | ||
1299 | |||
1300 | free_pingroups: | ||
1301 | pcs_free_pingroups(pcs); | ||
1302 | *num_maps = 1; | ||
1303 | free_function: | ||
1304 | pcs_remove_function(pcs, function); | ||
1305 | |||
1306 | free_pins: | ||
1307 | devm_kfree(pcs->dev, pins); | ||
1308 | |||
1309 | free_vals: | ||
1310 | devm_kfree(pcs->dev, vals); | ||
1311 | |||
1312 | return res; | ||
1313 | } | ||
1192 | /** | 1314 | /** |
1193 | * pcs_dt_node_to_map() - allocates and parses pinctrl maps | 1315 | * pcs_dt_node_to_map() - allocates and parses pinctrl maps |
1194 | * @pctldev: pinctrl instance | 1316 | * @pctldev: pinctrl instance |
@@ -1219,12 +1341,22 @@ static int pcs_dt_node_to_map(struct pinctrl_dev *pctldev, | |||
1219 | goto free_map; | 1341 | goto free_map; |
1220 | } | 1342 | } |
1221 | 1343 | ||
1222 | ret = pcs_parse_one_pinctrl_entry(pcs, np_config, map, num_maps, | 1344 | if (pcs->bits_per_mux) { |
1223 | pgnames); | 1345 | ret = pcs_parse_bits_in_pinctrl_entry(pcs, np_config, map, |
1224 | if (ret < 0) { | 1346 | num_maps, pgnames); |
1225 | dev_err(pcs->dev, "no pins entries for %s\n", | 1347 | if (ret < 0) { |
1226 | np_config->name); | 1348 | dev_err(pcs->dev, "no pins entries for %s\n", |
1227 | goto free_pgnames; | 1349 | np_config->name); |
1350 | goto free_pgnames; | ||
1351 | } | ||
1352 | } else { | ||
1353 | ret = pcs_parse_one_pinctrl_entry(pcs, np_config, map, | ||
1354 | num_maps, pgnames); | ||
1355 | if (ret < 0) { | ||
1356 | dev_err(pcs->dev, "no pins entries for %s\n", | ||
1357 | np_config->name); | ||
1358 | goto free_pgnames; | ||
1359 | } | ||
1228 | } | 1360 | } |
1229 | 1361 | ||
1230 | return 0; | 1362 | return 0; |