Changeset 39338


Ignore:
Timestamp:
2014-01-20T11:22:56+01:00 (4 years ago)
Author:
juhosg
Message:

generic: ar8216: add custom LED support for the AR8327 switch

Signed-off-by: Gabor Juhos <juhosg@…>

Location:
trunk/target/linux/generic/files
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/target/linux/generic/files/drivers/net/phy/ar8216.c

    r39337 r39338  
    3535#include <linux/workqueue.h> 
    3636#include <linux/of_device.h> 
     37#include <linux/leds.h> 
     38#include <linux/gpio.h> 
    3739 
    3840#include "ar8216.h" 
     
    8385}; 
    8486 
     87enum ar8327_led_pattern { 
     88        AR8327_LED_PATTERN_OFF = 0, 
     89        AR8327_LED_PATTERN_BLINK, 
     90        AR8327_LED_PATTERN_ON, 
     91        AR8327_LED_PATTERN_RULE, 
     92}; 
     93 
     94struct ar8327_led_entry { 
     95        unsigned reg; 
     96        unsigned shift; 
     97}; 
     98 
     99struct ar8327_led { 
     100        struct led_classdev cdev; 
     101        struct ar8xxx_priv *sw_priv; 
     102 
     103        char *name; 
     104        bool active_low; 
     105        u8 led_num; 
     106        enum ar8327_led_mode mode; 
     107 
     108        struct mutex mutex; 
     109        spinlock_t lock; 
     110        struct work_struct led_work; 
     111        bool enable_hw_mode; 
     112        enum ar8327_led_pattern pattern; 
     113}; 
     114 
    85115struct ar8327_data { 
    86116        u32 port0_status; 
    87117        u32 port6_status; 
     118 
     119        struct ar8327_led **leds; 
     120        unsigned int num_leds; 
    88121}; 
    89122 
     
    10911124} 
    10921125 
     1126#define AR8327_LED_ENTRY(_num, _reg, _shift) \ 
     1127        [_num] = { .reg = (_reg), .shift = (_shift) } 
     1128 
     1129static const struct ar8327_led_entry 
     1130ar8327_led_map[AR8327_NUM_LEDS] = { 
     1131        AR8327_LED_ENTRY(AR8327_LED_PHY0_0, 0, 14), 
     1132        AR8327_LED_ENTRY(AR8327_LED_PHY0_1, 1, 14), 
     1133        AR8327_LED_ENTRY(AR8327_LED_PHY0_2, 2, 14), 
     1134 
     1135        AR8327_LED_ENTRY(AR8327_LED_PHY1_0, 3, 8), 
     1136        AR8327_LED_ENTRY(AR8327_LED_PHY1_1, 3, 10), 
     1137        AR8327_LED_ENTRY(AR8327_LED_PHY1_2, 3, 12), 
     1138 
     1139        AR8327_LED_ENTRY(AR8327_LED_PHY2_0, 3, 14), 
     1140        AR8327_LED_ENTRY(AR8327_LED_PHY2_1, 3, 16), 
     1141        AR8327_LED_ENTRY(AR8327_LED_PHY2_2, 3, 18), 
     1142 
     1143        AR8327_LED_ENTRY(AR8327_LED_PHY3_0, 3, 20), 
     1144        AR8327_LED_ENTRY(AR8327_LED_PHY3_1, 3, 22), 
     1145        AR8327_LED_ENTRY(AR8327_LED_PHY3_2, 3, 24), 
     1146 
     1147        AR8327_LED_ENTRY(AR8327_LED_PHY4_0, 0, 30), 
     1148        AR8327_LED_ENTRY(AR8327_LED_PHY4_1, 1, 30), 
     1149        AR8327_LED_ENTRY(AR8327_LED_PHY4_2, 2, 30), 
     1150}; 
     1151 
     1152static void 
     1153ar8327_set_led_pattern(struct ar8xxx_priv *priv, unsigned int led_num, 
     1154                       enum ar8327_led_pattern pattern) 
     1155{ 
     1156        const struct ar8327_led_entry *entry; 
     1157 
     1158        entry = &ar8327_led_map[led_num]; 
     1159        ar8xxx_rmw(priv, AR8327_REG_LED_CTRL(entry->reg), 
     1160                   (3 << entry->shift), pattern << entry->shift); 
     1161} 
     1162 
     1163static void 
     1164ar8327_led_work_func(struct work_struct *work) 
     1165{ 
     1166        struct ar8327_led *aled; 
     1167        u8 pattern; 
     1168 
     1169        aled = container_of(work, struct ar8327_led, led_work); 
     1170 
     1171        spin_lock(&aled->lock); 
     1172        pattern = aled->pattern; 
     1173        spin_unlock(&aled->lock); 
     1174 
     1175        ar8327_set_led_pattern(aled->sw_priv, aled->led_num, 
     1176                               pattern); 
     1177} 
     1178 
     1179static void 
     1180ar8327_led_schedule_change(struct ar8327_led *aled, u8 pattern) 
     1181{ 
     1182        if (aled->pattern == pattern) 
     1183                return; 
     1184 
     1185        aled->pattern = pattern; 
     1186        schedule_work(&aled->led_work); 
     1187} 
     1188 
     1189static inline struct ar8327_led * 
     1190led_cdev_to_ar8327_led(struct led_classdev *led_cdev) 
     1191{ 
     1192        return container_of(led_cdev, struct ar8327_led, cdev); 
     1193} 
     1194 
     1195static int 
     1196ar8327_led_blink_set(struct led_classdev *led_cdev, 
     1197                     unsigned long *delay_on, 
     1198                     unsigned long *delay_off) 
     1199{ 
     1200        struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev); 
     1201 
     1202        if (*delay_on == 0 && *delay_off == 0) { 
     1203                *delay_on = 125; 
     1204                *delay_off = 125; 
     1205        } 
     1206 
     1207        if (*delay_on != 125 || *delay_off != 125) { 
     1208                /* 
     1209                 * The hardware only supports blinking at 4Hz. Fall back 
     1210                 * to software implementation in other cases. 
     1211                 */ 
     1212                return -EINVAL; 
     1213        } 
     1214 
     1215        spin_lock(&aled->lock); 
     1216 
     1217        aled->enable_hw_mode = false; 
     1218        ar8327_led_schedule_change(aled, AR8327_LED_PATTERN_BLINK); 
     1219 
     1220        spin_unlock(&aled->lock); 
     1221 
     1222        return 0; 
     1223} 
     1224 
     1225static void 
     1226ar8327_led_set_brightness(struct led_classdev *led_cdev, 
     1227                          enum led_brightness brightness) 
     1228{ 
     1229        struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev); 
     1230        u8 pattern; 
     1231        bool active; 
     1232 
     1233        active = (brightness != LED_OFF); 
     1234        active ^= aled->active_low; 
     1235 
     1236        pattern = (active) ? AR8327_LED_PATTERN_ON : 
     1237                             AR8327_LED_PATTERN_OFF; 
     1238 
     1239        spin_lock(&aled->lock); 
     1240 
     1241        aled->enable_hw_mode = false; 
     1242        ar8327_led_schedule_change(aled, pattern); 
     1243 
     1244        spin_unlock(&aled->lock); 
     1245} 
     1246 
     1247static ssize_t 
     1248ar8327_led_enable_hw_mode_show(struct device *dev, 
     1249                               struct device_attribute *attr, 
     1250                               char *buf) 
     1251{ 
     1252        struct led_classdev *led_cdev = dev_get_drvdata(dev); 
     1253        struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev); 
     1254        ssize_t ret = 0; 
     1255 
     1256        spin_lock(&aled->lock); 
     1257        ret += sprintf(buf, "%d\n", aled->enable_hw_mode); 
     1258        spin_unlock(&aled->lock); 
     1259 
     1260        return ret; 
     1261} 
     1262 
     1263static ssize_t 
     1264ar8327_led_enable_hw_mode_store(struct device *dev, 
     1265                                struct device_attribute *attr, 
     1266                                const char *buf, 
     1267                                size_t size) 
     1268{ 
     1269        struct led_classdev *led_cdev = dev_get_drvdata(dev); 
     1270        struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev); 
     1271        u8 pattern; 
     1272        u8 value; 
     1273        int ret; 
     1274 
     1275        ret = kstrtou8(buf, 10, &value); 
     1276        if (ret < 0) 
     1277                return -EINVAL; 
     1278 
     1279        spin_lock(&aled->lock); 
     1280 
     1281        aled->enable_hw_mode = !!value; 
     1282        if (aled->enable_hw_mode) 
     1283                pattern = AR8327_LED_PATTERN_RULE; 
     1284        else 
     1285                pattern = AR8327_LED_PATTERN_OFF; 
     1286 
     1287        ar8327_led_schedule_change(aled, pattern); 
     1288 
     1289        spin_unlock(&aled->lock); 
     1290 
     1291        return size; 
     1292} 
     1293 
     1294static DEVICE_ATTR(enable_hw_mode,  S_IRUGO | S_IWUSR, 
     1295                   ar8327_led_enable_hw_mode_show, 
     1296                   ar8327_led_enable_hw_mode_store); 
     1297 
     1298static int 
     1299ar8327_led_register(struct ar8xxx_priv *priv, struct ar8327_led *aled) 
     1300{ 
     1301        int ret; 
     1302 
     1303        ret = led_classdev_register(NULL, &aled->cdev); 
     1304        if (ret < 0) 
     1305                return ret; 
     1306 
     1307        if (aled->mode == AR8327_LED_MODE_HW) { 
     1308                ret = device_create_file(aled->cdev.dev, 
     1309                                         &dev_attr_enable_hw_mode); 
     1310                if (ret) 
     1311                        goto err_unregister; 
     1312        } 
     1313 
     1314        return 0; 
     1315 
     1316err_unregister: 
     1317        led_classdev_unregister(&aled->cdev); 
     1318        return ret; 
     1319} 
     1320 
     1321static void 
     1322ar8327_led_unregister(struct ar8327_led *aled) 
     1323{ 
     1324        if (aled->mode == AR8327_LED_MODE_HW) 
     1325                device_remove_file(aled->cdev.dev, &dev_attr_enable_hw_mode); 
     1326 
     1327        led_classdev_unregister(&aled->cdev); 
     1328        cancel_work_sync(&aled->led_work); 
     1329} 
     1330 
     1331static int 
     1332ar8327_led_create(struct ar8xxx_priv *priv, 
     1333                  const struct ar8327_led_info *led_info) 
     1334{ 
     1335        struct ar8327_data *data = &priv->chip_data.ar8327; 
     1336        struct ar8327_led *aled; 
     1337        int ret; 
     1338 
     1339        if (!IS_ENABLED(CONFIG_AR8216_PHY_LEDS)) 
     1340                return 0; 
     1341 
     1342        if (!led_info->name) 
     1343                return -EINVAL; 
     1344 
     1345        if (led_info->led_num >= AR8327_NUM_LEDS) 
     1346                return -EINVAL; 
     1347 
     1348        aled = kzalloc(sizeof(*aled) + strlen(led_info->name) + 1, 
     1349                       GFP_KERNEL); 
     1350        if (!aled) 
     1351                return -ENOMEM; 
     1352 
     1353        aled->sw_priv = priv; 
     1354        aled->led_num = led_info->led_num; 
     1355        aled->active_low = led_info->active_low; 
     1356        aled->mode = led_info->mode; 
     1357 
     1358        if (aled->mode == AR8327_LED_MODE_HW) 
     1359                aled->enable_hw_mode = true; 
     1360 
     1361        aled->name = (char *)(aled + 1); 
     1362        strcpy(aled->name, led_info->name); 
     1363 
     1364        aled->cdev.name = aled->name; 
     1365        aled->cdev.brightness_set = ar8327_led_set_brightness; 
     1366        aled->cdev.blink_set = ar8327_led_blink_set; 
     1367        aled->cdev.default_trigger = led_info->default_trigger; 
     1368 
     1369        spin_lock_init(&aled->lock); 
     1370        mutex_init(&aled->mutex); 
     1371        INIT_WORK(&aled->led_work, ar8327_led_work_func); 
     1372 
     1373        ret = ar8327_led_register(priv, aled); 
     1374        if (ret) 
     1375                goto err_free; 
     1376 
     1377        data->leds[data->num_leds++] = aled; 
     1378 
     1379        return 0; 
     1380 
     1381err_free: 
     1382        kfree(aled); 
     1383        return ret; 
     1384} 
     1385 
     1386static void 
     1387ar8327_led_destroy(struct ar8327_led *aled) 
     1388{ 
     1389        ar8327_led_unregister(aled); 
     1390        kfree(aled); 
     1391} 
     1392 
     1393static void 
     1394ar8327_leds_init(struct ar8xxx_priv *priv) 
     1395{ 
     1396        struct ar8327_data *data; 
     1397        unsigned i; 
     1398 
     1399        if (!IS_ENABLED(CONFIG_AR8216_PHY_LEDS)) 
     1400                return; 
     1401 
     1402        data = &priv->chip_data.ar8327; 
     1403 
     1404        for (i = 0; i < data->num_leds; i++) { 
     1405                struct ar8327_led *aled; 
     1406 
     1407                aled = data->leds[i]; 
     1408 
     1409                if (aled->enable_hw_mode) 
     1410                        aled->pattern = AR8327_LED_PATTERN_RULE; 
     1411                else 
     1412                        aled->pattern = AR8327_LED_PATTERN_OFF; 
     1413 
     1414                ar8327_set_led_pattern(priv, aled->led_num, aled->pattern); 
     1415        } 
     1416} 
     1417 
     1418static void 
     1419ar8327_leds_cleanup(struct ar8xxx_priv *priv) 
     1420{ 
     1421        struct ar8327_data *data = &priv->chip_data.ar8327; 
     1422        unsigned i; 
     1423 
     1424        if (!IS_ENABLED(CONFIG_AR8216_PHY_LEDS)) 
     1425                return; 
     1426 
     1427        for (i = 0; i < data->num_leds; i++) { 
     1428                struct ar8327_led *aled; 
     1429 
     1430                aled = data->leds[i]; 
     1431                ar8327_led_destroy(aled); 
     1432        } 
     1433 
     1434        kfree(data->leds); 
     1435} 
     1436 
    10931437static int 
    10941438ar8327_hw_config_pdata(struct ar8xxx_priv *priv, 
     
    11591503 
    11601504        priv->write(priv, AR8327_REG_POWER_ON_STRIP, new_pos); 
     1505 
     1506        if (pdata->leds && pdata->num_leds) { 
     1507                int i; 
     1508 
     1509                data->leds = kzalloc(pdata->num_leds * sizeof(void *), 
     1510                                     GFP_KERNEL); 
     1511                if (!data->leds) 
     1512                        return -ENOMEM; 
     1513 
     1514                for (i = 0; i < pdata->num_leds; i++) 
     1515                        ar8327_led_create(priv, &pdata->leds[i]); 
     1516        } 
    11611517 
    11621518        return 0; 
     
    12231579                return ret; 
    12241580 
     1581        ar8327_leds_init(priv); 
     1582 
    12251583        bus = priv->mii_bus; 
    12261584        for (i = 0; i < AR8327_NUM_PHYS; i++) { 
     
    12381596 
    12391597        return 0; 
     1598} 
     1599 
     1600static void 
     1601ar8327_cleanup(struct ar8xxx_priv *priv) 
     1602{ 
     1603        ar8327_leds_cleanup(priv); 
    12401604} 
    12411605 
     
    13961760        .caps = AR8XXX_CAP_GIGE | AR8XXX_CAP_MIB_COUNTERS, 
    13971761        .hw_init = ar8327_hw_init, 
     1762        .cleanup = ar8327_cleanup, 
    13981763        .init_globals = ar8327_init_globals, 
    13991764        .init_port = ar8327_init_port, 
  • trunk/target/linux/generic/files/drivers/net/phy/ar8216.h

    r38952 r39338  
    291291 
    292292#define AR8327_NUM_PORTS        7 
     293#define AR8327_NUM_LEDS         15 
    293294#define AR8327_NUM_PHYS         5 
    294295#define AR8327_PORTS_ALL        0x7f 
     296#define AR8327_NUM_LED_CTRL_REGS        4 
    295297 
    296298#define AR8327_REG_MASK                         0x000 
     
    344346 
    345347#define AR8327_REG_SERVICE_TAG                  0x048 
     348#define AR8327_REG_LED_CTRL(_i)                 (0x050 + (_i) * 4) 
    346349#define AR8327_REG_LED_CTRL0                    0x050 
    347350#define AR8327_REG_LED_CTRL1                    0x054 
  • trunk/target/linux/generic/files/include/linux/ar8216_platform.h

    r36798 r39338  
    7777}; 
    7878 
     79enum ar8327_led_num { 
     80        AR8327_LED_PHY0_0 = 0, 
     81        AR8327_LED_PHY0_1, 
     82        AR8327_LED_PHY0_2, 
     83        AR8327_LED_PHY1_0, 
     84        AR8327_LED_PHY1_1, 
     85        AR8327_LED_PHY1_2, 
     86        AR8327_LED_PHY2_0, 
     87        AR8327_LED_PHY2_1, 
     88        AR8327_LED_PHY2_2, 
     89        AR8327_LED_PHY3_0, 
     90        AR8327_LED_PHY3_1, 
     91        AR8327_LED_PHY3_2, 
     92        AR8327_LED_PHY4_0, 
     93        AR8327_LED_PHY4_1, 
     94        AR8327_LED_PHY4_2, 
     95}; 
     96 
     97enum ar8327_led_mode { 
     98        AR8327_LED_MODE_HW = 0, 
     99        AR8327_LED_MODE_SW, 
     100}; 
     101 
     102struct ar8327_led_info { 
     103        const char *name; 
     104        const char *default_trigger; 
     105        bool active_low; 
     106        enum ar8327_led_num led_num; 
     107        enum ar8327_led_mode mode; 
     108}; 
     109 
     110#define AR8327_LED_INFO(_led, _mode, _name) {   \ 
     111        .name = (_name),                        \ 
     112        .led_num = AR8327_LED_ ## _led,         \ 
     113        .mode = AR8327_LED_MODE_ ## _mode       \ 
     114} 
     115 
    79116struct ar8327_platform_data { 
    80117        struct ar8327_pad_cfg *pad0_cfg; 
     
    87124 
    88125        int (*get_port_link)(unsigned port); 
     126 
     127        unsigned num_leds; 
     128        const struct ar8327_led_info *leds; 
    89129}; 
    90130 
Note: See TracChangeset for help on using the changeset viewer.